On 09/08/17 22:54, Diana Picus wrote:
Reverting this also fixed the selfhost bots:
http://lab.llvm.org:8011/builders/clang-cmake-thumbv7-a15-full-sh/builds/2142
http://lab.llvm.org:8011/builders/clang-cmake-armv7-a15-selfhost/builds/2309
http://lab.llvm.org:8011/builders/clang-cmake-armv7-a15-selfhost-neon/builds/1819

I'm afraid the logs for those look even less helpful.
Not helpful indeed :) Do you have access to the machine and would you be willing to build in debug mode and send us some stack traces. I do not have any arm machines :(

On 9 August 2017 at 16:17, Diana Picus <diana.pi...@linaro.org> wrote:
Hi,

See attached. FWIW, when I ran this on a very similar machine, I got
194 failures, all of which went away after reverting. So there might
be something fishy going on.

Regards,
Diana

On 9 August 2017 at 15:02, Vassil Vassilev <v.g.vassi...@gmail.com> wrote:
Hi Diana,

   It seems the service is down. Could you send us the details of the
failures (incl stack traces if any)

Many thanks,
Vassil

On 09/08/17 15:27, Diana Picus via cfe-commits wrote:
Hi Richard,

I'm sorry but I've reverted this in r310464 because it was breaking
some ASAN tests on this bot:
http://lab.llvm.org:8011/builders/clang-cmake-armv7-a15-full/builds/9452

Please let me know if I can help debug this.

Cheers,
Diana

On 8 August 2017 at 21:14, Richard Smith via cfe-commits
<cfe-commits@lists.llvm.org> wrote:
I forgot to say:

Based on a patch by Vassil Vassilev, which was based on a patch by Bernd
Schmidt, which was based on a patch by Reid Kleckner.

On 8 August 2017 at 12:12, Richard Smith via cfe-commits
<cfe-commits@lists.llvm.org> wrote:
Author: rsmith
Date: Tue Aug  8 12:12:28 2017
New Revision: 310401

URL: http://llvm.org/viewvc/llvm-project?rev=310401&view=rev
Log:
PR19668, PR23034: Fix handling of move constructors and deleted copy
constructors when deciding whether classes should be passed indirectly.

This fixes ABI differences between Clang and GCC:

   * Previously, Clang ignored the move constructor when making this
     determination. It now takes the move constructor into account, per
     https://github.com/itanium-cxx-abi/cxx-abi/pull/17 (this change may
     seem recent, but the ABI change was agreed on the Itanium C++ ABI
     list a long time ago).

   * Previously, Clang's behavior when the copy constructor was deleted
     was unstable -- depending on whether the lazy declaration of the
     copy constructor had been triggered, you might get different
behavior.
     We now eagerly declare the copy constructor whenever its deletedness
     is unclear, and ignore deleted copy/move constructors when looking
for
     a trivial such constructor.

This also fixes an ABI difference between Clang and MSVC:

   * If the copy constructor would be implicitly deleted (but has not
been
     lazily declared yet), for instance because the class has an rvalue
     reference member, we would pass it directly. We now pass such a
class
     indirectly, matching MSVC.

Modified:
      cfe/trunk/include/clang/AST/DeclCXX.h
      cfe/trunk/lib/AST/ASTImporter.cpp
      cfe/trunk/lib/AST/DeclCXX.cpp
      cfe/trunk/lib/CodeGen/CGCXXABI.cpp
      cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
      cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
      cfe/trunk/lib/Sema/SemaDeclCXX.cpp
      cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
      cfe/trunk/lib/Serialization/ASTWriter.cpp
      cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp
      cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Aug  8 12:12:28 2017
@@ -375,6 +375,7 @@ class CXXRecordDecl : public RecordDecl
       /// \brief These flags are \c true if a defaulted corresponding
special
       /// member can't be fully analyzed without performing overload
resolution.
       /// @{
+    unsigned NeedOverloadResolutionForCopyConstructor : 1;
       unsigned NeedOverloadResolutionForMoveConstructor : 1;
       unsigned NeedOverloadResolutionForMoveAssignment : 1;
       unsigned NeedOverloadResolutionForDestructor : 1;
@@ -383,6 +384,7 @@ class CXXRecordDecl : public RecordDecl
       /// \brief These flags are \c true if an implicit defaulted
corresponding
       /// special member would be defined as deleted.
       /// @{
+    unsigned DefaultedCopyConstructorIsDeleted : 1;
       unsigned DefaultedMoveConstructorIsDeleted : 1;
       unsigned DefaultedMoveAssignmentIsDeleted : 1;
       unsigned DefaultedDestructorIsDeleted : 1;
@@ -415,6 +417,12 @@ class CXXRecordDecl : public RecordDecl
       /// constructor.
       unsigned HasDefaultedDefaultConstructor : 1;

+    /// \brief True if this class can be passed in a
non-address-preserving
+    /// fashion (such as in registers) according to the C++ language
rules.
+    /// This does not imply anything about how the ABI in use will
actually
+    /// pass an object of this class.
+    unsigned CanPassInRegisters : 1;
+
       /// \brief True if a defaulted default constructor for this class
would
       /// be constexpr.
       unsigned DefaultedDefaultConstructorIsConstexpr : 1;
@@ -811,18 +819,50 @@ public:
       return data().FirstFriend.isValid();
     }

