Skip to content

Commit

Permalink
(reland) [clang] Warn [[clang::lifetimebound]] misusages on types (ll…
Browse files Browse the repository at this point in the history
…vm#118501)

This relands llvm#118281 as-is, after it got reverted in commit
356df2d. The reland can go in after we
fixed some downstream codebases that had incorrectly placed attributes.

Original commit description:

> 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 llvm#96034.
  • Loading branch information
emaxx-google authored Jan 10, 2025
1 parent e9e7b2a commit 4f69f45
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 3 deletions.
17 changes: 16 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,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)

Expand All @@ -156,6 +156,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:

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8628,7 +8628,11 @@ 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_wrong_decl_type_str)
<< Attr << Attr.isRegularKeywordAttribute()
<< "parameters and implicit object parameters";
}

static void HandleLifetimeCaptureByAttr(TypeProcessingState &State,
Expand Down
18 changes: 16 additions & 2 deletions clang/test/SemaCXX/attr-lifetimebound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 &param [[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 <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 {
Expand Down

0 comments on commit 4f69f45

Please sign in to comment.