Search code examples
c++clanglanguage-lawyerconstexpr

Is it valid to use a reference to a local variable to initialize a constexpr variable?


The following code only compiles on GCC (checked it on 10.4 and 13.2 on godbolt.org) but not on Clang (fails on all versions I tried, for example 17.0.1 on godbolt.org):

struct A {
  static constexpr int b{1};
};

int main(int argc, char *argv[]) { 
    A a;
    A& aref{a};
    constexpr auto bb1{a.b};
    constexpr auto bb2{aref.b};
    return bb1+bb2; 
}

Clang outputs:

<source>:9:20: error: constexpr variable 'bb2' must be initialized by a constant expression
    9 |     constexpr auto bb2{aref.b};
      |                    ^  ~~~~~~~~
<source>:9:24: note: initializer of 'aref' is not a constant expression
    9 |     constexpr auto bb2{aref.b};
      |                        ^
<source>:7:14: note: declared here
    7 |     A& aref{a};
      |   

https://godbolt.org/z/nG4j3KefE

Why?


Solution

  • bb1 was always permitted.

    bb2 is allowed since P2280 which was accepted for C++23 as defect report for earlier revisions as well.

    Originally there was a specific rule that in a constant expression forbade any use of a reference variable (but only reference variables!) that wasn't usable in constant expressions (i.e. constexpr initialized with constant expresison) or had its lifetime started during the constant expression evaluation. This held even if no lvalue-to-rvalue conversion was applied and nothing else depended on the specific referenced objects. This was inconsistent with usage of non-reference variables and the defect report fixes that. Your example demonstrates the inconsistency.

    GCC technically didn't behave conforming before the defect report and Clang isn't behaving conforming since it, but probably simply hasn't implemented it yet.