user20562802
user20562802

Reputation:

Incomplete type works with gcc but not with clang and msvc

I have recently learnt about incomplete types and that under certain conditions they can be used as template arguments. In particular, like void, struct incomplete; are both incomplete types. Then I wrote the following program that works with gcc but not with msvc and clang. Live demo

struct incomplete;
template<typename T> struct C
{
    static constexpr T t{};
};

template<class T>
struct myClass {
    C<T> new_t() { return {}; }
};

int main() {
    myClass<incomplete> d;
    d.new_t();    
}

As we can see the above program compiles with gcc but not with msvc and clang. So I want to know which is the correct technical behavior.

Clang says:

<source>:4:24: error: constexpr variable cannot have non-literal type 'const incomplete'
    static constexpr T t{};

while msvc says:

<source>(4): error C2027: use of undefined type 'incomplete'
<source>(1): note: see declaration of 'incomplete'

while GCC accepts the code with both c++17 as well as c++20.

Which compiler is correct here?

Upvotes: 2

Views: 576

Answers (1)

Alan
Alan

Reputation: 1

The program is ill-formed and gcc is wrong in accepting the code because even though the definition of the static data member is not instantiated(because it is not odr-used), it's declaration will still be instantiated due to the implicit instantiation of C<incomplete> as per temp.inst#3. More importantly, if a declaration uses constexpr or inline (since C++17) specifier, the member must be declared to have complete type.

From temp.inst#3:

The implicit instantiation of a class template specialization causes:

  • the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and

(emphasis mine)

This means that the implicit instantiation C<incomplete> will cause the implicit instantiation of the declaration of the static data member.

Further from static data member documentation:

However, if the declaration uses constexpr or inline (since C++17) specifier, the member must be declared to have complete type.

(emphasis mine)

This means that since the implicitly instantiated declaration, declares a member of an incomplete type, the program is ill-formed.


Here is the gcc bug report:

static constexpr incomplete (depedent) data member of a class template and in-member initialized incorrectly accepted

Upvotes: 2

Related Questions