Author: NeKon69
Date: 2026-04-10T17:16:48Z
New Revision: 2cf353b5e8560723409f3f9164bddec76f499963

URL: 
https://github.com/llvm/llvm-project/commit/2cf353b5e8560723409f3f9164bddec76f499963
DIFF: 
https://github.com/llvm/llvm-project/commit/2cf353b5e8560723409f3f9164bddec76f499963.diff

LOG: [LifetimeSafety] Flow origins from lifetimebound args in `gsl::Pointer` 
construction (#189907)

This PR adds origin flow from `[[clang::lifetimebound]]` constructor
arguments during `gsl::Pointer` construction.

Fixes #175898

Added: 
    

Modified: 
    clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
    clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
    clang/test/Sema/warn-lifetime-safety.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index fcc915711550a..82b890b57817e 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -791,6 +791,17 @@ void FactsGenerator::handleFunctionCall(const Expr *Call,
             CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
             KillSrc));
         KillSrc = false;
+      } else if (IsArgLifetimeBound(I)) {
+        // Only flow the outer origin here. For lifetimebound args in
+        // gsl::Pointer construction, we do not have enough information to
+        // safely match inner origins, so the source and
+        // destination origin lists may have 
diff erent lengths.
+        // FIXME: Handle origin-shape mismatches gracefully so we can also flow
+        // inner origins.
+        CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
+            CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
+            KillSrc));
+        KillSrc = false;
       }
     } else if (shouldTrackPointerImplicitObjectArg(I)) {
       assert(ArgList->getLength() >= 2 &&

diff  --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp 
b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index d58f23e4b554c..0ed151b9db136 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -931,13 +931,11 @@ struct [[gsl::Pointer]] Pointer {
   Pointer(const Bar & bar [[clang::lifetimebound]]);
 };
 Pointer test3(Bar bar) {
-  // FIXME: Detect this using the CFG-based lifetime analysis (constructor of 
a pointer).
-  //        https://github.com/llvm/llvm-project/issues/175898
-  Pointer p = Pointer(Bar()); // expected-warning {{temporary}}
-  use(p);
-  p = Pointer(Bar()); // expected-warning {{object backing}}
-  use(p);
-  return bar; // expected-warning {{address of stack}}
+  Pointer p = Pointer(Bar()); // expected-warning {{temporary}} cfg-warning 
{{object whose reference is captured does not live long enough}} cfg-note 
{{destroyed here}}
+  use(p);                     // cfg-note {{later used here}}
+  p = Pointer(Bar());         // expected-warning {{object backing}} 
cfg-warning {{object whose reference is captured does not live long enough}} 
cfg-note {{destroyed here}}
+  use(p);                     // cfg-note {{later used here}}
+  return bar;                 // expected-warning {{address of stack}} 
cfg-warning {{address of stack memory is returned later}} cfg-note {{returned 
here}}
 }
 
 template<typename T>

diff  --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 941cedf22d1bb..77d8e3370676d 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2432,6 +2432,51 @@ void owner_outlives_lifetimebound_source() {
 
 } // namespace track_origins_for_lifetimebound_record_type
 
+namespace gslpointer_construction_from_lifetimebound {
+// https://github.com/llvm/llvm-project/issues/175898
+struct Bar {};
+template <typename T> struct [[gsl::Pointer]] Pointer {
+  Pointer();
+  Pointer(const T &bar [[clang::lifetimebound]]);
+  Pointer(const Pointer<T> &p);
+  const T &operator*() const [[clang::lifetimebound]];
+};
+
+template <typename T> void use(T);
+
+void local_pointer() {
+  Pointer<int> p;
+  {
+    int v;
+    p = Pointer(v); // expected-warning {{object whose reference is captured 
does not live long enough}}
+  }                 // expected-note {{destroyed here}}
+  use(*p);          // expected-note {{later used here}}
+}
+
+void nested_local_pointer() {
+  Pointer<Pointer<Pointer<Bar>>> ppp;
+  Pointer<Pointer<Bar>> pp;
+  Pointer<Bar> p;
+  {
+    Bar v;
+    p = Pointer(v);     // expected-warning {{object whose reference is 
captured does not live long enough}}
+    pp = Pointer(p);
+    ppp = Pointer(pp);
+  }                     // expected-note {{destroyed here}}
+  use(***ppp);          // expected-note {{later used here}}
+}
+
+struct PFieldFromParam {
+  Pointer<Bar> value;                      // function-note {{this field 
dangles}}
+  PFieldFromParam(Bar bar) : value(bar) {} // function-warning {{address of 
stack memory escapes to a field}}
+};
+
+struct PFieldFromTemp {
+  Pointer<Bar> value;                // function-note {{this field dangles}}
+  PFieldFromTemp() : value(Bar{}) {} // function-warning {{address of stack 
memory escapes to a field}}
+};
+
+} // namespace gslpointer_construction_from_lifetimebound
 namespace conditional_operator_control_flow {
 // https://github.com/llvm/llvm-project/issues/183895
 


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

Reply via email to