r310401 - PR19668, PR23034: Fix handling of move constructors and deleted copy
Vassil Vassilev via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 10 01:09:43 PDT 2017
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.picus at 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.vassilev at 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 at 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 at 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 at move_ctor@@YAXUA at 1@@Z"(%"struct.move_ctor::A"*)
>>>>>> }
>>>>>> @@ -73,12 +73,11 @@ void foo(A);
>>>>>> void bar() {
>>>>>> foo({});
>>>>>> }
>>>>>> -// FIXME: The copy ctor is deleted.
>>>>>> -// CHECK-DISABLED-LABEL: define void @_ZN11all_deleted3barEv()
>>>>>> -// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
>>>>>> -// CHECK-DISABLED-NOT: call
>>>>>> -// CHECK-DISABLED: call void
>>>>>> @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
>>>>>> -// CHECK-DISABLED-LABEL: declare void
>>>>>> @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)
>>>>>> +// CHECK-LABEL: define void @_ZN11all_deleted3barEv()
>>>>>> +// CHECK: call void @_Z{{.*}}C1Ev(
>>>>>> +// CHECK-NOT: call
>>>>>> +// CHECK: call void
>>>>>> @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
>>>>>> +// CHECK-LABEL: declare void
>>>>>> @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)
>>>>>>
>>>>>> // WIN64-LABEL: declare void
>>>>>> @"\01?foo at all_deleted@@YAXUA at 1@@Z"(%"struct.all_deleted::A"*)
>>>>>> }
>>>>>> @@ -93,14 +92,15 @@ void foo(A);
>>>>>> void bar() {
>>>>>> foo({});
>>>>>> }
>>>>>> -// FIXME: The copy and move ctors are implicitly deleted.
>>>>>> -// CHECK-DISABLED-LABEL: define void @_ZN18implicitly_deleted3barEv()
>>>>>> -// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
>>>>>> -// CHECK-DISABLED-NOT: call
>>>>>> -// CHECK-DISABLED: call void
>>>>>> @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*
>>>>>> %{{.*}})
>>>>>> -// CHECK-DISABLED-LABEL: declare void
>>>>>> @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
>>>>>> -
>>>>>> -// WIN64-LABEL: declare void
>>>>>>
>>>>>> @"\01?foo at implicitly_deleted@@YAXUA at 1@@Z"(%"struct.implicitly_deleted::A"*)
>>>>>> +// CHECK-LABEL: define void @_ZN18implicitly_deleted3barEv()
>>>>>> +// CHECK: call void @_Z{{.*}}C1Ev(
>>>>>> +// CHECK-NOT: call
>>>>>> +// CHECK: call void
>>>>>> @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*
>>>>>> %{{.*}})
>>>>>> +// CHECK-LABEL: declare void
>>>>>> @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
>>>>>> +
>>>>>> +// In MSVC 2013, the copy ctor is not deleted by a move assignment. In
>>>>>> MSVC 2015, it is.
>>>>>> +// WIN64-18-LABEL: declare void
>>>>>> @"\01?foo at implicitly_deleted@@YAXUA at 1@@Z"(i64
>>>>>> +// WIN64-19-LABEL: declare void
>>>>>>
>>>>>> @"\01?foo at implicitly_deleted@@YAXUA at 1@@Z"(%"struct.implicitly_deleted::A"*)
>>>>>> }
>>>>>>
>>>>>> namespace one_deleted {
>>>>>> @@ -113,12 +113,11 @@ void foo(A);
>>>>>> void bar() {
>>>>>> foo({});
>>>>>> }
>>>>>> -// FIXME: The copy constructor is implicitly deleted.
>>>>>> -// CHECK-DISABLED-LABEL: define void @_ZN11one_deleted3barEv()
>>>>>> -// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
>>>>>> -// CHECK-DISABLED-NOT: call
>>>>>> -// CHECK-DISABLED: call void
>>>>>> @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
>>>>>> -// CHECK-DISABLED-LABEL: declare void
>>>>>> @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)
>>>>>> +// CHECK-LABEL: define void @_ZN11one_deleted3barEv()
>>>>>> +// CHECK: call void @_Z{{.*}}C1Ev(
>>>>>> +// CHECK-NOT: call
>>>>>> +// CHECK: call void
>>>>>> @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
>>>>>> +// CHECK-LABEL: declare void
>>>>>> @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)
>>>>>>
>>>>>> // WIN64-LABEL: declare void
>>>>>> @"\01?foo at one_deleted@@YAXUA at 1@@Z"(%"struct.one_deleted::A"*)
>>>>>> }
>>>>>> @@ -195,12 +194,10 @@ void foo(B);
>>>>>> void bar() {
>>>>>> foo({});
>>>>>> }
>>>>>> -// FIXME: This class has a non-trivial copy ctor and a trivial copy
>>>>>> ctor.
>>>>>> It's
>>>>>> -// not clear whether we should pass by address or in registers.
>>>>>> -// CHECK-DISABLED-LABEL: define void @_ZN14two_copy_ctors3barEv()
>>>>>> -// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
>>>>>> -// CHECK-DISABLED: call void
>>>>>> @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
>>>>>> -// CHECK-DISABLED-LABEL: declare void
>>>>>> @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)
>>>>>> +// CHECK-LABEL: define void @_ZN14two_copy_ctors3barEv()
>>>>>> +// CHECK: call void @_Z{{.*}}C1Ev(
>>>>>> +// CHECK: call void
>>>>>> @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
>>>>>> +// CHECK-LABEL: declare void
>>>>>> @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)
>>>>>>
>>>>>> // WIN64-LABEL: declare void
>>>>>> @"\01?foo at two_copy_ctors@@YAXUB at 1@@Z"(%"struct.two_copy_ctors::B"*)
>>>>>> }
>>>>>> @@ -212,6 +209,7 @@ struct A {
>>>>>> void *p;
>>>>>> };
>>>>>> void *foo(A a) { return a.p; }
>>>>>> +// CHECK-LABEL: define i8*
>>>>>> @_ZN15definition_only3fooENS_1AE(%"struct.definition_only::A"*
>>>>>> // WIN64-LABEL: define i8*
>>>>>> @"\01?foo at definition_only@@YAPEAXUA at 1@@Z"(%"struct.definition_only::A"*
>>>>>> }
>>>>>>
>>>>>> @@ -226,6 +224,7 @@ struct A {
>>>>>> B b;
>>>>>> };
>>>>>> void *foo(A a) { return a.b.p; }
>>>>>> +// CHECK-LABEL: define i8*
>>>>>> @_ZN17deleted_by_member3fooENS_1AE(%"struct.deleted_by_member::A"*
>>>>>> // WIN64-LABEL: define i8*
>>>>>>
>>>>>> @"\01?foo at deleted_by_member@@YAPEAXUA at 1@@Z"(%"struct.deleted_by_member::A"*
>>>>>> }
>>>>>>
>>>>>> @@ -239,6 +238,7 @@ struct A : B {
>>>>>> A();
>>>>>> };
>>>>>> void *foo(A a) { return a.p; }
>>>>>> +// CHECK-LABEL: define i8*
>>>>>> @_ZN15deleted_by_base3fooENS_1AE(%"struct.deleted_by_base::A"*
>>>>>> // WIN64-LABEL: define i8*
>>>>>> @"\01?foo at deleted_by_base@@YAPEAXUA at 1@@Z"(%"struct.deleted_by_base::A"*
>>>>>> }
>>>>>>
>>>>>> @@ -253,6 +253,7 @@ struct A {
>>>>>> B b;
>>>>>> };
>>>>>> void *foo(A a) { return a.b.p; }
>>>>>> +// CHECK-LABEL: define i8*
>>>>>>
>>>>>> @_ZN22deleted_by_member_copy3fooENS_1AE(%"struct.deleted_by_member_copy::A"*
>>>>>> // WIN64-LABEL: define i8*
>>>>>>
>>>>>> @"\01?foo at deleted_by_member_copy@@YAPEAXUA at 1@@Z"(%"struct.deleted_by_member_copy::A"*
>>>>>> }
>>>>>>
>>>>>> @@ -266,6 +267,7 @@ struct A : B {
>>>>>> A();
>>>>>> };
>>>>>> void *foo(A a) { return a.p; }
>>>>>> +// CHECK-LABEL: define i8*
>>>>>> @_ZN20deleted_by_base_copy3fooENS_1AE(%"struct.deleted_by_base_copy::A"*
>>>>>> // WIN64-LABEL: define i8*
>>>>>>
>>>>>> @"\01?foo at deleted_by_base_copy@@YAPEAXUA at 1@@Z"(%"struct.deleted_by_base_copy::A"*
>>>>>> }
>>>>>>
>>>>>> @@ -275,6 +277,75 @@ struct A {
>>>>>> A(const A &o) = delete;
>>>>>> void *p;
>>>>>> };
>>>>>> +// CHECK-LABEL: define i8*
>>>>>> @_ZN15explicit_delete3fooENS_1AE(%"struct.explicit_delete::A"*
>>>>>> // WIN64-LABEL: define i8*
>>>>>> @"\01?foo at explicit_delete@@YAPEAXUA at 1@@Z"(%"struct.explicit_delete::A"*
>>>>>> void *foo(A a) { return a.p; }
>>>>>> }
>>>>>> +
>>>>>> +namespace implicitly_deleted_copy_ctor {
>>>>>> +struct A {
>>>>>> + // No move ctor due to copy assignment.
>>>>>> + A &operator=(const A&);
>>>>>> + // Deleted copy ctor due to rvalue ref member.
>>>>>> + int &&ref;
>>>>>> +};
>>>>>> +// CHECK-LABEL: define {{.*}}
>>>>>>
>>>>>> @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE(%"struct.implicitly_deleted_copy_ctor::A"*
>>>>>> +// WIN64-LABEL: define {{.*}}
>>>>>>
>>>>>> @"\01?foo at implicitly_deleted_copy_ctor@@YAAEAHUA at 1@@Z"(%"struct.implicitly_deleted_copy_ctor::A"*
>>>>>> +int &foo(A a) { return a.ref; }
>>>>>> +
>>>>>> +struct B {
>>>>>> + // Passed direct: has non-deleted trivial copy ctor.
>>>>>> + B &operator=(const B&);
>>>>>> + int &ref;
>>>>>> +};
>>>>>> +int &foo(B b) { return b.ref; }
>>>>>> +// CHECK-LABEL: define {{.*}}
>>>>>> @_ZN28implicitly_deleted_copy_ctor3fooENS_1BE(i32*
>>>>>> +// WIN64-LABEL: define {{.*}}
>>>>>> @"\01?foo at implicitly_deleted_copy_ctor@@YAAEAHUB at 1@@Z"(i64
>>>>>> +
>>>>>> +struct X { X(const X&); };
>>>>>> +struct Y { Y(const Y&) = default; };
>>>>>> +
>>>>>> +union C {
>>>>>> + C &operator=(const C&);
>>>>>> + // Passed indirect: copy ctor deleted due to variant member with
>>>>>> nontrivial copy ctor.
>>>>>> + X x;
>>>>>> + int n;
>>>>>> +};
>>>>>> +int foo(C c) { return c.n; }
>>>>>> +// CHECK-LABEL: define {{.*}}
>>>>>>
>>>>>> @_ZN28implicitly_deleted_copy_ctor3fooENS_1CE(%"union.implicitly_deleted_copy_ctor::C"*
>>>>>> +// WIN64-LABEL: define {{.*}}
>>>>>>
>>>>>> @"\01?foo at implicitly_deleted_copy_ctor@@YAHTC at 1@@Z"(%"union.implicitly_deleted_copy_ctor::C"*
>>>>>> +
>>>>>> +struct D {
>>>>>> + D &operator=(const D&);
>>>>>> + // Passed indirect: copy ctor deleted due to variant member with
>>>>>> nontrivial copy ctor.
>>>>>> + union {
>>>>>> + X x;
>>>>>> + int n;
>>>>>> + };
>>>>>> +};
>>>>>> +int foo(D d) { return d.n; }
>>>>>> +// CHECK-LABEL: define {{.*}}
>>>>>>
>>>>>> @_ZN28implicitly_deleted_copy_ctor3fooENS_1DE(%"struct.implicitly_deleted_copy_ctor::D"*
>>>>>> +// WIN64-LABEL: define {{.*}}
>>>>>>
>>>>>> @"\01?foo at implicitly_deleted_copy_ctor@@YAHUD at 1@@Z"(%"struct.implicitly_deleted_copy_ctor::D"*
>>>>>> +
>>>>>> +union E {
>>>>>> + // Passed direct: has non-deleted trivial copy ctor.
>>>>>> + E &operator=(const E&);
>>>>>> + Y y;
>>>>>> + int n;
>>>>>> +};
>>>>>> +int foo(E e) { return e.n; }
>>>>>> +// CHECK-LABEL: define {{.*}}
>>>>>> @_ZN28implicitly_deleted_copy_ctor3fooENS_1EE(i32
>>>>>> +// WIN64-LABEL: define {{.*}}
>>>>>> @"\01?foo at implicitly_deleted_copy_ctor@@YAHTE at 1@@Z"(i32
>>>>>> +
>>>>>> +struct F {
>>>>>> + // Passed direct: has non-deleted trivial copy ctor.
>>>>>> + F &operator=(const F&);
>>>>>> + union {
>>>>>> + Y y;
>>>>>> + int n;
>>>>>> + };
>>>>>> +};
>>>>>> +int foo(F f) { return f.n; }
>>>>>> +// CHECK-LABEL: define {{.*}}
>>>>>> @_ZN28implicitly_deleted_copy_ctor3fooENS_1FE(i32
>>>>>> +// WIN64-LABEL: define {{.*}}
>>>>>> @"\01?foo at implicitly_deleted_copy_ctor@@YAHUF at 1@@Z"(i32
>>>>>> +}
>>>>>>
>>>>>> Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
>>>>>> URL:
>>>>>>
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=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 at lists.llvm.org
>>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> cfe-commits mailing list
>>>>> cfe-commits at lists.llvm.org
>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>>
>>>> _______________________________________________
>>>> cfe-commits mailing list
>>>> cfe-commits at lists.llvm.org
>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>
>>>
More information about the cfe-commits
mailing list