https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114309

--- Comment #9 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to M Welinder from comment #0)
> The standard, quoted from
> https://en.cppreference.com/w/cpp/language/attributes/likely, clearly
> contemplates this case:

N.B. cppreference is not the standard, and the text you quote is paraphrasing a
note from the standard, it's not the standard's actual wording.

> Note that the standard expressions itself in terms of "paths of execution"
> whereas g++ appears to have a narrower "branches of `if'" world view.  I am
> not sure whether that's relevant.

I don't think it's relevant, no. The "paths of execution" case covers switch
cases and things that aren't `if`, but since your code uses `if` that's what
GCC's warning refers to.

Anyway, in GCC's testcase we have:

   9   if (a == 123)
  10     [[likely]] c = 5;           // { dg-warning "both" }
  11   else
  12     [[likely]] b = 77;

Here we have two possible paths, and the attributes tell the compiler that the
first is more likely than the second, and the second is more likely than the
first. Obviously that's suspicious.

But code in comment 0 is more like:

  if (a)
    ;
  else if (b) [[unlikely]]
    ;
  else [[unlikely]]
    ;

In this case, not all paths through the function are marked unlikely. A
compiler treats the code above as:

  if (a)
    ;
  else {
    if (b) [[unlikely]]
      ;
    else [[unlikely]]
      ;
  }

And here it's certainly true that both branches of the second `if` are marked.
But many users do not think of it like this, they consider a series of if-else
branches to all be alternatives to each other. GCC seems to be thinking too
locally and not considering the surrounding context. There are paths through
the function that never even reach the second `if` and so there are paths of
execution that the compiler should consider to be more likely than any that
reach the second `if`. So I do think this is a bug.


Maybe the compiler should treat that code like:

  if (a)
    ;
  else {
    [[unlikely]] if (b)
      ;
    else
      ;
  }

i.e. if both branches are [[unlikely]] then "hoist" the attribute to before the
`if`. That doesn't warn, because now the compiler sees that there's another
branch not marked unlikely.

Aside: It might make more sense to mark the crash function as [[gnu::cold]]
instead of marking calls to it as unlikely.

Reply via email to