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
