https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/204045
>From 1ee4bc273b8a1ecc17e8645a13ee97986d397ab2 Mon Sep 17 00:00:00 2001 From: Zeyi Xu <[email protected]> Date: Tue, 16 Jun 2026 10:02:39 +0800 Subject: [PATCH 1/3] [LifetimeSafety] Prefer macro spelling for lifetimebound fix-its --- clang/lib/Sema/SemaLifetimeSafety.h | 26 ++++++++++---- .../test/Sema/warn-lifetime-safety-fixits.cpp | 34 +++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index 6da4953dea56d..f76fb6a58b8f9 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -19,6 +19,7 @@ #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/Sema.h" #include <string> @@ -403,27 +404,39 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { } private: - std::pair<SourceLocation, StringRef> + std::string getLifetimeBoundFixItText(SourceLocation Loc, bool LeadingSpace) { + const Preprocessor &PP = S.getPreprocessor(); + const StringRef Spelling = PP.getLastMacroWithSpelling( + Loc, {tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), + tok::coloncolon, PP.getIdentifierInfo("lifetimebound"), + tok::r_square, tok::r_square}); + const std::string Text = + Spelling.empty() ? "[[clang::lifetimebound]]" : Spelling.str(); + return LeadingSpace ? " " + Text : Text + " "; + } + + std::pair<SourceLocation, std::string> getLifetimeBoundFixIt(const ParmVarDecl *Decl) { SourceLocation InsertionPoint = Lexer::getLocForEndOfToken( Decl->getEndLoc(), 0, S.getSourceManager(), S.getLangOpts()); - StringRef FixItText = " [[clang::lifetimebound]]"; + bool LeadingSpace = true; if (!Decl->getIdentifier()) { // For unnamed parameters, placing attributes after the type would be // parsed as a type attribute, not a parameter attribute. InsertionPoint = Decl->getBeginLoc(); - FixItText = "[[clang::lifetimebound]] "; + LeadingSpace = false; } else if (Decl->hasDefaultArg()) { // If the parameter has a default argument, place the attribute after the // named argument. InsertionPoint = Lexer::getLocForEndOfToken( Decl->getLocation(), 0, S.getSourceManager(), S.getLangOpts()); } - return {InsertionPoint, FixItText}; + return {InsertionPoint, + getLifetimeBoundFixItText(InsertionPoint, LeadingSpace)}; } - std::pair<SourceLocation, StringRef> + std::pair<SourceLocation, std::string> getLifetimeBoundFixIt(const CXXMethodDecl *MD) { const auto MDL = MD->getTypeSourceInfo()->getTypeLoc(); SourceLocation InsertionPoint = Lexer::getLocForEndOfToken( @@ -444,7 +457,8 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { ->getLocation(), 0, S.getSourceManager(), S.getLangOpts()); } - return {InsertionPoint, " [[clang::lifetimebound]]"}; + return {InsertionPoint, getLifetimeBoundFixItText(InsertionPoint, + /*LeadingSpace=*/true)}; } std::string getDiagSubjectDescription(const ValueDecl *VD) { diff --git a/clang/test/Sema/warn-lifetime-safety-fixits.cpp b/clang/test/Sema/warn-lifetime-safety-fixits.cpp index d9c7e8d3f0519..e1a89f9047457 100644 --- a/clang/test/Sema/warn-lifetime-safety-fixits.cpp +++ b/clang/test/Sema/warn-lifetime-safety-fixits.cpp @@ -174,3 +174,37 @@ struct TrailingReturn { return data; } }; + +#define MY_LIFETIMEBOUND_MACRO [[clang::lifetimebound]] + +View unnamed_macro(View); +// CHECK: :[[@LINE-1]]:20: warning: parameter in intra-TU function should be marked +// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:20-[[@LINE-2]]:20}:"MY_LIFETIMEBOUND_MACRO " +View unnamed_macro(View a) { + return a; +} + +View return_view_with_macro(View a) { + // CHECK: :[[@LINE-1]]:29: warning: parameter in intra-TU function should be marked + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:35-[[@LINE-2]]:35}:" MY_LIFETIMEBOUND_MACRO" + return a; +} + +#define FIRST_LIFETIMEBOUND_MACRO [[clang::lifetimebound]] +#define SECOND_LIFETIMEBOUND_MACRO [[clang::lifetimebound]] + +View return_view_with_latest_macro(View a) { + // CHECK: :[[@LINE-1]]:36: warning: parameter in intra-TU function should be marked + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:42-[[@LINE-2]]:42}:" SECOND_LIFETIMEBOUND_MACRO" + return a; +} + +struct MacroMember { + MyObj data; + + View get_view() { + // CHECK: :[[@LINE-1]]:18: warning: implicit this in intra-TU function should be marked + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:" SECOND_LIFETIMEBOUND_MACRO" + return data; + } +}; >From dc8807842ffcb6aa90f15f500f35e017a1d4ad54 Mon Sep 17 00:00:00 2001 From: Zeyi Xu <[email protected]> Date: Tue, 16 Jun 2026 11:07:22 +0800 Subject: [PATCH 2/3] fix crash !!! --- clang/lib/Sema/SemaLifetimeSafety.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index d2657252b3351..48099274ac982 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -424,6 +424,10 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { private: std::string getLifetimeBoundFixItText(SourceLocation Loc, bool LeadingSpace) { + if (Loc.isInvalid()) + return LeadingSpace ? " [[clang::lifetimebound]]" + : "[[clang::lifetimebound]] "; + const Preprocessor &PP = S.getPreprocessor(); const StringRef Spelling = PP.getLastMacroWithSpelling( Loc, {tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), >From 6b2543187c2df7d107289fe5872e611673cf643c Mon Sep 17 00:00:00 2001 From: Zeyi Xu <[email protected]> Date: Tue, 16 Jun 2026 21:32:20 +0800 Subject: [PATCH 3/3] add command line option --- clang/docs/LifetimeSafety.rst | 7 ++++++- clang/include/clang/Basic/LangOptions.h | 3 +++ clang/include/clang/Options/Options.td | 9 +++++++++ clang/lib/Sema/SemaLifetimeSafety.h | 17 ++++++++--------- .../annotation-suggestions-fixits.cpp | 11 +++++++++++ 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/clang/docs/LifetimeSafety.rst b/clang/docs/LifetimeSafety.rst index 9ae2e6ee54826..7f024e610fd2c 100644 --- a/clang/docs/LifetimeSafety.rst +++ b/clang/docs/LifetimeSafety.rst @@ -462,6 +462,11 @@ more accurate checks in calling code. To enable annotation suggestions, use ``-Wlifetime-safety-suggestions``. +Fix-it hints normally insert ``[[clang::lifetimebound]]``. If a visible +object-like macro expands to ``[[clang::lifetimebound]]``, Clang will use the +last such macro visible at the insertion point. To force a project-specific +macro spelling, use ``-lifetime-safety-lifetimebound-macro=<macro>``. + .. code-block:: c++ #include <string_view> @@ -688,5 +693,5 @@ Performance Lifetime analysis relies on Clang's CFG (Control Flow Graph). For functions with very large or complex CFGs, analysis time can sometimes be significant. To mitigate this, the analysis allows to skip functions where the number of CFG blocks exceeds -a certain threshold, controlled by the ``-flifetime-safety-max-cfg-blocks=N`` language +a certain threshold, controlled by the ``-lifetime-safety-max-cfg-blocks=N`` language option. diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 9af036156b1ad..53c4c1084784a 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -549,6 +549,9 @@ class LangOptions : public LangOptionsBase { /// A prefix map for __FILE__, __BASE_FILE__ and __builtin_FILE(). std::map<std::string, std::string, std::greater<std::string>> MacroPrefixMap; + /// Macro name to use in lifetimebound fix-it suggestions. + std::string LifetimeSafetyLifetimeBoundMacro; + /// Triples of the OpenMP targets that the host code codegen should /// take into account in order to generate accurate offloading descriptors. std::vector<llvm::Triple> OMPTargetTriples; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index a4b9cb802af4d..248e1651c2cb4 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -2025,6 +2025,15 @@ def lifetime_safety_max_cfg_blocks "count exceeding this threshold. Specify 0 for no limit.">, MarshallingInfoInt<LangOpts<"LifetimeSafetyMaxCFGBlocks">>; +def lifetime_safety_lifetimebound_macro + : Joined<["-"], "lifetime-safety-lifetimebound-macro=">, + Group<m_Group>, + Visibility<[ClangOption, CC1Option]>, + MetaVarName<"<macro>">, + HelpText<"Use the given macro name when suggesting lifetimebound " + "attributes">, + MarshallingInfoString<LangOpts<"LifetimeSafetyLifetimeBoundMacro">>; + defm lifetime_safety_inference : BoolFOption<"lifetime-safety-inference", LangOpts<"EnableLifetimeSafetyInference">, DefaultFalse, diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index 48099274ac982..f3f669428697f 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -424,15 +424,14 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { private: std::string getLifetimeBoundFixItText(SourceLocation Loc, bool LeadingSpace) { - if (Loc.isInvalid()) - return LeadingSpace ? " [[clang::lifetimebound]]" - : "[[clang::lifetimebound]] "; - - const Preprocessor &PP = S.getPreprocessor(); - const StringRef Spelling = PP.getLastMacroWithSpelling( - Loc, {tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), - tok::coloncolon, PP.getIdentifierInfo("lifetimebound"), - tok::r_square, tok::r_square}); + 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}); + } const std::string Text = Spelling.empty() ? "[[clang::lifetimebound]]" : Spelling.str(); return LeadingSpace ? " " + Text : Text + " "; diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp index e2c5816cc5193..7fc2c46a2f1ee 100644 --- a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp +++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp @@ -2,6 +2,11 @@ // RUN: -fexperimental-lifetime-safety-tu-analysis \ // RUN: -Wlifetime-safety-suggestions -Wlifetime-safety-annotation-placement -Wno-dangling \ // RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -fsyntax-only -std=c++17 -flifetime-safety-inference \ +// RUN: -fexperimental-lifetime-safety-tu-analysis \ +// RUN: -Wlifetime-safety-suggestions -Wlifetime-safety-annotation-placement -Wno-dangling \ +// RUN: -lifetime-safety-lifetimebound-macro=LIFETIMEBOUND_MACRO \ +// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s --check-prefix=CHECK-MACRO // RUN: cp %s %t.cpp // RUN: %clang_cc1 -std=c++17 -flifetime-safety-inference \ // RUN: -fexperimental-lifetime-safety-tu-analysis \ @@ -30,6 +35,8 @@ struct [[gsl::Pointer()]] View { View return_view(View a) { // CHECK: :[[@LINE-1]]:18: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions] // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:24-[[@LINE-2]]:24}:" {{\[\[}}clang::lifetimebound]]" + // CHECK-MACRO: :[[@LINE-3]]:18: warning: parameter in intra-TU function should be marked + // CHECK-MACRO: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:24}:" LIFETIMEBOUND_MACRO" return a; } @@ -196,6 +203,8 @@ View return_view_with_macro(View a) { View return_view_with_latest_macro(View a) { // CHECK: :[[@LINE-1]]:36: warning: parameter in intra-TU function should be marked // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:42-[[@LINE-2]]:42}:" SECOND_LIFETIMEBOUND_MACRO" + // CHECK-MACRO: :[[@LINE-3]]:36: warning: parameter in intra-TU function should be marked + // CHECK-MACRO: fix-it:"{{.*}}":{[[@LINE-4]]:42-[[@LINE-4]]:42}:" LIFETIMEBOUND_MACRO" return a; } @@ -205,6 +214,8 @@ struct MacroMember { View get_view() { // CHECK: :[[@LINE-1]]:18: warning: implicit this in intra-TU function should be marked // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:" SECOND_LIFETIMEBOUND_MACRO" + // CHECK-MACRO: :[[@LINE-3]]:18: warning: implicit this in intra-TU function should be marked + // CHECK-MACRO: fix-it:"{{.*}}":{[[@LINE-4]]:18-[[@LINE-4]]:18}:" LIFETIMEBOUND_MACRO" return data; } }; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
