Author: PushkarSingh Date: 2026-09-10T08:04:35+01:00 New Revision: a91c7395c3fb1a37f69f7d8fb0e78c048faf6cb7
URL: https://github.com/llvm/llvm-project/commit/a91c7395c3fb1a37f69f7d8fb0e78c048faf6cb7 DIFF: https://github.com/llvm/llvm-project/commit/a91c7395c3fb1a37f69f7d8fb0e78c048faf6cb7.diff LOG: [Lifetime Safety] Name operator calls in alias-chain diagnostics (#221803) This updates Lifetime Safety alias-chain diagnostics to identify overloaded operator and conversion calls instead of describing them generically as an `expression`. Previously, these calls were reported as `expression aliases the storage of ...`, which could make it unclear which operation introduced the alias. The diagnostic now reports the callee using the existing diagnostic name printer, producing descriptions such as: - `result of call to 'operator->'` - `result of call to 'operator()'` - `result of call to 'operator basic_string_view'` Template arguments are preserved for operator function-template specializations. For example: - `result of call to 'operator+<const int>'` - `result of call to 'operator-<__gnu_cxx::basic_iterator<const int>>'` This makes each aliasing step explicit and identifies the particular call responsible for propagating the alias. References to [#220248#discussion_r3905817437](https://github.com/llvm/llvm-project/pull/220248#discussion_r3905817437) Added: Modified: clang/lib/Sema/SemaLifetimeSafety.h clang/test/Sema/LifetimeSafety/invalidations.cpp clang/test/Sema/LifetimeSafety/nocfg.cpp clang/test/Sema/LifetimeSafety/safety.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index 0fd3486bcee46..620032c27f955 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -687,8 +687,6 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { const auto *FD = CE->getDirectCallee(); if (!FD) return "result of call"; - if (FD->isOverloadedOperator() || isa<CXXConversionDecl>(FD)) - return "expression"; std::string Name; llvm::raw_string_ostream OS(Name); FD->getNameForDiagnostic(OS, S.getPrintingPolicy(), diff --git a/clang/test/Sema/LifetimeSafety/invalidations.cpp b/clang/test/Sema/LifetimeSafety/invalidations.cpp index 127e375bc023c..593ba92cf7443 100644 --- a/clang/test/Sema/LifetimeSafety/invalidations.cpp +++ b/clang/test/Sema/LifetimeSafety/invalidations.cpp @@ -271,7 +271,7 @@ void IteratorUsedAfterPreIncrement() { std::vector<int> v; auto it = v.begin(); // expected-warning {{local variable 'v' is later invalidated}} \ // expected-note {{result of call to 'begin' aliases the storage of local variable 'v'}} - auto next = ++it; // expected-note {{expression aliases the storage of local variable 'v'}} + auto next = ++it; // expected-note {{result of call to 'operator++' aliases the storage of local variable 'v'}} v.push_back(1); // expected-note {{local variable 'v' is invalidated here}} (void)*next; // expected-note {{later used here}} } @@ -279,7 +279,7 @@ void IteratorUsedAfterPreIncrement() { void IteratorUsedAfterPostDecrement(std::vector<int> v) { auto it = v.rbegin(); // expected-warning {{parameter 'v' is later invalidated}} \ // expected-note {{result of call to 'rbegin' aliases the storage of parameter 'v'}} - auto prev = it--; // expected-note {{expression aliases the storage of parameter 'v'}} + auto prev = it--; // expected-note {{result of call to 'operator--' aliases the storage of parameter 'v'}} v.push_back(1); // expected-note {{parameter 'v' is invalidated here}} (void)*prev; // expected-note {{later used here}} } @@ -288,7 +288,7 @@ void IteratorUsedAfterAddition() { std::vector<int> v; auto it = v.cbegin(); // expected-warning {{local variable 'v' is later invalidated}} \ // expected-note {{result of call to 'cbegin' aliases the storage of local variable 'v'}} - auto next = it + 5; // expected-note {{expression aliases the storage of local variable 'v'}} + auto next = it + 5; // expected-note {{result of call to 'operator+' aliases the storage of local variable 'v'}} v.push_back(1); // expected-note {{local variable 'v' is invalidated here}} (void)*next; // expected-note {{later used here}} } @@ -297,7 +297,7 @@ void IteratorUsedAfterReverseSubtraction(std::vector<int> v) { auto it = v.crbegin(); // expected-warning {{parameter 'v' is later invalidated}} \ // expected-note {{result of call to 'crbegin' aliases the storage of parameter 'v'}} auto prev = 5 - it; // expected-note {{local variable 'it' aliases the storage of parameter 'v'}} \ - // expected-note {{expression aliases the storage of parameter 'v'}} + // expected-note {{result of call to 'operator-<__gnu_cxx::basic_iterator<const int>>' aliases the storage of parameter 'v'}} v.push_back(1); // expected-note {{parameter 'v' is invalidated here}} (void)*prev; // expected-note {{later used here}} } @@ -305,7 +305,7 @@ void IteratorUsedAfterReverseSubtraction(std::vector<int> v) { void IteratorUsedAfterAddAdd(std::vector<int> v) { auto it = v.cbegin(); // expected-warning {{parameter 'v' is later invalidated}} \ // expected-note {{result of call to 'cbegin' aliases the storage of parameter 'v'}} - auto next = (it + 5) + 5; // expected-note 2 {{expression aliases the storage of parameter 'v'}} + auto next = (it + 5) + 5; // expected-note 2 {{result of call to 'operator+' aliases the storage of parameter 'v'}} v.push_back(1); // expected-note {{parameter 'v' is invalidated here}} (void)*next; // expected-note {{later used here}} } @@ -314,7 +314,8 @@ void IteratorUsedAfterMixedAddition() { std::vector<int> v; auto it = v.cbegin(); // expected-warning {{local variable 'v' is later invalidated}} \ // expected-note {{result of call to 'cbegin' aliases the storage of local variable 'v'}} - auto next = 1 + it + 2 + 3; // expected-note 3 {{expression aliases the storage of local variable 'v'}} \ + auto next = 1 + it + 2 + 3; // expected-note {{result of call to 'operator+<const int>' aliases the storage of local variable 'v'}} \ + // expected-note 2 {{result of call to 'operator+' aliases the storage of local variable 'v'}} \ // expected-note {{local variable 'it' aliases the storage of local variable 'v'}} v.push_back(1); // expected-note {{local variable 'v' is invalidated here}} (void)*next; // expected-note {{later used here}} @@ -323,7 +324,8 @@ void IteratorUsedAfterMixedAddition() { void IteratorUsedAfterPreIncrementAddAssign(std::vector<int> v) { auto it = v.begin(); // expected-warning {{parameter 'v' is later invalidated}} \ // expected-note {{result of call to 'begin' aliases the storage of parameter 'v'}} - it = ++it + 1 + 2; // expected-note 3 {{expression aliases the storage of parameter 'v'}} + it = ++it + 1 + 2; // expected-note {{result of call to 'operator++' aliases the storage of parameter 'v'}} \ + // expected-note 2 {{result of call to 'operator+' aliases the storage of parameter 'v'}} v.push_back(1); // expected-note {{parameter 'v' is invalidated here}} (void)*it; // expected-note {{later used here}} } @@ -331,7 +333,7 @@ void IteratorUsedAfterPreIncrementAddAssign(std::vector<int> v) { void IteratorUsedAfterBeginAddAssign() { std::vector<int> v; auto it = v.begin() + 1; // expected-warning {{local variable 'v' is later invalidated}} \ - // expected-note {{expression aliases the storage of local variable 'v'}} \ + // expected-note {{result of call to 'operator+' aliases the storage of local variable 'v'}} \ // expected-note {{result of call to 'begin' aliases the storage of local variable 'v'}} v.push_back(1); // expected-note {{local variable 'v' is invalidated here}} (void)*it; // expected-note {{later used here}} @@ -341,7 +343,7 @@ void IteratorUsedAfterStdBeginAddAssign() { std::vector<int> v; std::vector<int>::iterator it; it = std::begin(v) + 1; // expected-warning {{local variable 'v' is later invalidated}} \ - // expected-note {{expression aliases the storage of local variable 'v'}} \ + // expected-note {{result of call to 'operator+' aliases the storage of local variable 'v'}} \ // expected-note {{result of call to 'begin<std::vector<int>>' aliases the storage of local variable 'v'}} v.push_back(1); // expected-note {{local variable 'v' is invalidated here}} (void)*it; // expected-note {{later used here}} @@ -404,7 +406,7 @@ namespace ElementReferences { void ReferenceToVectorElement() { std::vector<int> v = {1, 2, 3}; int& ref = v[0]; // expected-warning {{local variable 'v' is later invalidated}} \ - // expected-note {{expression aliases the storage of local variable 'v'}} + // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'v'}} v.push_back(4); // expected-note {{local variable 'v' is invalidated here}} ref = 10; // expected-note {{later used here}} (void)ref; @@ -413,7 +415,7 @@ void ReferenceToVectorElement() { void PointerRefToVectorElement() { std::vector<int*> v = {nullptr, nullptr}; int*& ref = v[0]; // expected-warning {{local variable 'v' is later invalidated}} \ - // expected-note {{expression aliases the storage of local variable 'v'}} + // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'v'}} v.push_back(nullptr); // expected-note {{local variable 'v' is invalidated here}} ref = nullptr; // expected-note {{later used here}} } @@ -421,7 +423,7 @@ void PointerRefToVectorElement() { void PointerToVectorElement() { std::vector<int> v = {1, 2, 3}; int* ptr = &v[0]; // expected-warning {{local variable 'v' is later invalidated}} \ - // expected-note {{expression aliases the storage of local variable 'v'}} + // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'v'}} v.resize(100); // expected-note {{local variable 'v' is invalidated here}} *ptr = 10; // expected-note {{later used here}} } @@ -447,7 +449,7 @@ void SelfInvalidatingMap() { // expected-note {{local variable 'mp' is invalidated here}} \ // expected-note {{later used here}} \ // expected-note {{local variable 'mp' is invalidated here}} \ - // expected-note {{expression aliases the storage of local variable 'mp'}} \ + // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'mp'}} \ // expected-note {{later used here}} } @@ -798,7 +800,7 @@ void FlatMapSubscriptMultipleCallsInvalidate(std::flat_map<int, int> mp, int a, // expected-note {{parameter 'mp' is invalidated here}} \ // expected-note {{later used here}} \ // expected-note {{parameter 'mp' is invalidated here}} \ - // expected-note 2 {{expression aliases the storage of parameter 'mp'}} \ + // expected-note 2 {{result of call to 'operator[]' aliases the storage of parameter 'mp'}} \ // expected-note {{later used here}} } @@ -851,7 +853,7 @@ struct S { void baz(){ std::vector<std::string> vec = {"42"}; v = vec[0]; // expected-warning {{local variable 'vec' is later invalidated}} \ - // expected-note {{expression aliases the storage of local variable 'vec'}} + // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'vec'}} vec.push_back("1"); // expected-note {{local variable 'vec' is invalidated here}} bar(); // expected-note {{later used here}} v = nullptr; @@ -865,7 +867,7 @@ void function_captured_ref_invalidated() { std::vector<int> v; v.push_back(1); std::function<void()> f = [&r = v[0]]() { (void)r; }; // expected-warning {{local variable 'v' is later invalidated}} \ - // expected-note {{expression aliases the storage of local variable 'v'}} + // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'v'}} v.push_back(2); // expected-note {{local variable 'v' is invalidated here}} (void)f; // expected-note {{later used here}} } diff --git a/clang/test/Sema/LifetimeSafety/nocfg.cpp b/clang/test/Sema/LifetimeSafety/nocfg.cpp index 5c5f0e6f7ce52..7ef209572c437 100644 --- a/clang/test/Sema/LifetimeSafety/nocfg.cpp +++ b/clang/test/Sema/LifetimeSafety/nocfg.cpp @@ -310,11 +310,11 @@ std::string_view danglingRefToOptionalFromTemp4() { void danglingReferenceFromTempOwner() { int &&r = *std::optional<int>(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \ // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} + // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} // https://github.com/llvm/llvm-project/issues/175893 int &&r2 = *std::optional<int>(5); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \ // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} + // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} // https://github.com/llvm/llvm-project/issues/175893 int &&r3 = std::optional<int>(5).value(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \ @@ -331,7 +331,7 @@ void danglingReferenceFromTempOwner() { std::string_view sv = *getTempOptStr(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \ // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} + // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} use(sv); // cfg-note {{later used here}} } @@ -343,7 +343,7 @@ void testLoops() { ; for (auto i : *getTempOptVec()) // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \ // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} cfg-note {{later used here}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} + // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} ; } @@ -1050,15 +1050,15 @@ void operator_star_arrow_reference() { auto temporary = []() { return std::vector<std::string>{{"1"}}; }; const char* x = temporary().begin()->data(); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ // cfg-note {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ + // cfg-note {{result of call to 'operator->' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ // cfg-note {{result of call to 'data' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} const char* y = (*temporary().begin()).data(); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ // cfg-note {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ + // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ // cfg-note {{result of call to 'data' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} const std::string& z = (*temporary().begin()); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ // cfg-note {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} + // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} use(p, q, r, x, y, z); // cfg-note 3 {{later used here}} } @@ -1072,15 +1072,15 @@ void operator_star_arrow_of_iterators_false_positive_no_cfg_analysis() { auto temporary = []() { return std::vector<std::pair<int, std::string>>{{1, "1"}}; }; const char* x = temporary().begin()->second.data(); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ // cfg-note {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ + // cfg-note {{result of call to 'operator->' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ // cfg-note {{result of call to 'data' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} const char* y = (*temporary().begin()).second.data(); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ // cfg-note {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ + // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ // cfg-note {{result of call to 'data' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} const std::string& z = (*temporary().begin()).second; // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ // cfg-note {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} + // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} use(p, q, r, x, y, z); // cfg-note 3 {{later used here}} } @@ -1131,23 +1131,23 @@ void test1() { std::string_view k1 = S().sv; // OK std::string_view k2 = S().s; // expected-warning {{object backing the pointer will}} \ // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} + // cfg-note {{result of call to 'operator basic_string_view' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} std::string_view k3 = Q().get()->sv; // OK std::string_view k4 = Q().get()->s; // expected-warning {{object backing the pointer will}} \ // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ // cfg-note {{result of call to 'get' aliases the storage of temporary object because the implicit object parameter is marked as lifetimebound}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} + // cfg-note {{result of call to 'operator basic_string_view' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} std::string_view lb1 = foo(S().s); // expected-warning {{object backing the pointer will}} \ // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ + // cfg-note {{result of call to 'operator basic_string_view' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ // cfg-note {{result of call to 'foo' aliases the storage of temporary object because parameter 'sv' is marked as lifetimebound}} std::string_view lb2 = foo(Q().get()->s); // expected-warning {{object backing the pointer will}} \ // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \ // cfg-note {{result of call to 'get' aliases the storage of temporary object because the implicit object parameter is marked as lifetimebound}} \ - // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ + // cfg-note {{result of call to 'operator basic_string_view' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \ // cfg-note {{result of call to 'foo' aliases the storage of temporary object because parameter 'sv' is marked as lifetimebound}} use(k1, k2, k3, k4, lb1, lb2); // cfg-note 4 {{later used here}} diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp index 1b269b265acb1..851f558c85dcd 100644 --- a/clang/test/Sema/LifetimeSafety/safety.cpp +++ b/clang/test/Sema/LifetimeSafety/safety.cpp @@ -1677,7 +1677,7 @@ void test_user_defined_deref_uaf() { MyObj obj; SmartPtr<MyObj> smart_ptr(&obj); p = &(*smart_ptr); // expected-warning {{local variable 'smart_ptr' does not live long enough}} \ - // expected-note {{expression aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}} + // expected-note {{result of call to 'operator*' aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}} } // expected-note {{local variable 'smart_ptr' is destroyed here}} (void)*p; // expected-note {{later used here}} } @@ -1695,7 +1695,7 @@ void test_user_defined_deref_with_view() { MyObj obj; SmartPtr<MyObj> smart_ptr(&obj); v = *smart_ptr; // expected-warning {{local variable 'smart_ptr' does not live long enough}} \ - // expected-note {{expression aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}} + // expected-note {{result of call to 'operator*' aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}} } // expected-note {{local variable 'smart_ptr' is destroyed here}} v.use(); // expected-note {{later used here}} } @@ -1706,7 +1706,7 @@ void test_user_defined_deref_arrow() { MyObj obj; SmartPtr<MyObj> smart_ptr(&obj); p = smart_ptr.operator->(); // expected-warning {{local variable 'smart_ptr' does not live long enough}} \ - // expected-note {{expression aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}} + // expected-note {{result of call to 'operator->' aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}} } // expected-note {{local variable 'smart_ptr' is destroyed here}} (void)*p; // expected-note {{later used here}} } @@ -1717,7 +1717,7 @@ void test_user_defined_deref_chained() { MyObj obj; SmartPtr<SmartPtr<MyObj>> double_ptr; p = &(**double_ptr); // expected-warning {{local variable 'double_ptr' does not live long enough}} \ - // expected-note 2 {{expression aliases the storage of local variable 'double_ptr' because the implicit object parameter is marked as lifetimebound}} + // expected-note 2 {{result of call to 'operator*' aliases the storage of local variable 'double_ptr' because the implicit object parameter is marked as lifetimebound}} } // expected-note {{local variable 'double_ptr' is destroyed here}} (void)*p; // expected-note {{later used here}} } @@ -2052,7 +2052,7 @@ void test_temporary() { S s; const std::string& zz = s.x(); // expected-warning {{local variable 's' does not live long enough}} \ // expected-note {{result of call to 'x' aliases the storage of local variable 's' because the implicit object parameter is marked as lifetimebound}} - z = zz; // expected-note {{expression aliases the storage of local variable 's'}} + z = zz; // expected-note {{result of call to 'operator basic_string_view' aliases the storage of local variable 's'}} } // expected-note {{local variable 's' is destroyed here}} (void)z; // expected-note {{later used here}} } @@ -2085,7 +2085,7 @@ void uaf() { S str; S* p = &str; // expected-warning {{local variable 'str' does not live long enough}} view = p->s; // expected-note {{local variable 'p' aliases the storage of local variable 'str'}} \ - // expected-note {{expression aliases the storage of local variable 'str' because the implicit object parameter is inferred as lifetimebound}} + // expected-note {{result of call to 'operator basic_string_view' aliases the storage of local variable 'str' because the implicit object parameter is inferred as lifetimebound}} } // expected-note {{local variable 'str' is destroyed here}} (void)view; // expected-note {{later used here}} } @@ -2112,7 +2112,7 @@ void uaf_union() { U u = U{"hello"}; U* up = &u; // expected-warning {{local variable 'u' does not live long enough}} view = up->s; // expected-note {{local variable 'up' aliases the storage of local variable 'u'}} \ - // expected-note {{expression aliases the storage of local variable 'u' because the implicit object parameter is inferred as lifetimebound}} + // expected-note {{result of call to 'operator basic_string_view' aliases the storage of local variable 'u' because the implicit object parameter is inferred as lifetimebound}} } // expected-note {{local variable 'u' is destroyed here}} (void)view; // expected-note {{later used here}} } @@ -2288,7 +2288,7 @@ void test_optional_arrow() { { std::optional<std::string> opt; p = opt->data(); // expected-warning {{local variable 'opt' does not live long enough}} \ - // expected-note {{expression aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} \ + // expected-note {{result of call to 'operator->' aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} \ // expected-note {{result of call to 'data' aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} } // expected-note {{local variable 'opt' is destroyed here}} (void)*p; // expected-note {{later used here}} @@ -2299,7 +2299,7 @@ void test_optional_arrow_lifetimebound() { { std::optional<MyObj> opt; v = opt->getView(); // expected-warning {{local variable 'opt' does not live long enough}} \ - // expected-note {{expression aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} \ + // expected-note {{result of call to 'operator->' aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} \ // expected-note {{result of call to 'getView' aliases the storage of local variable 'opt' because the implicit object parameter is marked as lifetimebound}} } // expected-note {{local variable 'opt' is destroyed here}} v.use(); // expected-note {{later used here}} @@ -2310,7 +2310,7 @@ void test_unique_ptr_arrow() { { std::unique_ptr<std::string> up; p = up->data(); // expected-warning {{local variable 'up' does not live long enough}} \ - // expected-note {{expression aliases the storage of local variable 'up' because the implicit object parameter is inferred as lifetimebound}} \ + // expected-note {{result of call to 'operator->' aliases the storage of local variable 'up' because the implicit object parameter is inferred as lifetimebound}} \ // expected-note {{result of call to 'data' aliases the storage of local variable 'up' because the implicit object parameter is inferred as lifetimebound}} } // expected-note {{local variable 'up' is destroyed here}} (void)*p; // expected-note {{later used here}} @@ -2701,8 +2701,8 @@ struct S { void indexing_with_static_operator() { S()(1, 2); - S& x = S()("1", // expected-note {{expression aliases the storage of temporary object because parameter 'a' is marked as lifetimebound}} \ - // expected-note {{expression aliases the storage of temporary object because parameter 'b' is marked as lifetimebound}} + S& x = S()("1", // expected-note {{result of call to 'operator()' aliases the storage of temporary object because parameter 'a' is marked as lifetimebound}} \ + // expected-note {{result of call to 'operator()' aliases the storage of temporary object because parameter 'b' is marked as lifetimebound}} 2, // expected-warning {{temporary object does not live long enough}} 3); // expected-warning {{temporary object does not live long enough}} expected-note 2 {{temporary object is destroyed here}} @@ -2810,7 +2810,7 @@ void chained_defaulted_assignment_propagation() { S a = getS(str); // expected-warning {{local variable 'str' does not live long enough}} \ // expected-note {{result of call to 'getS' aliases the storage of local variable 'str' because parameter 's' is marked as lifetimebound}} c = b = a; // expected-note {{local variable 'a' aliases the storage of local variable 'str'}} \ - // expected-note {{expression aliases the storage of local variable 'str'}} + // expected-note {{result of call to 'operator=' aliases the storage of local variable 'str'}} } // expected-note {{local variable 'str' is destroyed here}} use(c); // expected-note {{later used here}} } @@ -3873,7 +3873,7 @@ void deref_use_after_scope() { { optional<MyObj> opt; p = &*opt; // expected-warning {{local variable 'opt' does not live long enough}} \ - // expected-note {{expression aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} + // expected-note {{result of call to 'operator*' aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} } // expected-note {{local variable 'opt' is destroyed here}} (void)p->id; // expected-note {{later used here}} } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
