https://github.com/NeKon69 updated 
https://github.com/llvm/llvm-project/pull/190345

>From 813689c7f7392ec5c44d90ec8a030a9ba102985d Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Fri, 3 Apr 2026 16:32:34 +0300
Subject: [PATCH 1/4] [LifetimeSafety] Apply the fix

---
 .../Analysis/LifetimeSafety/FactsGenerator.cpp | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 75f2978d848b7..6108d34275092 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -94,6 +94,10 @@ static const Loan *createLoan(FactManager &FactMgr,
   return FactMgr.getLoanMgr().createLoan(Path, MTE);
 }
 
+static bool producesConditionalResult(const Expr *E) {
+  return isa<CXXThrowExpr>(E->IgnoreParenImpCasts());
+}
+
 void FactsGenerator::run() {
   llvm::TimeTraceScope TimeProfile("FactGenerator");
   const CFG &Cfg = *AC.getCFG();
@@ -404,8 +408,18 @@ void FactsGenerator::VisitConditionalOperator(const 
ConditionalOperator *CO) {
   if (hasOrigins(CO)) {
     // Merge origins from both branches of the conditional operator.
     // We kill to clear the initial state and merge both origins into it.
-    killAndFlowOrigin(*CO, *CO->getTrueExpr());
-    flowOrigin(*CO, *CO->getFalseExpr());
+    const Expr *TrueExpr = CO->getTrueExpr();
+    const Expr *FalseExpr = CO->getFalseExpr();
+    bool Initialized = false;
+    for (const Expr *Branch : {TrueExpr, FalseExpr}) {
+      if (producesConditionalResult(Branch))
+        continue;
+      if (!Initialized) {
+        killAndFlowOrigin(*CO, *Branch);
+        Initialized = true;
+      } else
+        flowOrigin(*CO, *Branch);
+    }
   }
 }
 

>From c43162e8d4de5a033ddc84a275f6fe3a44db78f7 Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Fri, 3 Apr 2026 16:41:36 +0300
Subject: [PATCH 2/4] add a test file

---
 .../test/Sema/warn-lifetime-safety-conditional-throw.cpp | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 clang/test/Sema/warn-lifetime-safety-conditional-throw.cpp

diff --git a/clang/test/Sema/warn-lifetime-safety-conditional-throw.cpp 
b/clang/test/Sema/warn-lifetime-safety-conditional-throw.cpp
new file mode 100644
index 0000000000000..2437618d131cd
--- /dev/null
+++ b/clang/test/Sema/warn-lifetime-safety-conditional-throw.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wlifetime-safety 
-Wno-dangling -verify %s
+
+// expected-no-diagnostics
+
+void conditional_throw_branches(bool cond, int *value) {
+  (void)(cond ? throw 1 : value);
+  (void)(cond ? value : throw 1);
+  (void)(cond ? throw 1 : throw 2);
+}

>From ac67df326082b1a1ed7237742789b85bafaff45e Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Fri, 3 Apr 2026 16:43:14 +0300
Subject: [PATCH 3/4] update functions body to represent what it actually does

---
 clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 6108d34275092..5eb2fcd150576 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -95,7 +95,7 @@ static const Loan *createLoan(FactManager &FactMgr,
 }
 
 static bool producesConditionalResult(const Expr *E) {
-  return isa<CXXThrowExpr>(E->IgnoreParenImpCasts());
+  return !isa<CXXThrowExpr>(E->IgnoreParenImpCasts());
 }
 
 void FactsGenerator::run() {
@@ -412,7 +412,7 @@ void FactsGenerator::VisitConditionalOperator(const 
ConditionalOperator *CO) {
     const Expr *FalseExpr = CO->getFalseExpr();
     bool Initialized = false;
     for (const Expr *Branch : {TrueExpr, FalseExpr}) {
-      if (producesConditionalResult(Branch))
+      if (!producesConditionalResult(Branch))
         continue;
       if (!Initialized) {
         killAndFlowOrigin(*CO, *Branch);

>From 38eaa5251fe4ca1bdd3c7ceb8b4b67195e8322f9 Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Sun, 5 Apr 2026 14:01:44 +0300
Subject: [PATCH 4/4] [LifetimeSafety] Improve ternary handling to ignore
 [[noreturn]] arms and only evaluate compile-time known branches

---
 .../Analyses/LifetimeSafety/FactsGenerator.h  |  2 +
 .../LifetimeSafety/FactsGenerator.cpp         | 42 ++++++++++++-------
 ...warn-lifetime-safety-conditional-throw.cpp | 41 ++++++++++++++++--
 3 files changed, 66 insertions(+), 19 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
index 8fe2436b04086..c17b603c00ddb 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
@@ -66,6 +66,8 @@ class FactsGenerator : public 
ConstStmtVisitor<FactsGenerator> {
 
   void handlePointerArithmetic(const BinaryOperator *BO);
 
+  void handleTernaryOperator(const ConditionalOperator *CO);
+
   void handleCXXCtorInitializer(const CXXCtorInitializer *CII);
 
   void handleLifetimeEnds(const CFGLifetimeEnds &LifetimeEnds);
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 5eb2fcd150576..617c3d53fd508 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -94,8 +94,8 @@ static const Loan *createLoan(FactManager &FactMgr,
   return FactMgr.getLoanMgr().createLoan(Path, MTE);
 }
 
-static bool producesConditionalResult(const Expr *E) {
-  return !isa<CXXThrowExpr>(E->IgnoreParenImpCasts());
+static bool isThrowExpr(const Expr *E) {
+  return isa<CXXThrowExpr>(E->IgnoreParenImpCasts());
 }
 
 void FactsGenerator::run() {
@@ -404,22 +404,32 @@ void FactsGenerator::VisitBinaryOperator(const 
BinaryOperator *BO) {
   // TODO: Handle assignments involving dereference like `*p = q`.
 }
 
+void FactsGenerator::handleTernaryOperator(const ConditionalOperator *CO) {
+  const auto *Map = AC.getCFGStmtMap();
+  const Expr *TrueExpr = CO->getTrueExpr();
+  const Expr *FalseExpr = CO->getFalseExpr();
+  bool TBHasConditionResult =
+      Map->getBlock(TrueExpr)->hasNoReturnElement() || isThrowExpr(TrueExpr);
+  bool FBHasConditionResult =
+      Map->getBlock(FalseExpr)->hasNoReturnElement() || isThrowExpr(FalseExpr);
+  bool FirstFlow = true;
+  auto HandleFlow = [&](const Expr *E, bool HasNoReturn) {
+    if (HasNoReturn)
+      return;
+    if (FirstFlow) {
+      killAndFlowOrigin(*CO, *E);
+      FirstFlow = false;
+    } else {
+      flowOrigin(*CO, *E);
+    }
+  };
+  HandleFlow(TrueExpr, TBHasConditionResult);
+  HandleFlow(FalseExpr, FBHasConditionResult);
+}
+
 void FactsGenerator::VisitConditionalOperator(const ConditionalOperator *CO) {
   if (hasOrigins(CO)) {
-    // Merge origins from both branches of the conditional operator.
-    // We kill to clear the initial state and merge both origins into it.
-    const Expr *TrueExpr = CO->getTrueExpr();
-    const Expr *FalseExpr = CO->getFalseExpr();
-    bool Initialized = false;
-    for (const Expr *Branch : {TrueExpr, FalseExpr}) {
-      if (!producesConditionalResult(Branch))
-        continue;
-      if (!Initialized) {
-        killAndFlowOrigin(*CO, *Branch);
-        Initialized = true;
-      } else
-        flowOrigin(*CO, *Branch);
-    }
+    handleTernaryOperator(CO);
   }
 }
 
diff --git a/clang/test/Sema/warn-lifetime-safety-conditional-throw.cpp 
b/clang/test/Sema/warn-lifetime-safety-conditional-throw.cpp
index 2437618d131cd..874d885c4bce5 100644
--- a/clang/test/Sema/warn-lifetime-safety-conditional-throw.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-conditional-throw.cpp
@@ -1,9 +1,44 @@
 // RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wlifetime-safety 
-Wno-dangling -verify %s
 
-// expected-no-diagnostics
-
-void conditional_throw_branches(bool cond, int *value) {
+void throw_branches(bool cond, int *value) {
   (void)(cond ? throw 1 : value);
   (void)(cond ? value : throw 1);
   (void)(cond ? throw 1 : throw 2);
 }
+
+int *f(int *p [[clang::lifetimebound]]);
+[[noreturn]] int *noret_f(int *p [[clang::lifetimebound]]);
+
+
+constexpr bool kTrue = true;
+constexpr bool kFalse = false;
+
+int *constexpr_dead_false(int *num) {
+  int local = 0;
+  return kTrue ? num : f(&local);
+}
+
+int *constexpr_dead_true(int *num) {
+  int local = 0;
+  return kFalse ? f(&local) : num;
+}
+
+int *constexpr_live_false(int *num) {
+  int local = 0;
+  return kFalse ? num : f(&local); // expected-warning {{address of stack 
memory is returned later}} // expected-note {{returned here}}
+}
+
+int *constexpr_live_true(int *num) {
+  int local = 0;
+  return kTrue ? f(&local) : num; // expected-warning {{address of stack 
memory is returned later}} // expected-note {{returned here}}
+}
+
+int *noreturn_dead_false(bool cond, int *num) {
+  int local = 0;
+  return cond ? num : noret_f(&local);
+}
+
+int *noreturn_dead_true(bool cond, int *num) {
+  int local = 0;
+  return cond ? noret_f(&local) : num;
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to