+  /// \brief \c true if a defaulted copy constructor for this class
would
be
+  /// deleted.
+  bool defaultedCopyConstructorIsDeleted() const {
+    assert((!needsOverloadResolutionForCopyConstructor() ||
+            (data().DeclaredSpecialMembers & SMF_CopyConstructor)) &&
+           "this property has not yet been computed by Sema");
+    return data().DefaultedCopyConstructorIsDeleted;
+  }
+
+  /// \brief \c true if a defaulted move constructor for this class
would
be
+  /// deleted.
+  bool defaultedMoveConstructorIsDeleted() const {
+    assert((!needsOverloadResolutionForMoveConstructor() ||
+            (data().DeclaredSpecialMembers & SMF_MoveConstructor)) &&
+           "this property has not yet been computed by Sema");
+    return data().DefaultedMoveConstructorIsDeleted;
+  }
+
+  /// \brief \c true if a defaulted destructor for this class would be
deleted.
+  bool defaultedDestructorIsDeleted() const {
+    return !data().DefaultedDestructorIsDeleted;
+  }
+
+  /// \brief \c true if we know for sure that this class has a single,
+  /// accessible, unambiguous copy constructor that is not deleted.
+  bool hasSimpleCopyConstructor() const {
+    return !hasUserDeclaredCopyConstructor() &&
+           !data().DefaultedCopyConstructorIsDeleted;
+  }
+
     /// \brief \c true if we know for sure that this class has a single,
     /// accessible, unambiguous move constructor that is not deleted.
     bool hasSimpleMoveConstructor() const {
       return !hasUserDeclaredMoveConstructor() && hasMoveConstructor()
&&
              !data().DefaultedMoveConstructorIsDeleted;
     }
+
     /// \brief \c true if we know for sure that this class has a single,
     /// accessible, unambiguous move assignment operator that is not
deleted.
     bool hasSimpleMoveAssignment() const {
       return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() &&
              !data().DefaultedMoveAssignmentIsDeleted;
     }
+
     /// \brief \c true if we know for sure that this class has an
accessible
     /// destructor that is not deleted.
     bool hasSimpleDestructor() const {
@@ -878,7 +918,16 @@ public:
     /// \brief Determine whether we need to eagerly declare a defaulted
copy
     /// constructor for this class.
     bool needsOverloadResolutionForCopyConstructor() const {
-    return data().HasMutableFields;
+    // C++17 [class.copy.ctor]p6:
+    //   If the class definition declares a move constructor or move
assignment
+    //   operator, the implicitly declared copy constructor is defined
as
+    //   deleted.
+    // In MSVC mode, sometimes a declared move assignment does not
delete
an
+    // implicit copy constructor, so defer this choice to Sema.
+    if (data().UserDeclaredSpecialMembers &
+        (SMF_MoveConstructor | SMF_MoveAssignment))
+      return true;
+    return data().NeedOverloadResolutionForCopyConstructor;
     }

     /// \brief Determine whether an implicit copy constructor for this
type
@@ -919,7 +968,16 @@ public:
              needsImplicitMoveConstructor();
     }

