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 different lengths. + // FIXME: Handle origin-shape mismatches gracefully so we can also flow + // inner origins. + CurrentBlockFacts.push_back(FactMgr.createFact( + 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 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 struct [[gsl::Pointer]] Pointer { + Pointer(); + Pointer(const T &bar [[clang::lifetimebound]]); + Pointer(const Pointer &p); + const T &operator*() const [[clang::lifetimebound]]; +}; + +template void use(T); + +void local_pointer() { + Pointer 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>> ppp; + Pointer> pp; + Pointer 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 value; // function-note {{this field dangles}} + PFieldFromParam(Bar bar) : value(bar) {} // function-warning {{address of stack memory escapes to a field}} +}; + +struct PFieldFromTemp { + Pointer 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