Javier-varez created this revision.
Herald added a project: All.
Javier-varez requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

>From [class.copy.ctor]:

  A non-template constructor for class X is a copy constructor if its first
  parameter is of type X&, const X&, volatile X& or const volatile X&, and
  either there are no other parameters or else all other parameters have
  default arguments (9.3.4.7).
  
  A copy/move constructor for class X is trivial if it is not user-provided and 
if:
  - class X has no virtual functions (11.7.3) and no virtual base classes 
(11.7.2), and
  - the constructor selected to copy/move each direct base class subobject is 
trivial, and
  - or each non-static data member of X that is of class type (or array 
thereof),
    the constructor selected to copy/move that member is trivial;
  
  otherwise the copy/move constructor is non-trivial.

So `T(T&) = default`; should be trivial assuming that the previous
provisions are met.

This works in GCC, but not in Clang at the moment:
https://godbolt.org/z/fTGe71b6P


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D127593

Files:
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/special/class.copy/p12-0x.cpp
  clang/test/CXX/special/class.copy/p25-0x.cpp


Index: clang/test/CXX/special/class.copy/p25-0x.cpp
===================================================================
--- clang/test/CXX/special/class.copy/p25-0x.cpp
+++ clang/test/CXX/special/class.copy/p25-0x.cpp
@@ -31,7 +31,22 @@
 struct NonConstCopy {
   NonConstCopy &operator=(NonConstCopy &) = default;
 };
