C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Relocation in C++

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Sun, 22 May 2022 22:12:52 -0600
On Sun, 22 May 2022 at 17:46, Thiago Macieira via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> On Sunday, 22 May 2022 16:32:30 PDT Edward Catmur via Std-Proposals wrote:
> > Next, it opts *out* of the ABI
> > change, by annotating the relocation operation with an attribute. This
> > opt-out means that the class is passed into functions as if it did not
> > declare the relocation operation, so this is compatible with previously
> > compiled code and with code compiled to an earlier standard version with
> > the relocation operation #if defined out.
>
> I repeat that every function must be annotated for their choice too, not
> the
> type. Types are used in libraries other than that which defined them. And
> that
> should be opt-in.
>

Uh, why? If you use another library's types in your API, then you're making
your library dependent on their ABI. After all, they can at any time add or
remove data members, alignment, virtual bases etc.

> Both opt-in and opt-out propagate to derived and composing classes as
> > necessary to maintain the Rule of Zero. ABI break (opt-in without
> opt-out)
> > also propagates (a class that breaks ABI for itself is assumed
> responsible
> > for breaking the ABI of derived and composing classes) but can be
> canceled
> > by the derived/composing class itself opting out.
>
> The problem is that we have actually a three-way question here for Rule of
> Zero.
>
> You can break the Rule of Zero to add your own (non-trivial) destructor and
> then opt-in to relocation.
>
> You can keep the Rule of Zero and if your type is already trivial, it gets
> trivial relocation. That requires no ABI break because it doesn't matter
> how
> many times you do no-op, it's still no-op.
>
> The problem is when you keep the Rule of Zero on a type that is not trivial
> because one of its bases or member sub-objects isn't trivially
> destructible.
> That means the choice of this other type of adding a relocation operator
> affects the current type, as per the discussion on synthesising relocation
> operators. Unless I misunderstood it, of course.
>

Making ABI-affecting changes to a base or member subobject affects ABI of
the derived or composing object, yes. This is part of the C++ experience.

> If the mechanism is opt-out per type, then libc++ will opt out
> > std::unique_ptr in the standard Library headers
>
> Why would they opt-out?
>

To preserve (function argument passing) ABI.


> > But a further criterion is rule-of-zero: classes that do not define
> special
> > member functions (destroy, move, copy) should not need to do anything to
> > gain the benefit of relocation. So those classes should not need to
> either
> > opt in or opt out, but this should happen automatically.
>
> See other email: does this include non-trivial rule-of-zero types?
>

Absolutely, yes.

This does mean that a non-trivial rule-of-zero class that is relocatable by
memberwise move-and-destroy on its (non-trivial) members will need to be
passed by move-and-destroy en bloc. That is, since it did not explicitly
opt into relocation, it is implicitly opted out of ABI break (under the
scheme I'm suggesting).

Then if the class type of a data member adds its own relocation operation,
thereby opting into relocation, without opting out of the concomitant ABI
break, that class is considered to have broken ABI for itself and for the
rule-of-zero type, so the latter is then passed by relocation and optional
callee-destroy, in an ABI break.

This is a relatively aggressive approach; a more conservative approach
would be to only break ABI in the rule-of-zero case only when either
necessary (if a member is immovable, relocatable, and not opted-out of ABI
break) or when it carries a clear performance benefit (if the rule-of-zero
type is trivially relocatable by virtue of its members, and small enough to
be passed in registers), and to use the caller-destroy ABI in all other
cases. This would be entirely by choice of the Itanium C++ ABI group; the
language would make it clear that the implementation is permitted to use
caller-destroy ABI for everything other than immovable relocatable types.

A type that is immovable, relocatable and opted out of ABI break becomes
nonrelocatable as a function parameter; this is fine since it means that
adding the (nonstandard) no-abi-break attribute has the effect of taking a
well-formed program and making it ill-formed, which is an acceptable
behavior for an attribute by Timur's ignorability rule.

Received on 2022-05-23 04:13:04