[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