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 05:27:27 PDT 2017


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
>


More information about the cfe-commits mailing list