[llvm-branch-commits] [clang] users/usx95/helpful-invalidations (PR #203577)
Utkarsh Saxena via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Jun 12 09:26:54 PDT 2026
https://github.com/usx95 created https://github.com/llvm/llvm-project/pull/203577
None
>From aa028d2ff815b19ad84c8b7aad77b5e9a564feb8 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Fri, 12 Jun 2026 16:25:09 +0000
Subject: [PATCH] users/usx95/helpful-invalidations
---
.../clang/Basic/DiagnosticSemaKinds.td | 8 +-
clang/lib/Sema/SemaLifetimeSafety.h | 22 ++-
.../Sema/LifetimeSafety/invalidations.cpp | 148 +++++++++---------
clang/test/Sema/LifetimeSafety/safety.cpp | 8 +-
4 files changed, 98 insertions(+), 88 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9691963d4fe7e..8097800e6744a 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10981,7 +10981,7 @@ def warn_lifetime_safety_use_after_scope_moved : Warning<
InGroup<LifetimeSafetyUseAfterScopeMoved>, DefaultIgnore;
def warn_lifetime_safety_use_after_free : Warning<
- "%select{allocated object|parameter}0 does not live long enough">,
+ "%0 does not live long enough">,
InGroup<LifetimeSafetyUseAfterFree>, DefaultIgnore;
def warn_lifetime_safety_return_stack_addr : Warning<
@@ -10995,15 +10995,15 @@ def warn_lifetime_safety_return_stack_addr_moved : Warning<
InGroup<LifetimeSafetyReturnStackAddrMoved>, DefaultIgnore;
def warn_lifetime_safety_invalidation
- : Warning<"%select{object whose reference is captured|parameter}0 is later invalidated">,
+ : Warning<"%0 is later invalidated">,
InGroup<LifetimeSafetyInvalidation>,
DefaultIgnore;
def warn_lifetime_safety_invalidated_field
- : Warning<"%select{object whose reference|parameter which}0 escapes to a field is later invalidated">,
+ : Warning<"%0 escapes to the %1 and is later invalidated">,
InGroup<LifetimeSafetyInvalidation>,
DefaultIgnore;
def warn_lifetime_safety_invalidated_global
- : Warning<"%select{object whose reference|parameter which}0 escapes to global or static storage is later invalidated">,
+ : Warning<"%0 escapes to the %1 and is later invalidated">,
InGroup<LifetimeSafetyInvalidation>,
DefaultIgnore;
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 565c30f74cf9a..554cbff9dac58 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -151,7 +151,7 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
? diag::note_lifetime_safety_freed_here
: diag::note_lifetime_safety_invalidated_here;
S.Diag(IssueExpr->getExprLoc(), WarnDiag)
- << false << IssueExpr->getSourceRange();
+ << getDiagSubjectDescription(IssueExpr) << IssueExpr->getSourceRange();
S.Diag(InvalidationExpr->getExprLoc(), UseDiag)
<< InvalidationExpr->getSourceRange();
S.Diag(UseExpr->getExprLoc(), diag::note_lifetime_safety_used_here)
@@ -168,7 +168,7 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
: diag::note_lifetime_safety_invalidated_here;
S.Diag(PVD->getSourceRange().getBegin(), WarnDiag)
- << true << PVD->getSourceRange();
+ << getDiagSubjectDescription(PVD) << PVD->getSourceRange();
S.Diag(InvalidationExpr->getExprLoc(), UseDiag)
<< InvalidationExpr->getSourceRange();
S.Diag(UseExpr->getExprLoc(), diag::note_lifetime_safety_used_here)
@@ -183,7 +183,9 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
: diag::note_lifetime_safety_invalidated_here;
S.Diag(IssueExpr->getExprLoc(),
diag::warn_lifetime_safety_invalidated_field)
- << false << IssueExpr->getSourceRange();
+ << getDiagSubjectDescription(IssueExpr)
+ << getDiagSubjectDescription(DanglingField)
+ << IssueExpr->getSourceRange();
S.Diag(InvalidationExpr->getExprLoc(), InvalidationDiag)
<< InvalidationExpr->getSourceRange();
S.Diag(DanglingField->getLocation(),
@@ -199,7 +201,9 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
: diag::note_lifetime_safety_invalidated_here;
S.Diag(PVD->getSourceRange().getBegin(),
diag::warn_lifetime_safety_invalidated_field)
- << true << PVD->getSourceRange();
+ << getDiagSubjectDescription(PVD)
+ << getDiagSubjectDescription(DanglingField)
+ << PVD->getSourceRange();
S.Diag(InvalidationExpr->getExprLoc(), InvalidationDiag)
<< InvalidationExpr->getSourceRange();
S.Diag(DanglingField->getLocation(),
@@ -215,7 +219,9 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
: diag::note_lifetime_safety_invalidated_here;
S.Diag(IssueExpr->getExprLoc(),
diag::warn_lifetime_safety_invalidated_global)
- << false << IssueExpr->getSourceRange();
+ << getDiagSubjectDescription(IssueExpr)
+ << getDiagSubjectDescription(DanglingGlobal)
+ << IssueExpr->getSourceRange();
S.Diag(InvalidationExpr->getExprLoc(), InvalidationDiag)
<< InvalidationExpr->getSourceRange();
if (DanglingGlobal->isStaticLocal() || DanglingGlobal->isStaticDataMember())
@@ -236,7 +242,9 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
: diag::note_lifetime_safety_invalidated_here;
S.Diag(PVD->getSourceRange().getBegin(),
diag::warn_lifetime_safety_invalidated_global)
- << true << PVD->getSourceRange();
+ << getDiagSubjectDescription(PVD)
+ << getDiagSubjectDescription(DanglingGlobal)
+ << PVD->getSourceRange();
S.Diag(InvalidationExpr->getExprLoc(), InvalidationDiag)
<< InvalidationExpr->getSourceRange();
if (DanglingGlobal->isStaticLocal() || DanglingGlobal->isStaticDataMember())
@@ -487,6 +495,8 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
E = E->IgnoreImpCasts();
if (isa<MaterializeTemporaryExpr>(E))
return "temporary object";
+ if (isa<CXXNewExpr>(E))
+ return "allocated object";
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
return getDiagSubjectDescription(DRE->getDecl());
diff --git a/clang/test/Sema/LifetimeSafety/invalidations.cpp b/clang/test/Sema/LifetimeSafety/invalidations.cpp
index 35077b547fc95..301822f066de8 100644
--- a/clang/test/Sema/LifetimeSafety/invalidations.cpp
+++ b/clang/test/Sema/LifetimeSafety/invalidations.cpp
@@ -7,7 +7,7 @@ bool Bool();
namespace SimpleResize {
void IteratorInvalidAfterResize(int new_size) {
std::vector<int> v;
- auto it = std::begin(v); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = std::begin(v); // expected-warning {{local variable 'v' is later invalidated}}
v.resize(new_size); // expected-note {{invalidated here}}
*it; // expected-note {{later used here}}
}
@@ -48,7 +48,7 @@ void PointerToContainerTest(std::vector<int>* v) {
namespace InvalidateBeforeSwap {
void InvalidateBeforeSwapIterators(std::vector<int> v1, std::vector<int> v2) {
- auto it1 = std::begin(v1); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it1 = std::begin(v1); // expected-warning {{parameter 'v1' is later invalidated}}
auto it2 = std::begin(v2);
if (it1 == std::end(v1) || it2 == std::end(v2)) return;
*it1 = 0; // ok
@@ -62,7 +62,7 @@ void InvalidateBeforeSwapIterators(std::vector<int> v1, std::vector<int> v2) {
}
void InvalidateBeforeSwapContainers(std::vector<int> v1, std::vector<int> v2) {
- auto it1 = std::begin(v1); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it1 = std::begin(v1); // expected-warning {{parameter 'v1' is later invalidated}}
auto it2 = std::begin(v2);
if (it1 == std::end(v1) || it2 == std::end(v2)) return;
*it1 = 0; // ok
@@ -77,7 +77,7 @@ bool A();
bool B();
void SameConditionInvalidatesThenValidatesIterator() {
std::vector<int> container;
- auto it = container.begin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = container.begin(); // expected-warning {{local variable 'container' is later invalidated}}
if (it == container.end()) return;
const bool a = A();
if (a) {
@@ -108,7 +108,7 @@ void MergeWithDifferentContainerValuesInvalidated() {
std::vector<int> v1, v2, v3;
auto it = std::find(v1.begin(), v1.end(), 10);
if (Bool()) {
- it = std::find(v2.begin(), v2.end(), 10); // expected-warning {{object whose reference is captured is later invalidated}}
+ it = std::find(v2.begin(), v2.end(), 10); // expected-warning {{local variable 'v2' is later invalidated}}
} else {
it = std::find(v3.begin(), v3.end(), 10);
}
@@ -119,7 +119,7 @@ void MergeWithDifferentContainerValuesInvalidated() {
namespace InvalidationInLoops {
void IteratorInvalidationInAForLoop(std::vector<int> v) {
- for (auto it = std::begin(v); // expected-warning {{object whose reference is captured is later invalidated}}
+ for (auto it = std::begin(v); // expected-warning {{parameter 'v' is later invalidated}}
it != std::end(v);
++it) { // expected-note {{later used here}}
if (Bool()) {
@@ -129,7 +129,7 @@ void IteratorInvalidationInAForLoop(std::vector<int> v) {
}
void IteratorInvalidationInAWhileLoop(std::vector<int> v) {
- auto it = std::begin(v); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = std::begin(v); // expected-warning {{parameter 'v' is later invalidated}}
while (it != std::end(v)) {
if (Bool()) {
v.erase(it); // expected-note {{invalidated here}}
@@ -154,7 +154,7 @@ void NoIteratorInvalidationInAWhileLoopErase(std::unordered_map<int, int> mp) {
}
void IteratorInvalidationInAForeachLoop(std::vector<int> v) {
- for (int& x : v) { // expected-warning {{object whose reference is captured is later invalidated}} \
+ for (int& x : v) { // expected-warning {{parameter 'v' is later invalidated}} \
// expected-note {{later used here}}
if (x % 2 == 0) {
v.erase(std::find(v.begin(), v.end(), 1)); // expected-note {{invalidated here}}
@@ -183,7 +183,7 @@ void IteratorCheckedAfterFind(std::vector<int> v) {
}
void IteratorCheckedAfterFindThenErased(std::vector<int> v) {
- auto it = std::find(std::begin(v), std::end(v), 3); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = std::find(std::begin(v), std::end(v), 3); // expected-warning {{parameter 'v' is later invalidated}}
if (it != std::end(v)) {
v.erase(it); // expected-note {{invalidated here}}
}
@@ -201,7 +201,7 @@ void UseReturnedIteratorAfterInsert(std::vector<int> v) {
}
void UseInvalidIteratorAfterInsert(std::vector<int> v) {
- auto it = std::begin(v); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = std::begin(v); // expected-warning {{parameter 'v' is later invalidated}}
v.insert(it, 10); // expected-note {{invalidated here}}
if (it != std::end(v)) { // expected-note {{later used here}}
*it;
@@ -220,7 +220,7 @@ void IteratorValidAfterInsert(std::vector<int> v) {
}
void IteratorInvalidAfterInsert(std::vector<int> v, int value) {
- auto it = std::begin(v); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = std::begin(v); // expected-warning {{parameter 'v' is later invalidated}}
v.insert(it, 0); // expected-note {{invalidated here}}
*it; // expected-note {{later used here}}
}
@@ -228,7 +228,7 @@ void IteratorInvalidAfterInsert(std::vector<int> v, int value) {
namespace SimpleInvalidIterators {
void IteratorUsedAfterErase(std::vector<int> v) {
- auto it = std::begin(v); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = std::begin(v); // expected-warning {{parameter 'v' is later invalidated}}
for (; it != std::end(v); ++it) { // expected-note {{later used here}}
if (*it > 3) {
v.erase(it); // expected-note {{invalidated here}}
@@ -236,7 +236,7 @@ void IteratorUsedAfterErase(std::vector<int> v) {
}
}
-void IteratorUsedAfterPushBackParam(std::vector<int>& v) { // expected-warning {{parameter is later invalidated}}
+void IteratorUsedAfterPushBackParam(std::vector<int>& v) { // expected-warning {{parameter 'v' is later invalidated}}
auto it = std::begin(v);
if (it != std::end(v) && *it == 3) {
v.push_back(4); // expected-note {{invalidated here}}
@@ -245,7 +245,7 @@ void IteratorUsedAfterPushBackParam(std::vector<int>& v) { // expected-warning {
}
void IteratorUsedAfterPushBack(std::vector<int> v) {
- auto it = std::begin(v); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = std::begin(v); // expected-warning {{parameter 'v' is later invalidated}}
if (it != std::end(v) && *it == 3) {
v.push_back(4); // expected-note {{invalidated here}}
}
@@ -254,14 +254,14 @@ void IteratorUsedAfterPushBack(std::vector<int> v) {
void IteratorUsedAfterPreIncrement() {
std::vector<int> v;
- auto it = v.begin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = v.begin(); // expected-warning {{local variable 'v' is later invalidated}}
auto next = ++it;
v.push_back(1); // expected-note {{invalidated here}}
(void)*next; // expected-note {{later used here}}
}
void IteratorUsedAfterPostDecrement(std::vector<int> v) {
- auto it = v.rbegin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = v.rbegin(); // expected-warning {{parameter 'v' is later invalidated}}
auto prev = it--;
v.push_back(1); // expected-note {{invalidated here}}
(void)*prev; // expected-note {{later used here}}
@@ -269,21 +269,21 @@ void IteratorUsedAfterPostDecrement(std::vector<int> v) {
void IteratorUsedAfterAddition() {
std::vector<int> v;
- auto it = v.cbegin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = v.cbegin(); // expected-warning {{local variable 'v' is later invalidated}}
auto next = it + 5;
v.push_back(1); // expected-note {{invalidated here}}
(void)*next; // expected-note {{later used here}}
}
void IteratorUsedAfterReverseSubtraction(std::vector<int> v) {
- auto it = v.crbegin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = v.crbegin(); // expected-warning {{parameter 'v' is later invalidated}}
auto prev = 5 - it;
v.push_back(1); // expected-note {{invalidated here}}
(void)*prev; // expected-note {{later used here}}
}
void IteratorUsedAfterAddAdd(std::vector<int> v) {
- auto it = v.cbegin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = v.cbegin(); // expected-warning {{parameter 'v' is later invalidated}}
auto next = (it + 5) + 5;
v.push_back(1); // expected-note {{invalidated here}}
(void)*next; // expected-note {{later used here}}
@@ -291,14 +291,14 @@ void IteratorUsedAfterAddAdd(std::vector<int> v) {
void IteratorUsedAfterMixedAddition() {
std::vector<int> v;
- auto it = v.cbegin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = v.cbegin(); // expected-warning {{local variable 'v' is later invalidated}}
auto next = 1 + it + 2 + 3;
v.push_back(1); // expected-note {{invalidated here}}
(void)*next; // expected-note {{later used here}}
}
void IteratorUsedAfterPreIncrementAddAssign(std::vector<int> v) {
- auto it = v.begin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = v.begin(); // expected-warning {{parameter 'v' is later invalidated}}
it = ++it + 1 + 2;
v.push_back(1); // expected-note {{invalidated here}}
(void)*it; // expected-note {{later used here}}
@@ -306,7 +306,7 @@ void IteratorUsedAfterPreIncrementAddAssign(std::vector<int> v) {
void IteratorUsedAfterBeginAddAssign() {
std::vector<int> v;
- auto it = v.begin() + 1; // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = v.begin() + 1; // expected-warning {{local variable 'v' is later invalidated}}
v.push_back(1); // expected-note {{invalidated here}}
(void)*it; // expected-note {{later used here}}
}
@@ -314,7 +314,7 @@ void IteratorUsedAfterBeginAddAssign() {
void IteratorUsedAfterStdBeginAddAssign() {
std::vector<int> v;
std::vector<int>::iterator it;
- it = std::begin(v) + 1; // expected-warning {{object whose reference is captured is later invalidated}}
+ it = std::begin(v) + 1; // expected-warning {{local variable 'v' is later invalidated}}
v.push_back(1); // expected-note {{invalidated here}}
(void)*it; // expected-note {{later used here}}
}
@@ -324,12 +324,12 @@ namespace InvalidatingThroughContainerAliases {
void IteratorInvalidatedThroughLocalReferenceAlias() {
std::vector<int> vv;
std::vector<int> &v = vv;
- auto it = vv.begin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = vv.begin(); // expected-warning {{local variable 'vv' is later invalidated}}
v.push_back(42); // expected-note {{invalidated here}}
(void)it; // expected-note {{later used here}}
}
-void IteratorInvalidatedThroughPointerParameter(std::vector<int> *v) { // expected-warning {{parameter is later invalidated}}
+void IteratorInvalidatedThroughPointerParameter(std::vector<int> *v) { // expected-warning {{parameter 'v' is later invalidated}}
auto it = v->begin();
v->push_back(42); // expected-note {{invalidated here}}
(void)it; // expected-note {{later used here}}
@@ -347,7 +347,7 @@ void ParenthesizedContainerInvalidatesIterator() {
namespace ContainerObjectAliases {
// FIXME: Distinguish owner-borrow from content-borrow.
-void PointerParameterObjectUseIsOk(std::vector<int> *v) { // expected-warning {{parameter is later invalidated}}
+void PointerParameterObjectUseIsOk(std::vector<int> *v) { // expected-warning {{parameter 'v' is later invalidated}}
v->push_back(42); // expected-note {{invalidated here}}
(void)v; // expected-note {{later used here}}
}
@@ -355,7 +355,7 @@ void PointerParameterObjectUseIsOk(std::vector<int> *v) { // expected-warning {{
// FIXME: Distinguish owner-borrow from content-borrow.
void LocalPointerAliasObjectUseIsOk() {
std::vector<int> vv;
- std::vector<int> *v = &vv; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::vector<int> *v = &vv; // expected-warning {{local variable 'vv' is later invalidated}}
v->push_back(42); // expected-note {{invalidated here}}
(void)*v; // expected-note {{later used here}}
}
@@ -363,7 +363,7 @@ void LocalPointerAliasObjectUseIsOk() {
// FIXME: Distinguish owner-borrow from content-borrow.
void LocalReferenceAliasObjectUseIsOk() {
std::vector<int> vv;
- std::vector<int> &v = vv; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::vector<int> &v = vv; // expected-warning {{local variable 'vv' is later invalidated}}
v.push_back(42); // expected-note {{invalidated here}}
(void)v; // expected-note {{later used here}}
}
@@ -374,7 +374,7 @@ namespace ElementReferences {
void ReferenceToVectorElement() {
std::vector<int> v = {1, 2, 3};
- int& ref = v[0]; // expected-warning {{object whose reference is captured is later invalidated}}
+ int& ref = v[0]; // expected-warning {{local variable 'v' is later invalidated}}
v.push_back(4); // expected-note {{invalidated here}}
ref = 10; // expected-note {{later used here}}
(void)ref;
@@ -382,14 +382,14 @@ void ReferenceToVectorElement() {
void PointerRefToVectorElement() {
std::vector<int*> v = {nullptr, nullptr};
- int*& ref = v[0]; // expected-warning {{object whose reference is captured is later invalidated}}
+ int*& ref = v[0]; // expected-warning {{local variable 'v' is later invalidated}}
v.push_back(nullptr); // expected-note {{invalidated here}}
ref = nullptr; // expected-note {{later used here}}
}
void PointerToVectorElement() {
std::vector<int> v = {1, 2, 3};
- int* ptr = &v[0]; // expected-warning {{object whose reference is captured is later invalidated}}
+ int* ptr = &v[0]; // expected-warning {{local variable 'v' is later invalidated}}
v.resize(100); // expected-note {{invalidated here}}
*ptr = 10; // expected-note {{later used here}}
}
@@ -405,13 +405,13 @@ void SelfInvalidatingMap() {
mp[1] = "42";
mp[2] // expected-note {{invalidated here}}
=
- mp[1]; // expected-warning {{object whose reference is captured is later invalidated}} expected-note {{later used here}}
+ mp[1]; // expected-warning {{local variable 'mp' is later invalidated}} expected-note {{later used here}}
}
void InvalidateErase() {
std::flat_map<int, std::string> mp;
// None of these containers provide iterator stability. So following is unsafe:
- auto it = mp.find(3); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = mp.find(3); // expected-warning {{local variable 'mp' is later invalidated}}
mp.erase(mp.find(4)); // expected-note {{invalidated here}}
if (it != mp.end()) // expected-note {{later used here}}
*it;
@@ -421,12 +421,12 @@ void InvalidateErase() {
namespace Strings {
void append(std::string str) {
- std::string_view view = str; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::string_view view = str; // expected-warning {{parameter 'str' is later invalidated}}
str += "456"; // expected-note {{invalidated here}}
(void)view; // expected-note {{later used here}}
}
void reassign(std::string str, std::string str2) {
- std::string_view view = str; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::string_view view = str; // expected-warning {{parameter 'str' is later invalidated}}
str = str2; // expected-note {{invalidated here}}
(void)view; // expected-note {{later used here}}
}
@@ -434,7 +434,7 @@ void reassign(std::string str, std::string str2) {
// FIXME: This should be diagnosed as use-after-invalidation but with potential move.
void ReassigningAfterMove(std::string str, std::string str2) {
- std::string_view view = str; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::string_view view = str; // expected-warning {{parameter 'str' is later invalidated}}
std::vector<std::string> someStorage;
someStorage.push_back(std::move(str));
str = str2; // expected-note {{invalidated here}}
@@ -478,7 +478,7 @@ void ConditionalFieldInvalidatesIterator(bool flag) {
// FIXME: Requires field-sensitive AccessPaths to fix.
void Invalidate1Use2ViaRefIsOk() {
S s;
- auto it = s.strings2.begin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = s.strings2.begin(); // expected-warning {{local variable 's' is later invalidated}}
auto& strings1 = s.strings1;
strings1.push_back("1"); // expected-note {{invalidated here}}
*it; // expected-note {{later used here}}
@@ -492,13 +492,13 @@ void Invalidate1UseSIsOk() {
// FIXME: Distinguish owner-borrow from content-borrow.
void PointerToContainerIsOk() {
std::vector<std::string> s;
- std::vector<std::string>* p = &s; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::vector<std::string>* p = &s; // expected-warning {{local variable 's' is later invalidated}}
p->push_back("1"); // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
}
void IteratorFromPointerToContainerIsInvalidated() {
std::vector<std::string> s;
- std::vector<std::string>* p = &s; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::vector<std::string>* p = &s; // expected-warning {{local variable 's' is later invalidated}}
auto it = p->begin();
p->push_back("1"); // expected-note {{invalidated here}}
*it; // expected-note {{later used here}}
@@ -507,7 +507,7 @@ void IteratorFromPointerToContainerIsInvalidated() {
// iterators into the outer container.
void ChangingRegionOwnedByContainerIsOk() {
std::vector<std::string> subdirs;
- for (std::string& path : subdirs) // expected-warning {{object whose reference is captured is later invalidated}} expected-note {{later used here}}
+ for (std::string& path : subdirs) // expected-warning {{local variable 'subdirs' is later invalidated}} expected-note {{later used here}}
path = std::string(); // expected-note {{invalidated here}}
}
@@ -520,7 +520,7 @@ std::string StableString;
struct SinkOwnerBorrow {
std::string *dest_; // expected-note {{this field dangles}}
- SinkOwnerBorrow(std::string *dest, int n) : dest_(dest) { // expected-warning {{parameter which escapes to a field is later invalidated}}
+ SinkOwnerBorrow(std::string *dest, int n) : dest_(dest) { // expected-warning {{parameter 'dest' escapes to the field 'dest_' and is later invalidated}}
if (n > 0)
dest->clear(); // expected-note {{invalidated here}}
}
@@ -529,7 +529,7 @@ struct SinkOwnerBorrow {
struct SinkInteriorBorrow {
const char *dest_; // expected-note {{this field dangles}}
- SinkInteriorBorrow(std::string *dest, int n) : dest_(dest->data()) { // expected-warning {{parameter which escapes to a field is later invalidated}}
+ SinkInteriorBorrow(std::string *dest, int n) : dest_(dest->data()) { // expected-warning {{parameter 'dest' escapes to the field 'dest_' and is later invalidated}}
if (n > 0)
dest->clear(); // expected-note {{invalidated here}}
}
@@ -547,38 +547,38 @@ struct S {
void InvalidatedFieldLocalVector() {
std::vector<std::string> strings;
- FieldFromLocalVector = *strings.begin(); // expected-warning {{object whose reference escapes to a field is later invalidated}}
+ FieldFromLocalVector = *strings.begin(); // expected-warning {{local variable 'strings' escapes to the field 'FieldFromLocalVector' and is later invalidated}}
strings.push_back("1"); // expected-note {{invalidated here}}
}
void InvalidatedFieldByValueParamVector(std::vector<std::string> strings) {
- FieldFromByValueParamVector = *strings.begin(); // expected-warning {{object whose reference escapes to a field is later invalidated}}
+ FieldFromByValueParamVector = *strings.begin(); // expected-warning {{parameter 'strings' escapes to the field 'FieldFromByValueParamVector' and is later invalidated}}
strings.push_back("1"); // expected-note {{invalidated here}}
}
void InvalidatedFieldLocalString() {
std::string s;
- FieldFromLocalString = s; // expected-warning {{object whose reference escapes to a field is later invalidated}}
+ FieldFromLocalString = s; // expected-warning {{local variable 's' escapes to the field 'FieldFromLocalString' and is later invalidated}}
s.clear(); // expected-note {{invalidated here}}
}
void InvalidatedFieldByValueParamString(std::string s) {
- FieldFromByValueParamString = s; // expected-warning {{object whose reference escapes to a field is later invalidated}}
+ FieldFromByValueParamString = s; // expected-warning {{parameter 's' escapes to the field 'FieldFromByValueParamString' and is later invalidated}}
s.clear(); // expected-note {{invalidated here}}
}
- void InvalidatedFieldRefParamString(std::string &s) { // expected-warning {{parameter which escapes to a field is later invalidated}}
+ void InvalidatedFieldRefParamString(std::string &s) { // expected-warning {{parameter 's' escapes to the field 'FieldFromRefParamString' and is later invalidated}}
FieldFromRefParamString = s;
s.~basic_string(); // expected-note {{invalidated here}}
}
void InvalidatedFieldDelete() {
- int *p = new int; // expected-warning {{object whose reference escapes to a field is later invalidated}}
+ int *p = new int; // expected-warning {{allocated object escapes to the field 'FieldFromNew' and is later invalidated}}
FieldFromNew = p;
delete p; // expected-note {{freed here}}
}
- void InvalidatedFieldDeleteParam(int *p) { // expected-warning {{parameter which escapes to a field is later invalidated}}
+ void InvalidatedFieldDeleteParam(int *p) { // expected-warning {{parameter 'p' escapes to the field 'FieldFromPointerParam' and is later invalidated}}
FieldFromPointerParam = p;
delete p; // expected-note {{freed here}}
}
@@ -607,27 +607,27 @@ struct S {
void InvalidatedGlobalLocalVector() {
std::vector<std::string> strings;
- GlobalFromLocalVector = *strings.begin(); // expected-warning {{object whose reference escapes to global or static storage is later invalidated}}
+ GlobalFromLocalVector = *strings.begin(); // expected-warning {{local variable 'strings' escapes to the global variable 'GlobalFromLocalVector' and is later invalidated}}
strings.push_back("1"); // expected-note {{invalidated here}}
}
void InvalidatedGlobalByValueParamString(std::string s) {
- GlobalFromByValueParamString = s; // expected-warning {{object whose reference escapes to global or static storage is later invalidated}}
+ GlobalFromByValueParamString = s; // expected-warning {{parameter 's' escapes to the global variable 'GlobalFromByValueParamString' and is later invalidated}}
s.clear(); // expected-note {{invalidated here}}
}
-void InvalidatedGlobalRefParamString(std::string &s) { // expected-warning {{parameter which escapes to global or static storage is later invalidated}}
+void InvalidatedGlobalRefParamString(std::string &s) { // expected-warning {{parameter 's' escapes to the global variable 'GlobalFromRefParamString' and is later invalidated}}
GlobalFromRefParamString = s;
s.~basic_string(); // expected-note {{invalidated here}}
}
void InvalidatedGlobalDelete() {
- int *p = new int; // expected-warning {{object whose reference escapes to global or static storage is later invalidated}}
+ int *p = new int; // expected-warning {{allocated object escapes to the global variable 'GlobalFromNew' and is later invalidated}}
GlobalFromNew = p;
delete p; // expected-note {{freed here}}
}
-void InvalidatedGlobalDeleteParam(int *p) { // expected-warning {{parameter which escapes to global or static storage is later invalidated}}
+void InvalidatedGlobalDeleteParam(int *p) { // expected-warning {{parameter 'p' escapes to the global variable 'GlobalFromPointerParam' and is later invalidated}}
GlobalFromPointerParam = p;
delete p; // expected-note {{freed here}}
}
@@ -635,13 +635,13 @@ void InvalidatedGlobalDeleteParam(int *p) { // expected-warning {{parameter whic
void InvalidatedStaticLocalString() {
static std::string_view StaticFromLocalString; // expected-note {{this static storage dangles}}
std::string s;
- StaticFromLocalString = s; // expected-warning {{object whose reference escapes to global or static storage is later invalidated}}
+ StaticFromLocalString = s; // expected-warning {{local variable 's' escapes to the static variable 'StaticFromLocalString' and is later invalidated}}
s.clear(); // expected-note {{invalidated here}}
}
void InvalidatedStaticMemberString() {
std::string s;
- S::StaticMember = s; // expected-warning {{object whose reference escapes to global or static storage is later invalidated}}
+ S::StaticMember = s; // expected-warning {{local variable 's' escapes to the static variable 'StaticMember' and is later invalidated}}
s.clear(); // expected-note {{invalidated here}}
}
@@ -714,14 +714,14 @@ void SetExtractDoesNotInvalidateOthers() {
void SetClearInvalidates() {
std::set<int> s;
- auto it = s.begin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = s.begin(); // expected-warning {{local variable 's' is later invalidated}}
s.clear(); // expected-note {{invalidated here}}
*it; // expected-note {{later used here}}
}
void MapClearInvalidates() {
std::map<int, int> m;
- auto it = m.begin(); // expected-warning {{object whose reference is captured is later invalidated}}
+ auto it = m.begin(); // expected-warning {{local variable 'm' is later invalidated}}
m.clear(); // expected-note {{invalidated here}}
*it; // expected-note {{later used here}}
}
@@ -740,7 +740,7 @@ void MapSubscriptMultipleCallsDoesNotInvalidate(std::map<int, int> mp, int a, in
}
void FlatMapSubscriptMultipleCallsInvalidate(std::flat_map<int, int> mp, int a, int b) {
- PrintMax(mp[a], mp[b]); // expected-warning {{object whose reference is captured is later invalidated}} \
+ PrintMax(mp[a], mp[b]); // expected-warning {{parameter 'mp' is later invalidated}} \
// expected-note {{invalidated here}} \
// expected-note {{later used here}}
}
@@ -750,7 +750,7 @@ void FlatMapSubscriptMultipleCallsInvalidate(std::flat_map<int, int> mp, int a,
namespace lambda_capture_invalidation {
void captured_view_invalidated_by_owner() {
std::string s = "42";
- std::string_view p = s; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::string_view p = s; // expected-warning {{local variable 's' is later invalidated}}
auto lambda = [=]() { return p; };
s.push_back('c'); // expected-note {{invalidated here}}
lambda(); // expected-note {{later used here}}
@@ -758,7 +758,7 @@ void captured_view_invalidated_by_owner() {
void multiple_captures_one_invalidated() {
std::string s1 = "a", s2 = "b";
- std::string_view p1 = s1, p2 = s2; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::string_view p1 = s1, p2 = s2; // expected-warning {{local variable 's1' is later invalidated}}
auto lambda = [=]() { return p1.size() + p2.size(); };
s1.clear(); // expected-note {{invalidated here}}
lambda(); // expected-note {{later used here}}
@@ -793,7 +793,7 @@ struct S {
void bar();
void baz(){
std::vector<std::string> vec = {"42"};
- v = vec[0]; // expected-warning {{object whose reference is captured is later invalidated}}
+ v = vec[0]; // expected-warning {{local variable 'vec' is later invalidated}}
vec.push_back("1"); // expected-note {{invalidated here}}
bar(); // expected-note {{later used here}}
v = nullptr;
@@ -806,7 +806,7 @@ namespace callable_wrappers {
void function_captured_ref_invalidated() {
std::vector<int> v;
v.push_back(1);
- std::function<void()> f = [&r = v[0]]() { (void)r; }; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::function<void()> f = [&r = v[0]]() { (void)r; }; // expected-warning {{local variable 'v' is later invalidated}}
v.push_back(2); // expected-note {{invalidated here}}
(void)f; // expected-note {{later used here}}
}
@@ -818,14 +818,14 @@ namespace explicit_destructor {
void explicit_destructor_invalidates_pointer() {
std::string s = "42";
- const char *p = s.data(); // expected-warning {{object whose reference is captured is later invalidated}}
+ const char *p = s.data(); // expected-warning {{local variable 's' is later invalidated}}
s.~basic_string(); // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
}
void pointer_destructor_invalidates_pointer() {
char storage[sizeof(std::string)];
- std::string *obj = new (storage) std::string("42"); // expected-warning {{object whose reference is captured is later invalidated}}
+ std::string *obj = new (storage) std::string("42"); // expected-warning {{local variable 'storage' is later invalidated}}
const char *p = obj->data();
obj->~basic_string(); // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
@@ -833,7 +833,7 @@ void pointer_destructor_invalidates_pointer() {
void destroy_at_invalidates_pointer() {
char storage[sizeof(std::string)];
- std::string *obj = new (storage) std::string("42"); // expected-warning {{object whose reference is captured is later invalidated}}
+ std::string *obj = new (storage) std::string("42"); // expected-warning {{local variable 'storage' is later invalidated}}
const char *p = obj->data();
std::destroy_at(obj); // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
@@ -852,21 +852,21 @@ void destroy_at_then_placement_new_rescues_pointer() {
void destroy_at_invalidates_array_pointer() {
std::string arr[1] = {"42"};
std::string (&arr_ref)[1] = arr;
- const char *p = arr[0].data(); // expected-warning {{object whose reference is captured is later invalidated}}
+ const char *p = arr[0].data(); // expected-warning {{local variable 'arr' is later invalidated}}
std::destroy_at(&arr_ref); // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
}
void reference_destructor_invalidates_pointer() {
std::string s = "42";
- std::string &ref = s; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::string &ref = s; // expected-warning {{local variable 's' is later invalidated}}
const char *p = ref.data();
std::destroy_at(&ref); // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
}
void destroy_at_ternary_operator(bool flag) {
- std::string* str1 = new std::string; // expected-warning {{object whose reference is captured is later invalidated}}
+ std::string* str1 = new std::string; // expected-warning {{allocated object is later invalidated}}
std::string* str2 = new std::string;
const char *p = str1->data();
std::destroy_at(flag ? str1 : str2); // expected-note {{invalidated here}}
@@ -880,7 +880,7 @@ struct StringOwner {
// FIXME: False-positive
void member_destructor_invalidates_pointer() {
StringOwner owner = {"42", "43"};
- const char *p = owner.s.data(); // expected-warning {{object whose reference is captured is later invalidated}}
+ const char *p = owner.s.data(); // expected-warning {{local variable 'owner' is later invalidated}}
owner.t.~basic_string(); // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
}
@@ -891,7 +891,7 @@ namespace unique_ptr_invalidation {
void invalid_after_reset() {
std::unique_ptr<int> up(new int);
- int *p = up.get(); // expected-warning {{object whose reference is captured is later invalidated}}
+ int *p = up.get(); // expected-warning {{local variable 'up' is later invalidated}}
up.reset(); // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
}
@@ -899,14 +899,14 @@ void invalid_after_reset() {
void invalid_after_move_assign() {
std::unique_ptr<int> up(new int);
std::unique_ptr<int> other(new int);
- int *p = up.get(); // expected-warning {{object whose reference is captured is later invalidated}}
+ int *p = up.get(); // expected-warning {{local variable 'up' is later invalidated}}
up = std::move(other); // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
}
void invalid_after_null_assign() {
std::unique_ptr<int> up(new int);
- int *p = up.get(); // expected-warning {{object whose reference is captured is later invalidated}}
+ int *p = up.get(); // expected-warning {{local variable 'up' is later invalidated}}
up = nullptr; // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
}
@@ -914,7 +914,7 @@ void invalid_after_null_assign() {
void invalid_after_ternary_reset(bool flag) {
std::unique_ptr<int> up(new int);
std::unique_ptr<int> other(new int);
- int *p = flag ? up.get() : other.get(); // expected-warning {{object whose reference is captured is later invalidated}}
+ int *p = flag ? up.get() : other.get(); // expected-warning {{local variable 'up' is later invalidated}}
up.reset(); // expected-note {{invalidated here}}
(void)*p; // expected-note {{later used here}}
}
diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp
index d976baa545b8c..1c4b3c117fb00 100644
--- a/clang/test/Sema/LifetimeSafety/safety.cpp
+++ b/clang/test/Sema/LifetimeSafety/safety.cpp
@@ -2943,7 +2943,7 @@ void delete_pointer_propagation_use_after_free() {
(void)(*pp)->id; // expected-note {{later used here}}
}
-void delete_param_pointer(int* x) { // expected-warning {{parameter does not live long enough}}
+void delete_param_pointer(int* x) { // expected-warning {{parameter 'x' does not live long enough}}
delete x; // expected-note {{freed here}}
(void)x; // expected-note {{later used here}}
}
@@ -2957,7 +2957,7 @@ struct S {
}
};
-void use_inner_origin_after_delete(MyObj* obj) { // expected-warning {{parameter does not live long enough}}
+void use_inner_origin_after_delete(MyObj* obj) { // expected-warning {{parameter 'obj' does not live long enough}}
int* p = &obj->id;
delete obj; // expected-note {{freed here}}
(void)*p; // expected-note {{later used here}}
@@ -3009,14 +3009,14 @@ void delete_through_pointer_field() {
void delete_stack_object() {
MyObj obj;
- MyObj* p = &obj; // expected-warning {{allocated object does not live long enough}}
+ MyObj* p = &obj; // expected-warning {{local variable 'obj' does not live long enough}}
delete &obj; // expected-note {{freed here}}
(void)p->id; // expected-note {{later used here}}
}
void delete_stack_object_int() {
int obj;
- int* p = &obj; // expected-warning {{allocated object does not live long enough}}
+ int* p = &obj; // expected-warning {{local variable 'obj' does not live long enough}}
delete &obj; // expected-note {{freed here}}
(void)*p; // expected-note {{later used here}}
}
More information about the llvm-branch-commits
mailing list