-  /// \brief Set that we attempted to declare an implicitly move
+  /// \brief Set that we attempted to declare an implicit copy
+  /// constructor, but overload resolution failed so we deleted it.
+  void setImplicitCopyConstructorIsDeleted() {
+    assert((data().DefaultedCopyConstructorIsDeleted ||
+            needsOverloadResolutionForCopyConstructor()) &&
+           "Copy constructor should not be deleted");
+    data().DefaultedCopyConstructorIsDeleted = true;
+  }
+
+  /// \brief Set that we attempted to declare an implicit move
     /// constructor, but overload resolution failed so we deleted it.
     void setImplicitMoveConstructorIsDeleted() {
       assert((data().DefaultedMoveConstructorIsDeleted ||
@@ -1316,6 +1374,18 @@ public:
       return data().HasIrrelevantDestructor;
     }

+  /// \brief Determine whether this class has at least one trivial,
non-deleted
+  /// copy or move constructor.
+  bool canPassInRegisters() const {
+    return data().CanPassInRegisters;
+  }
+
+  /// \brief Set that we can pass this RecordDecl in registers.
+  // FIXME: This should be set as part of completeDefinition.
+  void setCanPassInRegisters(bool CanPass) {
+    data().CanPassInRegisters = CanPass;
+  }
+
     /// \brief Determine whether this class has a non-literal or/
volatile
type
     /// non-static data member or base class.
     bool hasNonLiteralTypeFieldsOrBases() const {

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Aug  8 12:12:28 2017
@@ -956,12 +956,16 @@ bool ASTNodeImporter::ImportDefinition(R
       ToData.HasUninitializedFields = FromData.HasUninitializedFields;
       ToData.HasInheritedConstructor = FromData.HasInheritedConstructor;
       ToData.HasInheritedAssignment = FromData.HasInheritedAssignment;
+    ToData.NeedOverloadResolutionForCopyConstructor
+      = FromData.NeedOverloadResolutionForCopyConstructor;
       ToData.NeedOverloadResolutionForMoveConstructor
         = FromData.NeedOverloadResolutionForMoveConstructor;
       ToData.NeedOverloadResolutionForMoveAssignment
         = FromData.NeedOverloadResolutionForMoveAssignment;
       ToData.NeedOverloadResolutionForDestructor
         = FromData.NeedOverloadResolutionForDestructor;
+    ToData.DefaultedCopyConstructorIsDeleted
+      = FromData.DefaultedCopyConstructorIsDeleted;
       ToData.DefaultedMoveConstructorIsDeleted
         = FromData.DefaultedMoveConstructorIsDeleted;
       ToData.DefaultedMoveAssignmentIsDeleted
@@ -973,6 +977,7 @@ bool ASTNodeImporter::ImportDefinition(R
         = FromData.HasConstexprNonCopyMoveConstructor;
       ToData.HasDefaultedDefaultConstructor
         = FromData.HasDefaultedDefaultConstructor;
+    ToData.CanPassInRegisters = FromData.CanPassInRegisters;
       ToData.DefaultedDefaultConstructorIsConstexpr
         = FromData.DefaultedDefaultConstructorIsConstexpr;
       ToData.HasConstexprDefaultConstructor

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Aug  8 12:12:28 2017
@@ -55,15 +55,18 @@ CXXRecordDecl::DefinitionData::Definitio
         HasOnlyCMembers(true), HasInClassInitializer(false),
         HasUninitializedReferenceMember(false),
HasUninitializedFields(false),
         HasInheritedConstructor(false), HasInheritedAssignment(false),
+      NeedOverloadResolutionForCopyConstructor(false),
         NeedOverloadResolutionForMoveConstructor(false),
         NeedOverloadResolutionForMoveAssignment(false),
         NeedOverloadResolutionForDestructor(false),
+      DefaultedCopyConstructorIsDeleted(false),
         DefaultedMoveConstructorIsDeleted(false),
         DefaultedMoveAssignmentIsDeleted(false),
         DefaultedDestructorIsDeleted(false),
HasTrivialSpecialMembers(SMF_All),
         DeclaredNonTrivialSpecialMembers(0),
HasIrrelevantDestructor(true),
         HasConstexprNonCopyMoveConstructor(false),
         HasDefaultedDefaultConstructor(false),
+      CanPassInRegisters(false),
         DefaultedDefaultConstructorIsConstexpr(true),
         HasConstexprDefaultConstructor(false),
         HasNonLiteralTypeFieldsOrBases(false),
ComputedVisibleConversions(false),
@@ -352,8 +355,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier
         setHasVolatileMember(true);

       // Keep track of the presence of mutable fields.
-    if (BaseClassDecl->hasMutableFields())
+    if (BaseClassDecl->hasMutableFields()) {
         data().HasMutableFields = true;
+      data().NeedOverloadResolutionForCopyConstructor = true;
+    }

       if (BaseClassDecl->hasUninitializedReferenceMember())
         data().HasUninitializedReferenceMember = true;
@@ -406,6 +411,8 @@ void CXXRecordDecl::addedClassSubobject(
     //    -- a direct or virtual base class B that cannot be
copied/moved
[...]
     //    -- a non-static data member of class type M (or array thereof)
     //       that cannot be copied or moved [...]
+  if (!Subobj->hasSimpleCopyConstructor())
+    data().NeedOverloadResolutionForCopyConstructor = true;
     if (!Subobj->hasSimpleMoveConstructor())
       data().NeedOverloadResolutionForMoveConstructor = true;

@@ -426,6 +433,7 @@ void CXXRecordDecl::addedClassSubobject(
     //    -- any non-static data member has a type with a destructor
     //       that is deleted or inaccessible from the defaulted [ctor or
dtor].
     if (!Subobj->hasSimpleDestructor()) {
+    data().NeedOverloadResolutionForCopyConstructor = true;
       data().NeedOverloadResolutionForMoveConstructor = true;
       data().NeedOverloadResolutionForDestructor = true;
     }
@@ -711,8 +719,10 @@ void CXXRecordDecl::addedMember(Decl *D)
         data().IsStandardLayout = false;

       // Keep track of the presence of mutable fields.
-    if (Field->isMutable())
+    if (Field->isMutable()) {
         data().HasMutableFields = true;
+      data().NeedOverloadResolutionForCopyConstructor = true;
+    }

       // C++11 [class.union]p8, DR1460:
       //   If X is a union, a non-static data member of X that is not an
anonymous
@@ -756,6 +766,12 @@ void CXXRecordDecl::addedMember(Decl *D)
         //   A standard-layout class is a class that:
         //    -- has no non-static data members of type [...] reference,
         data().IsStandardLayout = false;
+
+      // C++1z [class.copy.ctor]p10:
+      //   A defaulted copy constructor for a class X is defined as
deleted if X has:
+      //    -- a non-static data member of rvalue reference type
+      if (T->isRValueReferenceType())
+        data().DefaultedCopyConstructorIsDeleted = true;
       }

       if (!Field->hasInClassInitializer() && !Field->isMutable()) {
@@ -809,6 +825,10 @@ void CXXRecordDecl::addedMember(Decl *D)
           // We may need to perform overload resolution to determine
whether a
           // field can be moved if it's const or volatile qualified.
           if (T.getCVRQualifiers() & (Qualifiers::Const |
Qualifiers::Volatile)) {
+          // We need to care about 'const' for the copy constructor
because an
+          // implicit copy constructor might be declared with a
non-const
+          // parameter.
+          data().NeedOverloadResolutionForCopyConstructor = true;
             data().NeedOverloadResolutionForMoveConstructor = true;
             data().NeedOverloadResolutionForMoveAssignment = true;
           }
@@ -819,6 +839,8 @@ void CXXRecordDecl::addedMember(Decl *D)
           //    -- X is a union-like class that has a variant member
with a
           //       non-trivial [corresponding special member]
           if (isUnion()) {
+          if (FieldRec->hasNonTrivialCopyConstructor())
+            data().DefaultedCopyConstructorIsDeleted = true;
             if (FieldRec->hasNonTrivialMoveConstructor())
               data().DefaultedMoveConstructorIsDeleted = true;
             if (FieldRec->hasNonTrivialMoveAssignment())
@@ -830,6 +852,8 @@ void CXXRecordDecl::addedMember(Decl *D)
           // For an anonymous union member, our overload resolution will
perform
           // overload resolution for its members.
           if (Field->isAnonymousStructOrUnion()) {
+          data().NeedOverloadResolutionForCopyConstructor |=
+
FieldRec->data().NeedOverloadResolutionForCopyConstructor;
             data().NeedOverloadResolutionForMoveConstructor |=

FieldRec->data().NeedOverloadResolutionForMoveConstructor;
             data().NeedOverloadResolutionForMoveAssignment |=
@@ -915,8 +939,10 @@ void CXXRecordDecl::addedMember(Decl *D)
           }

           // Keep track of the presence of mutable fields.
-        if (FieldRec->hasMutableFields())
+        if (FieldRec->hasMutableFields()) {
             data().HasMutableFields = true;
+          data().NeedOverloadResolutionForCopyConstructor = true;
+        }

           // C++11 [class.copy]p13:
           //   If the implicitly-defined constructor would satisfy the
@@ -1450,7 +1476,7 @@ void CXXRecordDecl::completeDefinition()

   void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap
*FinalOverriders) {
     RecordDecl::completeDefinition();
-
+
     // If the class may be abstract (but hasn't been marked as such),
check
for
     // any pure final overriders.
     if (mayBeAbstract()) {

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Tue Aug  8 12:12:28 2017
@@ -30,38 +30,9 @@ void CGCXXABI::ErrorUnsupportedABI(CodeG
   }

   bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const {
-  // If RD has a non-trivial move or copy constructor, we cannot copy
the
-  // argument.
-  if (RD->hasNonTrivialCopyConstructor() ||
RD->hasNonTrivialMoveConstructor())
-    return false;
-
-  // If RD has a non-trivial destructor, we cannot copy the argument.
-  if (RD->hasNonTrivialDestructor())
-    return false;
-
     // We can only copy the argument if there exists at least one
trivial,
     // non-deleted copy or move constructor.
-  // FIXME: This assumes that all lazily declared copy and move
constructors are
-  // not deleted.  This assumption might not be true in some corner
cases.
-  bool CopyDeleted = false;
-  bool MoveDeleted = false;
-  for (const CXXConstructorDecl *CD : RD->ctors()) {
-    if (CD->isCopyConstructor() || CD->isMoveConstructor()) {
-      assert(CD->isTrivial());
-      // We had at least one undeleted trivial copy or move ctor.
Return
-      // directly.
-      if (!CD->isDeleted())
-        return true;
-      if (CD->isCopyConstructor())
-        CopyDeleted = true;
-      else
-        MoveDeleted = true;
-    }
-  }
-
-  // If all trivial copy and move constructors are deleted, we cannot
copy the
-  // argument.
-  return !(CopyDeleted && MoveDeleted);
+  return RD->canPassInRegisters();
   }

   llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Aug  8 12:12:28 2017
@@ -63,11 +63,8 @@ public:
     bool classifyReturnType(CGFunctionInfo &FI) const override;

     RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override
{
-    // Structures with either a non-trivial destructor or a non-trivial
-    // copy constructor are always indirect.
-    // FIXME: Use canCopyArgument() when it is fixed to handle lazily
declared
-    // special members.
-    if (RD->hasNonTrivialDestructor() ||
RD->hasNonTrivialCopyConstructor())
+    // If C++ prohibits us from making a copy, pass by address.
+    if (!canCopyArgument(RD))
         return RAA_Indirect;
       return RAA_Default;
     }
@@ -1014,10 +1011,8 @@ bool ItaniumCXXABI::classifyReturnType(C
     if (!RD)
       return false;

-  // Return indirectly if we have a non-trivial copy ctor or
non-trivial
dtor.
-  // FIXME: Use canCopyArgument() when it is fixed to handle lazily
declared
-  // special members.
-  if (RD->hasNonTrivialDestructor() ||
RD->hasNonTrivialCopyConstructor()) {
+  // If C++ prohibits us from making a copy, return by address.
+  if (!canCopyArgument(RD)) {
       auto Align =
CGM.getContext().getTypeAlignInChars(FI.getReturnType());
       FI.getReturnInfo() = ABIArgInfo::getIndirect(Align,
/*ByVal=*/false);
       return true;

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Aug  8 12:12:28 2017
@@ -819,46 +819,44 @@ MicrosoftCXXABI::getRecordArgABI(const C
       return RAA_Default;

     case llvm::Triple::x86_64:
-    // Win64 passes objects with non-trivial copy ctors indirectly.
-    if (RD->hasNonTrivialCopyConstructor())
-      return RAA_Indirect;
-
-    // If an object has a destructor, we'd really like to pass it
indirectly
+    // If a class has a destructor, we'd really like to pass it
indirectly
       // because it allows us to elide copies.  Unfortunately, MSVC
makes
that
       // impossible for small types, which it will pass in a single
register or
       // stack slot. Most objects with dtors are large-ish, so handle
that
early.
       // We can't call out all large objects as being indirect because
there are
       // multiple x64 calling conventions and the C++ ABI code shouldn't
dictate
       // how we pass large POD types.
+    //
+    // Note: This permits small classes with nontrivial destructors to
be
+    // passed in registers, which is non-conforming.
       if (RD->hasNonTrivialDestructor() &&
           getContext().getTypeSize(RD->getTypeForDecl()) > 64)
         return RAA_Indirect;

-    // If this is true, the implicit copy constructor that Sema would
have
-    // created would not be deleted. FIXME: We should provide a more
direct way
-    // for CodeGen to ask whether the constructor was deleted.
-    if (!RD->hasUserDeclaredCopyConstructor() &&
-        !RD->hasUserDeclaredMoveConstructor() &&
-        !RD->needsOverloadResolutionForMoveConstructor() &&
-        !RD->hasUserDeclaredMoveAssignment() &&
-        !RD->needsOverloadResolutionForMoveAssignment())
-      return RAA_Default;
-
-    // Otherwise, Sema should have created an implicit copy constructor
if
-    // needed.
-    assert(!RD->needsImplicitCopyConstructor());
-
-    // We have to make sure the trivial copy constructor isn't deleted.
-    for (const CXXConstructorDecl *CD : RD->ctors()) {
-      if (CD->isCopyConstructor()) {
-        assert(CD->isTrivial());
-        // We had at least one undeleted trivial copy ctor.  Return
directly.
-        if (!CD->isDeleted())
-          return RAA_Default;
+    // If a class has at least one non-deleted, trivial copy
constructor,
it
+    // is passed according to the C ABI. Otherwise, it is passed
indirectly.
+    //
+    // Note: This permits classes with non-trivial copy or move ctors
to
be
+    // passed in registers, so long as they *also* have a trivial copy
ctor,
+    // which is non-conforming.
+    if (RD->needsImplicitCopyConstructor()) {
+      // If the copy ctor has not yet been declared, we can read its
triviality
+      // off the AST.
+      if (!RD->defaultedCopyConstructorIsDeleted() &&
+          RD->hasTrivialCopyConstructor())
+        return RAA_Default;
+    } else {
+      // Otherwise, we need to find the copy constructor(s) and ask.
+      for (const CXXConstructorDecl *CD : RD->ctors()) {
+        if (CD->isCopyConstructor()) {
+          // We had at least one nondeleted trivial copy ctor.  Return
directly.
+          if (!CD->isDeleted() && CD->isTrivial())
+            return RAA_Default;
+        }
         }
       }

-    // The trivial copy constructor was deleted.  Return indirectly.
+    // We have no trivial, non-deleted copy constructor.
       return RAA_Indirect;
     }


Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Aug  8 12:12:28 2017
@@ -5726,6 +5726,53 @@ static void DefineImplicitSpecialMember(
     }
   }

+/// Determine whether a type is permitted to be passed or returned in
+/// registers, per C++ [class.temporary]p3.
+static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) {
+  if (D->isDependentType() || D->isInvalidDecl())
+    return false;
+
+  // Per C++ [class.temporary]p3, the relevant condition is:
+  //   each copy constructor, move constructor, and destructor of X is
+  //   either trivial or deleted, and X has at least one non-deleted
copy
+  //   or move constructor
+  bool HasNonDeletedCopyOrMove = false;
+
+  if (D->needsImplicitCopyConstructor() &&
+      !D->defaultedCopyConstructorIsDeleted()) {
+    if (!D->hasTrivialCopyConstructor())
+      return false;
+    HasNonDeletedCopyOrMove = true;
+  }
+
+  if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor()
&&
+      !D->defaultedMoveConstructorIsDeleted()) {
+    if (!D->hasTrivialMoveConstructor())
+      return false;
+    HasNonDeletedCopyOrMove = true;
+  }
+
+  if (D->needsImplicitDestructor() &&
!D->defaultedDestructorIsDeleted()
&&
+      !D->hasTrivialDestructor())
+    return false;
+
+  for (const CXXMethodDecl *MD : D->methods()) {
+    if (MD->isDeleted())
+      continue;
+
+    auto *CD = dyn_cast<CXXConstructorDecl>(MD);
+    if (CD && CD->isCopyOrMoveConstructor())
+      HasNonDeletedCopyOrMove = true;
+    else if (!isa<CXXDestructorDecl>(MD))
+      continue;
+
+    if (!MD->isTrivial())
+      return false;
+  }
+
+  return HasNonDeletedCopyOrMove;
+}
+
   /// \brief Perform semantic checks on a class definition that has been
   /// completing, introducing implicitly-declared members, checking for
   /// abstract types, etc.
@@ -5870,6 +5917,8 @@ void Sema::CheckCompletedCXXClass(CXXRec
     }

     checkClassLevelDLLAttribute(Record);
+
+  Record->setCanPassInRegisters(computeCanPassInRegisters(*this,
Record));
   }

   /// Look up the special member function that would be called by a
special
@@ -7496,8 +7545,7 @@ void Sema::ActOnFinishCXXMemberSpecifica

reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
                 FieldCollector->getCurNumFields()), LBrac, RBrac,
AttrList);

-  CheckCompletedCXXClass(
-                        dyn_cast_or_null<CXXRecordDecl>(TagDecl));
+  CheckCompletedCXXClass(dyn_cast_or_null<CXXRecordDecl>(TagDecl));
   }

   /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
@@ -11929,8 +11977,10 @@ CXXConstructorDecl *Sema::DeclareImplici
     Scope *S = getScopeForContext(ClassDecl);
     CheckImplicitSpecialMemberDeclaration(S, CopyConstructor);

-  if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
+  if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) {
+    ClassDecl->setImplicitCopyConstructorIsDeleted();
       SetDeclDeleted(CopyConstructor, ClassLoc);
+  }

     if (S)
       PushOnScopeChains(CopyConstructor, S, false);

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Tue Aug  8 12:12:28
2017
@@ -1559,9 +1559,11 @@ void ASTDeclReader::ReadCXXDefinitionDat
     Data.HasUninitializedFields = Record.readInt();
     Data.HasInheritedConstructor = Record.readInt();
     Data.HasInheritedAssignment = Record.readInt();
+  Data.NeedOverloadResolutionForCopyConstructor = Record.readInt();
     Data.NeedOverloadResolutionForMoveConstructor = Record.readInt();
     Data.NeedOverloadResolutionForMoveAssignment = Record.readInt();
     Data.NeedOverloadResolutionForDestructor = Record.readInt();
+  Data.DefaultedCopyConstructorIsDeleted = Record.readInt();
     Data.DefaultedMoveConstructorIsDeleted = Record.readInt();
     Data.DefaultedMoveAssignmentIsDeleted = Record.readInt();
     Data.DefaultedDestructorIsDeleted = Record.readInt();
@@ -1570,6 +1572,7 @@ void ASTDeclReader::ReadCXXDefinitionDat
     Data.HasIrrelevantDestructor = Record.readInt();
     Data.HasConstexprNonCopyMoveConstructor = Record.readInt();
     Data.HasDefaultedDefaultConstructor = Record.readInt();
+  Data.CanPassInRegisters = Record.readInt();
     Data.DefaultedDefaultConstructorIsConstexpr = Record.readInt();
     Data.HasConstexprDefaultConstructor = Record.readInt();
     Data.HasNonLiteralTypeFieldsOrBases = Record.readInt();
@@ -1697,9 +1700,11 @@ void ASTDeclReader::MergeDefinitionData(
     MATCH_FIELD(HasUninitializedFields)
     MATCH_FIELD(HasInheritedConstructor)
     MATCH_FIELD(HasInheritedAssignment)
+  MATCH_FIELD(NeedOverloadResolutionForCopyConstructor)
     MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)
     MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)
     MATCH_FIELD(NeedOverloadResolutionForDestructor)
+  MATCH_FIELD(DefaultedCopyConstructorIsDeleted)
     MATCH_FIELD(DefaultedMoveConstructorIsDeleted)
     MATCH_FIELD(DefaultedMoveAssignmentIsDeleted)
     MATCH_FIELD(DefaultedDestructorIsDeleted)
@@ -1708,6 +1713,7 @@ void ASTDeclReader::MergeDefinitionData(
     MATCH_FIELD(HasIrrelevantDestructor)
     OR_FIELD(HasConstexprNonCopyMoveConstructor)
     OR_FIELD(HasDefaultedDefaultConstructor)
+  MATCH_FIELD(CanPassInRegisters)
     MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
     OR_FIELD(HasConstexprDefaultConstructor)
     MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Aug  8 12:12:28 2017
@@ -5875,9 +5875,11 @@ void ASTRecordWriter::AddCXXDefinitionDa
     Record->push_back(Data.HasUninitializedFields);
     Record->push_back(Data.HasInheritedConstructor);
     Record->push_back(Data.HasInheritedAssignment);
+  Record->push_back(Data.NeedOverloadResolutionForCopyConstructor);
     Record->push_back(Data.NeedOverloadResolutionForMoveConstructor);
     Record->push_back(Data.NeedOverloadResolutionForMoveAssignment);
     Record->push_back(Data.NeedOverloadResolutionForDestructor);
+  Record->push_back(Data.DefaultedCopyConstructorIsDeleted);
     Record->push_back(Data.DefaultedMoveConstructorIsDeleted);
     Record->push_back(Data.DefaultedMoveAssignmentIsDeleted);
     Record->push_back(Data.DefaultedDestructorIsDeleted);
@@ -5886,6 +5888,7 @@ void ASTRecordWriter::AddCXXDefinitionDa
     Record->push_back(Data.HasIrrelevantDestructor);
     Record->push_back(Data.HasConstexprNonCopyMoveConstructor);
     Record->push_back(Data.HasDefaultedDefaultConstructor);
+  Record->push_back(Data.CanPassInRegisters);
     Record->push_back(Data.DefaultedDefaultConstructorIsConstexpr);
     Record->push_back(Data.HasConstexprDefaultConstructor);
     Record->push_back(Data.HasNonLiteralTypeFieldsOrBases);

Modified: cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/uncopyable-args.cpp Tue Aug  8 12:12:28
2017
@@ -1,5 +1,6 @@
   // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown
-emit-llvm
-o - %s | FileCheck %s
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o
-
%s | FileCheck %s -check-prefix=WIN64
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o
-
%s -fms-compatibility -fms-compatibility-version=18 | FileCheck %s
-check-prefix=WIN64 -check-prefix=WIN64-18
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o
-
%s -fms-compatibility -fms-compatibility-version=19 | FileCheck %s
-check-prefix=WIN64 -check-prefix=WIN64-19

   namespace trivial {
   // Trivial structs should be passed directly.
@@ -52,12 +53,11 @@ void foo(A);
   void bar() {
     foo({});
   }
-// FIXME: The copy ctor is implicitly deleted.
-// CHECK-DISABLED-LABEL: define void @_ZN9move_ctor3barEv()
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
-// CHECK-DISABLED-NOT: call
-// CHECK-DISABLED: call void
@_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}})
-// CHECK-DISABLED-LABEL: declare void
@_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)
+// CHECK-LABEL: define void @_ZN9move_ctor3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT: call
+// CHECK: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*
%{{.*}})
+// CHECK-LABEL: declare void
@_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)

   // WIN64-LABEL: declare void
