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?
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.