[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 tokenvoid h(){} — end example]
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.
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.
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
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[[]{return2; }()]=2; // error even though attributes are not allowed in this context.int i [[vendor::attr([[]])]]; // well-formed implementation-defined attribute.} — end example]
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.
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: structalignas(8) S {};
structalignas(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:structalignas(16) S; // ill-formed, no diagnostic required: definition of S lacks alignmentextern S* p;
— end example]
[Example 4: alignas(double)void f(); // error: alignment applied to functionalignas(double)unsignedchar c[sizeof(double)]; // array of characters, suitably aligned for a doubleexternunsignedchar c[sizeof(double)]; // no alignas necessaryalignas(float)externunsignedchar c[sizeof(double)]; // error: different alignment in declaration — end example]
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.
— 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 incrementedreturn y; // statement may be replaced with return 42;} — end example]
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.
[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.
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.
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.
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.
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){case1:case2:
g();
[[fallthrough]];
case3:// warning on fallthrough discourageddo{[[fallthrough]]; // error: next statement is not part of the same substatement execution}while(false);
case6:do{[[fallthrough]]; // error: next statement is not part of the same substatement execution}while(n--);
case7:while(false){[[fallthrough]]; // error: next statement is not part of the same substatement execution}case5:
h();
case4:// implementation may warn on fallthrough
i();
[[fallthrough]]; // error}} — end example]
Recommended practice: 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.
A path of execution includes a label
if and only if it contains a jump to that label.
[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){case1:
g(1);
[[fallthrough]];
[[likely]]case2:// n == 2 is considered to be arbitrarily more
g(2); // likely than any other value of nbreak;
}return3;
} — end example]
The attribute may be applied to the declaration of a class,
a typedef-name,
a variable (including a structured binding declaration),
a non-static data member,
a function, an enumeration, or an enumerator.
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.
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.
This is typically because discarding the return value
of a nodiscard call has surprising consequences.
— end note]
The string-literal
in a nodiscardattribute-argument-clause
should be used in the message of the warning
as the rationale for why the result should not be discarded.
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.
[Example 1: [[ noreturn ]]void f(){throw"error"; // OK}[[ noreturn ]]void q(int i){// behavior is undefined if called with an argument <= 0if(i >0)throw"positive";
} — end example]
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.