This is an archive of the discontinued LLVM Phabricator instance.

Don't copy objects with trivial, deleted copy ctors
ClosedPublic

Authored by rnk on May 7 2014, 5:52 PM.

Details

Summary

This affects both the Itanium and Microsoft C++ ABIs.

Our C++ ABI code was checking if the object had a non-trivial copy ctor
or non-trivial dtor. Now we check if there are any trivial, non-deleted
copy or move ctors before passing an argument in registers.

On x86 Windows, we can mostly use the same logic, where we use inalloca
instead of passing by address. However, on Win64, there are register
parameters, and we have to do what MSVC does. MSVC ignores the presence
of non-trivial move constructors and only considers the presence of
non-trivial or deleted copy constructors. If a non-trivial or deleted
copy ctor is present, it passes the argument indirectly.

This change fixes bugs and makes us more ABI compatible with both GCC
and MSVC.

Fixes PR19668.

Diff Detail

Repository
rL LLVM

Event Timeline

rnk updated this revision to Diff 9197.May 7 2014, 5:52 PM
rnk retitled this revision from to Don't copy objects with trivial, deleted copy ctors.
rnk updated this object.
rnk added reviewers: rsmith, majnemer.
rnk added a subscriber: Unknown Object (MLST).
rsmith edited edge metadata.May 8 2014, 2:12 PM

Richard, you had concerns that this loop over ctors was incorrect, and that
I should really be making some change to CXXRecordDecl::DefinitionData.
Can you imagine some test cases that might be problematic?

Something like:

struct A {

A(const A&) = default;
A(const A&, int = 0);
void *p;

};
struct B : A {};

void foo(B); // B should be passed indirect, because its copy ctor is deleted, but it's also trivial and not-yet-declared so we might not realize this.

If so, do you think it's worth pursuing a more complete fix that
updates the flags, or is it OK to accept this as an incremental fix?

It's an extremely obscure case, so the incremental fix seems reasonable to me.

lib/CodeGen/CGCXXABI.cpp
49–50 ↗(On Diff #9197)

Please add a FIXME saying that we assume that all lazily-declared trivial copy/move constructors are not deleted, and that this assumption might not actually be true in some corner cases.

lib/CodeGen/ItaniumCXXABI.cpp
65–66 ↗(On Diff #9197)

This should probably be part of the 'canCopy' check; the proposed fix for DR1590 also requires a trivial destructor.

lib/CodeGen/MicrosoftCXXABI.cpp
431–435 ↗(On Diff #9197)

As an optimization, you could skip this if !hasTrivialCopyConstructor().

rnk added a comment.May 12 2014, 4:14 PM

OK. I added a two-copy ctor test case, but it's not enough of a corner case. We appear to eagerly declare the implicit special members for it.

PTAL

lib/CodeGen/CGCXXABI.cpp
49–50 ↗(On Diff #9197)

done

lib/CodeGen/ItaniumCXXABI.cpp
65–66 ↗(On Diff #9197)

I wasn't thinking about C++11 braced, copyless initialization when I named this. I intended to share it with win64, but those rules are more complicated. I'll fold this in.

lib/CodeGen/MicrosoftCXXABI.cpp
431–435 ↗(On Diff #9197)

done

rnk updated this revision to Diff 9328.May 12 2014, 4:15 PM
rnk edited edge metadata.
  • Review stuff and add a test case for multiple copy ctors
rnk updated this revision to Diff 9330.May 12 2014, 5:24 PM
  • Fix zero ctor case
rnk updated this revision to Diff 9363.May 13 2014, 1:33 PM
  • Simplify by exiting early
rnk closed this revision.May 19 2014, 7:24 AM
rnk updated this revision to Diff 9559.

Closed by commit rL208786 (authored by @rnk).