[clang] 638d673 - [LifetimeSafety] Add better lifetimebound fix-it spelling for C (#209967)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 16 08:28:26 PDT 2026
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;
+}
More information about the cfe-commits
mailing list