@"\01?foo@move_ctor@@YAXUA@1@@Z"(%"struct.move_ctor::A"*)
   }
@@ -73,12 +73,11 @@ void foo(A);
   void bar() {
     foo({});
   }
-// FIXME: The copy ctor is deleted.
-// CHECK-DISABLED-LABEL: define void @_ZN11all_deleted3barEv()
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
-// CHECK-DISABLED-NOT: call
-// CHECK-DISABLED: call void
@_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
-// CHECK-DISABLED-LABEL: declare void
@_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)
+// CHECK-LABEL: define void @_ZN11all_deleted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT: call
+// CHECK: call void
@_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
+// CHECK-LABEL: declare void
@_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)

   // WIN64-LABEL: declare void
@"\01?foo@all_deleted@@YAXUA@1@@Z"(%"struct.all_deleted::A"*)
   }
@@ -93,14 +92,15 @@ void foo(A);
   void bar() {
     foo({});
   }
-// FIXME: The copy and move ctors are implicitly deleted.
-// CHECK-DISABLED-LABEL: define void @_ZN18implicitly_deleted3barEv()
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
-// CHECK-DISABLED-NOT: call
-// CHECK-DISABLED: call void
@_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*
%{{.*}})
-// CHECK-DISABLED-LABEL: declare void
@_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
-
-// WIN64-LABEL: declare void

