[clang] [LifetimeSafety] Add fixit verification with FileCheck (PR #180488)
Baranov Victor via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 9 05:14:05 PST 2026
https://github.com/vbvictor updated https://github.com/llvm/llvm-project/pull/180488
>From e437d5e49f8503e68a07e5ecac94017fcca38296 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Mon, 9 Feb 2026 12:01:00 +0300
Subject: [PATCH 1/3] [LifetimeSafety] Add fixit verification with FileCheck
---
.../test/Sema/warn-lifetime-safety-fixits.cpp | 139 ++++++++++++++++++
1 file changed, 139 insertions(+)
create mode 100644 clang/test/Sema/warn-lifetime-safety-fixits.cpp
diff --git a/clang/test/Sema/warn-lifetime-safety-fixits.cpp b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
new file mode 100644
index 0000000000000..5d5ee215eea64
--- /dev/null
+++ b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -flifetime-safety-inference \
+// RUN: -fexperimental-lifetime-safety-tu-analysis \
+// RUN: -Wlifetime-safety-suggestions -Wno-dangling \
+// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+struct View;
+
+struct [[gsl::Owner]] MyObj {
+ int id;
+ MyObj(int i) : id(i) {}
+ MyObj() {}
+ ~MyObj() {}
+ MyObj operator+(MyObj);
+ View getView() const [[clang::lifetimebound]];
+};
+
+struct [[gsl::Pointer()]] View {
+ View(const MyObj &);
+ View();
+ void use() const;
+};
+
+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]]"
+ return a;
+}
+
+MyObj &return_multi(MyObj &a, bool c, MyObj &b) {
+ // CHECK-DAG: :[[@LINE-1]]:21: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:29-[[@LINE-2]]:29}:" {{\[\[}}clang::lifetimebound]]"
+ // CHECK-DAG: :[[@LINE-3]]:39: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-4]]:47-[[@LINE-4]]:47}:" {{\[\[}}clang::lifetimebound]]"
+ if (c)
+ return a;
+ return b;
+}
+
+View return_partial(View a [[clang::lifetimebound]], bool c, View b) {
+ // CHECK: :[[@LINE-1]]:62: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:68-[[@LINE-2]]:68}:" {{\[\[}}clang::lifetimebound]]"
+ if (c)
+ return a;
+ return b;
+}
+
+View param_with_attr(View a [[maybe_unused]]) {
+ // CHECK: :[[@LINE-1]]:22: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:28-[[@LINE-2]]:28}:" {{\[\[}}clang::lifetimebound]]"
+ return a;
+}
+
+View param_default(View a = View()) {
+ // CHECK: :[[@LINE-1]]:20: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:35-[[@LINE-2]]:35}:" {{\[\[}}clang::lifetimebound]]"
+ return a;
+}
+
+View multi_decl(View a);
+View multi_decl(View a);
+View multi_decl(View a) {
+ // CHECK: :[[@LINE-1]]:17: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:23-[[@LINE-2]]:23}:" {{\[\[}}clang::lifetimebound]]"
+ return a;
+}
+
+template <typename T>
+T *template_identity(T *a) {
+ // CHECK: :[[@LINE-1]]:22: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:26-[[@LINE-2]]:26}:" {{\[\[}}clang::lifetimebound]]"
+ return a;
+}
+
+MyObj *instantiate_template() {
+ MyObj local;
+ return template_identity(&local);
+}
+
+struct ViewMember {
+ ViewMember(int d) : data(d) {}
+ ~ViewMember() {}
+ MyObj data;
+
+ View get_view() {
+ // CHECK: :[[@LINE-1]]:18: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:" {{\[\[}}clang::lifetimebound]]"
+ return data;
+ }
+
+ View get_view_const() const {
+ // CHECK: :[[@LINE-1]]:30: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:30-[[@LINE-2]]:30}:" {{\[\[}}clang::lifetimebound]]"
+ return data;
+ }
+
+ const View get_view_const_noexcept() const noexcept {
+ // CHECK: :[[@LINE-1]]:54: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:54-[[@LINE-2]]:54}:" {{\[\[}}clang::lifetimebound]]"
+ return data;
+ }
+};
+
+struct Base {
+ Base() {}
+ virtual ~Base() {}
+ MyObj data;
+ virtual const MyObj &get_virtual() const {
+ // CHECK: :[[@LINE-1]]:43: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:43-[[@LINE-2]]:43}:" {{\[\[}}clang::lifetimebound]]"
+ return data;
+ }
+};
+
+struct Derived : Base {
+ const MyObj &get_virtual() const override {
+ // CHECK: :[[@LINE-1]]:35: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:35-[[@LINE-2]]:35}:" {{\[\[}}clang::lifetimebound]]"
+ return data;
+ }
+};
+
+struct DerivedFinal : Base {
+ const MyObj &get_virtual() const final {
+ // CHECK: :[[@LINE-1]]:35: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:35-[[@LINE-2]]:35}:" {{\[\[}}clang::lifetimebound]]"
+ return data;
+ }
+};
+
+struct OutOfLine {
+ OutOfLine() {}
+ ~OutOfLine() {}
+ const OutOfLine &get() const;
+};
+const OutOfLine &OutOfLine::get() const {
+ // CHECK: :[[@LINE-1]]:40: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:40-[[@LINE-2]]:40}:" {{\[\[}}clang::lifetimebound]]"
+ return *this;
+}
>From 66bbe2dd7d0cf1dd766343f682c434edf6d203ff Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Mon, 9 Feb 2026 12:08:14 +0300
Subject: [PATCH 2/3] add fixme
---
clang/test/Sema/warn-lifetime-safety-fixits.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/test/Sema/warn-lifetime-safety-fixits.cpp b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
index 5d5ee215eea64..4cd9ae40de4b8 100644
--- a/clang/test/Sema/warn-lifetime-safety-fixits.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
@@ -56,6 +56,7 @@ View param_default(View a = View()) {
return a;
}
+// FIXME: Iterate over redecls and add [[clang::lifetimebound]]
View multi_decl(View a);
View multi_decl(View a);
View multi_decl(View a) {
>From b1b7ebca134ab3d87ff204331a13def8a40311ba Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Mon, 9 Feb 2026 16:13:47 +0300
Subject: [PATCH 3/3] make shorter warning messages
---
.../test/Sema/warn-lifetime-safety-fixits.cpp | 28 +++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/clang/test/Sema/warn-lifetime-safety-fixits.cpp b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
index 4cd9ae40de4b8..82b36caf8d141 100644
--- a/clang/test/Sema/warn-lifetime-safety-fixits.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
@@ -27,9 +27,9 @@ View return_view(View a) {
}
MyObj &return_multi(MyObj &a, bool c, MyObj &b) {
- // CHECK-DAG: :[[@LINE-1]]:21: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK-DAG: :[[@LINE-1]]:21: warning: parameter in intra-TU function should be marked
// CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:29-[[@LINE-2]]:29}:" {{\[\[}}clang::lifetimebound]]"
- // CHECK-DAG: :[[@LINE-3]]:39: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK-DAG: :[[@LINE-3]]:39: warning: parameter in intra-TU function should be marked
// CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-4]]:47-[[@LINE-4]]:47}:" {{\[\[}}clang::lifetimebound]]"
if (c)
return a;
@@ -37,7 +37,7 @@ MyObj &return_multi(MyObj &a, bool c, MyObj &b) {
}
View return_partial(View a [[clang::lifetimebound]], bool c, View b) {
- // CHECK: :[[@LINE-1]]:62: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:62: warning: parameter in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:68-[[@LINE-2]]:68}:" {{\[\[}}clang::lifetimebound]]"
if (c)
return a;
@@ -45,13 +45,13 @@ View return_partial(View a [[clang::lifetimebound]], bool c, View b) {
}
View param_with_attr(View a [[maybe_unused]]) {
- // CHECK: :[[@LINE-1]]:22: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:22: warning: parameter in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:28-[[@LINE-2]]:28}:" {{\[\[}}clang::lifetimebound]]"
return a;
}
View param_default(View a = View()) {
- // CHECK: :[[@LINE-1]]:20: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:20: warning: parameter in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:35-[[@LINE-2]]:35}:" {{\[\[}}clang::lifetimebound]]"
return a;
}
@@ -60,14 +60,14 @@ View param_default(View a = View()) {
View multi_decl(View a);
View multi_decl(View a);
View multi_decl(View a) {
- // CHECK: :[[@LINE-1]]:17: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:17: warning: parameter in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:23-[[@LINE-2]]:23}:" {{\[\[}}clang::lifetimebound]]"
return a;
}
template <typename T>
T *template_identity(T *a) {
- // CHECK: :[[@LINE-1]]:22: warning: parameter in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:22: warning: parameter in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:26-[[@LINE-2]]:26}:" {{\[\[}}clang::lifetimebound]]"
return a;
}
@@ -83,19 +83,19 @@ struct ViewMember {
MyObj data;
View get_view() {
- // CHECK: :[[@LINE-1]]:18: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:18: warning: implicit this in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:" {{\[\[}}clang::lifetimebound]]"
return data;
}
View get_view_const() const {
- // CHECK: :[[@LINE-1]]:30: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:30: warning: implicit this in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:30-[[@LINE-2]]:30}:" {{\[\[}}clang::lifetimebound]]"
return data;
}
const View get_view_const_noexcept() const noexcept {
- // CHECK: :[[@LINE-1]]:54: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:54: warning: implicit this in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:54-[[@LINE-2]]:54}:" {{\[\[}}clang::lifetimebound]]"
return data;
}
@@ -106,7 +106,7 @@ struct Base {
virtual ~Base() {}
MyObj data;
virtual const MyObj &get_virtual() const {
- // CHECK: :[[@LINE-1]]:43: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:43: warning: implicit this in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:43-[[@LINE-2]]:43}:" {{\[\[}}clang::lifetimebound]]"
return data;
}
@@ -114,7 +114,7 @@ struct Base {
struct Derived : Base {
const MyObj &get_virtual() const override {
- // CHECK: :[[@LINE-1]]:35: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:35: warning: implicit this in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:35-[[@LINE-2]]:35}:" {{\[\[}}clang::lifetimebound]]"
return data;
}
@@ -122,7 +122,7 @@ struct Derived : Base {
struct DerivedFinal : Base {
const MyObj &get_virtual() const final {
- // CHECK: :[[@LINE-1]]:35: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:35: warning: implicit this in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:35-[[@LINE-2]]:35}:" {{\[\[}}clang::lifetimebound]]"
return data;
}
@@ -134,7 +134,7 @@ struct OutOfLine {
const OutOfLine &get() const;
};
const OutOfLine &OutOfLine::get() const {
- // CHECK: :[[@LINE-1]]:40: warning: implicit this in intra-TU function should be marked {{\[\[}}clang::lifetimebound]] [-Wlifetime-safety-intra-tu-suggestions]
+ // CHECK: :[[@LINE-1]]:40: warning: implicit this in intra-TU function should be marked
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:40-[[@LINE-2]]:40}:" {{\[\[}}clang::lifetimebound]]"
return *this;
}
More information about the cfe-commits
mailing list