Is the initializer of a constexpr variable at class scope allowed to reference the variable?

Viewed 357

The following code:

struct S {
    static constexpr int rolling_sum[4]{
        0,
        rolling_sum[0] + 1,
        rolling_sum[1] + 2,
        rolling_sum[2] + 3
    };
};

is accepted by clang (tested with version 12), but rejected by gcc (tested with version 11) with the following errors:

test.cpp:4:9: error: ‘rolling_sum’ was not declared in this scope
    4 |         rolling_sum[0] + 1,
      |         ^~~~~~~~~~~
test.cpp:5:9: error: ‘rolling_sum’ was not declared in this scope
    5 |         rolling_sum[1] + 2,
      |         ^~~~~~~~~~~
test.cpp:6:9: error: ‘rolling_sum’ was not declared in this scope
    6 |         rolling_sum[2] + 3
      |         ^~~~~~~~~~~

Is this code valid C++?

My guess is that it should be valid because [basic.scope.pdecl] p1 states that the point of declaration of a variable is just before its initializer, meaning the variable should be in scope in its initializer; but I'm not sure if I'm overlooking something else that could be relevant here.

3 Answers

You aren't missing anything. This is GCC bug 99059, reported in GCC 11.

Your case applies too, since just like static inline, a constexpr variable must be initialized at the point of declaration. The same lookup related bug would affect C++14 code as well.

As your cited [basic.scope.pdecl]/1 allows (as none of /3 and forward rejects it), your program is well-formed.

We may study a similar example for which GCC confusingly rejects parts of:

struct S {
    static constexpr int x{42};
    static constexpr int y[2]{
        S::x,        // #1 GCC: OK
        S::y[0] + 1  // #2 GCC: error: incomplete type 'S' used in nested name specifier
    };
};

with an error message at #2 that should arguably (were it not a rejects-invalid) be applied to #1.

The code is accepted by clang. It's also accepted by gcc if the array is declared at namespace scope, leading me to believe that :

rejecting it at class scope is likely a bug

ICC and MSVC reject it similar to GCC even.

I believe it's valid because the point of declaration of a variable is just before its initialize, and thus the variable should be in scope in its initializer. Point of declaration

But I'm not a wording expert and it's possible I'm mistaken, or overlooking something else that would make this invalid.

Bug 99059 is similar.

Related