r310983 - PR19668, PR23034: Fix handling of move constructors and deleted copy
Hans Wennborg via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 21 16:41:25 PDT 2017
Clean merge in r311410. Thanks.
On Mon, Aug 21, 2017 at 4:21 PM, Richard Smith <richardsmith at google.com> wrote:
> Yes, I'd very much like to get this into the upcoming release.
>
> On 21 August 2017 at 16:16, Hans Wennborg <hans at chromium.org> wrote:
>>
>> PR19668 was marked as a release blocker. Is this suitable for merging?
>>
>> On Tue, Aug 15, 2017 at 6:49 PM, Richard Smith via cfe-commits
>> <cfe-commits at lists.llvm.org> wrote:
>> > Author: rsmith
>> > Date: Tue Aug 15 18:49:53 2017
>> > New Revision: 310983
>> >
>> > URL: http://llvm.org/viewvc/llvm-project?rev=310983&view=rev
>> > Log:
>> > PR19668, PR23034: Fix handling of move constructors and deleted copy
>> > constructors when deciding whether classes should be passed indirectly.
>> >
>> > This fixes ABI differences between Clang and GCC:
>> >
>> > * Previously, Clang ignored the move constructor when making this
>> > determination. It now takes the move constructor into account, per
>> > https://github.com/itanium-cxx-abi/cxx-abi/pull/17 (this change may
>> > seem recent, but the ABI change was agreed on the Itanium C++ ABI
>> > list a long time ago).
>> >
>> > * Previously, Clang's behavior when the copy constructor was deleted
>> > was unstable -- depending on whether the lazy declaration of the
>> > copy constructor had been triggered, you might get different
>> > behavior.
>> > We now eagerly declare the copy constructor whenever its deletedness
>> > is unclear, and ignore deleted copy/move constructors when looking
>> > for
>> > a trivial such constructor.
>> >
>> > This also fixes an ABI difference between Clang and MSVC:
>> >
>> > * If the copy constructor would be implicitly deleted (but has not been
>> > lazily declared yet), for instance because the class has an rvalue
>> > reference member, we would pass it directly. We now pass such a class
>> > indirectly, matching MSVC.
>> >
>> > Based on a patch by Vassil Vassilev, which was based on a patch by Bernd
>> > Schmidt, which was based on a patch by Reid Kleckner!
>> >
>> > This is a re-commit of r310401, which was reverted in r310464 due to ARM
>> > failures (which should now be fixed).
>> >
>> > Modified:
>> > cfe/trunk/include/clang/AST/DeclCXX.h
>> > cfe/trunk/lib/AST/ASTImporter.cpp
>> > cfe/trunk/lib/AST/DeclCXX.cpp
>> > cfe/trunk/lib/CodeGen/CGCXXABI.cpp
>> > cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
>> > cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
>> > cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>> > cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
>> > cfe/trunk/lib/Serialization/ASTWriter.cpp
>> > cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp
>> > cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
>> >
>> > Modified: cfe/trunk/include/clang/AST/DeclCXX.h
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/include/clang/AST/DeclCXX.h (original)
>> > +++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Aug 15 18:49:53 2017
>> > @@ -374,6 +374,7 @@ class CXXRecordDecl : public RecordDecl
>> > /// \brief These flags are \c true if a defaulted corresponding
>> > special
>> > /// member can't be fully analyzed without performing overload
>> > resolution.
>> > /// @{
>> > + unsigned NeedOverloadResolutionForCopyConstructor : 1;
>> > unsigned NeedOverloadResolutionForMoveConstructor : 1;
>> > unsigned NeedOverloadResolutionForMoveAssignment : 1;
>> > unsigned NeedOverloadResolutionForDestructor : 1;
>> > @@ -382,6 +383,7 @@ class CXXRecordDecl : public RecordDecl
>> > /// \brief These flags are \c true if an implicit defaulted
>> > corresponding
>> > /// special member would be defined as deleted.
>> > /// @{
>> > + unsigned DefaultedCopyConstructorIsDeleted : 1;
>> > unsigned DefaultedMoveConstructorIsDeleted : 1;
>> > unsigned DefaultedMoveAssignmentIsDeleted : 1;
>> > unsigned DefaultedDestructorIsDeleted : 1;
>> > @@ -414,6 +416,12 @@ class CXXRecordDecl : public RecordDecl
>> > /// constructor.
>> > unsigned HasDefaultedDefaultConstructor : 1;
>> >
>> > + /// \brief True if this class can be passed in a
>> > non-address-preserving
>> > + /// fashion (such as in registers) according to the C++ language
>> > rules.
>> > + /// This does not imply anything about how the ABI in use will
>> > actually
>> > + /// pass an object of this class.
>> > + unsigned CanPassInRegisters : 1;
>> > +
>> > /// \brief True if a defaulted default constructor for this class
>> > would
>> > /// be constexpr.
>> > unsigned DefaultedDefaultConstructorIsConstexpr : 1;
>> > @@ -810,18 +818,50 @@ public:
>> > return data().FirstFriend.isValid();
>> > }
>> >
>> > + /// \brief \c true if a defaulted copy constructor for this class
>> > would be
>> > + /// deleted.
>> > + bool defaultedCopyConstructorIsDeleted() const {
>> > + assert((!needsOverloadResolutionForCopyConstructor() ||
>> > + (data().DeclaredSpecialMembers & SMF_CopyConstructor)) &&
>> > + "this property has not yet been computed by Sema");
>> > + return data().DefaultedCopyConstructorIsDeleted;
>> > + }
>> > +
>> > + /// \brief \c true if a defaulted move constructor for this class
>> > would be
>> > + /// deleted.
>> > + bool defaultedMoveConstructorIsDeleted() const {
>> > + assert((!needsOverloadResolutionForMoveConstructor() ||
>> > + (data().DeclaredSpecialMembers & SMF_MoveConstructor)) &&
>> > + "this property has not yet been computed by Sema");
>> > + return data().DefaultedMoveConstructorIsDeleted;
>> > + }
>> > +
>> > + /// \brief \c true if a defaulted destructor for this class would be
>> > deleted.
>> > + bool defaultedDestructorIsDeleted() const {
>> > + return !data().DefaultedDestructorIsDeleted;
>> > + }
>> > +
>> > + /// \brief \c true if we know for sure that this class has a single,
>> > + /// accessible, unambiguous copy constructor that is not deleted.
>> > + bool hasSimpleCopyConstructor() const {
>> > + return !hasUserDeclaredCopyConstructor() &&
>> > + !data().DefaultedCopyConstructorIsDeleted;
>> > + }
>> > +
>> > /// \brief \c true if we know for sure that this class has a single,
>> > /// accessible, unambiguous move constructor that is not deleted.
>> > bool hasSimpleMoveConstructor() const {
>> > return !hasUserDeclaredMoveConstructor() && hasMoveConstructor() &&
>> > !data().DefaultedMoveConstructorIsDeleted;
>> > }
>> > +
>> > /// \brief \c true if we know for sure that this class has a single,
>> > /// accessible, unambiguous move assignment operator that is not
>> > deleted.
>> > bool hasSimpleMoveAssignment() const {
>> > return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() &&
>> > !data().DefaultedMoveAssignmentIsDeleted;
>> > }
>> > +
>> > /// \brief \c true if we know for sure that this class has an
>> > accessible
>> > /// destructor that is not deleted.
>> > bool hasSimpleDestructor() const {
>> > @@ -877,7 +917,16 @@ public:
>> > /// \brief Determine whether we need to eagerly declare a defaulted
>> > copy
>> > /// constructor for this class.
>> > bool needsOverloadResolutionForCopyConstructor() const {
>> > - return data().HasMutableFields;
>> > + // C++17 [class.copy.ctor]p6:
>> > + // If the class definition declares a move constructor or move
>> > assignment
>> > + // operator, the implicitly declared copy constructor is defined
>> > as
>> > + // deleted.
>> > + // In MSVC mode, sometimes a declared move assignment does not
>> > delete an
>> > + // implicit copy constructor, so defer this choice to Sema.
>> > + if (data().UserDeclaredSpecialMembers &
>> > + (SMF_MoveConstructor | SMF_MoveAssignment))
>> > + return true;
>> > + return data().NeedOverloadResolutionForCopyConstructor;
>> > }
>> >
>> > /// \brief Determine whether an implicit copy constructor for this
>> > type
>> > @@ -918,7 +967,16 @@ public:
>> > needsImplicitMoveConstructor();
>> > }
>> >
>> > - /// \brief Set that we attempted to declare an implicitly move
>> > + /// \brief Set that we attempted to declare an implicit copy
>> > + /// constructor, but overload resolution failed so we deleted it.
>> > + void setImplicitCopyConstructorIsDeleted() {
>> > + assert((data().DefaultedCopyConstructorIsDeleted ||
>> > + needsOverloadResolutionForCopyConstructor()) &&
>> > + "Copy constructor should not be deleted");
>> > + data().DefaultedCopyConstructorIsDeleted = true;
>> > + }
>> > +
>> > + /// \brief Set that we attempted to declare an implicit move
>> > /// constructor, but overload resolution failed so we deleted it.
>> > void setImplicitMoveConstructorIsDeleted() {
>> > assert((data().DefaultedMoveConstructorIsDeleted ||
>> > @@ -1315,6 +1373,18 @@ public:
>> > return data().HasIrrelevantDestructor;
>> > }
>> >
>> > + /// \brief Determine whether this class has at least one trivial,
>> > non-deleted
>> > + /// copy or move constructor.
>> > + bool canPassInRegisters() const {
>> > + return data().CanPassInRegisters;
>> > + }
>> > +
>> > + /// \brief Set that we can pass this RecordDecl in registers.
>> > + // FIXME: This should be set as part of completeDefinition.
>> > + void setCanPassInRegisters(bool CanPass) {
>> > + data().CanPassInRegisters = CanPass;
>> > + }
>> > +
>> > /// \brief Determine whether this class has a non-literal or/
>> > volatile type
>> > /// non-static data member or base class.
>> > bool hasNonLiteralTypeFieldsOrBases() const {
>> >
>> > Modified: cfe/trunk/lib/AST/ASTImporter.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/AST/ASTImporter.cpp (original)
>> > +++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Aug 15 18:49:53 2017
>> > @@ -956,12 +956,16 @@ bool ASTNodeImporter::ImportDefinition(R
>> > ToData.HasUninitializedFields = FromData.HasUninitializedFields;
>> > ToData.HasInheritedConstructor = FromData.HasInheritedConstructor;
>> > ToData.HasInheritedAssignment = FromData.HasInheritedAssignment;
>> > + ToData.NeedOverloadResolutionForCopyConstructor
>> > + = FromData.NeedOverloadResolutionForCopyConstructor;
>> > ToData.NeedOverloadResolutionForMoveConstructor
>> > = FromData.NeedOverloadResolutionForMoveConstructor;
>> > ToData.NeedOverloadResolutionForMoveAssignment
>> > = FromData.NeedOverloadResolutionForMoveAssignment;
>> > ToData.NeedOverloadResolutionForDestructor
>> > = FromData.NeedOverloadResolutionForDestructor;
>> > + ToData.DefaultedCopyConstructorIsDeleted
>> > + = FromData.DefaultedCopyConstructorIsDeleted;
>> > ToData.DefaultedMoveConstructorIsDeleted
>> > = FromData.DefaultedMoveConstructorIsDeleted;
>> > ToData.DefaultedMoveAssignmentIsDeleted
>> > @@ -973,6 +977,7 @@ bool ASTNodeImporter::ImportDefinition(R
>> > = FromData.HasConstexprNonCopyMoveConstructor;
>> > ToData.HasDefaultedDefaultConstructor
>> > = FromData.HasDefaultedDefaultConstructor;
>> > + ToData.CanPassInRegisters = FromData.CanPassInRegisters;
>> > ToData.DefaultedDefaultConstructorIsConstexpr
>> > = FromData.DefaultedDefaultConstructorIsConstexpr;
>> > ToData.HasConstexprDefaultConstructor
>> >
>> > Modified: cfe/trunk/lib/AST/DeclCXX.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/AST/DeclCXX.cpp (original)
>> > +++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Aug 15 18:49:53 2017
>> > @@ -55,15 +55,18 @@ CXXRecordDecl::DefinitionData::Definitio
>> > HasOnlyCMembers(true), HasInClassInitializer(false),
>> > HasUninitializedReferenceMember(false),
>> > HasUninitializedFields(false),
>> > HasInheritedConstructor(false), HasInheritedAssignment(false),
>> > + NeedOverloadResolutionForCopyConstructor(false),
>> > NeedOverloadResolutionForMoveConstructor(false),
>> > NeedOverloadResolutionForMoveAssignment(false),
>> > NeedOverloadResolutionForDestructor(false),
>> > + DefaultedCopyConstructorIsDeleted(false),
>> > DefaultedMoveConstructorIsDeleted(false),
>> > DefaultedMoveAssignmentIsDeleted(false),
>> > DefaultedDestructorIsDeleted(false),
>> > HasTrivialSpecialMembers(SMF_All),
>> > DeclaredNonTrivialSpecialMembers(0),
>> > HasIrrelevantDestructor(true),
>> > HasConstexprNonCopyMoveConstructor(false),
>> > HasDefaultedDefaultConstructor(false),
>> > + CanPassInRegisters(true),
>> > DefaultedDefaultConstructorIsConstexpr(true),
>> > HasConstexprDefaultConstructor(false),
>> > HasNonLiteralTypeFieldsOrBases(false),
>> > ComputedVisibleConversions(false),
>> > @@ -352,8 +355,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier
>> > setHasVolatileMember(true);
>> >
>> > // Keep track of the presence of mutable fields.
>> > - if (BaseClassDecl->hasMutableFields())
>> > + if (BaseClassDecl->hasMutableFields()) {
>> > data().HasMutableFields = true;
>> > + data().NeedOverloadResolutionForCopyConstructor = true;
>> > + }
>> >
>> > if (BaseClassDecl->hasUninitializedReferenceMember())
>> > data().HasUninitializedReferenceMember = true;
>> > @@ -406,6 +411,8 @@ void CXXRecordDecl::addedClassSubobject(
>> > // -- a direct or virtual base class B that cannot be copied/moved
>> > [...]
>> > // -- a non-static data member of class type M (or array thereof)
>> > // that cannot be copied or moved [...]
>> > + if (!Subobj->hasSimpleCopyConstructor())
>> > + data().NeedOverloadResolutionForCopyConstructor = true;
>> > if (!Subobj->hasSimpleMoveConstructor())
>> > data().NeedOverloadResolutionForMoveConstructor = true;
>> >
>> > @@ -426,6 +433,7 @@ void CXXRecordDecl::addedClassSubobject(
>> > // -- any non-static data member has a type with a destructor
>> > // that is deleted or inaccessible from the defaulted [ctor or
>> > dtor].
>> > if (!Subobj->hasSimpleDestructor()) {
>> > + data().NeedOverloadResolutionForCopyConstructor = true;
>> > data().NeedOverloadResolutionForMoveConstructor = true;
>> > data().NeedOverloadResolutionForDestructor = true;
>> > }
>> > @@ -711,8 +719,10 @@ void CXXRecordDecl::addedMember(Decl *D)
>> > data().IsStandardLayout = false;
>> >
>> > // Keep track of the presence of mutable fields.
>> > - if (Field->isMutable())
>> > + if (Field->isMutable()) {
>> > data().HasMutableFields = true;
>> > + data().NeedOverloadResolutionForCopyConstructor = true;
>> > + }
>> >
>> > // C++11 [class.union]p8, DR1460:
>> > // If X is a union, a non-static data member of X that is not an
>> > anonymous
>> > @@ -756,6 +766,12 @@ void CXXRecordDecl::addedMember(Decl *D)
>> > // A standard-layout class is a class that:
>> > // -- has no non-static data members of type [...] reference,
>> > data().IsStandardLayout = false;
>> > +
>> > + // C++1z [class.copy.ctor]p10:
>> > + // A defaulted copy constructor for a class X is defined as
>> > deleted if X has:
>> > + // -- a non-static data member of rvalue reference type
>> > + if (T->isRValueReferenceType())
>> > + data().DefaultedCopyConstructorIsDeleted = true;
>> > }
>> >
>> > if (!Field->hasInClassInitializer() && !Field->isMutable()) {
>> > @@ -809,6 +825,10 @@ void CXXRecordDecl::addedMember(Decl *D)
>> > // We may need to perform overload resolution to determine
>> > whether a
>> > // field can be moved if it's const or volatile qualified.
>> > if (T.getCVRQualifiers() & (Qualifiers::Const |
>> > Qualifiers::Volatile)) {
>> > + // We need to care about 'const' for the copy constructor
>> > because an
>> > + // implicit copy constructor might be declared with a
>> > non-const
>> > + // parameter.
>> > + data().NeedOverloadResolutionForCopyConstructor = true;
>> > data().NeedOverloadResolutionForMoveConstructor = true;
>> > data().NeedOverloadResolutionForMoveAssignment = true;
>> > }
>> > @@ -819,6 +839,8 @@ void CXXRecordDecl::addedMember(Decl *D)
>> > // -- X is a union-like class that has a variant member with
>> > a
>> > // non-trivial [corresponding special member]
>> > if (isUnion()) {
>> > + if (FieldRec->hasNonTrivialCopyConstructor())
>> > + data().DefaultedCopyConstructorIsDeleted = true;
>> > if (FieldRec->hasNonTrivialMoveConstructor())
>> > data().DefaultedMoveConstructorIsDeleted = true;
>> > if (FieldRec->hasNonTrivialMoveAssignment())
>> > @@ -830,6 +852,8 @@ void CXXRecordDecl::addedMember(Decl *D)
>> > // For an anonymous union member, our overload resolution will
>> > perform
>> > // overload resolution for its members.
>> > if (Field->isAnonymousStructOrUnion()) {
>> > + data().NeedOverloadResolutionForCopyConstructor |=
>> > +
>> > FieldRec->data().NeedOverloadResolutionForCopyConstructor;
>> > data().NeedOverloadResolutionForMoveConstructor |=
>> >
>> > FieldRec->data().NeedOverloadResolutionForMoveConstructor;
>> > data().NeedOverloadResolutionForMoveAssignment |=
>> > @@ -915,8 +939,10 @@ void CXXRecordDecl::addedMember(Decl *D)
>> > }
>> >
>> > // Keep track of the presence of mutable fields.
>> > - if (FieldRec->hasMutableFields())
>> > + if (FieldRec->hasMutableFields()) {
>> > data().HasMutableFields = true;
>> > + data().NeedOverloadResolutionForCopyConstructor = true;
>> > + }
>> >
>> > // C++11 [class.copy]p13:
>> > // If the implicitly-defined constructor would satisfy the
>> > @@ -1450,7 +1476,7 @@ void CXXRecordDecl::completeDefinition()
>> >
>> > void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap
>> > *FinalOverriders) {
>> > RecordDecl::completeDefinition();
>> > -
>> > +
>> > // If the class may be abstract (but hasn't been marked as such),
>> > check for
>> > // any pure final overriders.
>> > if (mayBeAbstract()) {
>> >
>> > Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)
>> > +++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Tue Aug 15 18:49:53 2017
>> > @@ -30,38 +30,9 @@ void CGCXXABI::ErrorUnsupportedABI(CodeG
>> > }
>> >
>> > bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const {
>> > - // If RD has a non-trivial move or copy constructor, we cannot copy
>> > the
>> > - // argument.
>> > - if (RD->hasNonTrivialCopyConstructor() ||
>> > RD->hasNonTrivialMoveConstructor())
>> > - return false;
>> > -
>> > - // If RD has a non-trivial destructor, we cannot copy the argument.
>> > - if (RD->hasNonTrivialDestructor())
>> > - return false;
>> > -
>> > // We can only copy the argument if there exists at least one
>> > trivial,
>> > // non-deleted copy or move constructor.
>> > - // FIXME: This assumes that all lazily declared copy and move
>> > constructors are
>> > - // not deleted. This assumption might not be true in some corner
>> > cases.
>> > - bool CopyDeleted = false;
>> > - bool MoveDeleted = false;
>> > - for (const CXXConstructorDecl *CD : RD->ctors()) {
>> > - if (CD->isCopyConstructor() || CD->isMoveConstructor()) {
>> > - assert(CD->isTrivial());
>> > - // We had at least one undeleted trivial copy or move ctor.
>> > Return
>> > - // directly.
>> > - if (!CD->isDeleted())
>> > - return true;
>> > - if (CD->isCopyConstructor())
>> > - CopyDeleted = true;
>> > - else
>> > - MoveDeleted = true;
>> > - }
>> > - }
>> > -
>> > - // If all trivial copy and move constructors are deleted, we cannot
>> > copy the
>> > - // argument.
>> > - return !(CopyDeleted && MoveDeleted);
>> > + return RD->canPassInRegisters();
>> > }
>> >
>> > llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {
>> >
>> > Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
>> > +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Aug 15 18:49:53 2017
>> > @@ -63,11 +63,8 @@ public:
>> > bool classifyReturnType(CGFunctionInfo &FI) const override;
>> >
>> > RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override
>> > {
>> > - // Structures with either a non-trivial destructor or a non-trivial
>> > - // copy constructor are always indirect.
>> > - // FIXME: Use canCopyArgument() when it is fixed to handle lazily
>> > declared
>> > - // special members.
>> > - if (RD->hasNonTrivialDestructor() ||
>> > RD->hasNonTrivialCopyConstructor())
>> > + // If C++ prohibits us from making a copy, pass by address.
>> > + if (!canCopyArgument(RD))
>> > return RAA_Indirect;
>> > return RAA_Default;
>> > }
>> > @@ -1014,10 +1011,8 @@ bool ItaniumCXXABI::classifyReturnType(C
>> > if (!RD)
>> > return false;
>> >
>> > - // Return indirectly if we have a non-trivial copy ctor or
>> > non-trivial dtor.
>> > - // FIXME: Use canCopyArgument() when it is fixed to handle lazily
>> > declared
>> > - // special members.
>> > - if (RD->hasNonTrivialDestructor() ||
>> > RD->hasNonTrivialCopyConstructor()) {
>> > + // If C++ prohibits us from making a copy, return by address.
>> > + if (!canCopyArgument(RD)) {
>> > auto Align =
>> > CGM.getContext().getTypeAlignInChars(FI.getReturnType());
>> > FI.getReturnInfo() = ABIArgInfo::getIndirect(Align,
>> > /*ByVal=*/false);
>> > return true;
>> >
>> > Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
>> > +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Aug 15 18:49:53 2017
>> > @@ -819,46 +819,44 @@ MicrosoftCXXABI::getRecordArgABI(const C
>> > return RAA_Default;
>> >
>> > case llvm::Triple::x86_64:
>> > - // Win64 passes objects with non-trivial copy ctors indirectly.
>> > - if (RD->hasNonTrivialCopyConstructor())
>> > - return RAA_Indirect;
>> > -
>> > - // If an object has a destructor, we'd really like to pass it
>> > indirectly
>> > + // If a class has a destructor, we'd really like to pass it
>> > indirectly
>> > // because it allows us to elide copies. Unfortunately, MSVC makes
>> > that
>> > // impossible for small types, which it will pass in a single
>> > register or
>> > // stack slot. Most objects with dtors are large-ish, so handle
>> > that early.
>> > // We can't call out all large objects as being indirect because
>> > there are
>> > // multiple x64 calling conventions and the C++ ABI code shouldn't
>> > dictate
>> > // how we pass large POD types.
>> > + //
>> > + // Note: This permits small classes with nontrivial destructors to
>> > be
>> > + // passed in registers, which is non-conforming.
>> > if (RD->hasNonTrivialDestructor() &&
>> > getContext().getTypeSize(RD->getTypeForDecl()) > 64)
>> > return RAA_Indirect;
>> >
>> > - // If this is true, the implicit copy constructor that Sema would
>> > have
>> > - // created would not be deleted. FIXME: We should provide a more
>> > direct way
>> > - // for CodeGen to ask whether the constructor was deleted.
>> > - if (!RD->hasUserDeclaredCopyConstructor() &&
>> > - !RD->hasUserDeclaredMoveConstructor() &&
>> > - !RD->needsOverloadResolutionForMoveConstructor() &&
>> > - !RD->hasUserDeclaredMoveAssignment() &&
>> > - !RD->needsOverloadResolutionForMoveAssignment())
>> > - return RAA_Default;
>> > -
>> > - // Otherwise, Sema should have created an implicit copy constructor
>> > if
>> > - // needed.
>> > - assert(!RD->needsImplicitCopyConstructor());
>> > -
>> > - // We have to make sure the trivial copy constructor isn't deleted.
>> > - for (const CXXConstructorDecl *CD : RD->ctors()) {
>> > - if (CD->isCopyConstructor()) {
>> > - assert(CD->isTrivial());
>> > - // We had at least one undeleted trivial copy ctor. Return
>> > directly.
>> > - if (!CD->isDeleted())
>> > - return RAA_Default;
>> > + // If a class has at least one non-deleted, trivial copy
>> > constructor, it
>> > + // is passed according to the C ABI. Otherwise, it is passed
>> > indirectly.
>> > + //
>> > + // Note: This permits classes with non-trivial copy or move ctors
>> > to be
>> > + // passed in registers, so long as they *also* have a trivial copy
>> > ctor,
>> > + // which is non-conforming.
>> > + if (RD->needsImplicitCopyConstructor()) {
>> > + // If the copy ctor has not yet been declared, we can read its
>> > triviality
>> > + // off the AST.
>> > + if (!RD->defaultedCopyConstructorIsDeleted() &&
>> > + RD->hasTrivialCopyConstructor())
>> > + return RAA_Default;
>> > + } else {
>> > + // Otherwise, we need to find the copy constructor(s) and ask.
>> > + for (const CXXConstructorDecl *CD : RD->ctors()) {
>> > + if (CD->isCopyConstructor()) {
>> > + // We had at least one nondeleted trivial copy ctor. Return
>> > directly.
>> > + if (!CD->isDeleted() && CD->isTrivial())
>> > + return RAA_Default;
>> > + }
>> > }
>> > }
>> >
>> > - // The trivial copy constructor was deleted. Return indirectly.
>> > + // We have no trivial, non-deleted copy constructor.
>> > return RAA_Indirect;
>> > }
>> >
>> >
>> > Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
>> > +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Aug 15 18:49:53 2017
>> > @@ -5726,6 +5726,53 @@ static void DefineImplicitSpecialMember(
>> > }
>> > }
>> >
>> > +/// Determine whether a type is permitted to be passed or returned in
>> > +/// registers, per C++ [class.temporary]p3.
>> > +static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) {
>> > + if (D->isDependentType() || D->isInvalidDecl())
>> > + return false;
>> > +
>> > + // Per C++ [class.temporary]p3, the relevant condition is:
>> > + // each copy constructor, move constructor, and destructor of X is
>> > + // either trivial or deleted, and X has at least one non-deleted
>> > copy
>> > + // or move constructor
>> > + bool HasNonDeletedCopyOrMove = false;
>> > +
>> > + if (D->needsImplicitCopyConstructor() &&
>> > + !D->defaultedCopyConstructorIsDeleted()) {
>> > + if (!D->hasTrivialCopyConstructor())
>> > + return false;
>> > + HasNonDeletedCopyOrMove = true;
>> > + }
>> > +
>> > + if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor()
>> > &&
>> > + !D->defaultedMoveConstructorIsDeleted()) {
>> > + if (!D->hasTrivialMoveConstructor())
>> > + return false;
>> > + HasNonDeletedCopyOrMove = true;
>> > + }
>> > +
>> > + if (D->needsImplicitDestructor() &&
>> > !D->defaultedDestructorIsDeleted() &&
>> > + !D->hasTrivialDestructor())
>> > + return false;
>> > +
>> > + for (const CXXMethodDecl *MD : D->methods()) {
>> > + if (MD->isDeleted())
>> > + continue;
>> > +
>> > + auto *CD = dyn_cast<CXXConstructorDecl>(MD);
>> > + if (CD && CD->isCopyOrMoveConstructor())
>> > + HasNonDeletedCopyOrMove = true;
>> > + else if (!isa<CXXDestructorDecl>(MD))
>> > + continue;
>> > +
>> > + if (!MD->isTrivial())
>> > + return false;
>> > + }
>> > +
>> > + return HasNonDeletedCopyOrMove;
>> > +}
>> > +
>> > /// \brief Perform semantic checks on a class definition that has been
>> > /// completing, introducing implicitly-declared members, checking for
>> > /// abstract types, etc.
>> > @@ -5870,6 +5917,8 @@ void Sema::CheckCompletedCXXClass(CXXRec
>> > }
>> >
>> > checkClassLevelDLLAttribute(Record);
>> > +
>> > + Record->setCanPassInRegisters(computeCanPassInRegisters(*this,
>> > Record));
>> > }
>> >
>> > /// Look up the special member function that would be called by a
>> > special
>> > @@ -7496,8 +7545,7 @@ void Sema::ActOnFinishCXXMemberSpecifica
>> > reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
>> > FieldCollector->getCurNumFields()), LBrac, RBrac,
>> > AttrList);
>> >
>> > - CheckCompletedCXXClass(
>> > - dyn_cast_or_null<CXXRecordDecl>(TagDecl));
>> > + CheckCompletedCXXClass(dyn_cast_or_null<CXXRecordDecl>(TagDecl));
>> > }
>> >
>> > /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
>> > @@ -11929,8 +11977,10 @@ CXXConstructorDecl *Sema::DeclareImplici
>> > Scope *S = getScopeForContext(ClassDecl);
>> > CheckImplicitSpecialMemberDeclaration(S, CopyConstructor);
>> >
>> > - if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
>> > + if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) {
>> > + ClassDecl->setImplicitCopyConstructorIsDeleted();
>> > SetDeclDeleted(CopyConstructor, ClassLoc);
>> > + }
>> >
>> > if (S)
>> > PushOnScopeChains(CopyConstructor, S, false);
>> >
>> > Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
>> > +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Tue Aug 15 18:49:53
>> > 2017
>> > @@ -1559,9 +1559,11 @@ void ASTDeclReader::ReadCXXDefinitionDat
>> > Data.HasUninitializedFields = Record.readInt();
>> > Data.HasInheritedConstructor = Record.readInt();
>> > Data.HasInheritedAssignment = Record.readInt();
>> > + Data.NeedOverloadResolutionForCopyConstructor = Record.readInt();
>> > Data.NeedOverloadResolutionForMoveConstructor = Record.readInt();
>> > Data.NeedOverloadResolutionForMoveAssignment = Record.readInt();
>> > Data.NeedOverloadResolutionForDestructor = Record.readInt();
>> > + Data.DefaultedCopyConstructorIsDeleted = Record.readInt();
>> > Data.DefaultedMoveConstructorIsDeleted = Record.readInt();
>> > Data.DefaultedMoveAssignmentIsDeleted = Record.readInt();
>> > Data.DefaultedDestructorIsDeleted = Record.readInt();
>> > @@ -1570,6 +1572,7 @@ void ASTDeclReader::ReadCXXDefinitionDat
>> > Data.HasIrrelevantDestructor = Record.readInt();
>> > Data.HasConstexprNonCopyMoveConstructor = Record.readInt();
>> > Data.HasDefaultedDefaultConstructor = Record.readInt();
>> > + Data.CanPassInRegisters = Record.readInt();
>> > Data.DefaultedDefaultConstructorIsConstexpr = Record.readInt();
>> > Data.HasConstexprDefaultConstructor = Record.readInt();
>> > Data.HasNonLiteralTypeFieldsOrBases = Record.readInt();
>> > @@ -1697,9 +1700,11 @@ void ASTDeclReader::MergeDefinitionData(
>> > MATCH_FIELD(HasUninitializedFields)
>> > MATCH_FIELD(HasInheritedConstructor)
>> > MATCH_FIELD(HasInheritedAssignment)
>> > + MATCH_FIELD(NeedOverloadResolutionForCopyConstructor)
>> > MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)
>> > MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)
>> > MATCH_FIELD(NeedOverloadResolutionForDestructor)
>> > + MATCH_FIELD(DefaultedCopyConstructorIsDeleted)
>> > MATCH_FIELD(DefaultedMoveConstructorIsDeleted)
>> > MATCH_FIELD(DefaultedMoveAssignmentIsDeleted)
>> > MATCH_FIELD(DefaultedDestructorIsDeleted)
>> > @@ -1708,6 +1713,7 @@ void ASTDeclReader::MergeDefinitionData(
>> > MATCH_FIELD(HasIrrelevantDestructor)
>> > OR_FIELD(HasConstexprNonCopyMoveConstructor)
>> > OR_FIELD(HasDefaultedDefaultConstructor)
>> > + MATCH_FIELD(CanPassInRegisters)
>> > MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
>> > OR_FIELD(HasConstexprDefaultConstructor)
>> > MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)
>> >
>> > Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
>> > +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Aug 15 18:49:53 2017
>> > @@ -5875,9 +5875,11 @@ void ASTRecordWriter::AddCXXDefinitionDa
>> > Record->push_back(Data.HasUninitializedFields);
>> > Record->push_back(Data.HasInheritedConstructor);
>> > Record->push_back(Data.HasInheritedAssignment);
>> > + Record->push_back(Data.NeedOverloadResolutionForCopyConstructor);
>> > Record->push_back(Data.NeedOverloadResolutionForMoveConstructor);
>> > Record->push_back(Data.NeedOverloadResolutionForMoveAssignment);
>> > Record->push_back(Data.NeedOverloadResolutionForDestructor);
>> > + Record->push_back(Data.DefaultedCopyConstructorIsDeleted);
>> > Record->push_back(Data.DefaultedMoveConstructorIsDeleted);
>> > Record->push_back(Data.DefaultedMoveAssignmentIsDeleted);
>> > Record->push_back(Data.DefaultedDestructorIsDeleted);
>> > @@ -5886,6 +5888,7 @@ void ASTRecordWriter::AddCXXDefinitionDa
>> > Record->push_back(Data.HasIrrelevantDestructor);
>> > Record->push_back(Data.HasConstexprNonCopyMoveConstructor);
>> > Record->push_back(Data.HasDefaultedDefaultConstructor);
>> > + Record->push_back(Data.CanPassInRegisters);
>> > Record->push_back(Data.DefaultedDefaultConstructorIsConstexpr);
>> > Record->push_back(Data.HasConstexprDefaultConstructor);
>> > Record->push_back(Data.HasNonLiteralTypeFieldsOrBases);
>> >
>> > Modified: cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp (original)
>> > +++ cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp Tue Aug 15 18:49:53
>> > 2017
>> > @@ -1,5 +1,6 @@
>> > // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -emit-llvm
>> > -o - %s | FileCheck %s
>> > -// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o
>> > - %s | FileCheck %s -check-prefix=WIN64
>> > +// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o
>> > - %s -fms-compatibility -fms-compatibility-version=18 | FileCheck %s
>> > -check-prefix=WIN64 -check-prefix=WIN64-18
>> > +// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o
>> > - %s -fms-compatibility -fms-compatibility-version=19 | FileCheck %s
>> > -check-prefix=WIN64 -check-prefix=WIN64-19
>> >
>> > namespace trivial {
>> > // Trivial structs should be passed directly.
>> > @@ -52,12 +53,11 @@ void foo(A);
>> > void bar() {
>> > foo({});
>> > }
>> > -// FIXME: The copy ctor is implicitly deleted.
>> > -// CHECK-DISABLED-LABEL: define void @_ZN9move_ctor3barEv()
>> > -// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
>> > -// CHECK-DISABLED-NOT: call
>> > -// CHECK-DISABLED: call void
>> > @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}})
>> > -// CHECK-DISABLED-LABEL: declare void
>> > @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)
>> > +// CHECK-LABEL: define void @_ZN9move_ctor3barEv()
>> > +// CHECK: call void @_Z{{.*}}C1Ev(
>> > +// CHECK-NOT: call
>> > +// CHECK: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*
>> > %{{.*}})
>> > +// CHECK-LABEL: declare void
>> > @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)
>> >
>> > // WIN64-LABEL: declare void
>> > @"\01?foo at move_ctor@@YAXUA at 1@@Z"(%"struct.move_ctor::A"*)
>> > }
>> > @@ -73,12 +73,11 @@ void foo(A);
>> > void bar() {
>> > foo({});
>> > }
>> > -// FIXME: The copy ctor is deleted.
>> > -// CHECK-DISABLED-LABEL: define void @_ZN11all_deleted3barEv()
>> > -// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
>> > -// CHECK-DISABLED-NOT: call
>> > -// CHECK-DISABLED: call void
>> > @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
>> > -// CHECK-DISABLED-LABEL: declare void
>> > @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)
>> > +// CHECK-LABEL: define void @_ZN11all_deleted3barEv()
>> > +// CHECK: call void @_Z{{.*}}C1Ev(
>> > +// CHECK-NOT: call
>> > +// CHECK: call void
>> > @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
>> > +// CHECK-LABEL: declare void
>> > @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)
>> >
>> > // WIN64-LABEL: declare void
>> > @"\01?foo at all_deleted@@YAXUA at 1@@Z"(%"struct.all_deleted::A"*)
>> > }
>> > @@ -93,14 +92,15 @@ void foo(A);
>> > void bar() {
>> > foo({});
>> > }
>> > -// FIXME: The copy and move ctors are implicitly deleted.
>> > -// CHECK-DISABLED-LABEL: define void @_ZN18implicitly_deleted3barEv()
>> > -// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
>> > -// CHECK-DISABLED-NOT: call
>> > -// CHECK-DISABLED: call void
>> > @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*
>> > %{{.*}})
>> > -// CHECK-DISABLED-LABEL: declare void
>> > @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
>> > -
>> > -// WIN64-LABEL: declare void
>> > @"\01?foo at implicitly_deleted@@YAXUA at 1@@Z"(%"struct.implicitly_deleted::A"*)
>> > +// CHECK-LABEL: define void @_ZN18implicitly_deleted3barEv()
>> > +// CHECK: call void @_Z{{.*}}C1Ev(
>> > +// CHECK-NOT: call
>> > +// CHECK: call void
>> > @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*
>> > %{{.*}})
>> > +// CHECK-LABEL: declare void
>> > @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
>> > +
>> > +// In MSVC 2013, the copy ctor is not deleted by a move assignment. In
>> > MSVC 2015, it is.
>> > +// WIN64-18-LABEL: declare void
>> > @"\01?foo at implicitly_deleted@@YAXUA at 1@@Z"(i64
>> > +// WIN64-19-LABEL: declare void
>> > @"\01?foo at implicitly_deleted@@YAXUA at 1@@Z"(%"struct.implicitly_deleted::A"*)
>> > }
>> >
>> > namespace one_deleted {
>> > @@ -113,12 +113,11 @@ void foo(A);
>> > void bar() {
>> > foo({});
>> > }
>> > -// FIXME: The copy constructor is implicitly deleted.
>> > -// CHECK-DISABLED-LABEL: define void @_ZN11one_deleted3barEv()
>> > -// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
>> > -// CHECK-DISABLED-NOT: call
>> > -// CHECK-DISABLED: call void
>> > @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
>> > -// CHECK-DISABLED-LABEL: declare void
>> > @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)
>> > +// CHECK-LABEL: define void @_ZN11one_deleted3barEv()
>> > +// CHECK: call void @_Z{{.*}}C1Ev(
>> > +// CHECK-NOT: call
>> > +// CHECK: call void
>> > @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
>> > +// CHECK-LABEL: declare void
>> > @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)
>> >
>> > // WIN64-LABEL: declare void
>> > @"\01?foo at one_deleted@@YAXUA at 1@@Z"(%"struct.one_deleted::A"*)
>> > }
>> > @@ -195,12 +194,10 @@ void foo(B);
>> > void bar() {
>> > foo({});
>> > }
>> > -// FIXME: This class has a non-trivial copy ctor and a trivial copy
>> > ctor. It's
>> > -// not clear whether we should pass by address or in registers.
>> > -// CHECK-DISABLED-LABEL: define void @_ZN14two_copy_ctors3barEv()
>> > -// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
>> > -// CHECK-DISABLED: call void
>> > @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
>> > -// CHECK-DISABLED-LABEL: declare void
>> > @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)
>> > +// CHECK-LABEL: define void @_ZN14two_copy_ctors3barEv()
>> > +// CHECK: call void @_Z{{.*}}C1Ev(
>> > +// CHECK: call void
>> > @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
>> > +// CHECK-LABEL: declare void
>> > @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)
>> >
>> > // WIN64-LABEL: declare void
>> > @"\01?foo at two_copy_ctors@@YAXUB at 1@@Z"(%"struct.two_copy_ctors::B"*)
>> > }
>> > @@ -212,6 +209,7 @@ struct A {
>> > void *p;
>> > };
>> > void *foo(A a) { return a.p; }
>> > +// CHECK-LABEL: define i8*
>> > @_ZN15definition_only3fooENS_1AE(%"struct.definition_only::A"*
>> > // WIN64-LABEL: define i8*
>> > @"\01?foo at definition_only@@YAPEAXUA at 1@@Z"(%"struct.definition_only::A"*
>> > }
>> >
>> > @@ -226,6 +224,7 @@ struct A {
>> > B b;
>> > };
>> > void *foo(A a) { return a.b.p; }
>> > +// CHECK-LABEL: define i8*
>> > @_ZN17deleted_by_member3fooENS_1AE(%"struct.deleted_by_member::A"*
>> > // WIN64-LABEL: define i8*
>> > @"\01?foo at deleted_by_member@@YAPEAXUA at 1@@Z"(%"struct.deleted_by_member::A"*
>> > }
>> >
>> > @@ -239,6 +238,7 @@ struct A : B {
>> > A();
>> > };
>> > void *foo(A a) { return a.p; }
>> > +// CHECK-LABEL: define i8*
>> > @_ZN15deleted_by_base3fooENS_1AE(%"struct.deleted_by_base::A"*
>> > // WIN64-LABEL: define i8*
>> > @"\01?foo at deleted_by_base@@YAPEAXUA at 1@@Z"(%"struct.deleted_by_base::A"*
>> > }
>> >
>> > @@ -253,6 +253,7 @@ struct A {
>> > B b;
>> > };
>> > void *foo(A a) { return a.b.p; }
>> > +// CHECK-LABEL: define i8*
>> > @_ZN22deleted_by_member_copy3fooENS_1AE(%"struct.deleted_by_member_copy::A"*
>> > // WIN64-LABEL: define i8*
>> > @"\01?foo at deleted_by_member_copy@@YAPEAXUA at 1@@Z"(%"struct.deleted_by_member_copy::A"*
>> > }
>> >
>> > @@ -266,6 +267,7 @@ struct A : B {
>> > A();
>> > };
>> > void *foo(A a) { return a.p; }
>> > +// CHECK-LABEL: define i8*
>> > @_ZN20deleted_by_base_copy3fooENS_1AE(%"struct.deleted_by_base_copy::A"*
>> > // WIN64-LABEL: define i8*
>> > @"\01?foo at deleted_by_base_copy@@YAPEAXUA at 1@@Z"(%"struct.deleted_by_base_copy::A"*
>> > }
>> >
>> > @@ -275,6 +277,75 @@ struct A {
>> > A(const A &o) = delete;
>> > void *p;
>> > };
>> > +// CHECK-LABEL: define i8*
>> > @_ZN15explicit_delete3fooENS_1AE(%"struct.explicit_delete::A"*
>> > // WIN64-LABEL: define i8*
>> > @"\01?foo at explicit_delete@@YAPEAXUA at 1@@Z"(%"struct.explicit_delete::A"*
>> > void *foo(A a) { return a.p; }
>> > }
>> > +
>> > +namespace implicitly_deleted_copy_ctor {
>> > +struct A {
>> > + // No move ctor due to copy assignment.
>> > + A &operator=(const A&);
>> > + // Deleted copy ctor due to rvalue ref member.
>> > + int &&ref;
>> > +};
>> > +// CHECK-LABEL: define {{.*}}
>> > @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE(%"struct.implicitly_deleted_copy_ctor::A"*
>> > +// WIN64-LABEL: define {{.*}}
>> > @"\01?foo at implicitly_deleted_copy_ctor@@YAAEAHUA at 1@@Z"(%"struct.implicitly_deleted_copy_ctor::A"*
>> > +int &foo(A a) { return a.ref; }
>> > +
>> > +struct B {
>> > + // Passed direct: has non-deleted trivial copy ctor.
>> > + B &operator=(const B&);
>> > + int &ref;
>> > +};
>> > +int &foo(B b) { return b.ref; }
>> > +// CHECK-LABEL: define {{.*}}
>> > @_ZN28implicitly_deleted_copy_ctor3fooENS_1BE(i32*
>> > +// WIN64-LABEL: define {{.*}}
>> > @"\01?foo at implicitly_deleted_copy_ctor@@YAAEAHUB at 1@@Z"(i64
>> > +
>> > +struct X { X(const X&); };
>> > +struct Y { Y(const Y&) = default; };
>> > +
>> > +union C {
>> > + C &operator=(const C&);
>> > + // Passed indirect: copy ctor deleted due to variant member with
>> > nontrivial copy ctor.
>> > + X x;
>> > + int n;
>> > +};
>> > +int foo(C c) { return c.n; }
>> > +// CHECK-LABEL: define {{.*}}
>> > @_ZN28implicitly_deleted_copy_ctor3fooENS_1CE(%"union.implicitly_deleted_copy_ctor::C"*
>> > +// WIN64-LABEL: define {{.*}}
>> > @"\01?foo at implicitly_deleted_copy_ctor@@YAHTC at 1@@Z"(%"union.implicitly_deleted_copy_ctor::C"*
>> > +
>> > +struct D {
>> > + D &operator=(const D&);
>> > + // Passed indirect: copy ctor deleted due to variant member with
>> > nontrivial copy ctor.
>> > + union {
>> > + X x;
>> > + int n;
>> > + };
>> > +};
>> > +int foo(D d) { return d.n; }
>> > +// CHECK-LABEL: define {{.*}}
>> > @_ZN28implicitly_deleted_copy_ctor3fooENS_1DE(%"struct.implicitly_deleted_copy_ctor::D"*
>> > +// WIN64-LABEL: define {{.*}}
>> > @"\01?foo at implicitly_deleted_copy_ctor@@YAHUD at 1@@Z"(%"struct.implicitly_deleted_copy_ctor::D"*
>> > +
>> > +union E {
>> > + // Passed direct: has non-deleted trivial copy ctor.
>> > + E &operator=(const E&);
>> > + Y y;
>> > + int n;
>> > +};
>> > +int foo(E e) { return e.n; }
>> > +// CHECK-LABEL: define {{.*}}
>> > @_ZN28implicitly_deleted_copy_ctor3fooENS_1EE(i32
>> > +// WIN64-LABEL: define {{.*}}
>> > @"\01?foo at implicitly_deleted_copy_ctor@@YAHTE at 1@@Z"(i32
>> > +
>> > +struct F {
>> > + // Passed direct: has non-deleted trivial copy ctor.
>> > + F &operator=(const F&);
>> > + union {
>> > + Y y;
>> > + int n;
>> > + };
>> > +};
>> > +int foo(F f) { return f.n; }
>> > +// CHECK-LABEL: define {{.*}}
>> > @_ZN28implicitly_deleted_copy_ctor3fooENS_1FE(i32
>> > +// WIN64-LABEL: define {{.*}}
>> > @"\01?foo at implicitly_deleted_copy_ctor@@YAHUF at 1@@Z"(i32
>> > +}
>> >
>> > Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=310983&r1=310982&r2=310983&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
>> > (original)
>> > +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Tue Aug
>> > 15 18:49:53 2017
>> > @@ -1108,26 +1108,35 @@ TEST(ConstructorDeclaration, IsExplicit)
>> > }
>> >
>> > TEST(ConstructorDeclaration, Kinds) {
>> > - EXPECT_TRUE(matches("struct S { S(); };",
>> > - cxxConstructorDecl(isDefaultConstructor())));
>> > - EXPECT_TRUE(notMatches("struct S { S(); };",
>> > - cxxConstructorDecl(isCopyConstructor())));
>> > - EXPECT_TRUE(notMatches("struct S { S(); };",
>> > - cxxConstructorDecl(isMoveConstructor())));
>> > + EXPECT_TRUE(matches(
>> > + "struct S { S(); };",
>> > + cxxConstructorDecl(isDefaultConstructor(),
>> > unless(isImplicit()))));
>> > + EXPECT_TRUE(notMatches(
>> > + "struct S { S(); };",
>> > + cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));
>> > + EXPECT_TRUE(notMatches(
>> > + "struct S { S(); };",
>> > + cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));
>> >
>> > - EXPECT_TRUE(notMatches("struct S { S(const S&); };",
>> > - cxxConstructorDecl(isDefaultConstructor())));
>> > - EXPECT_TRUE(matches("struct S { S(const S&); };",
>> > - cxxConstructorDecl(isCopyConstructor())));
>> > - EXPECT_TRUE(notMatches("struct S { S(const S&); };",
>> > - cxxConstructorDecl(isMoveConstructor())));
>> > + EXPECT_TRUE(notMatches(
>> > + "struct S { S(const S&); };",
>> > + cxxConstructorDecl(isDefaultConstructor(),
>> > unless(isImplicit()))));
>> > + EXPECT_TRUE(matches(
>> > + "struct S { S(const S&); };",
>> > + cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));
>> > + EXPECT_TRUE(notMatches(
>> > + "struct S { S(const S&); };",
>> > + cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));
>> >
>> > - EXPECT_TRUE(notMatches("struct S { S(S&&); };",
>> > - cxxConstructorDecl(isDefaultConstructor())));
>> > - EXPECT_TRUE(notMatches("struct S { S(S&&); };",
>> > - cxxConstructorDecl(isCopyConstructor())));
>> > - EXPECT_TRUE(matches("struct S { S(S&&); };",
>> > - cxxConstructorDecl(isMoveConstructor())));
>> > + EXPECT_TRUE(notMatches(
>> > + "struct S { S(S&&); };",
>> > + cxxConstructorDecl(isDefaultConstructor(),
>> > unless(isImplicit()))));
>> > + EXPECT_TRUE(notMatches(
>> > + "struct S { S(S&&); };",
>> > + cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));
>> > + EXPECT_TRUE(matches(
>> > + "struct S { S(S&&); };",
>> > + cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));
>> > }
>> >
>> > TEST(ConstructorDeclaration, IsUserProvided) {
>> >
>> >
>> > _______________________________________________
>> > cfe-commits mailing list
>> > cfe-commits at lists.llvm.org
>> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>
More information about the cfe-commits
mailing list