llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-temporal-safety

Author: Utkarsh Saxena (usx95)

<details>
<summary>Changes</summary>

Fixes https://github.com/llvm/llvm-project/issues/177802

This enables the analysis to correctly track lifetimes through non-trivial view 
types that require temporary binding due to having a destructor.

This is fixed by handling `MaterializeTemporaryExpr` even for lifetime-extended 
temporaries and fixing the flow of origins.

---
Full diff: https://github.com/llvm/llvm-project/pull/177878.diff


3 Files Affected:

- (modified) 
clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h (+1) 
- (modified) clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp (+10-7) 
- (modified) clang/test/Sema/warn-lifetime-safety.cpp (+22-75) 


``````````diff
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 98fadaa11137f..dea868fd22ddd 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

``````````

</details>


https://github.com/llvm/llvm-project/pull/177878
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to