[clang] [LifetimeSafety] Add fix-it for misplaced lifetimebound attributes (PR #199149)
Utkarsh Saxena via cfe-commits
cfe-commits at lists.llvm.org
Mon May 25 04:17:28 PDT 2026
================
@@ -74,29 +90,63 @@ struct IntraSuppressedObj {
};
IntraSuppressedObj &intra_suppressed(IntraSuppressedObj &obj); // expected-warning {{'lifetimebound' attribute on this definition is not visible to callers before the definition; add it to the declaration instead}}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:{{[0-9]+}}-[[@LINE-1]]:{{[0-9]+}}}:" {{\[\[clang::lifetimebound\]\]}}"
+
IntraSuppressedObj &intra_suppressed(
IntraSuppressedObj &obj [[clang::lifetimebound]]) { // expected-note {{'lifetimebound' attribute appears here on the definition}}
return obj;
}
struct View {
friend View friend_redecl(MyObj &obj); // expected-warning {{'lifetimebound' attribute on this definition is not visible to callers before the definition; add it to the declaration instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:{{[0-9]+}}-[[@LINE-1]]:{{[0-9]+}}}:" {{\[\[clang::lifetimebound\]\]}}"
};
// FIXME: This diagnoses an attribute inherited from another redeclaration, not one written on the definition. Once we enforce that redeclarations agree on lifetimebound, handle this with a dedicated warning and note.
View friend_redecl(MyObj &obj [[clang::lifetimebound]]); // expected-note {{'lifetimebound' attribute appears here on the definition}}
-
View friend_redecl(MyObj &obj) {
return View{};
}
template <typename T>
// FIXME: Current analysis suggests adding to the primary template declaration, which is not ideal, as it will affect all specializations.
MyObj &spec_func(T &obj); // expected-warning {{'lifetimebound' attribute on this definition is not visible to callers before the definition; add it to the declaration instead}}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:{{[0-9]+}}-[[@LINE-1]]:{{[0-9]+}}}:" {{\[\[clang::lifetimebound\]\]}}"
template <>
// FIXME: Attribute is inhetired, diagnostic's wording is not correct.
MyObj &spec_func<MyObj>(MyObj &obj [[clang::lifetimebound]]); // expected-note {{'lifetimebound' attribute appears here on the definition}}
template <>
MyObj &spec_func<MyObj>(MyObj &obj) { return obj; }
+
+MyObj get_default_obj();
+
+const MyObj &default_arg_param(const MyObj &obj = get_default_obj()); // expected-warning {{'lifetimebound' attribute on this definition is not visible to callers before the definition; add it to the declaration instead}}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:48-[[@LINE-1]]:48}:" {{\[\[clang::lifetimebound\]\]}}"
+
+const MyObj &default_arg_param(const MyObj &obj [[clang::lifetimebound]]) { // expected-note {{'lifetimebound' attribute appears here on the definition}}
+ return obj;
+}
+
+struct Base {
+ virtual const MyObj& virtual_get(const MyObj& obj) const = 0;
+};
+
+struct Derived : Base {
+ auto virtual_get(const MyObj& obj) const -> const MyObj& override; // expected-warning {{'lifetimebound' attribute on this definition is not visible to callers before the definition; add it to the declaration instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:36-[[@LINE-1]]:36}:" {{\[\[clang::lifetimebound\]\]}}"
+};
+
+auto Derived::virtual_get(const MyObj& obj [[clang::lifetimebound]]) const -> const MyObj& { // expected-note {{'lifetimebound' attribute appears here on the definition}}
+ return obj;
+}
+
+#define REF_PARAM MyObj &obj
+
+MyObj ¯o_param(REF_PARAM); // expected-warning {{'lifetimebound' attribute on this definition is not visible to callers before the definition; add it to the declaration instead}}
+// Fix-it suppressed for macro.
+
+MyObj ¯o_param(MyObj &obj [[clang::lifetimebound]]) { // expected-note {{'lifetimebound' attribute appears here on the definition}}
+ return obj;
+}
----------------
usx95 wrote:
There could be a contention on the location here actually. E.g. In principle, fixit can also be attached inside the macro definition as well. But we may choose not to support that.
Can you try testing multiple params and see what we currently do:
```cpp
#define REF_PARAMS MyObj &obj1, MyObj &obj2
MyObj ¯o_param(bool condition, REF_PARAMS);
MyObj ¯o_params(bool condition,
MyObj &obj1 [[clang::lifetimebound]],
MyObj &obj2 [[clang::lifetimebound]]) {
return condition ? obj1 : obj2;
}
```
That said, I am happy with the current state of having the same behaviour for suggestions and verification. For more functional changes, e.g. handling macros, we could followup separately.
https://github.com/llvm/llvm-project/pull/199149
More information about the cfe-commits
mailing list