-using _ = not_trivially_assignable<NonConstCopy>;
+static_assert(__has_trivial_assign(NonConstCopy), "");
+static_assert(__is_trivially_assignable(NonConstCopy&, NonConstCopy&), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&, const NonConstCopy &), 
"");
+static_assert(!__is_trivially_assignable(NonConstCopy&, NonConstCopy), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&, NonConstCopy&&), "");
+static_assert(__is_trivially_assignable(NonConstCopy&&, NonConstCopy&), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&&, const NonConstCopy 
&), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&&, NonConstCopy), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&&, NonConstCopy&&), "");
+
+struct DefaultedSpecialMembers {
+  DefaultedSpecialMembers &operator=(const DefaultedSpecialMembers &) = 
default;
+  DefaultedSpecialMembers &operator=(DefaultedSpecialMembers &) = default;
+  DefaultedSpecialMembers &operator=(DefaultedSpecialMembers &&) = default;
+};
+using _ = trivially_assignable<DefaultedSpecialMembers>;
 
 // class X has no virtual functions
 struct VFn {
Index: clang/test/CXX/special/class.copy/p12-0x.cpp
===================================================================
--- clang/test/CXX/special/class.copy/p12-0x.cpp
+++ clang/test/CXX/special/class.copy/p12-0x.cpp
@@ -28,7 +28,18 @@
 struct NonConstCopy {
   NonConstCopy(NonConstCopy &) = default;
 };
-using _ = not_trivially_copyable<NonConstCopy>;
+static_assert(__has_trivial_copy(NonConstCopy), "");
+static_assert(__is_trivially_constructible(NonConstCopy, NonConstCopy&), "");
+static_assert(!__is_trivially_constructible(NonConstCopy, NonConstCopy), "");
+static_assert(!__is_trivially_constructible(NonConstCopy, const NonConstCopy 
&), "");
+static_assert(!__is_trivially_constructible(NonConstCopy, NonConstCopy &&), 
"");
+
+struct DefaultedSpecialMembers {
+  DefaultedSpecialMembers(const DefaultedSpecialMembers&) = default;
+  DefaultedSpecialMembers(DefaultedSpecialMembers &) = default;
+  DefaultedSpecialMembers(DefaultedSpecialMembers &&) = default;
+};
+using _ = trivially_copyable<DefaultedSpecialMembers>;
 
 // class X has no virtual functions
 struct VFn {
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -9772,11 +9772,9 @@
 
   case CXXCopyConstructor:
   case CXXCopyAssignment: {
-    // Trivial copy operations always have const, non-volatile parameter types.
-    ConstArg = true;
     const ParmVarDecl *Param0 = MD->getParamDecl(0);
     const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>();
-    if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) {
+    if (!RT) {
       if (Diagnose)
         Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
           << Param0->getSourceRange() << Param0->getType()
@@ -9784,6 +9782,10 @@
                Context.getRecordType(RD).withConst());
       return false;
     }
+
+    if (RT && ((RT->getPointeeType().getCVRQualifiers() & Qualifiers::Const) 
== Qualifiers::Const)) {
+      ConstArg = true;
+    }
     break;
   }
 


Index: clang/test/CXX/special/class.copy/p25-0x.cpp
===================================================================
--- clang/test/CXX/special/class.copy/p25-0x.cpp
+++ clang/test/CXX/special/class.copy/p25-0x.cpp
@@ -31,7 +31,22 @@
 struct NonConstCopy {
   NonConstCopy &operator=(NonConstCopy &) = default;
 };
-using _ = not_trivially_assignable<NonConstCopy>;
+static_assert(__has_trivial_assign(NonConstCopy), "");
+static_assert(__is_trivially_assignable(NonConstCopy&, NonConstCopy&), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&, const NonConstCopy &), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&, NonConstCopy), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&, NonConstCopy&&), "");
+static_assert(__is_trivially_assignable(NonConstCopy&&, NonConstCopy&), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&&, const NonConstCopy &), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&&, NonConstCopy), "");
+static_assert(!__is_trivially_assignable(NonConstCopy&&, NonConstCopy&&), "");
+
+struct DefaultedSpecialMembers {
+  DefaultedSpecialMembers &operator=(const DefaultedSpecialMembers &) = default;
+  DefaultedSpecialMembers &operator=(DefaultedSpecialMembers &) = default;
+  DefaultedSpecialMembers &operator=(DefaultedSpecialMembers &&) = default;
+};
+using _ = trivially_assignable<DefaultedSpecialMembers>;
 
 // class X has no virtual functions
 struct VFn {
Index: clang/test/CXX/special/class.copy/p12-0x.cpp
===================================================================
--- clang/test/CXX/special/class.copy/p12-0x.cpp
+++ clang/test/CXX/special/class.copy/p12-0x.cpp
@@ -28,7 +28,18 @@
 struct NonConstCopy {
   NonConstCopy(NonConstCopy &) = default;
 };
-using _ = not_trivially_copyable<NonConstCopy>;
+static_assert(__has_trivial_copy(NonConstCopy), "");
+static_assert(__is_trivially_constructible(NonConstCopy, NonConstCopy&), "");
+static_assert(!__is_trivially_constructible(NonConstCopy, NonConstCopy), "");
+static_assert(!__is_trivially_constructible(NonConstCopy, const NonConstCopy &), "");
+static_assert(!__is_trivially_constructible(NonConstCopy, NonConstCopy &&), "");
+
+struct DefaultedSpecialMembers {
+  DefaultedSpecialMembers(const DefaultedSpecialMembers&) = default;
+  DefaultedSpecialMembers(DefaultedSpecialMembers &) = default;
+  DefaultedSpecialMembers(DefaultedSpecialMembers &&) = default;
+};
+using _ = trivially_copyable<DefaultedSpecialMembers>;
 
 // class X has no virtual functions
 struct VFn {
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -9772,11 +9772,9 @@
 
   case CXXCopyConstructor:
   case CXXCopyAssignment: {
-    // Trivial copy operations always have const, non-volatile parameter types.
-    ConstArg = true;
     const ParmVarDecl *Param0 = MD->getParamDecl(0);
     const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>();
-    if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) {
+    if (!RT) {
       if (Diagnose)
         Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
           << Param0->getSourceRange() << Param0->getType()
@@ -9784,6 +9782,10 @@
                Context.getRecordType(RD).withConst());
       return false;
     }
+
+    if (RT && ((RT->getPointeeType().getCVRQualifiers() & Qualifiers::Const) == Qualifiers::Const)) {
+      ConstArg = true;
+    }
     break;
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to