Author: Zeyi Xu
Date: 2026-07-16T15:28:21Z
New Revision: 638d6736400891b03f211487ccb643a49f14f743

URL: 
https://github.com/llvm/llvm-project/commit/638d6736400891b03f211487ccb643a49f14f743
DIFF: 
https://github.com/llvm/llvm-project/commit/638d6736400891b03f211487ccb643a49f14f743.diff

LOG: [LifetimeSafety] Add better lifetimebound fix-it spelling for C (#209967)

Use `__attribute__((lifetimebound))` as the default lifetimebound fix-it
spelling in pre-C23 C.
C++ and C23 continue to use `[[clang::lifetimebound]]` as the default
spelling.

When no explicit lifetimebound macro is configured, pre-C23 C only looks
for `__attribute__((lifetimebound))`, C++ and C23 keep looking for
`[[clang::lifetimebound]]` macros first, then
`__attribute__((lifetimebound))`.

Follow up of https://github.com/llvm/llvm-project/pull/204045

Added: 
    clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c

Modified: 
    clang/lib/Sema/SemaLifetimeSafety.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaLifetimeSafety.h 
b/clang/lib/Sema/SemaLifetimeSafety.h
index c659a9d1c4da5..1d9f94be7e22d 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -540,15 +540,21 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
 
   std::string getLifetimeBoundFixItText(SourceLocation Loc, bool LeadingSpace,
                                         bool AllowGNUAttrMacro = true) {
+    const bool UseCXX11AttrSpelling =
+        S.getLangOpts().CPlusPlus || S.getLangOpts().C23;
+    const StringRef Fallback = UseCXX11AttrSpelling
+                                   ? "[[clang::lifetimebound]]"
+                                   : "__attribute__((lifetimebound))";
     StringRef Spelling = S.getLangOpts().LifetimeSafetyLifetimeBoundMacro;
     if (Spelling.empty() && Loc.isValid()) {
       const Preprocessor &PP = S.getPreprocessor();
-      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 (UseCXX11AttrSpelling)
+        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 = getLastCachedMacroWithSpelling(
@@ -557,8 +563,7 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
              PP.getIdentifierInfo("lifetimebound"), tok::r_paren, 
tok::r_paren},
             GNULifetimeBoundMacroCache);
     }
-    const std::string Text =
-        Spelling.empty() ? "[[clang::lifetimebound]]" : Spelling.str();
+    const std::string Text = Spelling.empty() ? Fallback.str() : 
Spelling.str();
     return LeadingSpace ? " " + Text : Text + " ";
   }
 

