https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/175443
>From 5c9260a48009c1de6ec6439fa3ca7083f070986c Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk <[email protected]> Date: Sun, 11 Jan 2026 17:37:56 +0200 Subject: [PATCH 1/2] [Clang] eliminate -Winvalid-noreturn false positive after throw + unreachable try/catch blocks --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/Analysis/CFG.cpp | 13 ++++++++++-- clang/lib/Sema/AnalysisBasedWarnings.cpp | 21 +------------------ .../Analysis/auto-obj-dtors-cfg-output.cpp | 20 ++++++++++++------ clang/test/Analysis/misc-ps-region-store.cpp | 4 ++-- clang/test/SemaCXX/return-noreturn.cpp | 7 +++++++ 6 files changed, 36 insertions(+), 30 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c4384fcea5504..31cfd05254a60 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -564,6 +564,7 @@ Bug Fixes in This Version - Fixed a crash when parsing malformed #pragma clang loop vectorize_width(4,8,16) by diagnosing invalid comma-separated argument lists. (#GH166325) - Clang now treats enumeration constants of fixed-underlying enums as the enumerated type. (#GH172118) +- Fixed a ``-Winvalid-noreturn`` false positive for unreachable ``try`` blocks following an unconditional ``throw``. (#GH174822) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index f8a2afec79700..4531cbc29f338 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -4740,11 +4740,20 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { // Save the current "try" context. SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock); - cfg->addTryDispatchBlock(TryTerminatedBlock); + cfg->addTryDispatchBlock(NewTryTerminatedBlock); assert(Terminator->getTryBlock() && "try must contain a non-NULL body"); Block = nullptr; - return addStmt(Terminator->getTryBlock()); + + CFGBlock *TryBodyEntry = addStmt(Terminator->getTryBlock()); + if (TryBodyEntry) { + addSuccessor(NewTryTerminatedBlock, TryBodyEntry); + } else { + CFGBlock *EmptyTryBody = createBlock(/*add_successor*/ false); + addSuccessor(NewTryTerminatedBlock, EmptyTryBody); + addSuccessor(EmptyTryBody, TrySuccessor); + } + return NewTryTerminatedBlock; } CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) { diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 7b08648080710..99e59b361a187 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -567,26 +567,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(), - live); - - bool AddEHEdges = AC.getAddEHEdges(); - if (!AddEHEdges && count != cfg->getNumBlockIDs()) - // When there are things remaining dead, and we didn't add EH edges - // from CallExprs to the catch clauses, we have to go back and - // mark them as live. - for (const auto *B : *cfg) { - if (!live[B->getBlockID()]) { - if (B->preds().empty()) { - const Stmt *Term = B->getTerminatorStmt(); - if (isa_and_nonnull<CXXTryStmt>(Term)) - // When not adding EH edges from calls, catch clauses - // can otherwise seem dead. Avoid noting them as dead. - count += reachable_code::ScanReachableFromBlock(B, live); - continue; - } - } - } + reachable_code::ScanReachableFromBlock(&cfg->getEntry(), live); // Now we know what is live, we check the live precessors of the exit block // and look for fall through paths, being careful to ignore normal returns, diff --git a/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp b/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp index 96b9a5508cc08..882f30a7120a3 100644 --- a/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp +++ b/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp @@ -1296,17 +1296,21 @@ void test_for_inc_conditional() { (void)0; } -// CHECK: [B3 (ENTRY)] -// CHECK-NEXT: Succs (1): B0 +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 // CHECK: [B1] // CHECK-NEXT: T: try ... -// CHECK-NEXT: Succs (2): B2 B0 +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (3): B2 B0 B3 // CHECK: [B2] // CHECK-NEXT: catch (const A &e): // CHECK-NEXT: 1: catch (const A &e) { // CHECK-NEXT: } // CHECK-NEXT: Preds (1): B1 // CHECK-NEXT: Succs (1): B0 +// CHECK: [B3] +// CHECK-NEXT: Preds (1): B1 +// CHECK-NEXT: Succs (1): B0 // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (3): B2 B1 B3 void test_catch_const_ref() { @@ -1315,11 +1319,12 @@ void test_catch_const_ref() { } } -// CHECK: [B3 (ENTRY)] -// CHECK-NEXT: Succs (1): B0 +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 // CHECK: [B1] // CHECK-NEXT: T: try ... -// CHECK-NEXT: Succs (2): B2 B0 +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (3): B2 B0 B3 // CHECK: [B2] // CHECK-NEXT: catch (A e): // CHECK-NEXT: 1: catch (A e) { @@ -1327,6 +1332,9 @@ void test_catch_const_ref() { // CHECK-NEXT: 2: [B2.1].~A() (Implicit destructor) // CHECK-NEXT: Preds (1): B1 // CHECK-NEXT: Succs (1): B0 +// CHECK: [B3] +// CHECK-NEXT: Preds (1): B1 +// CHECK-NEXT: Succs (1): B0 // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (3): B2 B1 B3 void test_catch_copy() { diff --git a/clang/test/Analysis/misc-ps-region-store.cpp b/clang/test/Analysis/misc-ps-region-store.cpp index 958ad5ea40ea5..7d9c7bf634459 100644 --- a/clang/test/Analysis/misc-ps-region-store.cpp +++ b/clang/test/Analysis/misc-ps-region-store.cpp @@ -526,7 +526,7 @@ MyEnum rdar10892489_positive() { } catch (MyEnum e) { int *p = 0; // FALSE NEGATIVE - *p = 0xDEADBEEF; // {{null}} + *p = 0xDEADBEEF; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} return e; } return MyEnumValue; @@ -552,7 +552,7 @@ void PR11545_positive() { { int *p = 0; // FALSE NEGATIVE - *p = 0xDEADBEEF; // {{null}} + *p = 0xDEADBEEF; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} } } diff --git a/clang/test/SemaCXX/return-noreturn.cpp b/clang/test/SemaCXX/return-noreturn.cpp index 873e4c7e12f23..9137534c5149b 100644 --- a/clang/test/SemaCXX/return-noreturn.cpp +++ b/clang/test/SemaCXX/return-noreturn.cpp @@ -262,3 +262,10 @@ int functionTryBlock3(int s) try { } catch (...) { return 0; } // ok, both paths return. + +namespace GH174822 { +[[noreturn]] void t() { + throw 1; + try {} catch(...) {} +} +} >From 88134cc37c65fc14da5cdc476771f9b11390679f Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk <[email protected]> Date: Mon, 12 Jan 2026 09:23:49 +0200 Subject: [PATCH 2/2] cleanup --- clang/lib/Analysis/CFG.cpp | 5 ++--- clang/test/Analysis/misc-ps-region-store.cpp | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 4531cbc29f338..e1d7f75c812c7 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -4745,11 +4745,10 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { assert(Terminator->getTryBlock() && "try must contain a non-NULL body"); Block = nullptr; - CFGBlock *TryBodyEntry = addStmt(Terminator->getTryBlock()); - if (TryBodyEntry) { + if (CFGBlock *TryBodyEntry = addStmt(Terminator->getTryBlock())) { addSuccessor(NewTryTerminatedBlock, TryBodyEntry); } else { - CFGBlock *EmptyTryBody = createBlock(/*add_successor*/ false); + CFGBlock *EmptyTryBody = createBlock(/*add_successor=*/false); addSuccessor(NewTryTerminatedBlock, EmptyTryBody); addSuccessor(EmptyTryBody, TrySuccessor); } diff --git a/clang/test/Analysis/misc-ps-region-store.cpp b/clang/test/Analysis/misc-ps-region-store.cpp index 7d9c7bf634459..c0b7d648f78ee 100644 --- a/clang/test/Analysis/misc-ps-region-store.cpp +++ b/clang/test/Analysis/misc-ps-region-store.cpp @@ -525,7 +525,6 @@ MyEnum rdar10892489_positive() { throw MyEnumValue; } catch (MyEnum e) { int *p = 0; - // FALSE NEGATIVE *p = 0xDEADBEEF; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} return e; } @@ -551,7 +550,6 @@ void PR11545_positive() { catch (...) { int *p = 0; - // FALSE NEGATIVE *p = 0xDEADBEEF; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
