Clean merge in r311410. Thanks.
On Mon, Aug 21, 2017 at 4:21 PM, Richard Smith <richardsm...@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 <h...@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@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@move_ctor@@YAXUA@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@all_deleted@@YAXUA@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@implicitly_deleted@@YAXUA@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@implicitly_deleted@@YAXUA@1@@Z"(i64 >> > +// WIN64-19-LABEL: declare void >> > @"\01?foo@implicitly_deleted@@YAXUA@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@one_deleted@@YAXUA@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@two_copy_ctors@@YAXUB@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@definition_only@@YAPEAXUA@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@deleted_by_member@@YAPEAXUA@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@deleted_by_base@@YAPEAXUA@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@deleted_by_member_copy@@YAPEAXUA@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@deleted_by_base_copy@@YAPEAXUA@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@explicit_delete@@YAPEAXUA@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@implicitly_deleted_copy_ctor@@YAAEAHUA@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@implicitly_deleted_copy_ctor@@YAAEAHUB@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@implicitly_deleted_copy_ctor@@YAHTC@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@implicitly_deleted_copy_ctor@@YAHUD@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@implicitly_deleted_copy_ctor@@YAHTE@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@implicitly_deleted_copy_ctor@@YAHUF@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@lists.llvm.org >> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > > _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits