10 Declarations [dcl.dcl]

10.6 Attributes [dcl.attr]

10.6.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
:
This rule imposes no constraints on how an attribute-using-prefix affects the tokens in an attribute-argument-clause.
end note
]
[Example
:
[[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
:
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 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 (Clause [stmt.stmt], Clause [dcl.dcl], Clause [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, that declaration shall be a definition.
For an attribute-token (including an attribute-scoped-token) not specified in this International Standard, the behavior is implementation-defined.
Any attribute-token that is not recognized by the implementation is ignored.
[Note
:
Each implementation should choose a distinctive name for the attribute-namespace in an attribute-scoped-token.
end note
]
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
:
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
:
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
]

10.6.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 or definition of a class (in an elaborated-type-specifier or class-head, respectively) and to the declaration or definition of an enumeration (in an opaque-enum-declaration or enum-head, respectively ([dcl.enum])).
An alignment-specifier with an ellipsis is a pack expansion.
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 )) ([expr.alignof]).
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
:
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
:
// Translation unit #1:
struct S { int x; } s, *p = &s;

// Translation unit #2:
struct alignas(16) S;           // error: definition of S lacks alignment, no diagnostic required
extern S* p;
end example
]
[Example
:
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
:
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
]

10.6.3 Carries dependency attribute [dcl.attr.depend]

The attribute-token carries_­dependency specifies dependency propagation into and out of functions.
It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present.
The attribute may be applied to the declarator-id of a parameter-declaration in a function declaration or lambda, in which case it specifies that the initialization of the parameter carries a dependency to each lvalue-to-rvalue conversion of that object.
The attribute may also be applied to the declarator-id of a function declaration, 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
:
The carries_­dependency attribute does not change the meaning of the program, but may result in generation of more efficient code.
end note
]
[Example
:
/* 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
]

10.6.4 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
:
In particular, deprecated is appropriate for names and entities that are deemed obsolescent or unsafe.
end note
]
It shall appear at most once in each attribute-list.
An attribute-argument-clause may be present and, if present, it shall have the form:
( string-literal )
[Note
:
The string-literal in the attribute-argument-clause could 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, or a template specialization.
A name or entity declared without the deprecated attribute can later be redeclared with the attribute and vice-versa.
[Note
:
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.
[Note
:
Implementations may 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 may include the text provided within the attribute-argument-clause of any deprecated attribute applied to the name or entity.
end note
]

10.6.5 Fallthrough attribute [dcl.attr.fallthrough]

The attribute-token fallthrough may be applied to a null statement; such a statement is a fallthrough statement.
The attribute-token fallthrough shall appear at most once in each attribute-list and no attribute-argument-clause shall be present.
A fallthrough statement may only appear within an enclosing switch statement.
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.
The program is ill-formed if there is no such statement.
[Note
:
The use of a fallthrough statement is intended to 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.
Implementations are encouraged to issue a warning if a fallthrough statement is not dynamically reachable.
end note
]
[Example
:
void f(int n) {
  void g(), h(), i();
  switch (n) {
  case 1:
  case 2:
    g();
    [[fallthrough]];
  case 3:                       // warning on fallthrough discouraged
    h();
  case 4:                       // implementation may warn on fallthrough
    i();
    [[fallthrough]];            // ill-formed
  }
}
end example
]

10.6.6 Maybe unused attribute [dcl.attr.unused]

The attribute-token maybe_­unused indicates that a name or entity is possibly intentionally unused.
It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present.
The attribute may be applied to the declaration of a class, a typedef-name, a variable, a non-static data member, a function, an enumeration, or an enumerator.
[Note
:
For an entity marked maybe_­unused, implementations are encouraged not to emit a warning that the entity is unused, or that the entity is used despite the presence of the attribute.
end note
]
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.
[Example
:
[[maybe_unused]] void f([[maybe_unused]] bool thing1,
                        [[maybe_unused]] bool thing2) {
  [[maybe_unused]] bool b = thing1 && thing2;
  assert(b);
}
Implementations are encouraged not to warn that b is unused, whether or not NDEBUG is defined.
end example
]

10.6.7 Nodiscard attribute [dcl.attr.nodiscard]

The attribute-token nodiscard may be applied to the declarator-id in a function declaration or to the declaration of a class or enumeration.
It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present.
[Note
:
A nodiscard call is a function call expression that calls a function previously declared nodiscard, or whose return type is a possibly cv-qualified class or enumeration type marked nodiscard.
Appearance of a nodiscard call as a potentially-evaluated discarded-value expression (Clause [expr]) is discouraged unless explicitly cast to void.
Implementations are encouraged to issue a warning in such cases.
This is typically because discarding the return value of a nodiscard call has surprising consequences.
end note
]
[Example
:
struct [[nodiscard]] error_info { /* ... */ };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
  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
]

10.6.8 Noreturn attribute [dcl.attr.noreturn]

The attribute-token noreturn specifies that a function does not return.
It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present.
The attribute may be applied to the declarator-id in a function declaration.
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
:
The function may terminate by throwing an exception.
end note
]
[Note
:
Implementations are encouraged to issue a warning if a function marked [[noreturn]] might return.
end note
]
[Example
:
[[ 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
]