[clang] [LifetimeSafety] Detect use of a reference type as a use of underlying origin (PR #184295)
Zhijie Wang via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 26 18:22:17 PDT 2026
https://github.com/aeft updated https://github.com/llvm/llvm-project/pull/184295
>From 746e45f465c57d7503de664f8239cdc2eebf39d9 Mon Sep 17 00:00:00 2001
From: Alex Wang <yesterda9 at gmail.com>
Date: Mon, 2 Mar 2026 23:34:35 -0800
Subject: [PATCH 1/2] [LifetimeSafety] Detect use of a reference type as a use
of underlying origin
---
clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 3 ++-
clang/test/Sema/warn-lifetime-safety-invalidations.cpp | 8 +++-----
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 80a73a2bf687e..90d604100438b 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -366,7 +366,8 @@ void FactsGenerator::handleAssignment(const Expr *LHSExpr,
// assigned.
RHSList = getRValueOrigins(RHSExpr, RHSList);
- if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr))
+ if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr);
+ DRE_LHS && !DRE_LHS->getDecl()->getType()->isReferenceType())
markUseAsWrite(DRE_LHS);
// Kill the old loans of the destination origin and flow the new loans
// from the source origin.
diff --git a/clang/test/Sema/warn-lifetime-safety-invalidations.cpp b/clang/test/Sema/warn-lifetime-safety-invalidations.cpp
index 486edd7a1a023..6820823bd7f7f 100644
--- a/clang/test/Sema/warn-lifetime-safety-invalidations.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-invalidations.cpp
@@ -259,11 +259,9 @@ namespace ElementReferences {
void ReferenceToVectorElement() {
std::vector<int> v = {1, 2, 3};
- int& ref = v[0];
- v.push_back(4);
- // FIXME: Detect this as a use of 'ref'.
- // https://github.com/llvm/llvm-project/issues/180187
- ref = 10;
+ int& ref = v[0]; // expected-warning {{object whose reference is captured is later invalidated}}
+ v.push_back(4); // expected-note {{invalidated here}}
+ ref = 10; // expected-note {{later used here}}
(void)ref;
}
>From 3cd496a35b4a46f341911250f0346026ab71968d Mon Sep 17 00:00:00 2001
From: Alex Wang <yesterda9 at gmail.com>
Date: Tue, 3 Mar 2026 12:49:12 -0800
Subject: [PATCH 2/2] fix reference to pointer
---
clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 8 +++++---
.../test/Sema/warn-lifetime-safety-invalidations.cpp | 12 ++++++++++++
clang/test/Sema/warn-lifetime-safety.cpp | 12 ++++++++++++
3 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 90d604100438b..b6afecfe55281 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -366,9 +366,11 @@ void FactsGenerator::handleAssignment(const Expr *LHSExpr,
// assigned.
RHSList = getRValueOrigins(RHSExpr, RHSList);
- if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr);
- DRE_LHS && !DRE_LHS->getDecl()->getType()->isReferenceType())
- markUseAsWrite(DRE_LHS);
+ if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
+ QualType QT = DRE_LHS->getDecl()->getType();
+ if (!QT->isReferenceType() || hasOrigins(QT->getPointeeType()))
+ markUseAsWrite(DRE_LHS);
+ }
// Kill the old loans of the destination origin and flow the new loans
// from the source origin.
flow(LHSList->peelOuterOrigin(), RHSList, /*Kill=*/true);
diff --git a/clang/test/Sema/warn-lifetime-safety-invalidations.cpp b/clang/test/Sema/warn-lifetime-safety-invalidations.cpp
index 6820823bd7f7f..bab4b28a9e172 100644
--- a/clang/test/Sema/warn-lifetime-safety-invalidations.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-invalidations.cpp
@@ -265,6 +265,18 @@ void ReferenceToVectorElement() {
(void)ref;
}
+void PointerRefToVectorElement() {
+ std::vector<int*> v = {nullptr, nullptr};
+ int*& ref = v[0];
+ v.push_back(nullptr);
+ // FIXME: Writing through a reference to an invalidated vector element
+ // should be detected. Origin_outer (reference binding) is incorrectly
+ // killed by markUseAsWrite.
+ int y;
+ ref = &y;
+ (void)*ref;
+}
+
void PointerToVectorElement() {
std::vector<int> v = {1, 2, 3};
int* ptr = &v[0]; // expected-warning {{object whose reference is captured is later invalidated}}
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 76d43445f8636..866542303414a 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -752,6 +752,18 @@ void no_error_if_dangle_then_rescue_gsl() {
v.use(); // This is safe.
}
+void no_error_if_dangle_then_rescue_via_ref() {
+ MyObj safe;
+ MyObj* p;
+ MyObj*& ref = p;
+ {
+ MyObj temp;
+ ref = &temp; // p temporarily points to temp via ref.
+ }
+ ref = &safe; // p is "rescued" via ref before use.
+ (void)*ref; // This is safe.
+}
+
void no_error_loan_from_current_iteration(bool cond) {
// See https://github.com/llvm/llvm-project/issues/156959.
MyObj b;
More information about the cfe-commits
mailing list