https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127614
Bug ID: 127614
Summary: definition of static constexpr member with placeholder
type and requires-expression initializer defers
definition instantiation despite the definition being
required to exist
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: irvsrc at gmail dot com
Target Milestone: ---
As shown below, the definition of `b1` and `b2` (static constexpr member with
placeholder type and requires-expression initializer) defers the instantiation
of its definition despite the definition being required to exist.
```
template<typename t>
struct base {
bool constexpr static b1 = requires { t::d; }; // declaration instantiated,
definition not instantiated, ok
auto constexpr static b2 = requires { t::d; }; // declaration instantiated,
definition not instantiated, error, definition should be instantiated
decltype(auto) constexpr static b3 = requires { t::d; }; // error also
occurs with placeholder type decltype(auto), not just auto
// int constexpr static base_var4 = t::d; // well-formed, ok
// auto constexpr static base_var5 = t::d; // ill-formed, ok
// decltype(auto) constexpr static base_var6 = t::d; // ill-formed, ok
};
struct deri : base<deri> {
auto constexpr static d = 0;
};
auto main() -> int {
static_assert(deri::b1); // ok
static_assert(!deri::b2); // error
static_assert(!deri::b3); // error
}
```
- `bool constexpr static b1 = requires { t::d; };`
[temp.inst] (3) (3.1) (4) requires instantiation of the static data member's
declaration, but not its definition unless used in a way that requires it to
exist.
Since its type is already known, the initializer should be deferred until
needed, by at which point `deri` is complete, and the requires-expression
should evaluate to true.
This does happen, so this is correct.
- `auto constexpr static b2 = requires { t::d; };`
[dcl.spec.auto] (5) requires the declaration's type to be deduced from its
initializer.
Therefore, this requires deduction from the requires-expression (the definition
to exist) during instantiation of `base<deri>`, while `deri` is incomplete,
where [class.member.lookup] (3) (4) requires member lookup to fail, and
therefore [expr.prim.req] (5) requires the requires-expression to evaluate to
false.
This does not happen, so this is incorrect.
Notes:
As shown in the example, this incorrect behavior:
- Occurs with both placeholder types `auto` and `decltype(auto)`
- Occurs only when the expression is a requires-expression (from my tests)
- Occurs across all GCC and C++ versions supporting requires-expression
Compile with at least C++20 or later.