[clang] [clang] Warn [[clang::lifetimebound]] misusages on types (PR #118281)

Maksim Ivanov via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 2 07:50:50 PST 2024


https://github.com/emaxx-google updated https://github.com/llvm/llvm-project/pull/118281

>From ffba96ae0b32a25b810c46c46e9c360c3eef400d Mon Sep 17 00:00:00 2001
From: Maksim Ivanov <emaxx at google.com>
Date: Mon, 2 Dec 2024 10:03:25 +0000
Subject: [PATCH 1/3] [clang] Warn [[clang::lifetimebound]] misusages on types

Emit the "cannot be applied to types" warning instead of silently
ignoring the attribute when it's attempted to be used on a type (instead
of a function argument or the function definition).

Before this commit, the warning has been printed when the attribute was
(mis)used on a decl-specifier, but not in other places in a declarator.

Examples where the warning starts being emitted with this commit:

  int * [[clang::lifetimebound]] x;

  void f(int * [[clang::lifetimebound]] x);

  void g(int * [[clang::lifetimebound]]);

Note that the last example is the case of an unnamed function parameter.
While in theory Clang could've supported the [[clang::lifetimebound]],
it doesn't currently, so the commit at least makes the situation better
by highlighting this as a warning instead of a silent ignore.
---
 clang/lib/Sema/SemaType.cpp               |  3 +++
 clang/test/SemaCXX/attr-lifetimebound.cpp | 13 +++++++++++--
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index f32edc5ac06440..2cc083ff6689d6 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8612,7 +8612,10 @@ static void HandleLifetimeBoundAttr(TypeProcessingState &State,
     CurType = State.getAttributedType(
         createSimpleAttr<LifetimeBoundAttr>(State.getSema().Context, Attr),
         CurType, CurType);
+    return;
   }
+  State.getSema().Diag(Attr.getLoc(), diag::err_attribute_not_type_attr)
+      << Attr << Attr.isRegularKeywordAttribute();
 }
 
 static void HandleLifetimeCaptureByAttr(TypeProcessingState &State,
diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp
index f89b556f5bba08..5f10dea97c29b4 100644
--- a/clang/test/SemaCXX/attr-lifetimebound.cpp
+++ b/clang/test/SemaCXX/attr-lifetimebound.cpp
@@ -9,11 +9,20 @@ namespace usage_invalid {
     ~A() [[clang::lifetimebound]]; // expected-error {{cannot be applied to a destructor}}
     static int *static_class_member() [[clang::lifetimebound]]; // expected-error {{static member function has no implicit object parameter}}
     int *explicit_object(this A&) [[clang::lifetimebound]]; // expected-error {{explicit object member function has no implicit object parameter}}
-    int not_function [[clang::lifetimebound]]; // expected-error {{only applies to parameters and implicit object parameters}}
-    int [[clang::lifetimebound]] also_not_function; // expected-error {{cannot be applied to types}}
+    int attr_on_var [[clang::lifetimebound]]; // expected-error {{only applies to parameters and implicit object parameters}}
+    int [[clang::lifetimebound]] attr_on_int; // expected-error {{cannot be applied to types}}
+    int * [[clang::lifetimebound]] attr_on_int_ptr; // expected-error {{cannot be applied to types}}
+    int * [[clang::lifetimebound]] * attr_on_int_ptr_ptr; // expected-error {{cannot be applied to types}}
+    int (* [[clang::lifetimebound]] attr_on_func_ptr)(); // expected-error {{cannot be applied to types}}
     void void_return_member() [[clang::lifetimebound]]; // expected-error {{'lifetimebound' attribute cannot be applied to an implicit object parameter of a function that returns void; did you mean 'lifetime_capture_by(X)'}}
   };
   int *attr_with_param(int &param [[clang::lifetimebound(42)]]); // expected-error {{takes no arguments}}
+
+  void attr_on_ptr_arg(int * [[clang::lifetimebound]] ptr); // expected-error {{cannot be applied to types}}
+  static_assert((int [[clang::lifetimebound]]) 12); // expected-error {{cannot be applied to types}}
+  int* attr_on_unnamed_arg(const int& [[clang::lifetimebound]]); // expected-error {{cannot be applied to types}}
+  template <typename T>
+  int* attr_on_template_ptr_arg(T * [[clang::lifetimebound]] ptr); // expected-error {{cannot be applied to types}}
 }
 
 namespace usage_ok {

>From 8bd3f8db4c92a3c7f098dde65274590d6ee8592c Mon Sep 17 00:00:00 2001
From: Maksim Ivanov <emaxx at google.com>
Date: Mon, 2 Dec 2024 15:47:08 +0000
Subject: [PATCH 2/3] change warning

---
 clang/lib/Sema/SemaType.cpp               |  5 +++--
 clang/test/SemaCXX/attr-lifetimebound.cpp | 12 ++++++------
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 2cc083ff6689d6..75130436282fbd 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8614,8 +8614,9 @@ static void HandleLifetimeBoundAttr(TypeProcessingState &State,
         CurType, CurType);
     return;
   }
