https://github.com/snarang181 updated https://github.com/llvm/llvm-project/pull/145166
>From 359dfb1a835617a83ae13865817480e68aa67750 Mon Sep 17 00:00:00 2001 From: Samarth Narang <snar...@umass.edu> Date: Sat, 21 Jun 2025 08:42:00 -0400 Subject: [PATCH 1/2] Suppress noreturn warning if last statement in a function is a throw --- clang/lib/Sema/AnalysisBasedWarnings.cpp | 45 ++++++++++++++++++++ clang/test/SemaCXX/wreturn-always-throws.cpp | 22 ++++++++++ 2 files changed, 67 insertions(+) create mode 100644 clang/test/SemaCXX/wreturn-always-throws.cpp diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 2a107a36e24b4..85a5d99c710d5 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -626,6 +626,31 @@ struct CheckFallThroughDiagnostics { } // anonymous namespace +static bool isKnownToAlwaysThrow(const FunctionDecl *FD) { + if (!FD->hasBody()) + return false; + const Stmt *Body = FD->getBody(); + const Stmt *OnlyStmt = nullptr; + + if (const auto *Compound = dyn_cast<CompoundStmt>(Body)) { + if (Compound->size() != 1) + return false; // More than one statement, can't be known to always throw. + OnlyStmt = *Compound->body_begin(); + } else { + OnlyStmt = Body; + } + + // Unwrap ExprWithCleanups if necessary. + if (const auto *EWC = dyn_cast<ExprWithCleanups>(OnlyStmt)) { + OnlyStmt = EWC->getSubExpr(); + } + // Check if the only statement is a throw expression. + if (isa<CXXThrowExpr>(OnlyStmt)) { + return true; // Known to always throw. + } + return false; // Not known to always throw. +} + /// CheckFallThroughForBody - Check that we don't fall off the end of a /// function that should return a value. Check that we don't fall off the end /// of a noreturn function. We assume that functions and blocks not marked @@ -681,6 +706,26 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, if (CD.diag_FallThrough_HasNoReturn) S.Diag(RBrace, CD.diag_FallThrough_HasNoReturn) << CD.FunKind; } else if (!ReturnsVoid && CD.diag_FallThrough_ReturnsNonVoid) { + // If the final statement is a call to an always-throwing function, + // don't warn about the fall-through. + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *CS = dyn_cast<CompoundStmt>(Body)) { + if (!CS->body_empty()) { + const Stmt *LastStmt = CS->body_back(); + // Unwrap ExprWithCleanups if necessary. + if (const auto *EWC = dyn_cast<ExprWithCleanups>(LastStmt)) { + LastStmt = EWC->getSubExpr(); + } + if (const auto *CE = dyn_cast<CallExpr>(LastStmt)) { + if (const FunctionDecl *Callee = CE->getDirectCallee()) { + if (isKnownToAlwaysThrow(Callee)) { + return; // Don't warn about fall-through. + } + } + } + } + } + } bool NotInAllControlPaths = FallThroughType == MaybeFallThrough; S.Diag(RBrace, CD.diag_FallThrough_ReturnsNonVoid) << CD.FunKind << NotInAllControlPaths; diff --git a/clang/test/SemaCXX/wreturn-always-throws.cpp b/clang/test/SemaCXX/wreturn-always-throws.cpp new file mode 100644 index 0000000000000..0bbce0f5c1871 --- /dev/null +++ b/clang/test/SemaCXX/wreturn-always-throws.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wreturn-type -verify %s +// expected-no-diagnostics + +namespace std { + class string { + public: + string(const char*); // constructor for runtime_error + }; + class runtime_error { + public: + runtime_error(const string &); + }; +} + +void throwError(const std::string& msg) { + throw std::runtime_error(msg); +} + +int ensureZero(const int i) { + if (i == 0) return 0; + throwError("ERROR"); // no-warning +} >From 1009d62354fae31724da3f4d8c44367c7d66281b Mon Sep 17 00:00:00 2001 From: Samarth Narang <70980689+snarang...@users.noreply.github.com> Date: Sat, 21 Jun 2025 11:05:17 -0400 Subject: [PATCH 2/2] Update clang/lib/Sema/AnalysisBasedWarnings.cpp Co-authored-by: Copilot <175728472+copi...@users.noreply.github.com> --- clang/lib/Sema/AnalysisBasedWarnings.cpp | 47 ++++++++++++------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 85a5d99c710d5..6d54282c9f0e5 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -624,33 +624,32 @@ struct CheckFallThroughDiagnostics { } }; -} // anonymous namespace - -static bool isKnownToAlwaysThrow(const FunctionDecl *FD) { - if (!FD->hasBody()) - return false; - const Stmt *Body = FD->getBody(); - const Stmt *OnlyStmt = nullptr; - - if (const auto *Compound = dyn_cast<CompoundStmt>(Body)) { - if (Compound->size() != 1) - return false; // More than one statement, can't be known to always throw. - OnlyStmt = *Compound->body_begin(); - } else { - OnlyStmt = Body; - } + bool isKnownToAlwaysThrow(const FunctionDecl *FD) { + if (!FD->hasBody()) + return false; + const Stmt *Body = FD->getBody(); + const Stmt *OnlyStmt = nullptr; + + if (const auto *Compound = dyn_cast<CompoundStmt>(Body)) { + if (Compound->size() != 1) + return false; // More than one statement, can't be known to always throw. + OnlyStmt = *Compound->body_begin(); + } else { + OnlyStmt = Body; + } - // Unwrap ExprWithCleanups if necessary. - if (const auto *EWC = dyn_cast<ExprWithCleanups>(OnlyStmt)) { - OnlyStmt = EWC->getSubExpr(); - } - // Check if the only statement is a throw expression. - if (isa<CXXThrowExpr>(OnlyStmt)) { - return true; // Known to always throw. + // Unwrap ExprWithCleanups if necessary. + if (const auto *EWC = dyn_cast<ExprWithCleanups>(OnlyStmt)) { + OnlyStmt = EWC->getSubExpr(); + } + // Check if the only statement is a throw expression. + if (isa<CXXThrowExpr>(OnlyStmt)) { + return true; // Known to always throw. + } + return false; // Not known to always throw. } - return false; // Not known to always throw. -} +} // anonymous namespace /// CheckFallThroughForBody - Check that we don't fall off the end of a /// function that should return a value. Check that we don't fall off the end /// of a noreturn function. We assume that functions and blocks not marked _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits