https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/177878
>From a4297bd3992edf0e17965a44a3197918a04ac1c4 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Sat, 24 Jan 2026 20:02:17 +0000 Subject: [PATCH] Handle non-trivial view types of temporaries --- .../Analyses/LifetimeSafety/FactsGenerator.h | 1 + .../LifetimeSafety/FactsGenerator.cpp | 17 ++-- clang/test/Sema/warn-lifetime-safety.cpp | 97 +++++-------------- 3 files changed, 33 insertions(+), 82 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h index e4487b0d1dbc7..8b45337bee218 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h @@ -48,6 +48,7 @@ class FactsGenerator : public ConstStmtVisitor<FactsGenerator> { void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE); void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *FCE); void VisitInitListExpr(const InitListExpr *ILE); + void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE); void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE); private: diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index c1b8322c5ec55..fb859eeb856af 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -418,12 +418,14 @@ void FactsGenerator::VisitInitListExpr(const InitListExpr *ILE) { killAndFlowOrigin(*ILE, *ILE->getInit(0)); } +void FactsGenerator::VisitCXXBindTemporaryExpr( + const CXXBindTemporaryExpr *BTE) { + killAndFlowOrigin(*BTE, *BTE->getSubExpr()); +} + void FactsGenerator::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *MTE) { assert(MTE->isGLValue()); - // We defer from handling lifetime extended materializations. - if (MTE->getStorageDuration() != SD_FullExpression) - return; OriginList *MTEList = getOriginsList(*MTE); if (!MTEList) return; @@ -431,15 +433,16 @@ void FactsGenerator::VisitMaterializeTemporaryExpr( assert((!SubExprList || MTEList->getLength() == (SubExprList->getLength() + 1)) && "MTE top level origin should contain a loan to the MTE itself"); - MTEList = getRValueOrigins(MTE, MTEList); + + OriginList *RValMTEList = getRValueOrigins(MTE, MTEList); + flow(RValMTEList, SubExprList, /*Kill=*/true); + OriginID OuterMTEID = MTEList->getOuterOriginID(); if (getChildBinding(MTE)) { // Issue a loan to MTE for the storage location represented by MTE. const Loan *L = createLoan(FactMgr, MTE); - OriginList *List = getOriginsList(*MTE); CurrentBlockFacts.push_back( - FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID())); + FactMgr.createFact<IssueFact>(L->getID(), OuterMTEID)); } - flow(MTEList, SubExprList, /*Kill=*/true); } void FactsGenerator::handleLifetimeEnds(const CFGLifetimeEnds &LifetimeEnds) { diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index c80556715fedf..ca3f239af540c 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -14,7 +14,6 @@ struct [[gsl::Owner]] MyObj { MyObj operator+(MyObj); View getView() const [[clang::lifetimebound]]; - const int* getData() const [[clang::lifetimebound]]; }; struct [[gsl::Owner]] MyTrivialObj { @@ -26,10 +25,6 @@ struct [[gsl::Pointer()]] View { View(const MyTrivialObj &); // Borrows from MyTrivialObj View(); void use() const; - - const MyObj* data() const; - const MyObj& operator*() const; - const MyObj* operator->() const; }; class TriviallyDestructedClass { @@ -1460,76 +1455,6 @@ void bar() { } } -namespace DereferenceViews { -const MyObj& testDeref(MyObj obj) { - View v = obj; // expected-warning {{address of stack memory is returned later}} - return *v; // expected-note {{returned here}} -} -const MyObj* testDerefAddr(MyObj obj) { - View v = obj; // expected-warning {{address of stack memory is returned later}} - return &*v; // expected-note {{returned here}} -} -const MyObj* testData(MyObj obj) { - View v = obj; // expected-warning {{address of stack memory is returned later}} - return v.data(); // expected-note {{returned here}} -} -const int* testLifetimeboundAccessorOfMyObj(MyObj obj) { - View v = obj; // expected-warning {{address of stack memory is returned later}} - const MyObj* ptr = v.data(); - return ptr->getData(); // expected-note {{returned here}} -} -const int* testLifetimeboundAccessorOfMyObjThroughDeref(MyObj obj) { - View v = obj; // expected-warning {{address of stack memory is returned later}} - return v->getData(); // expected-note {{returned here}} -} -} // namespace DereferenceViews - -namespace ViewsBeginEndIterators { -template <typename T> -struct [[gsl::Pointer]] Iterator { - Iterator operator++(); - T& operator*() const; - T* operator->() const; - bool operator!=(const Iterator& other) const; -}; - -template <typename T> -struct [[gsl::Owner]] Container { -using It = Iterator<T>; -It begin() const [[clang::lifetimebound]]; -It end() const [[clang::lifetimebound]]; -}; - -MyObj Global; - -const MyObj& ContainerMyObjReturnRef(Container<MyObj> c) { - for (const MyObj& x : c) { // expected-warning {{address of stack memory is returned later}} - return x; // expected-note {{returned here}} - } - return Global; -} - -View ContainerMyObjReturnView(Container<MyObj> c) { - for (const MyObj& x : c) { // expected-warning {{address of stack memory is returned later}} - return x; // expected-note {{returned here}} - } - for (View x : c) { // expected-warning {{address of stack memory is returned later}} - return x; // expected-note {{returned here}} - } - return Global; -} - -View ContainerViewsOk(Container<View> c) { - for (View x : c) { - return x; - } - for (const View& x : c) { - return x; - } - return Global; -} -} // namespace ViewsBeginEndIterators - namespace reference_type_decl_ref_expr { struct S { S(); @@ -1691,3 +1616,25 @@ void test() { } } // namespace attr_on_template_params + +namespace non_trivial_views { +struct [[gsl::Pointer]] View { + View(const std::string&); + ~View(); // Forces a CXXBindTemporaryExpr. +}; + +View test1(std::string a) { + // Make sure we handle CXXBindTemporaryExpr of view types. + return View(a); // expected-warning {{address of stack memory is returned later}} expected-note {{returned here}} +} + +View test2(std::string a) { + View b = View(a); // expected-warning {{address of stack memory is returned later}} + return b; // expected-note {{returned here}} +} + +View test3(std::string a) { + const View& b = View(a); // expected-warning {{address of stack memory is returned later}} + return b; // expected-note {{returned here}} +} +} // namespace non_trivial_views _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