@"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(%"struct.implicitly_deleted::A"*)
+// CHECK-LABEL: define void @_ZN18implicitly_deleted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT: call
+// CHECK: call void
@_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*
%{{.*}})
+// CHECK-LABEL: declare void
@_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
+
+// In MSVC 2013, the copy ctor is not deleted by a move assignment. In
MSVC 2015, it is.
+// WIN64-18-LABEL: declare void
@"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(i64
+// WIN64-19-LABEL: declare void

@"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(%"struct.implicitly_deleted::A"*)
   }

   namespace one_deleted {
@@ -113,12 +113,11 @@ void foo(A);
   void bar() {
     foo({});
   }
-// FIXME: The copy constructor is implicitly deleted.
-// CHECK-DISABLED-LABEL: define void @_ZN11one_deleted3barEv()
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
-// CHECK-DISABLED-NOT: call
-// CHECK-DISABLED: call void
@_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
-// CHECK-DISABLED-LABEL: declare void
@_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)
+// CHECK-LABEL: define void @_ZN11one_deleted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT: call
+// CHECK: call void
@_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
+// CHECK-LABEL: declare void
@_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)

   // WIN64-LABEL: declare void
@"\01?foo@one_deleted@@YAXUA@1@@Z"(%"struct.one_deleted::A"*)
   }
