Statement Attributes (Using the GNU Compiler Collection (GCC)) (original) (raw)
6.4.6 Statement Attributes ¶
GCC allows attributes to be set on statements. See Attribute Syntax, for details of the exact syntax for using attributes. Other attributes are available for functions (see Declaring Attributes of Functions), variables (see Specifying Attributes of Variables), labels (see Label Attributes), enumerators (see Enumerator Attributes), and for types (see Specifying Attributes of Types).
fallthrough
¶
The fallthrough
attribute with a null statement serves as a fallthrough statement. It hints to the compiler that a statement that falls through to another case label, or user-defined label in a switch statement is intentional and thus the-Wimplicit-fallthrough warning must not trigger. The fallthrough attribute may appear at most once in each attribute list, and may not be mixed with other attributes. It can only be used in a switch statement (the compiler will issue an error otherwise), after a preceding statement and before a logically succeeding case label, or user-defined label.
This example uses the fallthrough
statement attribute to indicate that the -Wimplicit-fallthrough warning should not be emitted:
switch (cond) { case 1: bar (1); attribute((fallthrough)); case 2: … }
assume
¶
The assume
attribute with a null statement serves as portable assumption. It should have a single argument, a conditional expression, which is not evaluated. If the argument would evaluate to true at the point where it appears, it has no effect, otherwise there is undefined behavior. This is a GNU variant of the ISO C++23 standard assume
attribute, but it can be used in any version of both C and C++.
int foo (int x, int y) { attribute((assume(x == 42))); attribute((assume(++y == 43))); return x + y; }
y
is not actually incremented and the compiler can but does not have to optimize it to just return 42 + 42;
.
musttail
¶
The gnu::musttail
or clang::musttail
standard attribute or musttail
GNU attribute can be applied to a return
statement with a return-value expression that is a function call. It asserts that the call must be a tail call that does not allocate extra stack space, so it is safe to use tail recursion to implement long-running loops.
[[gnu::musttail]] return foo();
attribute((musttail)) return bar();
If the compiler cannot generate a musttail
tail call it reports an error. On some targets, tail calls may not be supported at all. The musttail
attribute asserts that the lifetime of automatic variables, function parameters and temporaries (unless they have non-trivial destruction) can end before the actual call instruction, and that any access to those from inside of the called function results is considered undefined behavior. Enabling -O1 or -O2 can improve the success of tail calls.
int foo (int *); void bar (int *); struct S { S (); ~S (); int s; };
int baz (int *x) { if (x == 1) { int a = 42; / The call is a tail call (would not be without the attribute). Dereferencing the pointer in the callee is undefined behavior, and there is a warning emitted for this by default (-Wmusttail-local-addr). */ [[gnu::musttail]] return foo (&a); } else if (x == 2) { int a = 42; bar (&a); / The call is a tail call (would not be without the attribute). If bar stores the pointer anywhere, dereferencing it in foo is undefined behavior. There is a warning emitted for this with -Wextra, which implies -Wmaybe-musttail-local-addr. / [[gnu::musttail]] return foo (nullptr); } else { S s; / The s variable requires non-trivial destruction which ought to be performed after the foo call returns, so this is rejected. */ [[gnu::musttail]] return foo (&s.s); } }
To avoid the -Wmaybe-musttail-local-addr warning in the above *x == 2
case and similar code, consider defining the maybe-escaped variables in a separate scope that ends before the return statement, if that is possible, to make it clear that the variable is not live during the call. So:
else if (x == 2) { { int a = 42; bar (&a); } / The call is a tail call (would not be without the attribute). If bar stores the pointer anywhere, dereferencing it in foo is undefined behavior even without tail call optimization, and there is no warning. */ [[gnu::musttail]] return foo (nullptr); }
It is not possible to avoid the warning in this way if the maybe-escaped variable is a function argument, because those are in scope for the whole function.