Home > Back-end >  Incomplete type works with gcc but not with clang and msvc
Incomplete type works with gcc but not with clang and msvc

Time:12-02

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?

CodePudding user response:

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:

GCC accepts invalid program involving constexpr static data member of class template

CodePudding user response:

According to [basic.def] 5. this is ill formed:

In the definition of an object, the type of that object shall not be an incomplete type ([basic.types.general]), an abstract class type ([class.abstract]), or a (possibly multi-dimensional) array thereof.

This does not seem to make any allowances for non-odr-used members of class templates.

  • Related