https://github.com/aeft created https://github.com/llvm/llvm-project/pull/192180

Before this PR, `FactsGenerator` handled cast nodes with 
`VisitImplicitCastExpr` (`CastKind` switch case) and 
`VisitCXXFunctionalCastExpr` (handle`gsl::Pointer` types). Other explicit casts 
(`CStyleCastExpr`, `CXXStaticCastExpr`, ...) had no handler, so origin was 
silently dropped. This is the root cause of #190912: the dangle in `a = 
StringView(s);` is missed even though the equivalent `StringView tmp(s); a = 
tmp;` is reported.

The policy for "does this cast propagate origin?" is a function of `CastKind`, 
independent of whether the cast is implicit or explicit. This PR replaces 
`VisitImplicitCastExpr` with a generic `VisitCastExpr`. 
`VisitCXXFunctionalCastExpr` is retained only to preserve the `handleTestPoint` 
logic, then delegates to `VisitCastExpr`.

This mirrors `clang/lib/AST/ExprConstant.cpp`, where each evaluator implements 
only `VisitCastExpr` and switches on `CastKind`; the few ExprClass-specific 
overrides (e.g., `VisitCXXDynamicCastExpr`) exist solely to attach 
constexpr-validity diagnostics before delegating back.

Scope: the set of `CastKind`s that propagate origin is unchanged.

Fixes: #190912

>From a6222a8ab95cc1b45e9ac7d3e35d8ae7289ad7d2 Mon Sep 17 00:00:00 2001
From: Zhijie Wang <[email protected]>
Date: Tue, 14 Apr 2026 19:03:39 -0700
Subject: [PATCH] [LifetimeSafety] Propagate origins through explicit cast
 expressions

---
 .../Analyses/LifetimeSafety/FactsGenerator.h  |  2 +-
 .../LifetimeSafety/FactsGenerator.cpp         | 15 +++++------
 clang/test/Sema/warn-lifetime-safety.cpp      | 27 +++++++++++++++++++
 3 files changed, 35 insertions(+), 9 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
index 3cf5971973c2a..a86f22a181a70 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
@@ -41,7 +41,7 @@ class FactsGenerator : public 
ConstStmtVisitor<FactsGenerator> {
   void VisitMemberExpr(const MemberExpr *ME);
   void VisitCallExpr(const CallExpr *CE);
   void VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *N);
-  void VisitImplicitCastExpr(const ImplicitCastExpr *ICE);
+  void VisitCastExpr(const CastExpr *CE);
   void VisitUnaryOperator(const UnaryOperator *UO);
   void VisitReturnStmt(const ReturnStmt *RS);
   void VisitBinaryOperator(const BinaryOperator *BO);
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index cae56ddd3d7c3..d27eb1be22429 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -270,14 +270,14 @@ void FactsGenerator::VisitCXXNullPtrLiteralExpr(
   getOriginsList(*N);
 }
 
-void FactsGenerator::VisitImplicitCastExpr(const ImplicitCastExpr *ICE) {
-  OriginList *Dest = getOriginsList(*ICE);
+void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
+  OriginList *Dest = getOriginsList(*CE);
   if (!Dest)
     return;
-  const Expr *SubExpr = ICE->getSubExpr();
+  const Expr *SubExpr = CE->getSubExpr();
   OriginList *Src = getOriginsList(*SubExpr);
 
-  switch (ICE->getCastKind()) {
+  switch (CE->getCastKind()) {
   case CK_LValueToRValue:
     // TODO: Decide what to do for x-values here.
     if (!SubExpr->isLValue())
@@ -288,11 +288,11 @@ void FactsGenerator::VisitImplicitCastExpr(const 
ImplicitCastExpr *ICE) {
     // `int *p, *q; p = q;`) should propagate the inner origin (what the 
pointer
     // points to), not the outer origin (the pointer's storage location). Strip
     // the outer lvalue origin.
-    flow(getOriginsList(*ICE), getRValueOrigins(SubExpr, Src),
+    flow(getOriginsList(*CE), getRValueOrigins(SubExpr, Src),
          /*Kill=*/true);
     return;
   case CK_NullToPointer:
-    getOriginsList(*ICE);
+    getOriginsList(*CE);
     // TODO: Flow into them a null origin.
     return;
   case CK_NoOp:
@@ -517,8 +517,7 @@ void FactsGenerator::VisitCXXFunctionalCastExpr(
   // expression.
   if (handleTestPoint(FCE))
     return;
-  if (isGslPointerType(FCE->getType()))
-    killAndFlowOrigin(*FCE, *FCE->getSubExpr());
+  VisitCastExpr(FCE);
 }
 
 void FactsGenerator::VisitInitListExpr(const InitListExpr *ILE) {
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index f87b5cbdd0230..9f4456465281a 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -936,6 +936,33 @@ void lifetimebound_ctor() {
   (void)v;   // expected-note {{later used here}}
 }
 
+void lifetimebound_ctor_functional_cast() {
+  LifetimeBoundCtor v;
+  {
+    MyObj obj;
+    v = LifetimeBoundCtor(obj); // expected-warning {{object whose reference 
is captured does not live long enough}}
+  }                             // expected-note {{destroyed here}}
+  (void)v;                      // expected-note {{later used here}}
+}
+
+void lifetimebound_ctor_c_style_cast() {
+  LifetimeBoundCtor v;
+  {
+    MyObj obj;
+    v = (LifetimeBoundCtor)(obj); // expected-warning {{object whose reference 
is captured does not live long enough}}
+  }                               // expected-note {{destroyed here}}
+  (void)v;                        // expected-note {{later used here}}
+}
+
+void lifetimebound_ctor_static_cast() {
+  LifetimeBoundCtor v;
+  {
+    MyObj obj;
+    v = static_cast<LifetimeBoundCtor>(obj); // expected-warning {{object 
whose reference is captured does not live long enough}}
+  }                                          // expected-note {{destroyed 
here}}
+  (void)v;                                   // expected-note {{later used 
here}}
+}
+
 View lifetimebound_return_of_local() {
   MyObj stack;
   return Identity(stack); // expected-warning {{address of stack memory is 
returned later}}

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

Reply via email to