Home > database >  GCC __builtin_expect checking pointer nullability of temporary during constexpr context results in s
GCC __builtin_expect checking pointer nullability of temporary during constexpr context results in s

Time:12-14

I'm using __builtin_expect to perform a null pointer check in a constexpr function like so:

constexpr int Add(const int * x, const int * y)
{
    assert(__builtin_expect(!!(x && y), 1));
    return *x   *y;
}

I also have a wrapper method for const refs to allow for passing temporaries:

constexpr int Add(const int & x, const int & y)
{
    return Add(&x, &y);
}

I then create a global constant using temporaries:

static constexpr int result = Add(1, 2);

Printing this value results in 0:


int main() {
    std::cout << result; // 0
}

What exactly is going on here?

Removal of __builtin_expect fails to compile with GCC complaining about pointer comparisons to temporaries inside constexpr context maybe related.

Godbolt

CodePudding user response:

This is a compiler bug, specifically https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85944.

The issue is not related to __builtin_expect. It is about the null pointer check itself in the constant expression context. It should be fine. During the evaluation as constant expression it is known to the compiler that the pointers are referring to temporary objects whose lifetime spans that of the constant expression evaluation and therefore not null. All conditions for Add(1, 2) to be a core constant expression are satisfied.

But GCC does not seem to handle this information correctly for temporaries at namespace scope. If result is made a block scope variable (either with or without static), then everything works as expected.

For a simple workaround, you can of course use by-value parameters in the second overload instead or alternatively you can store the arguments in constexpr variables first and then pass on to Add. Wrapping the initializer in a lambda to introduce a block scope will probably also be work fine:

static constexpr int result = []{ return Add(1, 2); }();
  • Related