Index: clang-tidy/readability/ElseAfterReturnCheck.cpp =================================================================== --- clang-tidy/readability/ElseAfterReturnCheck.cpp +++ clang-tidy/readability/ElseAfterReturnCheck.cpp @@ -22,7 +22,9 @@ const auto ControlFlowInterruptorMatcher = stmt(anyOf(returnStmt().bind("return"), continueStmt().bind("continue"), breakStmt().bind("break"), - expr(ignoringImplicit(cxxThrowExpr().bind("throw"))))); + expr(ignoringImplicit(cxxThrowExpr().bind("throw"))), + callExpr(hasDeclaration(functionDecl(isNoReturn()))) + .bind("noreturn call"))); Finder->addMatcher( compoundStmt(forEach( ifStmt(hasThen(stmt( @@ -37,7 +39,8 @@ const auto *If = Result.Nodes.getNodeAs("if"); SourceLocation ElseLoc = If->getElseLoc(); std::string ControlFlowInterruptor; - for (const auto *BindingName : {"return", "continue", "break", "throw"}) + for (const auto *BindingName : + {"return", "continue", "break", "throw", "noreturn call"}) if (Result.Nodes.getNodeAs(BindingName)) ControlFlowInterruptor = BindingName; Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -186,6 +186,8 @@ Finds property declarations in Objective-C files that do not follow the pattern of property names in Apple's programming guide. +- The 'readability-else-after-return' check was adjusted to handle throw expressions that require cleanups, calls to functions marked with noreturn attribute. + - New `readability-static-accessed-through-instance `_ check Index: test/clang-tidy/readability-else-after-return.cpp =================================================================== --- test/clang-tidy/readability-else-after-return.cpp +++ test/clang-tidy/readability-else-after-return.cpp @@ -11,6 +11,28 @@ my_exception(const std::string &s); }; +__attribute__((noreturn)) void my_noreturn(); +[[noreturn]] void my_noreturn2(); +[[noreturn]] __attribute__((noreturn)) void my_noreturn3(); +struct my_struct { + [[noreturn]] static void test(); + [[noreturn]] void test_2(); +}; +struct my_assign { + my_assign(); + [[noreturn]] my_assign& operator=(const my_assign& c); +}; +struct my_copy { + my_copy(); + [[noreturn]] my_copy(const my_copy& c); +}; +struct noreturn_ctor { + [[noreturn]] noreturn_ctor(); +}; +struct noreturn_dtor { + [[noreturn]] noreturn_dtor(); +}; + void f(int a) { if (a > 0) return; @@ -103,5 +125,69 @@ // CHECK-FIXES: {{^}} } // comment-10 x++; } + if (x) { + my_noreturn(); + } else { // comment-11 + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'noreturn call' + // CHECK-FIXES: {{^}} } // comment-11 + x++; + } + if (x) { + my_noreturn2(); + } else { // comment-12 + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'noreturn call' + // CHECK-FIXES: {{^}} } // comment-12 + x++; + } + if (x) { + my_noreturn3(); + } else { // comment-13 + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'noreturn call' + // CHECK-FIXES: {{^}} } // comment-13 + x++; + } + if (x) { + my_struct::test(); + } else { // comment-14 + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'noreturn call' + // CH1ECK-FIXES: {{^}} } // comment-14 + x++; + } + if (x) { + my_struct s; + s.test_2(); + } else { // comment-15 + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'noreturn call' + // CHECK-FIXES: {{^}} } // comment-15 + x++; + } + if (x) { + my_assign a0; + my_assign a1; + a1 = a0; + } else { // comment-16 + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'noreturn call' + // CHECK-FIXES: {{^}} } // comment-16 + x++; + } + if (x) { + // FIXME + my_copy c0; + my_copy c1(c0); + } else { // comment-17 + x++; + } + if (x) { + // FIXME + noreturn_ctor n; + } else { // comment-18 + x++; + } + if (x) { + // FIXME + noreturn_dtor n; + } else { // comment-19 + x++; + } } }