C++20 has handy [[likely]]
/[[unlikely]]
attributes which guide code generation. For example, you can specify a branch is likely to be taken by:
if (b) [[likely]] { /*...*/ }
Similarly, it is possible to use these attributes in switch
statements . . . somehow? The documentation suggests the following example (slightly formatted):
switch (i) {
case 1:
[[fallthrough]];
[[likely]] case 2:
return 1;
}
The implication is clearly that the [[likely]]
/[[unlikely]]
goes before the case
statement. The internet seems to almost universally promulgate this usage.
However, consider the following similar code (all I've done is move the [[likely]]
to the other case
):
switch (i) {
[[likely]] case 1:
[[fallthrough]];
case 2:
return 1;
}
This fails to compile on clang! While that may be related to a compiler bug with [[fallthrough]]
, it got me looking at the standards. The relevant standard has the following example (see §VII):
implementations are encouraged to optimize for that case being executed (eg. a having the value 1 in the following code):
switch (a) {
case 1: [[likely]]
foo();
break;
//...
}
That is, the attribute comes after the case label, not before.
So . . . which is it? Offhand, I'd expect the standard to be correct, but that is actually a proposal, not the real standard AFAICT—it could have been changed since. And, I'd expect the documentation, if nothing else, to be correct at least about the fundamental syntax—except that it doesn't even compile.
Both examples are valid, and Clang is exhibiting a bug. The relevant verbiage from the last standard draft for C++20 is
[dcl.attr.likelihood]
1 The attribute-tokens
likely
andunlikely
may be applied to labels or statements.
Where the relevant grammar productions for statements and labeled statements have an attribute specifier sequence at the appropriate locations.
[stmt.pre]
statement: labeled-statement attribute-specifier-seq expression-statement attribute-specifier-seq compound-statement attribute-specifier-seq selection-statement attribute-specifier-seq iteration-statement attribute-specifier-seq jump-statement declaration-statement attribute-specifier-seq try-block
[stmt.label]
labeled-statement: attribute-specifier-seq identifier : statement attribute-specifier-seq case constant-expression : statement attribute-specifier-seq default : statement
In
switch (i) {
case 1:
[[fallthrough]];
[[likely]] case 2:
return 1;
}
The attribute applies to case 2:
wheras in
switch (a) {
case 1: [[likely]]
foo();
break;
//...
}
it applies to the statement foo();
.