https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/205250
>From 1ca4f441b6209697f1c7d8c97c1d9a12d03f129c Mon Sep 17 00:00:00 2001 From: Zeyi Xu <[email protected]> Date: Tue, 23 Jun 2026 11:54:15 +0800 Subject: [PATCH 1/3] [LifetimeSafety] Cache lifetimebound macro lookup. NFC. --- clang/lib/Sema/SemaLifetimeSafety.h | 91 ++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 8 deletions(-) diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index 4bde272fb40a1..c2f7a56e166c4 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -442,21 +442,94 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { } private: + struct LifetimeBoundMacroCache { + bool IsBuilt = false; + llvm::SmallVector<const IdentifierInfo *> Candidates; + }; + + void buildLifetimeBoundMacroCache(LifetimeBoundMacroCache &Cache, + llvm::ArrayRef<TokenValue> Tokens) { + if (Cache.IsBuilt) + return; + + const Preprocessor &PP = S.getPreprocessor(); + // Collect macro names that were ever defined as a lifetimebound attribute. + for (const auto &M : PP.macros()) { + const IdentifierInfo *II = M.first; + const MacroDirective *MD = PP.getLocalMacroDirectiveHistory(II); + if (!MD) + continue; + + // Include earlier matching definitions to handle redefinitions. + for (MacroDirective::DefInfo Def = MD->getDefinition(); Def; + Def = Def.getPreviousDefinition()) { + const MacroInfo *MI = Def.getMacroInfo(); + if (MI->isObjectLike() && Tokens.size() == MI->getNumTokens() && + std::equal(Tokens.begin(), Tokens.end(), MI->tokens_begin())) { + Cache.Candidates.push_back(II); + break; + } + } + } + Cache.IsBuilt = true; + } + + StringRef getLastCachedMacroWithSpelling(SourceLocation Loc, + llvm::ArrayRef<TokenValue> Tokens, + LifetimeBoundMacroCache &Cache) { + if (Loc.isInvalid()) + return {}; + + buildLifetimeBoundMacroCache(Cache, Tokens); + + const Preprocessor &PP = S.getPreprocessor(); + const SourceManager &SM = S.getSourceManager(); + SourceLocation BestLocation; + StringRef BestSpelling; + for (const IdentifierInfo *II : Cache.Candidates) { + const MacroDirective *MD = PP.getLocalMacroDirectiveHistory(II); + if (!MD) + continue; + const MacroDirective::DefInfo Def = MD->findDirectiveAtLoc(Loc, SM); + if (!Def || !Def.getMacroInfo()) + continue; + + // Ensure the macro definition active at Loc still has this spelling. + const MacroInfo *MI = Def.getMacroInfo(); + if (!MI->isObjectLike() || Tokens.size() != MI->getNumTokens() || + !std::equal(Tokens.begin(), Tokens.end(), MI->tokens_begin())) + continue; + + // Choose the matching macro defined latest before Loc. + SourceLocation Location = Def.getLocation(); + if (BestLocation.isInvalid() || + (Location.isValid() && + SM.isBeforeInTranslationUnit(BestLocation, Location))) { + BestLocation = Location; + BestSpelling = II->getName(); + } + } + return BestSpelling; + } + std::string getLifetimeBoundFixItText(SourceLocation Loc, bool LeadingSpace, bool AllowGNUAttrMacro = true) { StringRef Spelling = S.getLangOpts().LifetimeSafetyLifetimeBoundMacro; if (Spelling.empty() && Loc.isValid()) { const Preprocessor &PP = S.getPreprocessor(); - Spelling = PP.getLastMacroWithSpelling( - Loc, {tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), - tok::coloncolon, PP.getIdentifierInfo("lifetimebound"), - tok::r_square, tok::r_square}); + Spelling = getLastCachedMacroWithSpelling( + Loc, + {tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), + tok::coloncolon, PP.getIdentifierInfo("lifetimebound"), + tok::r_square, tok::r_square}, + ClangLifetimeBoundMacroCache); if (Spelling.empty() && AllowGNUAttrMacro) - Spelling = PP.getLastMacroWithSpelling( - Loc, {tok::kw___attribute, tok::l_paren, tok::l_paren, - PP.getIdentifierInfo("lifetimebound"), tok::r_paren, - tok::r_paren}); + Spelling = getLastCachedMacroWithSpelling( + Loc, + {tok::kw___attribute, tok::l_paren, tok::l_paren, + PP.getIdentifierInfo("lifetimebound"), tok::r_paren, tok::r_paren}, + GNULifetimeBoundMacroCache); } const std::string Text = Spelling.empty() ? "[[clang::lifetimebound]]" : Spelling.str(); @@ -589,6 +662,8 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { } } + LifetimeBoundMacroCache ClangLifetimeBoundMacroCache; + LifetimeBoundMacroCache GNULifetimeBoundMacroCache; Sema &S; }; >From 798dc68f9eba602bb6d4c0c1d83abaf7fd451dce Mon Sep 17 00:00:00 2001 From: Zeyi Xu <[email protected]> Date: Tue, 23 Jun 2026 11:57:14 +0800 Subject: [PATCH 2/3] small style nit fixes --- clang/lib/Sema/SemaLifetimeSafety.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index c2f7a56e166c4..b3f5a3b477a4d 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -444,11 +444,11 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { private: struct LifetimeBoundMacroCache { bool IsBuilt = false; - llvm::SmallVector<const IdentifierInfo *> Candidates; + SmallVector<const IdentifierInfo *> Candidates; }; void buildLifetimeBoundMacroCache(LifetimeBoundMacroCache &Cache, - llvm::ArrayRef<TokenValue> Tokens) { + ArrayRef<TokenValue> Tokens) { if (Cache.IsBuilt) return; >From dda6eb03e8f5268e184a3b88005e57ae0be5f51e Mon Sep 17 00:00:00 2001 From: Zeyi Xu <[email protected]> Date: Wed, 24 Jun 2026 04:59:47 +0800 Subject: [PATCH 3/3] add tests --- .../annotation-suggestions-fixits.cpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp index 99f0d16cd8e68..e2fb9dd5df40a 100644 --- a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp +++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp @@ -239,6 +239,39 @@ View return_view_with_latest_macro(View a) { return a; } +#define REDEFINED_LIFETIMEBOUND_MACRO [[clang::lifetimebound]] + +View return_view_with_redefined_macro(View a) { + // CHECK: :[[@LINE-1]]:39: warning: parameter in intra-TU function should be marked + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:45-[[@LINE-2]]:45}:" REDEFINED_LIFETIMEBOUND_MACRO" + return a; +} + +#undef REDEFINED_LIFETIMEBOUND_MACRO +#define REDEFINED_LIFETIMEBOUND_MACRO [[maybe_unused]] + +View return_view_after_redefined_macro(View a) { + // CHECK: :[[@LINE-1]]:40: warning: parameter in intra-TU function should be marked + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:46-[[@LINE-2]]:46}:" SECOND_LIFETIMEBOUND_MACRO" + return a; +} + +#define UNDEFINED_LIFETIMEBOUND_MACRO [[clang::lifetimebound]] + +View return_view_with_undefined_macro(View a) { + // CHECK: :[[@LINE-1]]:39: warning: parameter in intra-TU function should be marked + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:45-[[@LINE-2]]:45}:" UNDEFINED_LIFETIMEBOUND_MACRO" + return a; +} + +#undef UNDEFINED_LIFETIMEBOUND_MACRO + +View return_view_after_undefined_macro(View a) { + // CHECK: :[[@LINE-1]]:40: warning: parameter in intra-TU function should be marked + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:46-[[@LINE-2]]:46}:" SECOND_LIFETIMEBOUND_MACRO" + return a; +} + struct MacroMember { MyObj data; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