@@ -195,12 +194,10 @@ void foo(B);
   void bar() {
     foo({});
   }
-// FIXME: This class has a non-trivial copy ctor and a trivial copy
ctor.
It's
-// not clear whether we should pass by address or in registers.
-// CHECK-DISABLED-LABEL: define void @_ZN14two_copy_ctors3barEv()
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
-// CHECK-DISABLED: call void
@_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
-// CHECK-DISABLED-LABEL: declare void
@_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)
+// CHECK-LABEL: define void @_ZN14two_copy_ctors3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK: call void
@_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
+// CHECK-LABEL: declare void
@_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)

   // WIN64-LABEL: declare void
@"\01?foo@two_copy_ctors@@YAXUB@1@@Z"(%"struct.two_copy_ctors::B"*)
   }
@@ -212,6 +209,7 @@ struct A {
     void *p;
   };
   void *foo(A a) { return a.p; }
+// CHECK-LABEL: define i8*
@_ZN15definition_only3fooENS_1AE(%"struct.definition_only::A"*
   // WIN64-LABEL: define i8*
@"\01?foo@definition_only@@YAPEAXUA@1@@Z"(%"struct.definition_only::A"*
   }

@@ -226,6 +224,7 @@ struct A {
     B b;
   };
   void *foo(A a) { return a.b.p; }
+// CHECK-LABEL: define i8*
@_ZN17deleted_by_member3fooENS_1AE(%"struct.deleted_by_member::A"*
   // WIN64-LABEL: define i8*

@"\01?foo@deleted_by_member@@YAPEAXUA@1@@Z"(%"struct.deleted_by_member::A"*
   }

@@ -239,6 +238,7 @@ struct A : B {
     A();
   };
   void *foo(A a) { return a.p; }
+// CHECK-LABEL: define i8*
@_ZN15deleted_by_base3fooENS_1AE(%"struct.deleted_by_base::A"*
   // WIN64-LABEL: define i8*
@"\01?foo@deleted_by_base@@YAPEAXUA@1@@Z"(%"struct.deleted_by_base::A"*
   }

@@ -253,6 +253,7 @@ struct A {
     B b;
   };
   void *foo(A a) { return a.b.p; }
+// CHECK-LABEL: define i8*

@_ZN22deleted_by_member_copy3fooENS_1AE(%"struct.deleted_by_member_copy::A"*
   // WIN64-LABEL: define i8*

@"\01?foo@deleted_by_member_copy@@YAPEAXUA@1@@Z"(%"struct.deleted_by_member_copy::A"*
   }

@@ -266,6 +267,7 @@ struct A : B {
     A();
   };
   void *foo(A a) { return a.p; }
+// CHECK-LABEL: define i8*
@_ZN20deleted_by_base_copy3fooENS_1AE(%"struct.deleted_by_base_copy::A"*
   // WIN64-LABEL: define i8*

@"\01?foo@deleted_by_base_copy@@YAPEAXUA@1@@Z"(%"struct.deleted_by_base_copy::A"*
   }

@@ -275,6 +277,75 @@ struct A {
     A(const A &o) = delete;
     void *p;
   };
+// CHECK-LABEL: define i8*
@_ZN15explicit_delete3fooENS_1AE(%"struct.explicit_delete::A"*
   // WIN64-LABEL: define i8*
@"\01?foo@explicit_delete@@YAPEAXUA@1@@Z"(%"struct.explicit_delete::A"*
   void *foo(A a) { return a.p; }
   }
+
+namespace implicitly_deleted_copy_ctor {
+struct A {
+  // No move ctor due to copy assignment.
+  A &operator=(const A&);
+  // Deleted copy ctor due to rvalue ref member.
+  int &&ref;
+};
+// CHECK-LABEL: define {{.*}}

@_ZN28implicitly_deleted_copy_ctor3fooENS_1AE(%"struct.implicitly_deleted_copy_ctor::A"*
+// WIN64-LABEL: define {{.*}}

@"\01?foo@implicitly_deleted_copy_ctor@@YAAEAHUA@1@@Z"(%"struct.implicitly_deleted_copy_ctor::A"*
+int &foo(A a) { return a.ref; }
+
+struct B {
+  // Passed direct: has non-deleted trivial copy ctor.
+  B &operator=(const B&);
+  int &ref;
+};
+int &foo(B b) { return b.ref; }
+// CHECK-LABEL: define {{.*}}
@_ZN28implicitly_deleted_copy_ctor3fooENS_1BE(i32*
+// WIN64-LABEL: define {{.*}}
@"\01?foo@implicitly_deleted_copy_ctor@@YAAEAHUB@1@@Z"(i64
+
+struct X { X(const X&); };
+struct Y { Y(const Y&) = default; };
+
+union C {
+  C &operator=(const C&);
+  // Passed indirect: copy ctor deleted due to variant member with
nontrivial copy ctor.
+  X x;
+  int n;
+};
+int foo(C c) { return c.n; }
+// CHECK-LABEL: define {{.*}}

@_ZN28implicitly_deleted_copy_ctor3fooENS_1CE(%"union.implicitly_deleted_copy_ctor::C"*
+// WIN64-LABEL: define {{.*}}

@"\01?foo@implicitly_deleted_copy_ctor@@YAHTC@1@@Z"(%"union.implicitly_deleted_copy_ctor::C"*
+
+struct D {
+  D &operator=(const D&);
+  // Passed indirect: copy ctor deleted due to variant member with
nontrivial copy ctor.
+  union {
+    X x;
+    int n;
+  };
+};
+int foo(D d) { return d.n; }
+// CHECK-LABEL: define {{.*}}

@_ZN28implicitly_deleted_copy_ctor3fooENS_1DE(%"struct.implicitly_deleted_copy_ctor::D"*
+// WIN64-LABEL: define {{.*}}

@"\01?foo@implicitly_deleted_copy_ctor@@YAHUD@1@@Z"(%"struct.implicitly_deleted_copy_ctor::D"*
+
+union E {
+  // Passed direct: has non-deleted trivial copy ctor.
+  E &operator=(const E&);
+  Y y;
+  int n;
+};
+int foo(E e) { return e.n; }
+// CHECK-LABEL: define {{.*}}
@_ZN28implicitly_deleted_copy_ctor3fooENS_1EE(i32
+// WIN64-LABEL: define {{.*}}
@"\01?foo@implicitly_deleted_copy_ctor@@YAHTE@1@@Z"(i32
+
+struct F {
+  // Passed direct: has non-deleted trivial copy ctor.
+  F &operator=(const F&);
+  union {
+    Y y;
+    int n;
+  };
+};
+int foo(F f) { return f.n; }
+// CHECK-LABEL: define {{.*}}
@_ZN28implicitly_deleted_copy_ctor3fooENS_1FE(i32
+// WIN64-LABEL: define {{.*}}
@"\01?foo@implicitly_deleted_copy_ctor@@YAHUF@1@@Z"(i32
+}

Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
URL:

http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=310401&r1=310400&r2=310401&view=diff


==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
(original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Tue Aug
8 12:12:28 2017
@@ -1108,26 +1108,35 @@ TEST(ConstructorDeclaration, IsExplicit)
   }

   TEST(ConstructorDeclaration, Kinds) {
-  EXPECT_TRUE(matches("struct S { S(); };",
-                      cxxConstructorDecl(isDefaultConstructor())));
-  EXPECT_TRUE(notMatches("struct S { S(); };",
-                         cxxConstructorDecl(isCopyConstructor())));
-  EXPECT_TRUE(notMatches("struct S { S(); };",
-                         cxxConstructorDecl(isMoveConstructor())));
+  EXPECT_TRUE(matches(
+      "struct S { S(); };",
+      cxxConstructorDecl(isDefaultConstructor(),
unless(isImplicit()))));
+  EXPECT_TRUE(notMatches(
+      "struct S { S(); };",
+      cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));
+  EXPECT_TRUE(notMatches(
+      "struct S { S(); };",
+      cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));

-  EXPECT_TRUE(notMatches("struct S { S(const S&); };",
-                         cxxConstructorDecl(isDefaultConstructor())));
-  EXPECT_TRUE(matches("struct S { S(const S&); };",
-                      cxxConstructorDecl(isCopyConstructor())));
-  EXPECT_TRUE(notMatches("struct S { S(const S&); };",
-                         cxxConstructorDecl(isMoveConstructor())));
+  EXPECT_TRUE(notMatches(
+      "struct S { S(const S&); };",
+      cxxConstructorDecl(isDefaultConstructor(),
unless(isImplicit()))));
+  EXPECT_TRUE(matches(
+      "struct S { S(const S&); };",
+      cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));
+  EXPECT_TRUE(notMatches(
+      "struct S { S(const S&); };",
+      cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));

-  EXPECT_TRUE(notMatches("struct S { S(S&&); };",
-                         cxxConstructorDecl(isDefaultConstructor())));
-  EXPECT_TRUE(notMatches("struct S { S(S&&); };",
-                         cxxConstructorDecl(isCopyConstructor())));
-  EXPECT_TRUE(matches("struct S { S(S&&); };",
-                      cxxConstructorDecl(isMoveConstructor())));
+  EXPECT_TRUE(notMatches(
+      "struct S { S(S&&); };",
+      cxxConstructorDecl(isDefaultConstructor(),
unless(isImplicit()))));
+  EXPECT_TRUE(notMatches(
+      "struct S { S(S&&); };",
+      cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));
+  EXPECT_TRUE(matches(
+      "struct S { S(S&&); };",
+      cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));
   }

   TEST(ConstructorDeclaration, IsUserProvided) {


_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to