struct incomplete_type;
#if 0
struct incomplete_type {
static void foo() {}
};
#endif
template<typename T>
struct problem_type
{
constexpr problem_type(int) noexcept {};
constexpr problem_type(double) noexcept : problem_type(5) {}
~problem_type() {
T::foo();
}
};
void bar(problem_type<incomplete_type> arg=5.0) noexcept;
When bar has a default parameter which calls a forwarding constructor which is also constexpr, the compiler also attempts to instantiate the destructor, which fails, because T::foo cannot be called because T is an incomplete type.
The problem does not occur if the default parameter does not invoke a forwarding constructor (e.g. if we change 5.0 to 5), if the forwarding constructor is not constexpr, or (of course) if the type T is complete at this point.
The problem does also occur if the destructor is constexpr, even if the constructor is not forwarding.
noexcept appears to be irrelevant, but I have left it in to ensure the compiler is not attempting to generate stack unwinding code.
This only occurs on clang (12.0.1), not on gcc (11.2) or Visual Studio (19.29). See godbolt
Note that the function bar is not defined or called.
Why does this not compile in clang?