r310401 - PR19668, PR23034: Fix handling of move constructors and deleted copy

Diana Picus via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 9 12:54:38 PDT 2017


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