Reverting this also fixed the selfhost bots: http://lab.llvm.org:8011/builders/clang-cmake-thumbv7-a15-full-sh/builds/2142 http://lab.llvm.org:8011/builders/clang-cmake-armv7-a15-selfhost/builds/2309 http://lab.llvm.org:8011/builders/clang-cmake-armv7-a15-selfhost-neon/builds/1819
I'm afraid the logs for those look even less helpful. On 9 August 2017 at 16:17, Diana Picus <diana.pi...@linaro.org> wrote: > Hi, > > See attached. FWIW, when I ran this on a very similar machine, I got > 194 failures, all of which went away after reverting. So there might > be something fishy going on. > > Regards, > Diana > > On 9 August 2017 at 15:02, Vassil Vassilev <v.g.vassi...@gmail.com> wrote: >> Hi Diana, >> >> It seems the service is down. Could you send us the details of the >> failures (incl stack traces if any) >> >> Many thanks, >> Vassil >> >> On 09/08/17 15:27, Diana Picus via cfe-commits wrote: >>> >>> Hi Richard, >>> >>> I'm sorry but I've reverted this in r310464 because it was breaking >>> some ASAN tests on this bot: >>> http://lab.llvm.org:8011/builders/clang-cmake-armv7-a15-full/builds/9452 >>> >>> Please let me know if I can help debug this. >>> >>> Cheers, >>> Diana >>> >>> On 8 August 2017 at 21:14, Richard Smith via cfe-commits >>> <cfe-commits@lists.llvm.org> wrote: >>>> >>>> I forgot to say: >>>> >>>> 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. >>>> >>>> On 8 August 2017 at 12:12, Richard Smith via cfe-commits >>>> <cfe-commits@lists.llvm.org> wrote: >>>>> >>>>> Author: rsmith >>>>> Date: Tue Aug 8 12:12:28 2017 >>>>> New Revision: 310401 >>>>> >>>>> URL: http://llvm.org/viewvc/llvm-project?rev=310401&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. >>>>> >>>>> 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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/include/clang/AST/DeclCXX.h (original) >>>>> +++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Aug 8 12:12:28 2017 >>>>> @@ -375,6 +375,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; >>>>> @@ -383,6 +384,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; >>>>> @@ -415,6 +417,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; >>>>> @@ -811,18 +819,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 { >>>>> @@ -878,7 +918,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 >>>>> @@ -919,7 +968,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 || >>>>> @@ -1316,6 +1374,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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/lib/AST/ASTImporter.cpp (original) >>>>> +++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Aug 8 12:12:28 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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/lib/AST/DeclCXX.cpp (original) >>>>> +++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Aug 8 12:12:28 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(false), >>>>> 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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original) >>>>> +++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Tue Aug 8 12:12:28 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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) >>>>> +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Aug 8 12:12:28 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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original) >>>>> +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Aug 8 12:12:28 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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) >>>>> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Aug 8 12:12:28 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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) >>>>> +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Tue Aug 8 12:12:28 >>>>> 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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) >>>>> +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Aug 8 12:12:28 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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp (original) >>>>> +++ cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp Tue Aug 8 12:12:28 >>>>> 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=310401&r1=310400&r2=310401&view=diff >>>>> >>>>> >>>>> ============================================================================== >>>>> --- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp >>>>> (original) >>>>> +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Tue Aug >>>>> 8 12:12:28 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 >>>> >>> _______________________________________________ >>> 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