diff  --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c 
b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c
new file mode 100644
index 0000000000000..0ad009fa0c559
--- /dev/null
+++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c
@@ -0,0 +1,132 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \
+// RUN:   -Wlifetime-safety-suggestions -Wno-dangling \
+// RUN:   -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -std=c23 -fexperimental-lifetime-safety-c \
+// RUN:   -Wlifetime-safety-suggestions -Wno-dangling \
+// RUN:   -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s 
--check-prefix=CHECK-C23
+// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \
+// RUN:   -Wlifetime-safety-suggestions -Wno-dangling \
+// RUN:   '-DLIFETIMEBOUND_MACRO=__attribute__((lifetimebound))' \
+// RUN:   -lifetime-safety-lifetimebound-macro=LIFETIMEBOUND_MACRO \
+// RUN:   -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s 
--check-prefix=CHECK-MACRO
+// RUN: cp %s %t.c
+// RUN: %clang_cc1 -std=c17 -fexperimental-lifetime-safety-c \
+// RUN:   -Wlifetime-safety-suggestions -Wno-dangling -fixit %t.c
+// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \
+// RUN:   -Werror=lifetime-safety-suggestions -Wno-dangling %t.c
+
+int *return_pointer(int *p) {
+  // CHECK: :[[@LINE-1]]:27: warning: parameter in intra-TU function should be 
marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:27-[[@LINE-2]]:27}:" 
__attribute__((lifetimebound))"
+  // CHECK-C23: :[[@LINE-3]]:27: warning: parameter in intra-TU function 
should be marked
+  // CHECK-C23: fix-it:"{{.*}}":{[[@LINE-4]]:27-[[@LINE-4]]:27}:" 
{{\[\[}}clang::lifetimebound]]"
+  // CHECK-MACRO: :[[@LINE-5]]:27: warning: parameter in intra-TU function 
should be marked
+  // CHECK-MACRO: fix-it:"{{.*}}":{[[@LINE-6]]:27-[[@LINE-6]]:27}:" 
LIFETIMEBOUND_MACRO"
+  return p;
+}
+
+int *return_multi(int *a, int cond, int *b) {
+  // CHECK-DAG: :[[@LINE-1]]:25: warning: parameter in intra-TU function 
should be marked
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:25-[[@LINE-2]]:25}:" 
__attribute__((lifetimebound))"
+  // CHECK-DAG: :[[@LINE-3]]:43: warning: parameter in intra-TU function 
should be marked
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-4]]:43-[[@LINE-4]]:43}:" 
__attribute__((lifetimebound))"
+  if (cond)
+    return a;
+  return b;
+}
+
+int *return_partial(int *a __attribute__((lifetimebound)), int cond, int *b) {
+  // CHECK: :[[@LINE-1]]:76: warning: parameter in intra-TU function should be 
marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:76-[[@LINE-2]]:76}:" 
__attribute__((lifetimebound))"
+  // CHECK-C23: :[[@LINE-3]]:76: warning: parameter in intra-TU function 
should be marked
+  // CHECK-C23: fix-it:"{{.*}}":{[[@LINE-4]]:76-[[@LINE-4]]:76}:" 
{{\[\[}}clang::lifetimebound]]"
+  if (cond)
+    return a;
+  return b;
+}
+
+#define GNU_LIFETIMEBOUND_MACRO __attribute__((lifetimebound))
+
+int *unnamed_pointer(int *);
+// CHECK: :[[@LINE-1]]:22: warning: parameter in intra-TU function should be 
marked
+// CHECK: 
fix-it:"{{.*}}":{[[@LINE-2]]:22-[[@LINE-2]]:22}:"GNU_LIFETIMEBOUND_MACRO "
+// CHECK-C23: :[[@LINE-3]]:22: warning: parameter in intra-TU function should 
be marked
+// CHECK-C23: 
fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:22}:"GNU_LIFETIMEBOUND_MACRO "
+int *unnamed_pointer(int *p) {
+  return p;
+}
+
+int *return_pointer_with_gnu_macro(int *p) {
+  // CHECK: :[[@LINE-1]]:42: warning: parameter in intra-TU function should be 
marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:42-[[@LINE-2]]:42}:" 
GNU_LIFETIMEBOUND_MACRO"
+  // CHECK-C23: :[[@LINE-3]]:42: warning: parameter in intra-TU function 
should be marked
+  // CHECK-C23: fix-it:"{{.*}}":{[[@LINE-4]]:42-[[@LINE-4]]:42}:" 
GNU_LIFETIMEBOUND_MACRO"
+  return p;
+}
+
+#define FIRST_GNU_LIFETIMEBOUND_MACRO __attribute__((lifetimebound))
+#define SECOND_GNU_LIFETIMEBOUND_MACRO __attribute__((lifetimebound))
+
+int *return_pointer_with_latest_gnu_macro(int *p) {
+  // CHECK: :[[@LINE-1]]:49: warning: parameter in intra-TU function should be 
marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:49-[[@LINE-2]]:49}:" 
SECOND_GNU_LIFETIMEBOUND_MACRO"
+  // CHECK-C23: :[[@LINE-3]]:49: warning: parameter in intra-TU function 
should be marked
+  // CHECK-C23: fix-it:"{{.*}}":{[[@LINE-4]]:49-[[@LINE-4]]:49}:" 
SECOND_GNU_LIFETIMEBOUND_MACRO"
+  return p;
+}
+
+#define REDEFINED_GNU_LIFETIMEBOUND_MACRO __attribute__((lifetimebound))
+
+int *return_pointer_with_redefined_gnu_macro(int *p) {
+  // CHECK: :[[@LINE-1]]:52: warning: parameter in intra-TU function should be 
marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:52-[[@LINE-2]]:52}:" 
REDEFINED_GNU_LIFETIMEBOUND_MACRO"
+  return p;
+}
+
+#undef REDEFINED_GNU_LIFETIMEBOUND_MACRO
+#define REDEFINED_GNU_LIFETIMEBOUND_MACRO __attribute__((unused))
+
+int *return_pointer_after_redefined_gnu_macro(int *p) {
+  // CHECK: :[[@LINE-1]]:53: warning: parameter in intra-TU function should be 
marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:53-[[@LINE-2]]:53}:" 
SECOND_GNU_LIFETIMEBOUND_MACRO"
+  return p;
+}
+
+#define UNDEFINED_GNU_LIFETIMEBOUND_MACRO __attribute__((lifetimebound))
+
+int *return_pointer_with_undefined_gnu_macro(int *p) {
+  // CHECK: :[[@LINE-1]]:52: warning: parameter in intra-TU function should be 
marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:52-[[@LINE-2]]:52}:" 
UNDEFINED_GNU_LIFETIMEBOUND_MACRO"
+  return p;
+}
+
+#undef UNDEFINED_GNU_LIFETIMEBOUND_MACRO
+
+int *return_pointer_after_undefined_gnu_macro(int *p) {
+  // CHECK: :[[@LINE-1]]:53: warning: parameter in intra-TU function should be 
marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:53-[[@LINE-2]]:53}:" 
SECOND_GNU_LIFETIMEBOUND_MACRO"
+  return p;
+}
+
+#define CLANG_LIFETIMEBOUND_MACRO [[clang::lifetimebound]]
+
+int *return_pointer_with_clang_macro(int *p) {
+  // CHECK: :[[@LINE-1]]:44: warning: parameter in intra-TU function should be 
marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:44-[[@LINE-2]]:44}:" 
SECOND_GNU_LIFETIMEBOUND_MACRO"
+  // CHECK-C23: :[[@LINE-3]]:44: warning: parameter in intra-TU function 
should be marked
+  // CHECK-C23: fix-it:"{{.*}}":{[[@LINE-4]]:44-[[@LINE-4]]:44}:" 
CLANG_LIFETIMEBOUND_MACRO"
+  return p;
+}
+
+#define FIRST_CLANG_LIFETIMEBOUND_MACRO [[clang::lifetimebound]]
+#define SECOND_CLANG_LIFETIMEBOUND_MACRO [[clang::lifetimebound]]
+
+int *return_pointer_with_latest_clang_macro(int *p) {
+  // CHECK: :[[@LINE-1]]:51: warning: parameter in intra-TU function should be 
marked
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:51-[[@LINE-2]]:51}:" 
SECOND_GNU_LIFETIMEBOUND_MACRO"
+  // CHECK-C23: :[[@LINE-3]]:51: warning: parameter in intra-TU function 
should be marked
+  // CHECK-C23: fix-it:"{{.*}}":{[[@LINE-4]]:51-[[@LINE-4]]:51}:" 
SECOND_CLANG_LIFETIMEBOUND_MACRO"
+  // CHECK-MACRO: :[[@LINE-5]]:51: warning: parameter in intra-TU function 
should be marked
+  // CHECK-MACRO: fix-it:"{{.*}}":{[[@LINE-6]]:51-[[@LINE-6]]:51}:" 
LIFETIMEBOUND_MACRO"
+  return p;
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to