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

Reply via email to