From 4849d593ab07c47f9f520bea636f62d159d57006 Mon Sep 17 00:00:00 2001 From: Maksim Ivanov Date: Tue, 3 Dec 2024 10:10:11 +0000 Subject: [PATCH] [clang] Warn [[clang::lifetimebound]] misusages on types (#118281) 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]]` analysis for unnamed parameters, it doesn't currently, so the commit at least makes the situation better by highlighting this as a warning instead of a silent ignore - which was reported at #96034. --- clang/docs/ReleaseNotes.rst | 17 ++++++++++++++++- clang/lib/Sema/SemaType.cpp | 4 ++++ clang/test/SemaCXX/attr-lifetimebound.cpp | 18 ++++++++++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 01c7899e36c932..4e4dcd83cc28ed 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -139,7 +139,7 @@ C++ Specific Potentially Breaking Changes // Fixed version: unsigned operator""_udl_name(unsigned long long); -- Clang will now produce an error diagnostic when [[clang::lifetimebound]] is +- Clang will now produce an error diagnostic when ``[[clang::lifetimebound]]`` is applied on a parameter or an implicit object parameter of a function that returns void. This was previously ignored and had no effect. (#GH107556) @@ -148,6 +148,21 @@ C++ Specific Potentially Breaking Changes // Now diagnoses with an error. void f(int& i [[clang::lifetimebound]]); +- Clang will now produce an error diagnostic when ``[[clang::lifetimebound]]`` + is applied on a type (instead of a function parameter or an implicit object + parameter); this includes the case when the attribute is specified for an + unnamed function parameter. These were previously ignored and had no effect. + (#GH118281) + + .. code-block:: c++ + + // Now diagnoses with an error. + int* [[clang::lifetimebound]] x; + // Now diagnoses with an error. + void f(int* [[clang::lifetimebound]] i); + // Now diagnoses with an error. + void g(int* [[clang::lifetimebound]]); + - Clang now rejects all field accesses on null pointers in constant expressions. The following code used to work but will now be rejected: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f32edc5ac06440..75130436282fbd 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8612,7 +8612,11 @@ static void HandleLifetimeBoundAttr(TypeProcessingState &State, CurType = State.getAttributedType( createSimpleAttr(State.getSema().Context, Attr), CurType, CurType); + return; } + 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 f89b556f5bba08..c7abec61873efb 100644 --- a/clang/test/SemaCXX/attr-lifetimebound.cpp +++ b/clang/test/SemaCXX/attr-lifetimebound.cpp @@ -9,11 +9,25 @@ 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 {{'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 ¶m [[clang::lifetimebound(42)]]); // expected-error {{takes no arguments}} + + 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 {{'lifetimebound' attribute only applies to parameters and implicit object parameters}} + template + 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 {