[cxx-abi-dev] ABI for new inheriting constructor rules

John McCall rjmccall at apple.com
Thu May 12 22:08:25 UTC 2016


> On May 12, 2016, at 2:47 PM, Richard Smith <richardsmith at google.com> wrote:
> On 12 May 2016 at 13:34, John McCall <rjmccall at apple.com <mailto:rjmccall at apple.com>> wrote:
>> On May 12, 2016, at 12:07 PM, Richard Smith <richardsmith at google.com <mailto:richardsmith at google.com>> wrote:
>> On 12 May 2016 at 11:45, John McCall <rjmccall at apple.com <mailto:rjmccall at apple.com>> wrote:
>>> On May 6, 2016, at 2:29 PM, Richard Smith <richardsmith at google.com <mailto:richardsmith at google.com>> wrote:
>>> Per http://wg21.link/p0136r1 <http://wg21.link/p0136r1> an inheriting constructor declaration no longer results in the implicit synthesis of derived class constructors, and instead the behavior of a call to an inherited constructor is that:
>>> 
>>>  1) the portion of a hypothetical defaulted default constructor prior to the base constructor invocation is executed, then
>>>  2) the inherited constructor is invoked, then
>>>  3) the portion of a hypothetical defaulted default constructor after the base constructor invocation is executed
>>> 
>>> There are a couple of obvious ways we could avoid emitting the code for (1) and (3) in every inherited constructor call site:
>> 
>> This only affects interoperation to the extent that it's done with vague linkage, since as far as I know there's no way to give an inherited constructor a strong definition.
>> 
>> Yes.
>> 
>> I think we should recommend using (A) in all cases where it's possible, which as far as I know is everything except variadic constructors, and then just inline all the appropriate initialization for variadics.
>> 
>> OK, sounds fine to me. I don't really think the variadic case will come up enough to worry about it. The other benefit of the prefix/suffix functions is that we can factor out some of the duplication from the CI functions themselves, but that seems very much like a secondary benefit.
> 
> I mean, if we wanted to, we could apply that as a code-size optimization across ordinary constructors when we happen to notice that they have equivalent initializers.
> 
>> (A) has to deal with both constructor variants, though.
>> 
>> Good point. Maybe CI1<type> / CI2<type>?
> 
> That makes sense to me if we do need to distinguish inherited constructors.
> 
>>  
>> Is there a reason we can't just continue to mangle the symbol as a C1 or C2 in the derived class?  Just concern about ODR differences when there happens to be a non-trivially-copyable type passed by value?
>> 
>> For a C2 constructor that inherits a constructor from a virtual base, the signature will be different from the old approach, because parameters will no longer be passed at all (whereas before they were passed and discarded). That's probably fine for most calling conventions, but seems risky in general. [As a further optimization, we could share the same C2 constructor for all inherited constructors that inherit from the same (set of) virtual base(s), but I'm not sure that's worth putting into the ABI.]
>> 
>> I'm also concerned about there being edge cases where overload resolution could pick between constructors from two different base classes despite them mangling the same. Highly-contrived example:
>> 
>> constexpr int f(), g();
>> struct A { template<int = f()> A(int); };
>> struct B { template<int = g()> B(int); };
>> struct C : A, B {
>>   using A::A;
>>   using B::B;
>> };
>> 
>> TU1:
>> constexpr int f() { return 0; }
>> C c(0);
>> constexpr int g() { return 0; }
>> 
>> TU2:
>> constexpr int g() { return 0; }
>> C c(0);
>> constexpr int f() { return 0; }
>> 
>> I think this is valid, with TU1 calling A(int) and TU2 calling B(int).
> 
> That is a really amazing example.  I feel enriched. :)
> 
> C++ truly is a remarkable language.
>  
> I'm surprised that the language model here has changed so much, though.  The inherited constructors really aren't treated as declarations in the derived class?  I would expect it to be a much better language model to treat them as declarations that just have non-standard semantics when invoked.
> 
> The new semantic model fixes a whole laundry list of issues caused by building separate declarations for them -- we want to access-check the constructor as if it were in the base class, we want to handle default arguments as we would for the base class overload set, we want failures in the delegating call in the inheriting constructor count as "immediate context" for the purposes of SFINAE, and so on (see wg21.link/cwg1573, wg21.link/cwg1645, wg21.link/cwg1715, wg21.link/cwg1736, wg21.link/cwg1941, wg21.link/cwg1991). Synthesizing a constructor / constructor template makes it hard to get these cases right, as well as giving the wrong semantics for argument passing.

Alright, I accept that we should mangle these differently, and 'CI' <variant> <type> seems reasonable.

John.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://sourcerytools.com/pipermail/cxx-abi-dev/attachments/20160512/4feecb78/attachment.html>


More information about the cxx-abi-dev mailing list