In a lambda, what does the second list of attributes do?

848 Views Asked by At

C++23 allows [[...]] attributes in lambda expressions:

auto lambda = [] [[nodiscard]]
{
    return 42;
};

But the grammar has place for two lists of attributes, roughly before and after the parameter list:

auto lambda = [] [[nodiscard]] () [[deprecated]]
//               (1)~~~~~~~~~~    (2)~~~~~~~~~~~  // (2) seems to have no effect here
{
    return 42;
};

The two lists apply to different things, but I can't figure out what the second list is for, and what attributes I can put here. For any attribute I tried at (2), Clang warns: '...' attribute cannot be applied to types.

The standard says this:

[expr.prim.lambda.closure]/6

... An attribute-specifier-seq [at location (2)] appertains to the type of the corresponding function call operator or operator template.

An attribute-specifier-seq [at location (1)] appertains to the corresponding function call operator or operator template.

"appertains to the type of the corresponding function call operator" leaves me confused. What attributes can I put here? Is this solely for compiler-specific attributes, and if so, what non-standard attributes can be used here?

Also apparently the list (2) existed well before C++23 (this proposal added the list (1)).

1

There are 1 best solutions below

0
On BEST ANSWER

Attributes at location (2) apply to the type of operator() (which is a function type), whereas at location (1) they apply to the function declaration itself.

None of the standard attributes apply to types, so no standard attribute applies when put in location (2).

Looking at vendor-specific type attributes from https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html and https://clang.llvm.org/docs/AttributeReference.html#type-attributes, you can see that most type attributes only apply to object types of some kind (e.g., [[gnu::aligned]], [[gnu::vector_size]]).

One attribute that seems to apply to any type (including function types) is [[clang::annotate_type(...)]]:

// [] [[clang::annotate_type("xyz") () {}  // Error
[] () [[clang::annotate_type("xyz")]] {}
// (For completeness, `clang::annotate` is used for declarations)
[] [[clang::annotate("annotates operator()")]] () [[clang::annotate_type("annotates type of operator(), `void()`")]] {}

There may be other attributes that apply to function types, but I haven't found them.

It also perfectly mirrors attribute placement in regular function declarations:

struct X {
    auto operator() [[clang::annotate("annotates operator()")]] () [[clang::annotate_type("annotates void()")]] {}
};

But yes, you usually want the attributes to apply to the function declaration and not the function type, so you should never have to use an attributes at location (2).