9 Declarations [dcl.dcl]

9.12 Attributes [dcl.attr]

9.12.1 Attribute syntax and semantics [dcl.attr.grammar]

If an attribute-specifier contains an attribute-using-prefix, the attribute-list following that attribute-using-prefix shall not contain an attribute-scoped-token and every attribute-token in that attribute-list is treated as if its identifier were prefixed with N​::​, where N is the attribute-namespace specified in the attribute-using-prefix.
[Note 1: 
This rule imposes no constraints on how an attribute-using-prefix affects the tokens in an attribute-argument-clause.
— end note]
[Example 1: [[using CC: opt(1), debug]] // same as [[CC​::​opt(1), CC​::​debug]] void f() {} [[using CC: opt(1)]] [[CC::debug]] // same as [[CC​::​opt(1)]] [[CC​::​debug]] void g() {} [[using CC: CC::opt(1)]] // error: cannot combine using and scoped attribute token void h() {} — end example]
[Note 2: 
For each individual attribute, the form of the balanced-token-seq will be specified.
— end note]
In an attribute-list, an ellipsis may appear only if that attribute's specification permits it.
An attribute followed by an ellipsis is a pack expansion.
An attribute-specifier that contains no attributes has no effect.
The order in which the attribute-tokens appear in an attribute-list is not significant.
If a keyword or an alternative token that satisfies the syntactic requirements of an identifier ([lex.name]) is contained in an attribute-token, it is considered an identifier.
No name lookup is performed on any of the identifiers contained in an attribute-token.
The attribute-token determines additional requirements on the attribute-argument-clause (if any).
Each attribute-specifier-seq is said to appertain to some entity or statement, identified by the syntactic context where it appears ([stmt.stmt], [dcl.dcl], [dcl.decl]).
If an attribute-specifier-seq that appertains to some entity or statement contains an attribute or alignment-specifier that is not allowed to apply to that entity or statement, the program is ill-formed.
If an attribute-specifier-seq appertains to a friend declaration ([class.friend]), that declaration shall be a definition.
[Note 3: 
An attribute-specifier-seq cannot appertain to an explicit instantiation ([temp.explicit]).
— end note]
For an attribute-token (including an attribute-scoped-token) not specified in this document, the behavior is implementation-defined; any such attribute-token that is not recognized by the implementation is ignored.
[Note 4: 
A program is ill-formed if it contains an attribute specified in [dcl.attr] that violates the rules specifying to which entity or statement the attribute can apply or the syntax rules for the attribute's attribute-argument-clause, if any.
— end note]
[Note 5: 
The attributes specified in [dcl.attr] have optional semantics: given a well-formed program, removing all instances of any one of those attributes results in a program whose set of possible executions ([intro.abstract]) for a given input is a subset of those of the original program for the same input, absent implementation-defined guarantees with respect to that attribute.
— end note]
An attribute-token is reserved for future standardization if
Each implementation should choose a distinctive name for the attribute-namespace in an attribute-scoped-token.
Two consecutive left square bracket tokens shall appear only when introducing an attribute-specifier or within the balanced-token-seq of an attribute-argument-clause.
[Note 6: 
If two consecutive left square brackets appear where an attribute-specifier is not allowed, the program is ill-formed even if the brackets match an alternative grammar production.
— end note]
[Example 2: int p[10]; void f() { int x = 42, y[5]; int(p[[x] { return x; }()]); // error: invalid attribute on a nested declarator-id and // not a function-style cast of an element of p. y[[] { return 2; }()] = 2; // error even though attributes are not allowed in this context. int i [[vendor::attr([[]])]]; // well-formed implementation-defined attribute. } — end example]

9.12.2 Alignment specifier [dcl.align]

An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied to a bit-field, a function parameter, or an exception-declaration ([except.handle]).
An alignment-specifier may also be applied to the declaration of a class (in an elaborated-type-specifier ([dcl.type.elab]) or class-head ([class]), respectively).
An alignment-specifier with an ellipsis is a pack expansion ([temp.variadic]).
When the alignment-specifier is of the form alignas( constant-expression ):
  • the constant-expression shall be an integral constant expression
  • if the constant expression does not evaluate to an alignment value ([basic.align]), or evaluates to an extended alignment and the implementation does not support that alignment in the context of the declaration, the program is ill-formed.
An alignment-specifier of the form alignas( type-id ) has the same effect as alignas(alignof( type-id )).
The alignment requirement of an entity is the strictest nonzero alignment specified by its alignment-specifiers, if any; otherwise, the alignment-specifiers have no effect.
The combined effect of all alignment-specifiers in a declaration shall not specify an alignment that is less strict than the alignment that would be required for the entity being declared if all alignment-specifiers appertaining to that entity were omitted.
[Example 1: struct alignas(8) S {}; struct alignas(1) U { S s; }; // error: U specifies an alignment that is less strict than if the alignas(1) were omitted. — end example]
If the defining declaration of an entity has an alignment-specifier, any non-defining declaration of that entity shall either specify equivalent alignment or have no alignment-specifier.
Conversely, if any declaration of an entity has an alignment-specifier, every defining declaration of that entity shall specify an equivalent alignment.
No diagnostic is required if declarations of an entity have different alignment-specifiers in different translation units.
[Example 2: // Translation unit #1: struct S { int x; } s, *p = &s; // Translation unit #2: struct alignas(16) S; // ill-formed, no diagnostic required: definition of S lacks alignment extern S* p; — end example]
[Example 3: 
An aligned buffer with an alignment requirement of A and holding N elements of type T can be declared as: alignas(T) alignas(A) T buffer[N];
Specifying alignas(T) ensures that the final requested alignment will not be weaker than alignof(T), and therefore the program will not be ill-formed.
— end example]
[Example 4: alignas(double) void f(); // error: alignment applied to function alignas(double) unsigned char c[sizeof(double)]; // array of characters, suitably aligned for a double extern unsigned char c[sizeof(double)]; // no alignas necessary alignas(float) extern unsigned char c[sizeof(double)]; // error: different alignment in declaration — end example]

9.12.3 Assumption attribute [dcl.attr.assume]

The attribute-token assume may be applied to a null statement; such a statement is an assumption.
An attribute-argument-clause shall be present and shall have the form: The expression is contextually converted to bool ([conv.general]).
The expression is not evaluated.
If the converted expression would evaluate to true at the point where the assumption appears, the assumption has no effect.
Otherwise, the behavior is undefined.
[Note 1: 
The expression is potentially evaluated ([basic.def.odr]).
The use of assumptions is intended to allow implementations to analyze the form of the expression and deduce information used to optimize the program.
Implementations are not required to deduce any information from any particular assumption.
It is expected that the value of a has-attribute-expression for the assume attribute is 0 if an implementation does not attempt to deduce any such information from assumptions.
— end note]
[Example 1: int divide_by_32(int x) { [[assume(x >= 0)]]; return x/32; // The instructions produced for the division // may omit handling of negative values. } int f(int y) { [[assume(++y == 43)]]; // y is not incremented return y; // statement may be replaced with return 42; } — end example]

9.12.4 Carries dependency attribute [dcl.attr.depend]

The attribute-token carries_dependency specifies dependency propagation into and out of functions.
No attribute-argument-clause shall be present.
The attribute may be applied to a parameter of a function or lambda, in which case it specifies that the initialization of the parameter carries a dependency to ([intro.multithread]) each lvalue-to-rvalue conversion ([conv.lval]) of that object.
The attribute may also be applied to a function or a lambda call operator, in which case it specifies that the return value, if any, carries a dependency to the evaluation of the function call expression.
The first declaration of a function shall specify the carries_dependency attribute for its declarator-id if any declaration of the function specifies the carries_dependency attribute.
Furthermore, the first declaration of a function shall specify the carries_dependency attribute for a parameter if any declaration of that function specifies the carries_dependency attribute for that parameter.
If a function or one of its parameters is declared with the carries_dependency attribute in its first declaration in one translation unit and the same function or one of its parameters is declared without the carries_dependency attribute in its first declaration in another translation unit, the program is ill-formed, no diagnostic required.
[Note 1: 
The carries_dependency attribute does not change the meaning of the program, but might result in generation of more efficient code.
— end note]
[Example 1: /* Translation unit A. */ struct foo { int* a; int* b; }; std::atomic<struct foo *> foo_head[10]; int foo_array[10][10]; [[carries_dependency]] struct foo* f(int i) { return foo_head[i].load(memory_order::consume); } int g(int* x, int* y [[carries_dependency]]) { return kill_dependency(foo_array[*x][*y]); } /* Translation unit B. */ [[carries_dependency]] struct foo* f(int i); int g(int* x, int* y [[carries_dependency]]); int c = 3; void h(int i) { struct foo* p; p = f(i); do_something_with(g(&c, p->a)); do_something_with(g(p->a, &c)); }
The carries_dependency attribute on function f means that the return value carries a dependency out of f, so that the implementation need not constrain ordering upon return from f.
Implementations of f and its caller may choose to preserve dependencies instead of emitting hardware memory ordering instructions (a.k.a. fences).
Function g's second parameter has a carries_dependency attribute, but its first parameter does not.
Therefore, function h's first call to g carries a dependency into g, but its second call does not.
The implementation might need to insert a fence prior to the second call to g.
— end example]

9.12.5 Deprecated attribute [dcl.attr.deprecated]

The attribute-token deprecated can be used to mark names and entities whose use is still allowed, but is discouraged for some reason.
[Note 1: 
In particular, deprecated is appropriate for names and entities that are deemed obsolescent or unsafe.
— end note]
An attribute-argument-clause may be present and, if present, it shall have the form:
[Note 2: 
The unevaluated-string in the attribute-argument-clause can be used to explain the rationale for deprecation and/or to suggest a replacing entity.
— end note]
The attribute may be applied to the declaration of a class, a typedef-name, a variable, a non-static data member, a function, a namespace, an enumeration, an enumerator, a concept, or a template specialization.
An entity declared without the deprecated attribute can later be redeclared with the attribute and vice-versa.
[Note 3: 
Thus, an entity initially declared without the attribute can be marked as deprecated by a subsequent redeclaration.
However, after an entity is marked as deprecated, later redeclarations do not un-deprecate the entity.
— end note]
Redeclarations using different forms of the attribute (with or without the attribute-argument-clause or with different attribute-argument-clauses) are allowed.
Recommended practice: Implementations should use the deprecated attribute to produce a diagnostic message in case the program refers to a name or entity other than to declare it, after a declaration that specifies the attribute.
The diagnostic message should include the text provided within the attribute-argument-clause of any deprecated attribute applied to the name or entity.
The value of a has-attribute-expression for the deprecated attribute should be 0 unless the implementation can issue such diagnostic messages.

9.12.6 Fallthrough attribute [dcl.attr.fallthrough]

The attribute-token fallthrough may be applied to a null statement; such a statement is a fallthrough statement.
No attribute-argument-clause shall be present.
A fallthrough statement may only appear within an enclosing switch statement ([stmt.switch]).
The next statement that would be executed after a fallthrough statement shall be a labeled statement whose label is a case label or default label for the same switch statement and, if the fallthrough statement is contained in an iteration statement, the next statement shall be part of the same execution of the substatement of the innermost enclosing iteration statement.
The program is ill-formed if there is no such statement.
Recommended practice: The use of a fallthrough statement should suppress a warning that an implementation might otherwise issue for a case or default label that is reachable from another case or default label along some path of execution.
The value of a has-attribute-expression for the fallthrough attribute should be 0 if the attribute does not cause suppression of such warnings.
Implementations should issue a warning if a fallthrough statement is not dynamically reachable.
[Example 1: void f(int n) { void g(), h(), i(); switch (n) { case 1: case 2: g(); [[fallthrough]]; case 3: // warning on fallthrough discouraged do { [[fallthrough]]; // error: next statement is not part of the same substatement execution } while (false); case 6: do { [[fallthrough]]; // error: next statement is not part of the same substatement execution } while (n--); case 7: while (false) { [[fallthrough]]; // error: next statement is not part of the same substatement execution } case 5: h(); case 4: // implementation may warn on fallthrough i(); [[fallthrough]]; // error } } — end example]

9.12.7 Likelihood attributes [dcl.attr.likelihood]

The attribute-tokens likely and unlikely may be applied to labels or statements.
No attribute-argument-clause shall be present.
The attribute-token likely shall not appear in an attribute-specifier-seq that contains the attribute-token unlikely.
[Note 1: 
The use of the likely attribute is intended to allow implementations to optimize for the case where paths of execution including it are arbitrarily more likely than any alternative path of execution that does not include such an attribute on a statement or label.
The use of the unlikely attribute is intended to allow implementations to optimize for the case where paths of execution including it are arbitrarily more unlikely than any alternative path of execution that does not include such an attribute on a statement or label.
It is expected that the value of a has-attribute-expression for the likely and unlikely attributes is 0 if the implementation does not attempt to use these attributes for such optimizations.
A path of execution includes a label if and only if it contains a jump to that label.
— end note]
[Note 2: 
Excessive usage of either of these attributes is liable to result in performance degradation.
— end note]
[Example 1: void g(int); int f(int n) { if (n > 5) [[unlikely]] { // n > 5 is considered to be arbitrarily unlikely g(0); return n * 2 + 1; } switch (n) { case 1: g(1); [[fallthrough]]; [[likely]] case 2: // n == 2 is considered to be arbitrarily more g(2); // likely than any other value of n break; } return 3; } — end example]

9.12.8 Maybe unused attribute [dcl.attr.unused]

The attribute-token maybe_unused indicates that a name, label, or entity is possibly intentionally unused.
No attribute-argument-clause shall be present.
The attribute may be applied to the declaration of a class, typedef-name, variable (including a structured binding declaration), non-static data member, function, enumeration, or enumerator, or to an identifier label ([stmt.label]).
A name or entity declared without the maybe_unused attribute can later be redeclared with the attribute and vice versa.
An entity is considered marked after the first declaration that marks it.
Recommended practice: For an entity marked maybe_unused, implementations should not emit a warning that the entity or its structured bindings (if any) are used or unused.
For a structured binding declaration not marked maybe_unused, implementations should not emit such a warning unless all of its structured bindings are unused.
For a label to which maybe_unused is applied, implementations should not emit a warning that the label is used or unused.
The value of a has-attribute-expression for the maybe_unused attribute should be 0 if the attribute does not cause suppression of such warnings.
[Example 1: [[maybe_unused]] void f([[maybe_unused]] bool thing1, [[maybe_unused]] bool thing2) { [[maybe_unused]] bool b = thing1 && thing2; assert(b); #ifdef NDEBUG goto x; #endif [[maybe_unused]] x: }
Implementations should not warn that b or x is unused, whether or not NDEBUG is defined.
— end example]

9.12.9 Nodiscard attribute [dcl.attr.nodiscard]

The attribute-token nodiscard may be applied to a function or a lambda call operator or to the declaration of a class or enumeration.
An attribute-argument-clause may be present and, if present, shall have the form:
A name or entity declared without the nodiscard attribute can later be redeclared with the attribute and vice-versa.
[Note 1: 
Thus, an entity initially declared without the attribute can be marked as nodiscard by a subsequent redeclaration.
However, after an entity is marked as nodiscard, later redeclarations do not remove the nodiscard from the entity.
— end note]
Redeclarations using different forms of the attribute (with or without the attribute-argument-clause or with different attribute-argument-clauses) are allowed.
A nodiscard type is a (possibly cv-qualified) class or enumeration type marked nodiscard in a reachable declaration.
A nodiscard call is either
  • a function call expression ([expr.call]) that calls a function declared nodiscard in a reachable declaration or whose return type is a nodiscard type, or
  • an explicit type conversion ([expr.type.conv], [expr.static.cast], [expr.cast]) that constructs an object through a constructor declared nodiscard in a reachable declaration, or that initializes an object of a nodiscard type.
Recommended practice: Appearance of a nodiscard call as a potentially-evaluated discarded-value expression ([expr.prop]) is discouraged unless explicitly cast to void.
Implementations should issue a warning in such cases.
The value of a has-attribute-expression for the nodiscard attribute should be 0 unless the implementation can issue such warnings.
[Note 2: 
This is typically because discarding the return value of a nodiscard call has surprising consequences.
— end note]
The unevaluated-string in a nodiscard attribute-argument-clause should be used in the message of the warning as the rationale for why the result should not be discarded.
[Example 1: struct [[nodiscard]] my_scopeguard { /* ... */ }; struct my_unique { my_unique() = default; // does not acquire resource [[nodiscard]] my_unique(int fd) { /* ... */ } // acquires resource ~my_unique() noexcept { /* ... */ } // releases resource, if any /* ... */ }; struct [[nodiscard]] error_info { /* ... */ }; error_info enable_missile_safety_mode(); void launch_missiles(); void test_missiles() { my_scopeguard(); // warning encouraged (void)my_scopeguard(), // warning not encouraged, cast to void launch_missiles(); // comma operator, statement continues my_unique(42); // warning encouraged my_unique(); // warning not encouraged enable_missile_safety_mode(); // warning encouraged launch_missiles(); } error_info &foo(); void f() { foo(); } // warning not encouraged: not a nodiscard call, because neither // the (reference) return type nor the function is declared nodiscard — end example]

9.12.10 Noreturn attribute [dcl.attr.noreturn]

The attribute-token noreturn specifies that a function does not return.
No attribute-argument-clause shall be present.
The attribute may be applied to a function or a lambda call operator.
The first declaration of a function shall specify the noreturn attribute if any declaration of that function specifies the noreturn attribute.
If a function is declared with the noreturn attribute in one translation unit and the same function is declared without the noreturn attribute in another translation unit, the program is ill-formed, no diagnostic required.
If a function f is called where f was previously declared with the noreturn attribute and f eventually returns, the behavior is undefined.
[Note 1: 
The function can terminate by throwing an exception.
— end note]
Recommended practice: Implementations should issue a warning if a function marked [[noreturn]] might return.
The value of a has-attribute-expression for the noreturn attribute should be 0 unless the implementation can issue such warnings.
[Example 1: [[ noreturn ]] void f() { throw "error"; // OK } [[ noreturn ]] void q(int i) { // behavior is undefined if called with an argument <= 0 if (i > 0) throw "positive"; } — end example]

9.12.11 No unique address attribute [dcl.attr.nouniqueaddr]

The attribute-token no_unique_address specifies that a non-static data member is a potentially-overlapping subobject ([intro.object]).
No attribute-argument-clause shall be present.
The attribute may appertain to a non-static data member other than a bit-field.
[Note 1: 
The non-static data member can share the address of another non-static data member or that of a base class, and any padding that would normally be inserted at the end of the object can be reused as storage for other members.
— end note]
Recommended practice: The value of a has-attribute-expression for the no_unique_address attribute should be 0 for a given implementation unless this attribute can cause a potentially-overlapping subobject to have zero size.
[Example 1: template<typename Key, typename Value, typename Hash, typename Pred, typename Allocator> class hash_map { [[no_unique_address]] Hash hasher; [[no_unique_address]] Pred pred; [[no_unique_address]] Allocator alloc; Bucket *buckets; // ... public: // ... };
Here, hasher, pred, and alloc could have the same address as buckets if their respective types are all empty.
— end example]