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

John McCall rjmccall at apple.com
Mon Nov 26 20:23:34 UTC 2012


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.

Note that AFAICT this problem is not new to C++11;  the following C++98 program never formally invokes A's (trivial) copy constructor, and yet every implementation that I know of will actually return the object in registers — in effect, adding a trivial copy:
  struct A {
    A *self;
    A() : self(this) {}
    template <class T> A(T &t) : self(this) {}
  };
  A foo() {
    A temp;
    return temp;
  }

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


More information about the cxx-abi-dev mailing list