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

Richard Smith richardsmith at google.com
Thu May 12 19:07:44 UTC 2016


On 12 May 2016 at 11:45, John McCall <rjmccall at apple.com> wrote:

> On May 6, 2016, at 2:29 PM, Richard Smith <richardsmith at google.com> wrote:
> Per 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.

(A) has to deal with both constructor variants, though.
>

Good point. Maybe CI1<type> / CI2<type>?


> 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).

John.
>
>
>
>
>
> Approach A: synthesize a fake constructor of the derived class
>
> Strawman: add a new form of mangled name for a fake constructor that
> forwards to a base class constructor, whose <encoding> is that of the base
> class constructor, except that the <nested name> is that of the derived
> class and the <unqualified-name> is
>
>  <ctor-dtor-name> ::= CI <base class type>
>
>  This would give code largely similar to what we generate with the C++11
> inheriting constructor rules, except that the additional copy constructions
> and destructions for parameters would be removed. The downsides are that
> this only works if we can forward all the arguments (and in particular, we
> can't do this for varargs constructors), and generates one additional copy
> of the derived class default initialization code for each base class
> constructor.
>
>
>
> Approach B: factor out the duplicated portion of the construction
>
> Strawman: add three new forms of mangled name for these constructor
> fragments:
>
>   <ctor-dtor-name> ::= CP [<seq-id>] _  # default constructor prefix
>   <ctor-dtor-name> ::= CS [<seq-id>] _  # default constructor suffix
>   <ctor-dtor-name> ::= DP [<seq-id>] _  # default constructor cleanup
> prefix
>
> where in the first and third case the <seq-id> represents the position of
> the last virtual or direct base class that is constructed or destroyed by
> the function, and in the second case it represents the position of the last
> virtual or direct base class that is not constructed by the function (where
> in each case the base classes are enumerated in the order in which they
> would be constructed).
>
> The CS symbols would destroy the entire class object if an exception is
> thrown. (I think it'd be fine except in pathological cases to provide only
> the CS symbols; maybe we could drop the CP/DP ones.)
>
>
> Or perhaps a hybrid of these (it may be reasonable for the constructors
> from approach A to call the fragments from approach B, especially when
> optimizing for code size). In any case, use of these new symbols would be
> optional; implementations could instead choose to emit the code inline.
> Thoughts?
> _______________________________________________
> cxx-abi-dev mailing list
> cxx-abi-dev at codesourcery.com
> http://sourcerytools.com/cgi-bin/mailman/listinfo/cxx-abi-dev
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://sourcerytools.com/pipermail/cxx-abi-dev/attachments/20160512/5d74d8c0/attachment-0001.html>


More information about the cxx-abi-dev mailing list