Hi Vassil, My build is in progress, but since it's a full build it's probably going to take another couple of hours to complete. I'll let you know when it's done.
Thanks, Diana On 10 August 2017 at 10:09, Vassil Vassilev <v.g.vassi...@gmail.com> wrote: > It looks like I can not reproduce it on osx (non-arm)... :( > On 09/08/17 22:54, Diana Picus wrote: >> >> 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