[clang] ed1cc5b - [LifetimeSafety] Propagate origins through BaseToDerived casts (#231896)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 14 11:00:43 PDT 2026
Author: Balázs Benics
Date: 2026-10-14T19:00:36+01:00
New Revision: ed1cc5b6583155512baf116ab45542de1fc23770
URL: https://github.com/llvm/llvm-project/commit/ed1cc5b6583155512baf116ab45542de1fc23770
DIFF: https://github.com/llvm/llvm-project/commit/ed1cc5b6583155512baf116ab45542de1fc23770.diff
LOG: [LifetimeSafety] Propagate origins through BaseToDerived casts (#231896)
In addition to what the title says, I added a few tests demonstrating
the pre-existing origin shape mismatch detection and borrow drop
behavior.
Assissted-By: claude
Added:
Modified:
clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
clang/test/Sema/LifetimeSafety/safety.cpp
Removed:
################################################################################
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index b67288a190f17..6a805bb7be2d8 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -309,6 +309,9 @@ void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
return;
case CK_UncheckedDerivedToBase:
case CK_DerivedToBase:
+ case CK_BaseToDerived:
+ // The conversion cast doesn't change what it refers to, so preserve the
+ // borrow if we can.
// It is possible that the derived class and base class have
diff erent
// gsl::Pointer annotations. Skip if their origin shape
diff er.
if (Dest && Src && Dest->getLength() == Src->getLength())
diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp
index 63874c9bb8bae..18800830cb59f 100644
--- a/clang/test/Sema/LifetimeSafety/safety.cpp
+++ b/clang/test/Sema/LifetimeSafety/safety.cpp
@@ -4804,3 +4804,73 @@ void asm_inout_operand_is_read() {
}
} // namespace class_reads
} // namespace what_is_a_use
+
+namespace DowncastTests {
+
+struct Base {};
+struct Derived : Base {};
+Derived *DowncastReturnsStackAddress() {
+ Derived d;
+ Base *b = &d; // expected-warning {{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 {{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
+}
+
+} // namespace DowncastTests
+
+namespace DifferentOriginShapes {
+
+struct [[gsl::Pointer]] GslBase {};
+struct [[gsl::Pointer]] GslDerived : GslBase {};
+
+GslDerived *MatchingAnnotationsStillDetected() {
+ GslDerived d;
+ GslBase *b = &d; // expected-warning {{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
diff erent 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
+}
+} // namespace DifferentOriginShapes
More information about the cfe-commits
mailing list