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

            Bug ID: 114309
           Summary: Undesirable warning with [[unlikely]]
           Product: gcc
           Version: 13.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: terra at gnome dot org
  Target Milestone: ---

g++ warns over the following program which uses [[unlikely]] for aborting error
reporting and conditionally chooses between two error messages:

# /usr/local/products/gcc/13.1.0/bin/g++ -O2 -c ttt-if-dual-unlikely.C
ttt-if-dual-unlikely.C: In function ‘void if_dual_warning(int)’:
ttt-if-dual-unlikely.C:3:19: warning: both branches of ‘if’ statement marked as
‘unlikely’ [-Wattributes]
    3 | #define barf(msg) [[unlikely]] crash(msg)
      |                   ^~~~~~~~~~~~
ttt-if-dual-unlikely.C:22:5: note: in expansion of macro ‘barf’
   22 |     barf("foo");
      |     ^~~~

g++ is correct that both branches have [[unlikely]].  What is not correct is to
warn over it.  g++ should instead simply infer that the second "if" is itself
unlikely to be reached.

The standard, quoted from
https://en.cppreference.com/w/cpp/language/attributes/likely, clearly
contemplates this case:

"Applies to a statement to allow the compiler to optimize for the case where
paths of execution including that statement are less likely than any
alternative path of execution that does not include such a statement."

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.

Issuing this warning is a made a bit worse by the lack of a simple, local way
to suppress the warning in the same way that "if ((var = val)) { ... }" is a
way to suppress the warning about assignment in condition.


# cat ttt-if-dual-unlikely.C
#include <iostream>

#define barf(msg) [[unlikely]] crash(msg)

void
crash (const char*msg)
{
  std::cerr << msg << std::endl;
  abort ();
}


void
if_dual_warning (int i)
{
  bool runtime_cond0 = i > 0;
  bool runtime_cond1 = i > 1;

  if (runtime_cond0) {
    std::cerr << "Something\n";
  } else if (runtime_cond1) {
    barf("foo");
  } else {
    barf("bar");
  }
}

Reply via email to