[cxx-abi-dev] Transfer modes for parameters and return values

Richard Smith richardsmith at google.com
Mon Nov 26 21:09:26 UTC 2012


On Mon, Nov 26, 2012 at 12:23 PM, John McCall <rjmccall at apple.com> wrote:

> On Nov 25, 2012, at 9:03 PM, Richard Smith <richardsmith at google.com>
> wrote:
>
> On Fri, Nov 23, 2012 at 12:37 PM, Jason Merrill <jason at redhat.com> wrote:
>
>> On 06/03/2009 04:59 PM, David Vandevoorde wrote:
>>
>>> In 3.1.1 and 3.1.4, the ABI specifies that "by value" class type
>>> parameters and class type return values are passed via the address of a
>>> reference if the class type has
>>>      (a) a nontrivial destructor, or
>>>      (b) a nontrivial copy constructor.
>>>
>>> Should we now also add to that:
>>>      (c) a (nontrivial) move constructor
>>> ?
>>>
>>
>> This change doesn't seem to have been applied to the ABI, though G++
>> implements it.  What are other compilers doing?
>
>
> I happened to be looking into this very recently... Clang implements the
> ABI as currently specified (along with the corresponding miscompiles).
> However, the proposed approach doesn't appear to remove all the
> miscompiles, for at least two reasons:
>
> 1) A parameter can be passed or a return value constructed by calling a
> constructor which is not a copy or move constructor. This can happen when a
> templated constructor is selected:
>
>  struct A {
>   A(const A&) = default; // suppress implicit move constructor, still
> trivial
>   template<typename T> A(T &&); // chosen for copies from non-const
> objects and for moves, not a copy constructor nor a move constructor
>  };
>
> 2) A parameter can be passed or a return value constructed by
> copy-list-initialization with no copy or move occurring:
>
> struct B {
>   B(int);
>   B(const B&) = delete; // deleted, but still trivial
>   B(B&&) = delete; // likewise
>   B *p = this;
> };
> B f(B x) {
>   return { 1 };
> }
> void g() {
>   f({2});
> }
>
> Both of these cases can lead to miscompiles with both g++ 4.7 and Clang
> trunk due to the ABI's rules. Both problems can also arise for classes with
> no user-declared special members.
>
> The second issue in particular seems unsolvable without a major ABI break
> or a core language change (we cannot pass types in registers if they have
> any non-trivial constructors).
>
>
> I think a relatively modest core language change would simply be to say
> that passing or returning a trivially copyable type is allowed to introduce
> extra copies.  That would make your examples have unspecified behavior.
>

The rule would need more finessing (as proposed, it would be disastrous for
'struct B', and would still require an ABI break for classes which have
trivial copy construction but non-trivial copy assignment), but I think
something along these lines could be workable.

Suggestion for core language:

When an object of class type C is passed to or returned from a function, if
C has a trivial, accessible copy or move constructor that is not deleted,
and has no non-trivial copy constructors, move constructors, nor
destructors, implementations are permitted to perform an additional copy or
move of the object using the trivial constructor (even if it would not be
selected by overload resolution to perform a copy or move of the object).
[Note: This latitude is granted to allow objects of class type to be passed
to or returned from functions in registers -- end note]

Suggestion for Itanium ABI:

[parameters and return values are passed by address if] the type has a
non-trivial copy constructor, move constructor or destructor, or if neither
the copy constructor nor the move constructor is public and non-deleted.

If that seems reasonable, I'll take this over to the core reflector for
more discussion.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://sourcerytools.com/pipermail/cxx-abi-dev/attachments/20121126/918e54b0/attachment-0001.html>


More information about the cxx-abi-dev mailing list