Hi Diana,

On 14/08/17 11:27, Diana Picus wrote:
Hi,

Strangely enough, it turns out that if I run
Asan-armhf-with-calls-Noinst-Test on the command line it fails,
although it doesn't fail when run with lit. I've attached the stack
trace from gdb. It looks like some trouble passing down va_arg
parameters, but I haven't looked into too much details. The segfault
happens when we try to do a   ldrb   r3, [r0, r1], with r1 set to 0 by
the current function and r0 passed down from the caller. I'm not sure
if this is the exact same problem as the other tests, but feel free to
have a look at that code.
  That smells like our patch is interfering in some way...

Meanwhile, I've removed some clutter from Asan-armhf-with-calls-Test
(which is the original failure that we were seeing) and left only one
failing test that seemed small enough. I'll try to look at the
disassembly before/after the patch and maybe even run valgrind on it
(running it on the original binary naturally takes forever).

Let me know if there's anything else I could try. I can also send you
disassembly or even LLVM IR for the Asan-armhf-with-calls-Noinst-Test
if you think it helps.
Would you be able to run clang -E on the translation unit that crashes and send it over? If you could give us a minimal reproducer it would be even better.

Cheers, Vassil

Cheers,
Diana

On 11 August 2017 at 15:34, Diana Picus <diana.pi...@linaro.org> wrote:
Well, these are ASAN tests, I'm not sure how that would interact with Valgrind.
Anyway, I'll try to reproduce the environment, I'm guessing it would
be best to catch this in gdb so I can actually see what's going on.

On 11 August 2017 at 15:21, Vassil Vassilev <v.g.vassi...@gmail.com> wrote:
That's really strange. It looks like some random behavior. Did you run some 
memory checker like valgrind?

Do the environment provided by the test runner and yours match?

Sent from my phone. Please excuse my brevity.

On 11 Aug 2017, at 15:58, Diana Picus <diana.pi...@linaro.org> wrote:

Hi again,

I finally got the debug build, but unfortunately the stack traces that
the tests print look the same. My suspicion is that this is because
the addresses printed by the tests are funny (i.e. odd numbers instead
of divisible by 4). I tried to follow those addresses in an objdump of
the executable, but I didn't have much success since most of them
weren't really pointing to call instructions.

When I try to run the tests manually in the shell or in gdb, they pass.

I'm not sure what else to try. Thoughts?

Thanks,
Diana

On 11 August 2017 at 11:14, Diana Picus <diana.pi...@linaro.org> wrote:
Hi guys,

I'm SO sorry about the delays. I've been having all sorts of trouble
getting that debug build on the board (from ld running out of memory
to the board just crashing on me, in which case I need to ask someone
else to reboot it because I can't power cycle it remotely). I can
assure you this is one of my top priorities, I'll get those stack
traces as soon as I can.

Thanks for your patience and sorry again,
Diana

On 10 August 2017 at 22:55, Richard Smith <rich...@metafoo.co.uk> wrote:
Any news on this? We want this change in Clang 5, so the sooner we can
understand and fix this regression the better...

On 10 August 2017 at 01:28, Diana Picus via cfe-commits
<cfe-commits@lists.llvm.org> wrote:
Hi Vassil,

My build is in progress, but since it's a full build it's probably
going to take another couple of hours to complete. I'll let you know
when it's done.

Thanks,
Diana

On 10 August 2017 at 10:09, Vassil Vassilev <v.g.vassi...@gmail.com>
wrote:
It looks like I can not reproduce it on osx (non-arm)... :(
On 09/08/17 22:54, Diana Picus wrote:

Reverting this also fixed the selfhost bots:


http://lab.llvm.org:8011/builders/clang-cmake-thumbv7-a15-full-sh/builds/2142


http://lab.llvm.org:8011/builders/clang-cmake-armv7-a15-selfhost/builds/2309


http://lab.llvm.org:8011/builders/clang-cmake-armv7-a15-selfhost-neon/builds/1819

I'm afraid the logs for those look even less helpful.

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

Hi,

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

Regards,
Diana

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

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

Many thanks,
Vassil

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

Hi Richard,

I'm sorry but I've reverted this in r310464 because it was breaking
some ASAN tests on this bot:


http://lab.llvm.org:8011/builders/clang-cmake-armv7-a15-full/builds/9452

Please let me know if I can help debug this.

Cheers,
Diana

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

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

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

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

This fixes ABI differences between Clang and GCC:

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

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

This also fixes an ABI difference between Clang and MSVC:

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

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

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



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




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

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

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

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

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

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

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



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




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

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



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




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

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

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

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

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

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

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

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

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

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

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

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



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




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

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

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

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



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




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

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

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

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



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




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

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

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

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


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



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




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

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

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

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

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

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

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

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

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

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



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




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

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



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




==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Aug  8 12:12:28
2017
@@ -5875,9 +5875,11 @@ void ASTRecordWriter::AddCXXDefinitionDa
     Record->push_back(Data.HasUninitializedFields);
     Record->push_back(Data.HasInheritedConstructor);
     Record->push_back(Data.HasInheritedAssignment);
+
Record->push_back(Data.NeedOverloadResolutionForCopyConstructor);

Record->push_back(Data.NeedOverloadResolutionForMoveConstructor);

Record->push_back(Data.NeedOverloadResolutionForMoveAssignment);
     Record->push_back(Data.NeedOverloadResolutionForDestructor);
+  Record->push_back(Data.DefaultedCopyConstructorIsDeleted);
     Record->push_back(Data.DefaultedMoveConstructorIsDeleted);
     Record->push_back(Data.DefaultedMoveAssignmentIsDeleted);
     Record->push_back(Data.DefaultedDestructorIsDeleted);
@@ -5886,6 +5888,7 @@ void ASTRecordWriter::AddCXXDefinitionDa
     Record->push_back(Data.HasIrrelevantDestructor);
     Record->push_back(Data.HasConstexprNonCopyMoveConstructor);
     Record->push_back(Data.HasDefaultedDefaultConstructor);
+  Record->push_back(Data.CanPassInRegisters);

Record->push_back(Data.DefaultedDefaultConstructorIsConstexpr);
     Record->push_back(Data.HasConstexprDefaultConstructor);
     Record->push_back(Data.HasNonLiteralTypeFieldsOrBases);

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



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




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

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

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

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

@_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*
%{{.*}})
-// CHECK-DISABLED-LABEL: declare void

@_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
-
-// WIN64-LABEL: declare void



@"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(%"struct.implicitly_deleted::A"*)
+// CHECK-LABEL: define void @_ZN18implicitly_deleted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT: call
+// CHECK: call void

@_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*
%{{.*}})
+// CHECK-LABEL: declare void

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



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

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

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

   // WIN64-LABEL: declare void

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


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

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



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

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


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

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



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



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

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


@_ZN20deleted_by_base_copy3fooENS_1AE(%"struct.deleted_by_base_copy::A"*
   // WIN64-LABEL: define i8*



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

@@ -275,6 +277,75 @@ struct A {
     A(const A &o) = delete;
     void *p;
   };
+// CHECK-LABEL: define i8*
@_ZN15explicit_delete3fooENS_1AE(%"struct.explicit_delete::A"*
   // WIN64-LABEL: define i8*


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



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



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



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



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



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



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

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



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




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

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

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

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

   TEST(ConstructorDeclaration, IsUserProvided) {


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


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

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


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


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

Reply via email to