Home > Blockchain >  Clang rejects inheritance program that gcc and msvc accepts
Clang rejects inheritance program that gcc and msvc accepts

Time:11-27

I learnt about Inheritance in C . Then to check that I've understood the concept correctly, I have written the below given program that is rejected by clang but accepted by gcc and msvc. Live Demo

#include <array>
#include <iostream>
class Base
{
private: 
    int data;
public:
    Base(int pdata):data(pdata) {}
    Base(const Base&){std::cout <<" Copy base";}

};

class Derived : public Base
{ 
    
};
 
int main()
{
    Derived d(1); //rejected by clang but accepted by gcc and msvc
} 

I am using C 20 and want to know which compiler is correct here in C 20. I've also noticed that with C 17 all compilers reject this but from c 20 onwards, gcc and msvc start compiling the program. So it seems there was some change in the c 20 standard. But I don't know what that change is(assuming there is any such change) and whether or not the program is well formed in c 20.

The clang c 20 error says:

<source>:19:12: error: no matching conversion for functional-style cast from 'int' to 'Derived'
    Base d(Derived(1));

CodePudding user response:

This is a C 20 feature called parenthesized initialization of aggregates that clang has not yet implemented. That is, the program is well-formed from C 20 onwards. This can be seen from compiler support documentation:

C 20 feature Paper(s) GCC Clang MSVC
Parenthesized initialization of aggregates P0960R 10 19.28 (16.8)*

As we can see in the above table, the entry for clang is empty/blank meaning that this feature has not been implemented in clang as of now.


Now let's look at how exactly this program is well-formed in c 20.

From direct initialization:

T object ( arg );          (1) 

The effects of direct initialization are:

  • If T is a class type,
    • otherwise (from C 20), if the destination type is a (possibly cv-qualified) aggregate class, it is initialized as described in aggregate initialization except that narrowing conversions are permitted, designated initializers are not allowed, a temporary bound to a reference does not have its lifetime extended, there is no brace elision, and any elements without an initializer are value-initialized.

(emphasis mine)

This means that since Derived is an aggregate class, aggregate initialization will be performed for Derived d(1); from C 20.

Note also that Derived is an aggregate from C 17 onwards but Derived d(1); is aggregate initialization only from C 20 onwards due to P0960R.

Now from aggregate initialization:

The effects of aggregate initialization are: 2) Determine the explicitly initialized elements of the aggregate as follows:

  • Otherwise, if the initializer list is non-empty, the explicitly initialized elements of the aggregate are the first n elements of the aggregate, where n is the number of elements in the initializer list. 3) Initialize each element of the aggregate in the element order. That is, all value computations and side effects associated with a given element are sequenced before those of any element that follows it in order (since C 11).

(emphasis mine)

This means that the base class subobject of the derived object is the explicitly initialized element of the aggregate and it will be copy initialized as per Initializing elements:

For each explicitly initialized element:

  • Otherwise, the element is copy-initialized from the corresponding initializer clause of the initializer list:
    • If the initializer clause is an expression, implicit conversions are allowed as per copy-initialization, except that narrowing conversions are prohibited (since C 11).

(emphasis mine)

This means that the base subobject will be initialized as per the rules of copy initialization with the expression 1 as the initializer. Thus the program is well-formed from C 20 onwards and gcc and msvc are correct in accepting the program. OTOH, clang has not yet implemented this feature.

CodePudding user response:

The code is valid C 20, but not all C 20 features are supported by all compilers. You've run into a feature (parenthesized initialization) which Clang does not yet have.

This kind of thing happens with each new C standard. The support can seem nearly complete the year a standard is released, but with a few missing bits which can take several years to appear (if ever).

  • Related