[clang] [LifetimeSafety] Propagate origins through BaseToDerived casts (PR #231896)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 14 07:51:32 PDT 2026
================
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -verify %s
+
+struct Base {};
+struct Derived : Base {};
+Derived *DowncastReturnsStackAddress() {
+ Derived d;
+ Base *b = &d;
+ // expected-warning at -1 {{stack memory associated with local variable 'd' is returned}}
+ return static_cast<Derived *>(b); // expected-note {{returned here}}
+}
+
+// A downcast that does not outlive the pointee is fine.
+void use(Derived *);
+void DowncastWithinScopeIsOk() {
+ Derived d;
+ Base *b = &d;
+ use(static_cast<Derived *>(b)); // ok
+}
+
+struct RefBase {};
+struct RefDerived : RefBase {};
+RefDerived *DowncastReferenceReturnsStackAddress() {
+ RefDerived d;
+ RefBase &b = d;
+ // expected-warning at -1 {{stack memory associated with local variable 'd' is returned}}
+ RefDerived &r = static_cast<RefDerived &>(b);
+ return &r; // expected-note {{returned here}}
+}
+
+void use(Derived &);
+void DowncastReferenceWithinScopeIsOk() {
+ Derived d;
+ Base &b = d;
+ use(static_cast<Derived &>(b)); // ok
+}
+
+// ****************************************************************************
+// Different origin shapes for BaseToDerived and DerivedToBase casts.
+// ****************************************************************************
+
+struct [[gsl::Pointer]] GslBase {};
+struct [[gsl::Pointer]] GslDerived : GslBase {};
+
+GslDerived *MatchingAnnotationsStillDetected() {
+ GslDerived d;
+ GslBase *b = &d;
+ // expected-warning at -1 {{stack memory associated with local variable 'd' is returned}}
+ return static_cast<GslDerived *>(b); // expected-note {{returned here}}
+}
+
+// Base is a gsl::Pointer but the derived is not.
+// They have different origin shapes, thus the borrow is dropped, thus no dangling is reported.
+struct [[gsl::Pointer]] GslOnlyBase {};
+struct PlainFromGsl : GslOnlyBase {};
+
+PlainFromGsl *BaseAnnotatedMismatchDropsBorrow() {
+ PlainFromGsl d;
+ GslOnlyBase *b = &d; // FN: See comment above.
+ return static_cast<PlainFromGsl *>(b); // no note
+}
+
+// Mismatch the other way: derived is a gsl::Pointer, base is not.
+// Same outcome.
+struct PlainBase2 {};
+struct [[gsl::Pointer]] GslOnlyDerived : PlainBase2 {};
+
+GslOnlyDerived *DerivedAnnotatedMismatchDropsBorrow() {
+ GslOnlyDerived d;
+ PlainBase2 *b = &d; // FN: See comment above.
+ return static_cast<GslOnlyDerived *>(b); // no note
----------------
NeKon69 wrote:
Could you also align all of the `expected-` comments similar to this?
https://github.com/llvm/llvm-project/pull/231896
More information about the cfe-commits
mailing list