-  State.getSema().Diag(Attr.getLoc(), diag::err_attribute_not_type_attr)
-      << Attr << Attr.isRegularKeywordAttribute();
+  State.getSema().Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type_str)
+      << Attr << Attr.isRegularKeywordAttribute()
+      << "parameters and implicit object parameters";
 }
 
 static void HandleLifetimeCaptureByAttr(TypeProcessingState &State,
diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp
index 5f10dea97c29b4..928ec12686e23c 100644
--- a/clang/test/SemaCXX/attr-lifetimebound.cpp
+++ b/clang/test/SemaCXX/attr-lifetimebound.cpp
@@ -11,18 +11,18 @@ namespace usage_invalid {
     int *explicit_object(this A&) [[clang::lifetimebound]]; // expected-error {{explicit object member function has no implicit object parameter}}
     int attr_on_var [[clang::lifetimebound]]; // expected-error {{only applies to parameters and implicit object parameters}}
     int [[clang::lifetimebound]] attr_on_int; // expected-error {{cannot be applied to types}}
-    int * [[clang::lifetimebound]] attr_on_int_ptr; // expected-error {{cannot be applied to types}}
-    int * [[clang::lifetimebound]] * attr_on_int_ptr_ptr; // expected-error {{cannot be applied to types}}
-    int (* [[clang::lifetimebound]] attr_on_func_ptr)(); // expected-error {{cannot be applied to types}}
+    int * [[clang::lifetimebound]] attr_on_int_ptr; // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
+    int * [[clang::lifetimebound]] * attr_on_int_ptr_ptr; // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
+    int (* [[clang::lifetimebound]] attr_on_func_ptr)(); // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
     void void_return_member() [[clang::lifetimebound]]; // expected-error {{'lifetimebound' attribute cannot be applied to an implicit object parameter of a function that returns void; did you mean 'lifetime_capture_by(X)'}}
   };
   int *attr_with_param(int &param [[clang::lifetimebound(42)]]); // expected-error {{takes no arguments}}
 
-  void attr_on_ptr_arg(int * [[clang::lifetimebound]] ptr); // expected-error {{cannot be applied to types}}
+  void attr_on_ptr_arg(int * [[clang::lifetimebound]] ptr); // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
   static_assert((int [[clang::lifetimebound]]) 12); // expected-error {{cannot be applied to types}}
-  int* attr_on_unnamed_arg(const int& [[clang::lifetimebound]]); // expected-error {{cannot be applied to types}}
+  int* attr_on_unnamed_arg(const int& [[clang::lifetimebound]]); // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
   template <typename T>
-  int* attr_on_template_ptr_arg(T * [[clang::lifetimebound]] ptr); // expected-error {{cannot be applied to types}}
+  int* attr_on_template_ptr_arg(T * [[clang::lifetimebound]] ptr); // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
 }
 
 namespace usage_ok {

>From b003a4d3d82b10b99978ba7eb0f9928dcd4fd286 Mon Sep 17 00:00:00 2001
From: Maksim Ivanov <emaxx at google.com>
Date: Mon, 2 Dec 2024 15:50:20 +0000
Subject: [PATCH 3/3] test func types

---
 clang/test/SemaCXX/attr-lifetimebound.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp
index 928ec12686e23c..c7abec61873efb 100644
--- a/clang/test/SemaCXX/attr-lifetimebound.cpp
+++ b/clang/test/SemaCXX/attr-lifetimebound.cpp
@@ -23,6 +23,11 @@ namespace usage_invalid {
   int* attr_on_unnamed_arg(const int& [[clang::lifetimebound]]); // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
   template <typename T>
   int* attr_on_template_ptr_arg(T * [[clang::lifetimebound]] ptr); // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
+
+  int (*func_ptr)(int) [[clang::lifetimebound]]; // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
+  int (*(*func_ptr_ptr)(int) [[clang::lifetimebound]])(int); // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
+  struct X {};
+  int (X::*member_func_ptr)(int) [[clang::lifetimebound]]; // expected-error {{'lifetimebound' attribute only applies to parameters and implicit object parameters}}
 }
 
 namespace usage_ok {



More information about the cfe-commits mailing list