If I have an incomplete type, and evaluate some concept for it, for example some concept from the standard library:
#include <concepts>
int main() {
struct S;
return std::destructible<S>;
}
What result must be produced here by the program?
On practice I see that EDG returns 1
here. GCC and MSVC both return 0
. And Clang with libc++
fails the compilation:
/opt/compiler-explorer/clang-20.1.0/bin/../include/c++/v1/__type_traits/is_nothrow_destructible.h:28:31: error: incomplete type 'S' used in type trait expression
28 | : integral_constant<bool, __is_nothrow_destructible(_Tp)> {};
| ^
Online demo: https://gcc.godbolt.org/z/9as4jKM1q
Which implementation is correct?
TL;DR: it's undefined behavior.
The definition of std::destructible
is ([concept.destructible]):
template<class T>
concept destructible = is_nothrow_destructible_v<T>;
The definition of is_nothrow_destructible_v
is ([meta.type.synop]):
template<class T>
constexpr bool is_nothrow_destructible_v = is_nothrow_destructible<T>::value;
And is_nothrow_destructible
requires that ([meta.unary.prop]):
T
shall be a complete type, cvvoid
, or an array of unknown bound.
So in order to determine the value of std::destructible<S>
, we need to evaluate is_nothrow_destructible_v<S>
, which is defined in terms of is_nothrow_destructible<S>::value
, which requires S
to be a complete type. Since S
is an incomplete type, the precondition is violated, and thus the behavior is undefined.