https://github.com/berkaysahiin updated https://github.com/llvm/llvm-project/pull/185202
>From 9fd4db3e3ca72eccca786f26e58e4b67d5f0ecdc Mon Sep 17 00:00:00 2001 From: Berkay <[email protected]> Date: Sat, 7 Mar 2026 19:37:50 +0300 Subject: [PATCH 1/4] [clang-tidy] extend readability-else-after-return to remove else after calls to [[noreturn]] functions --- .../readability/ElseAfterReturnCheck.cpp | 22 ++++++++++++++++++- clang-tools-extra/docs/ReleaseNotes.rst | 9 ++++++-- .../readability/else-after-return.cpp | 12 ++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp index 7e93d619e2a9f..4160f0fcf1dc1 100644 --- a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp @@ -39,6 +39,23 @@ class PPConditionalCollector : public PPCallbacks { const SourceManager &SM; }; +bool isNoReturnStmt(const Stmt &Stmt) { + const auto *Call = dyn_cast<CallExpr>(&Stmt); + if (!Call) + return false; + + const FunctionDecl *Func = Call->getDirectCallee(); + if (!Func) + return false; + + return Func->isNoReturn(); +} + +AST_MATCHER(Stmt, isNoReturnStmt) { + const Stmt &S = Node; + return isNoReturnStmt(S); +} + AST_MATCHER_P(Stmt, stripLabelLikeStatements, ast_matchers::internal::Matcher<Stmt>, InnerMatcher) { const Stmt *S = Node.stripLabelLikeStatements(); @@ -174,7 +191,8 @@ void ElseAfterReturnCheck::registerPPCallbacks(const SourceManager &SM, void ElseAfterReturnCheck::registerMatchers(MatchFinder *Finder) { const auto InterruptsControlFlow = stmt(anyOf( returnStmt().bind(InterruptingStr), continueStmt().bind(InterruptingStr), - breakStmt().bind(InterruptingStr), cxxThrowExpr().bind(InterruptingStr))); + breakStmt().bind(InterruptingStr), cxxThrowExpr().bind(InterruptingStr), + stmt(isNoReturnStmt()).bind(InterruptingStr))); const auto IfWithInterruptingThenElse = ifStmt(unless(isConstexpr()), unless(isConsteval()), @@ -237,6 +255,8 @@ static StringRef getControlFlowString(const Stmt &Stmt) { return "break"; if (isa<CXXThrowExpr>(Stmt)) return "throw"; + if (isNoReturnStmt(Stmt)) + return "noreturn"; llvm_unreachable("Unknown control flow interrupter"); } diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index b0b4cd646c3bd..33437d2004079 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -295,8 +295,13 @@ Changes in existing checks when a member expression has a non-identifier name. - Improved :doc:`readability-else-after-return - <clang-tidy/checks/readability/else-after-return>` check by fixing missed - diagnostics when ``if`` statements appear in unbraced ``switch`` case labels. + <clang-tidy/checks/readability/else-after-return>` check: + + - Fixed missed diagnostics when ``if`` statements appear in unbraced + ``switch`` case labels. + + - Diagnose and remove redundant ``else`` branches after calls to + ``[[noreturn]]`` functions. - Improved :doc:`readability-enum-initial-value <clang-tidy/checks/readability/enum-initial-value>` check: the warning message diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return.cpp index e987687a764cd..f0788dbf3221b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return.cpp @@ -438,3 +438,15 @@ void testLabels(bool b) { f(0); } } + +[[noreturn]] void noReturn(); + +void testNoReturn() { + if (true) { + noReturn(); + } else { // comment-28 + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'noreturn' + // CHECK-FIXES: {{^}} } // comment-28 + f(0); + } +} >From 68d5017a4f90bd14c555b6d47684427dfcd0f73a Mon Sep 17 00:00:00 2001 From: Berkay <[email protected]> Date: Sat, 7 Mar 2026 20:14:02 +0300 Subject: [PATCH 2/4] [clang-tidy] supress the linter --- .../clang-tidy/readability/ElseAfterReturnCheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp index 4160f0fcf1dc1..d4cb863eb9645 100644 --- a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp @@ -39,7 +39,7 @@ class PPConditionalCollector : public PPCallbacks { const SourceManager &SM; }; -bool isNoReturnStmt(const Stmt &Stmt) { +bool isNoReturnStmt(const Stmt &Stmt) { // NOLINT const auto *Call = dyn_cast<CallExpr>(&Stmt); if (!Call) return false; >From 512f99ee87536c9faaea5e0238c4d1a64c75dcff Mon Sep 17 00:00:00 2001 From: Berkay <[email protected]> Date: Tue, 10 Mar 2026 01:12:44 +0300 Subject: [PATCH 3/4] Removes custom matcher & Updates warning messages --- .../readability/ElseAfterReturnCheck.cpp | 43 ++++++++----------- .../readability/else-after-return.cpp | 15 ++++++- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp index d4cb863eb9645..4e62236a80920 100644 --- a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp @@ -39,23 +39,6 @@ class PPConditionalCollector : public PPCallbacks { const SourceManager &SM; }; -bool isNoReturnStmt(const Stmt &Stmt) { // NOLINT - const auto *Call = dyn_cast<CallExpr>(&Stmt); - if (!Call) - return false; - - const FunctionDecl *Func = Call->getDirectCallee(); - if (!Func) - return false; - - return Func->isNoReturn(); -} - -AST_MATCHER(Stmt, isNoReturnStmt) { - const Stmt &S = Node; - return isNoReturnStmt(S); -} - AST_MATCHER_P(Stmt, stripLabelLikeStatements, ast_matchers::internal::Matcher<Stmt>, InnerMatcher) { const Stmt *S = Node.stripLabelLikeStatements(); @@ -65,7 +48,7 @@ AST_MATCHER_P(Stmt, stripLabelLikeStatements, } // namespace static constexpr char InterruptingStr[] = "interrupting"; -static constexpr char WarningMessage[] = "do not use 'else' after '%0'"; +static constexpr char WarningMessage[] = "do not use 'else' after %0"; static constexpr char WarnOnUnfixableStr[] = "WarnOnUnfixable"; static constexpr char WarnOnConditionVariablesStr[] = "WarnOnConditionVariables"; @@ -134,6 +117,18 @@ static bool containsDeclInScope(const Stmt *Node) { return false; } +static bool isNoReturnStmt(const Stmt &Stmt) { + const auto *Call = dyn_cast<CallExpr>(&Stmt); + if (!Call) + return false; + + const FunctionDecl *Func = Call->getDirectCallee(); + if (!Func) + return false; + + return Func->isNoReturn(); +} + static void removeElseAndBrackets(DiagnosticBuilder &Diag, ASTContext &Context, const Stmt *Else, SourceLocation ElseLoc) { auto Remap = [&](SourceLocation Loc) { @@ -192,7 +187,7 @@ void ElseAfterReturnCheck::registerMatchers(MatchFinder *Finder) { const auto InterruptsControlFlow = stmt(anyOf( returnStmt().bind(InterruptingStr), continueStmt().bind(InterruptingStr), breakStmt().bind(InterruptingStr), cxxThrowExpr().bind(InterruptingStr), - stmt(isNoReturnStmt()).bind(InterruptingStr))); + callExpr(callee(functionDecl(isNoReturn()))).bind(InterruptingStr))); const auto IfWithInterruptingThenElse = ifStmt(unless(isConstexpr()), unless(isConsteval()), @@ -248,15 +243,15 @@ static bool hasPreprocessorBranchEndBetweenLocations( static StringRef getControlFlowString(const Stmt &Stmt) { if (isa<ReturnStmt>(Stmt)) - return "return"; + return "'return'"; if (isa<ContinueStmt>(Stmt)) - return "continue"; + return "'continue'"; if (isa<BreakStmt>(Stmt)) - return "break"; + return "'break'"; if (isa<CXXThrowExpr>(Stmt)) - return "throw"; + return "'throw'"; if (isNoReturnStmt(Stmt)) - return "noreturn"; + return "calling a function that doesn't return"; llvm_unreachable("Unknown control flow interrupter"); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return.cpp index f0788dbf3221b..1f1ac2151234f 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return.cpp @@ -441,12 +441,25 @@ void testLabels(bool b) { [[noreturn]] void noReturn(); +struct NoReturnMember { + [[noreturn]] void noReturn(); +}; + void testNoReturn() { if (true) { noReturn(); } else { // comment-28 - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'noreturn' + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after calling a function that doesn't return // CHECK-FIXES: {{^}} } // comment-28 f(0); } + + if (true) { + NoReturnMember f; + f.noReturn(); + } else { // comment-29 + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after calling a function that doesn't return + // CHECK-FIXES: {{^}} } // comment-29 + f(0); + } } >From 76dc2ce7c0e0ff6df3d918a9dcf7e057ff8bb754 Mon Sep 17 00:00:00 2001 From: Berkay <[email protected]> Date: Thu, 12 Mar 2026 19:51:49 +0300 Subject: [PATCH 4/4] Removes unused function && Remove whitespaces --- .../readability/ElseAfterReturnCheck.cpp | 15 ++------------- clang-tools-extra/docs/ReleaseNotes.rst | 2 +- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp index baf55797f5d78..91ef0024fe9b9 100644 --- a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp @@ -8,6 +8,7 @@ #include "ElseAfterReturnCheck.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" @@ -117,18 +118,6 @@ static bool containsDeclInScope(const Stmt *Node) { return false; } -static bool isNoReturnStmt(const Stmt &Stmt) { - const auto *Call = dyn_cast<CallExpr>(&Stmt); - if (!Call) - return false; - - const FunctionDecl *Func = Call->getDirectCallee(); - if (!Func) - return false; - - return Func->isNoReturn(); -} - static void removeElseAndBrackets(DiagnosticBuilder &Diag, ASTContext &Context, const Stmt *Else, SourceLocation ElseLoc) { auto Remap = [&](SourceLocation Loc) { @@ -251,7 +240,7 @@ static StringRef getControlFlowString(const Stmt &Stmt) { return "'break'"; if (isa<CXXThrowExpr>(Stmt)) return "'throw'"; - if (isNoReturnStmt(Stmt)) + if (isa<CallExpr>(Stmt)) return "calling a function that doesn't return"; llvm_unreachable("Unknown control flow interrupter"); } diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 18130d2f207eb..ff8d8867cecb2 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -309,7 +309,7 @@ Changes in existing checks - Fixed missed diagnostics when ``if`` statements appear in unbraced ``switch`` case labels. - + - Added support for handling attributed ``if`` then-branches such as ``[[likely]]`` and ``[[unlikely]]``. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
