xref: /llvm-project/clang/test/CXX/special/class.copy/p12-0x.cpp (revision 0b89d1d59f82cf5b45c250cd5c3351e43ce35ef9)
1 // RUN: %clang_cc1 -std=c++11 -verify %s -Wno-deprecated-builtins -Wno-defaulted-function-deleted
2 // RUN: %clang_cc1 -std=c++11 -verify %s -Wno-deprecated-builtins -Wno-defaulted-function-deleted -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14
3 
4 // expected-no-diagnostics
5 
6 template<typename T, bool B> struct trivially_copyable_check {
7   static_assert(B == __has_trivial_copy(T), "");
8   static_assert(B == __is_trivially_constructible(T, T), "");
9   static_assert(B == __is_trivially_constructible(T, const T &), "");
10   static_assert(B == __is_trivially_constructible(T, T &&), "");
11   typedef void type;
12 };
13 template<typename T> using trivially_copyable =
14   typename trivially_copyable_check<T, true>::type;
15 template<typename T> using not_trivially_copyable =
16   typename trivially_copyable_check<T, false>::type;
17 
18 struct Trivial {};
19 using _ = trivially_copyable<Trivial>;
20 
21 // A copy/move constructor for class X is trivial if it is not user-provided,
22 struct UserProvided {
23   UserProvided(const UserProvided &);
24 };
25 using _ = not_trivially_copyable<UserProvided>;
26 
27 // its declared parameter type is the same as if it had been implicitly
28 // declared,
29 struct NonConstCopy {
30   NonConstCopy(NonConstCopy &) = default;
31 };
32 #if defined(CLANG_ABI_COMPAT) && CLANG_ABI_COMPAT <= 14
33 // Up until (and including) Clang 14, non-const copy constructors were not trivial because of dr2171
34 using _ = not_trivially_copyable<NonConstCopy>;
35 #else
36 // In the latest Clang version, all defaulted constructors are trivial, even if non-const, because
37 // dr2171 is fixed.
38 static_assert(__has_trivial_copy(NonConstCopy), "");
39 static_assert(__is_trivially_constructible(NonConstCopy, NonConstCopy &), "");
40 static_assert(!__is_trivially_constructible(NonConstCopy, NonConstCopy), "");
41 static_assert(!__is_trivially_constructible(NonConstCopy, const NonConstCopy &), "");
42 static_assert(!__is_trivially_constructible(NonConstCopy, NonConstCopy &&), "");
43 
44 struct DefaultedSpecialMembers {
45   DefaultedSpecialMembers(const DefaultedSpecialMembers &) = default;
46   DefaultedSpecialMembers(DefaultedSpecialMembers &) = default;
47   DefaultedSpecialMembers(DefaultedSpecialMembers &&) = default;
48 };
49 using _ = trivially_copyable<DefaultedSpecialMembers>;
50 #endif
51 
52 // class X has no virtual functions
53 struct VFn {
54   virtual void f();
55 };
56 using _ = not_trivially_copyable<VFn>;
57 
58 // and no virtual base classes
59 struct VBase : virtual Trivial {};
60 using _ = not_trivially_copyable<VBase>;
61 
62 // and the constructor selected to copy/move each [direct subobject] is trivial
63 struct TemplateCtor {
64   template<typename T> TemplateCtor(T &);
65 };
66 using _ = trivially_copyable<TemplateCtor>;
67 struct TemplateCtorMember {
68   TemplateCtor tc;
69 };
70 using _ = trivially_copyable<TemplateCtorMember>;
71 
72 // We can select a non-trivial copy ctor even if there is a trivial one.
73 struct MutableTemplateCtorMember {
74   mutable TemplateCtor mtc;
75 };
76 static_assert(!__is_trivially_constructible(MutableTemplateCtorMember, const MutableTemplateCtorMember &), "");
77 static_assert(__is_trivially_constructible(MutableTemplateCtorMember, MutableTemplateCtorMember &&), "");
78 struct MutableTemplateCtorMember2 {
79   MutableTemplateCtorMember2(const MutableTemplateCtorMember2 &) = default;
80   MutableTemplateCtorMember2(MutableTemplateCtorMember2 &&) = default;
81   mutable TemplateCtor mtc;
82 };
83 static_assert(!__is_trivially_constructible(MutableTemplateCtorMember2, const MutableTemplateCtorMember2 &), "");
84 static_assert(__is_trivially_constructible(MutableTemplateCtorMember2, MutableTemplateCtorMember2 &&), "");
85 
86 // Both trivial and non-trivial special members.
87 struct TNT {
88   TNT(const TNT &) = default; // trivial
89   TNT(TNT &); // non-trivial
90 
91   TNT(TNT &&) = default; // trivial
92   TNT(const TNT &&); // non-trivial
93 };
94 
95 static_assert(!__has_trivial_copy(TNT), "lie deliberately for gcc compatibility");
96 static_assert(__is_trivially_constructible(TNT, TNT), "");
97 static_assert(!__is_trivially_constructible(TNT, TNT &), "");
98 static_assert(__is_trivially_constructible(TNT, const TNT &), "");
99 static_assert(!__is_trivially_constructible(TNT, volatile TNT &), "");
100 static_assert(__is_trivially_constructible(TNT, TNT &&), "");
101 static_assert(!__is_trivially_constructible(TNT, const TNT &&), "");
102 static_assert(!__is_trivially_constructible(TNT, volatile TNT &&), "");
103 
104 // This has only trivial special members.
105 struct DerivedFromTNT : TNT {};
106 
107 static_assert(__has_trivial_copy(DerivedFromTNT), "");
108 static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT), "");
109 static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &), "");
110 static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &), "");
111 static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &), "");
112 static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &&), "");
113 static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &&), "");
114 static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &&), "");
115 
116 // This has only trivial special members.
117 struct TNTMember {
118   TNT tnt;
119 };
120 
121 static_assert(__has_trivial_copy(TNTMember), "");
122 static_assert(__is_trivially_constructible(TNTMember, TNTMember), "");
123 static_assert(__is_trivially_constructible(TNTMember, TNTMember &), "");
124 static_assert(__is_trivially_constructible(TNTMember, const TNTMember &), "");
125 static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &), "");
126 static_assert(__is_trivially_constructible(TNTMember, TNTMember &&), "");
127 static_assert(__is_trivially_constructible(TNTMember, const TNTMember &&), "");
128 static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &&), "");
129 
130 struct NCCTNT : NonConstCopy, TNT {};
131 
132 static_assert(!__has_trivial_copy(NCCTNT), "");
133 static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT), "");
134 static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &), "");
135 static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &), "");
136 static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &), "");
137 static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &&), "");
138 static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &&), "");
139 static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &&), "");
140 
141 struct TemplateCtorNoMove {
142   TemplateCtorNoMove(const TemplateCtorNoMove &) = default;
143   template<typename T> TemplateCtorNoMove(T &&);
144 };
145 static_assert(__is_trivially_constructible(TemplateCtorNoMove, const TemplateCtorNoMove &), "");
146 static_assert(!__is_trivially_constructible(TemplateCtorNoMove, TemplateCtorNoMove &&), "");
147 
148 struct UseTemplateCtorNoMove {
149   TemplateCtorNoMove tcnm;
150 };
151 static_assert(__is_trivially_constructible(UseTemplateCtorNoMove, const UseTemplateCtorNoMove &), "");
152 static_assert(!__is_trivially_constructible(UseTemplateCtorNoMove, UseTemplateCtorNoMove &&), "");
153 
154 struct TemplateCtorNoMoveSFINAE {
155   TemplateCtorNoMoveSFINAE(const TemplateCtorNoMoveSFINAE &) = default;
156   template<typename T, typename U = typename T::error> TemplateCtorNoMoveSFINAE(T &&);
157 };
158 static_assert(__is_trivially_constructible(TemplateCtorNoMoveSFINAE, const TemplateCtorNoMoveSFINAE &), "");
159 static_assert(__is_trivially_constructible(TemplateCtorNoMoveSFINAE, TemplateCtorNoMoveSFINAE &&), "");
160 
161 struct UseTemplateCtorNoMoveSFINAE {
162   TemplateCtorNoMoveSFINAE tcnm;
163 };
164 static_assert(__is_trivially_constructible(UseTemplateCtorNoMoveSFINAE, const UseTemplateCtorNoMoveSFINAE &), "");
165 static_assert(__is_trivially_constructible(UseTemplateCtorNoMoveSFINAE, UseTemplateCtorNoMoveSFINAE &&), "");
166 
167 namespace TrivialityDependsOnImplicitDeletion {
168   struct PrivateMove {
169     PrivateMove(const PrivateMove &) = default;
170   private:
171     PrivateMove(PrivateMove &&);
172     friend class Access;
173   };
174   static_assert(__is_trivially_constructible(PrivateMove, const PrivateMove &), "");
175   static_assert(!__is_trivially_constructible(PrivateMove, PrivateMove &&), "");
176 
177   struct NoAccess {
178     PrivateMove pm;
179     // NoAccess's move is deleted, so moves of it use PrivateMove's copy ctor,
180     // which is trivial.
181   };
182   static_assert(__is_trivially_constructible(NoAccess, const NoAccess &), "");
183   static_assert(__is_trivially_constructible(NoAccess, NoAccess &&), "");
184   struct TopNoAccess : NoAccess {};
185   static_assert(__is_trivially_constructible(TopNoAccess, const TopNoAccess &), "");
186   static_assert(__is_trivially_constructible(TopNoAccess, TopNoAccess &&), "");
187 
188   struct Access {
189     PrivateMove pm;
190     // NoAccess's move would *not* be deleted, so is *not* suppressed,
191     // so moves of it use PrivateMove's move ctor, which is not trivial.
192   };
193   static_assert(__is_trivially_constructible(Access, const Access &), "");
194   static_assert(!__is_trivially_constructible(Access, Access &&), "");
195   struct TopAccess : Access {};
196   static_assert(__is_trivially_constructible(TopAccess, const TopAccess &), "");
197   static_assert(!__is_trivially_constructible(TopAccess, TopAccess &&), "");
198 }
199 
200 namespace TrivialityDependsOnDestructor {
201   class HasInaccessibleDestructor { ~HasInaccessibleDestructor() = default; };
202   struct HasImplicitlyDeletedDestructor : HasInaccessibleDestructor {};
203   struct HasImplicitlyDeletedCopyCtor : HasImplicitlyDeletedDestructor {
204     HasImplicitlyDeletedCopyCtor() = default;
205     template<typename T> HasImplicitlyDeletedCopyCtor(T &&);
206     // Copy ctor is deleted but trivial.
207     // Move ctor is suppressed.
208     HasImplicitlyDeletedCopyCtor(const HasImplicitlyDeletedCopyCtor&) = default;
209     HasImplicitlyDeletedCopyCtor(HasImplicitlyDeletedCopyCtor&&) = default;
210   };
211   struct Test : HasImplicitlyDeletedCopyCtor {
212     Test(const Test&) = default;
213     Test(Test&&) = default;
214   };
215   // Implicit copy ctor calls deleted trivial copy ctor.
216   static_assert(__has_trivial_copy(Test), "");
217   // This is false because the destructor is deleted.
218   static_assert(!__is_trivially_constructible(Test, const Test &), "");
219   // Implicit move ctor calls template ctor.
220   static_assert(!__is_trivially_constructible(Test, Test &&), "");
221 
222   struct HasAccessibleDestructor { ~HasAccessibleDestructor() = default; };
223   struct HasImplicitlyDefaultedDestructor : HasAccessibleDestructor {};
224   struct HasImplicitlyDefaultedCopyCtor : HasImplicitlyDefaultedDestructor {
225     template<typename T> HasImplicitlyDefaultedCopyCtor(T &&);
226     // Copy ctor is trivial.
227     // Move ctor is trivial.
228   };
229   struct Test2 : HasImplicitlyDefaultedCopyCtor {};
230   // Implicit copy ctor calls trivial copy ctor.
231   static_assert(__has_trivial_copy(Test2), "");
232   static_assert(__is_trivially_constructible(Test2, const Test2 &), "");
233   // Implicit move ctor calls trivial move ctor.
234   static_assert(__is_trivially_constructible(Test2, Test2 &&), "");
235 }
236