llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: PushkarSingh (iitianpushkar) <details> <summary>Changes</summary> 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) --- Patch is 33.79 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/221803.diff 4 Files Affected: - (modified) clang/lib/Sema/SemaLifetimeSafety.h (-2) - (modified) clang/test/Sema/LifetimeSafety/invalidations.cpp (+18-16) - (modified) clang/test/Sema/LifetimeSafety/nocfg.cpp (+14-14) - (modified) clang/test/Sema/LifetimeSafety/safety.cpp (+14-14) ``````````diff 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 tem... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/221803 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
