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


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to