https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/209967
>From 70ee406a62d658ace43b44f90de1dfd070d2fdc9 Mon Sep 17 00:00:00 2001 From: Zeyi Xu <[email protected]> Date: Thu, 16 Jul 2026 13:24:00 +0800 Subject: [PATCH 1/2] [LifetimeSafety] Add better lifetimebound fix-it spelling for C --- clang/lib/Sema/SemaLifetimeSafety.h | 21 ++- .../annotation-suggestions-fixits.c | 137 ++++++++++++++++++ 2 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index 48edf5f3f070f..099c8be601e39 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -534,15 +534,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( @@ -551,8 +557,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..0ec676d53c7b5 --- /dev/null +++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c @@ -0,0 +1,137 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \ +// RUN: -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis \ +// 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: -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis \ +// 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: -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis \ +// 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: -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis \ +// RUN: -Wlifetime-safety-suggestions -Wno-dangling -fixit %t.c +// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \ +// RUN: -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis \ +// 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; +} >From 2fab618444638e9deb49bde813206ea2520e7899 Mon Sep 17 00:00:00 2001 From: Zeyi Xu <[email protected]> Date: Thu, 16 Jul 2026 21:02:55 +0800 Subject: [PATCH 2/2] address feedback --- .../test/Sema/LifetimeSafety/annotation-suggestions-fixits.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c index 0ec676d53c7b5..0ad009fa0c559 100644 --- a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c +++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c @@ -1,23 +1,18 @@ // RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \ -// RUN: -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis \ // 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: -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis \ // 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: -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis \ // 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: -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis \ // RUN: -Wlifetime-safety-suggestions -Wno-dangling -fixit %t.c // RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \ -// RUN: -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis \ // RUN: -Werror=lifetime-safety-suggestions -Wno-dangling %t.c int *return_pointer(int *p) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
