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
