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

Reply via email to