https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/180446
>From 56ce0554ba3d564116cbf363a97b5869f579d78e Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Sun, 8 Feb 2026 22:29:52 +0000 Subject: [PATCH] Improve liveness to detect more invaldiations --- .../Analysis/LifetimeSafety/FactsGenerator.cpp | 6 ++++++ clang/test/Sema/Inputs/lifetime-analysis.h | 16 +++++++++++----- .../Sema/warn-lifetime-safety-invalidations.cpp | 17 ++++++++++++++--- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index b69f69ddbae34..40661289b2f2b 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -366,6 +366,9 @@ void FactsGenerator::VisitBinaryOperator(const BinaryOperator *BO) { // result should have the same loans as the pointer operand. if (BO->isCompoundAssignmentOp()) return; + if (auto *RHSOrigins = getOriginsList(*BO->getRHS())) + CurrentBlockFacts.push_back( + FactMgr.createFact<UseFact>(BO->getRHS(), RHSOrigins)); if (BO->isAssignmentOp()) handleAssignment(BO->getLHS(), BO->getRHS()); // TODO: Handle assignments involving dereference like `*p = q`. @@ -582,6 +585,9 @@ void FactsGenerator::handleFunctionCall(const Expr *Call, FD = getDeclWithMergedLifetimeBoundAttrs(FD); if (!FD) return; + for (const Expr *Arg : Args) + if (OriginList *ArgList = getOriginsList(*Arg)) + CurrentBlockFacts.push_back(FactMgr.createFact<UseFact>(Arg, ArgList)); handleInvalidatingCall(Call, FD, Args); handleMovedArgsInCall(FD, Args); diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h b/clang/test/Sema/Inputs/lifetime-analysis.h index f30db1a29b149..880e4650f21d0 100644 --- a/clang/test/Sema/Inputs/lifetime-analysis.h +++ b/clang/test/Sema/Inputs/lifetime-analysis.h @@ -75,11 +75,6 @@ struct vector { void clear(); }; -template<class Key,class T> -struct unordered_map { - T& operator[](const Key& key); -}; - template<class T> void swap( T& a, T& b ); @@ -89,6 +84,17 @@ struct pair { B second; }; +template<class Key,class T> +struct unordered_map { + using iterator = __gnu_cxx::basic_iterator<std::pair<const Key, T>>; + T& operator[](const Key& key); + iterator begin(); + iterator end(); + iterator find(const Key& key); + void erase(iterator); +}; + + template<typename T> struct basic_string_view { basic_string_view(); diff --git a/clang/test/Sema/warn-lifetime-safety-invalidations.cpp b/clang/test/Sema/warn-lifetime-safety-invalidations.cpp index c9ce0c35c53d2..1e7ba3e6f1970 100644 --- a/clang/test/Sema/warn-lifetime-safety-invalidations.cpp +++ b/clang/test/Sema/warn-lifetime-safety-invalidations.cpp @@ -260,9 +260,20 @@ void PointerToVectorElement() { } void SelfInvalidatingMap() { - std::unordered_map<int, int> mp; - mp[1] = 1; - mp[2] = mp[1]; // FIXME: Detect this. We are mising a UseFact for the assignment params. + std::unordered_map<int, std::string> mp; + // TODO: We do not have a way to differentiate between pointer stability and iterator stability! + // std::unordered_map and other containers provide pointer/reference stability. Therefore the following is safe in practice. + // On the other hand, std::flat_hash_map (since C++23) does not provide pointer stability on insertion. + mp[1] = "42"; + mp[2] = mp[1]; // expected-warning {{object whose reference is captured is later invalidated}} \ + // expected-note {{invalidated here}} \ + // expected-note {{later used here}} + + // None of these containers provide iterator stability. So following is invalid: + auto it = mp.find(3); // expected-warning {{object whose reference is captured is later invalidated}} + mp.erase(mp.find(4)); // expected-note {{invalidated here}} + if (it != mp.end()) // expected-note {{later used here}} + *it; } } // namespace ElementReferences _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
