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.

Reply via email to