[clang] 2cf353b - [LifetimeSafety] Flow origins from lifetimebound args in `gsl::Pointer` construction (#189907)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 10 10:16:53 PDT 2026
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
More information about the cfe-commits
mailing list