1 | // RUN: %clang_cc1 -std=c++11 -verify %s |
2 | |
3 | // expected-no-diagnostics |
4 | |
5 | template<typename T, bool B> struct trivially_assignable_check { |
6 | static_assert(B == __has_trivial_assign(T), ""); |
7 | static_assert(B == __is_trivially_assignable(T&, T), ""); |
8 | static_assert(B == __is_trivially_assignable(T&, const T &), ""); |
9 | static_assert(B == __is_trivially_assignable(T&, T &&), ""); |
10 | static_assert(B == __is_trivially_assignable(T&&, T), ""); |
11 | static_assert(B == __is_trivially_assignable(T&&, const T &), ""); |
12 | static_assert(B == __is_trivially_assignable(T&&, T &&), ""); |
13 | typedef void type; |
14 | }; |
15 | template<typename T> using trivially_assignable = |
16 | typename trivially_assignable_check<T, true>::type; |
17 | template<typename T> using not_trivially_assignable = |
18 | typename trivially_assignable_check<T, false>::type; |
19 | |
20 | struct Trivial {}; |
21 | using _ = trivially_assignable<Trivial>; |
22 | |
23 | // A copy/move assignment operator for class X is trivial if it is not user-provided, |
24 | struct UserProvided { |
25 | UserProvided &operator=(const UserProvided &); |
26 | }; |
27 | using _ = not_trivially_assignable<UserProvided>; |
28 | |
29 | // its declared parameter type is the same as if it had been implicitly |
30 | // declared, |
31 | struct NonConstCopy { |
32 | NonConstCopy &operator=(NonConstCopy &) = default; |
33 | }; |
34 | using _ = not_trivially_assignable<NonConstCopy>; |
35 | |
36 | // class X has no virtual functions |
37 | struct VFn { |
38 | virtual void f(); |
39 | }; |
40 | using _ = not_trivially_assignable<VFn>; |
41 | |
42 | // and no virtual base classes |
43 | struct VBase : virtual Trivial {}; |
44 | using _ = not_trivially_assignable<VBase>; |
45 | |
46 | // and the assignment operator selected to copy/move each [direct subobject] is trivial |
47 | struct TemplateCtor { |
48 | template<typename T> TemplateCtor operator=(T &); |
49 | }; |
50 | using _ = trivially_assignable<TemplateCtor>; |
51 | struct TemplateCtorMember { |
52 | TemplateCtor tc; |
53 | }; |
54 | using _ = trivially_assignable<TemplateCtorMember>; |
55 | struct MutableTemplateCtorMember { |
56 | mutable TemplateCtor mtc; |
57 | }; |
58 | static_assert(!__is_trivially_assignable(MutableTemplateCtorMember, const MutableTemplateCtorMember &), ""); |
59 | static_assert(__is_trivially_assignable(MutableTemplateCtorMember, MutableTemplateCtorMember &&), ""); |
60 | |
61 | // Both trivial and non-trivial special members. |
62 | struct TNT { |
63 | TNT &operator=(const TNT &) = default; // trivial |
64 | TNT &operator=(TNT &); // non-trivial |
65 | |
66 | TNT &operator=(TNT &&) = default; // trivial |
67 | TNT &operator=(const TNT &&); // non-trivial |
68 | }; |
69 | |
70 | static_assert(!__has_trivial_assign(TNT), "lie deliberately for gcc compatibility"); |
71 | static_assert(__is_trivially_assignable(TNT, TNT), ""); |
72 | static_assert(!__is_trivially_assignable(TNT, TNT &), ""); |
73 | static_assert(__is_trivially_assignable(TNT, const TNT &), ""); |
74 | static_assert(!__is_trivially_assignable(TNT, volatile TNT &), ""); |
75 | static_assert(__is_trivially_assignable(TNT, TNT &&), ""); |
76 | static_assert(!__is_trivially_assignable(TNT, const TNT &&), ""); |
77 | static_assert(!__is_trivially_assignable(TNT, volatile TNT &&), ""); |
78 | |
79 | // This has only trivial special members. |
80 | struct DerivedFromTNT : TNT {}; |
81 | |
82 | static_assert(__has_trivial_assign(DerivedFromTNT), ""); |
83 | static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT), ""); |
84 | static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &), ""); |
85 | static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &), ""); |
86 | static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &), ""); |
87 | static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &&), ""); |
88 | static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &&), ""); |
89 | static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &&), ""); |
90 | |
91 | // This has only trivial special members. |
92 | struct TNTMember { |
93 | TNT tnt; |
94 | }; |
95 | |
96 | static_assert(__has_trivial_assign(TNTMember), ""); |
97 | static_assert(__is_trivially_assignable(TNTMember, TNTMember), ""); |
98 | static_assert(__is_trivially_assignable(TNTMember, TNTMember &), ""); |
99 | static_assert(__is_trivially_assignable(TNTMember, const TNTMember &), ""); |
100 | static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &), ""); |
101 | static_assert(__is_trivially_assignable(TNTMember, TNTMember &&), ""); |
102 | static_assert(__is_trivially_assignable(TNTMember, const TNTMember &&), ""); |
103 | static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &&), ""); |
104 | |
105 | struct NCCTNT : NonConstCopy, TNT {}; |
106 | |
107 | static_assert(!__has_trivial_assign(NCCTNT), ""); |
108 | static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT), ""); |
109 | static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &), ""); |
110 | static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &), ""); |
111 | static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &), ""); |
112 | static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &&), ""); |
113 | static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &&), ""); |
114 | static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &&), ""); |
115 | |
116 | struct MultipleTrivial { |
117 | // All four of these are trivial. |
118 | MultipleTrivial &operator=(const MultipleTrivial &) & = default; |
119 | MultipleTrivial &operator=(const MultipleTrivial &) && = default; |
120 | MultipleTrivial &operator=(MultipleTrivial &&) & = default; |
121 | MultipleTrivial &operator=(MultipleTrivial &&) && = default; |
122 | }; |
123 | |
124 | using _ = trivially_assignable<MultipleTrivial>; |
125 | |
126 | struct RefQualifier { |
127 | RefQualifier &operator=(const RefQualifier &) & = default; |
128 | RefQualifier &operator=(const RefQualifier &) &&; |
129 | RefQualifier &operator=(RefQualifier &&) &; |
130 | RefQualifier &operator=(RefQualifier &&) && = default; |
131 | }; |
132 | struct DerivedFromRefQualifier : RefQualifier { |
133 | // Both of these call the trivial copy operation. |
134 | DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) & = default; |
135 | DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) && = default; |
136 | // Both of these call the non-trivial move operation. |
137 | DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) & = default; |
138 | DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) && = default; |
139 | }; |
140 | static_assert(__is_trivially_assignable(DerivedFromRefQualifier&, const DerivedFromRefQualifier&), ""); |
141 | static_assert(__is_trivially_assignable(DerivedFromRefQualifier&&, const DerivedFromRefQualifier&), ""); |
142 | static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&, DerivedFromRefQualifier&&), ""); |
143 | static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&&, DerivedFromRefQualifier&&), ""); |
144 | |
145 | struct TemplateAssignNoMove { |
146 | TemplateAssignNoMove &operator=(const TemplateAssignNoMove &) = default; |
147 | template<typename T> TemplateAssignNoMove &operator=(T &&); |
148 | }; |
149 | static_assert(__is_trivially_assignable(TemplateAssignNoMove, const TemplateAssignNoMove &), ""); |
150 | static_assert(!__is_trivially_assignable(TemplateAssignNoMove, TemplateAssignNoMove &&), ""); |
151 | |
152 | struct UseTemplateAssignNoMove { |
153 | TemplateAssignNoMove tanm; |
154 | }; |
155 | static_assert(__is_trivially_assignable(UseTemplateAssignNoMove, const UseTemplateAssignNoMove &), ""); |
156 | static_assert(!__is_trivially_assignable(UseTemplateAssignNoMove, UseTemplateAssignNoMove &&), ""); |
157 | |
158 | struct TemplateAssignNoMoveSFINAE { |
159 | TemplateAssignNoMoveSFINAE &operator=(const TemplateAssignNoMoveSFINAE &) = default; |
160 | template<typename T, typename U = typename T::error> TemplateAssignNoMoveSFINAE &operator=(T &&); |
161 | }; |
162 | static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, const TemplateAssignNoMoveSFINAE &), ""); |
163 | static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, TemplateAssignNoMoveSFINAE &&), ""); |
164 | |
165 | struct UseTemplateAssignNoMoveSFINAE { |
166 | TemplateAssignNoMoveSFINAE tanm; |
167 | }; |
168 | static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, const UseTemplateAssignNoMoveSFINAE &), ""); |
169 | static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, UseTemplateAssignNoMoveSFINAE &&), ""); |
170 | |
171 | namespace TrivialityDependsOnImplicitDeletion { |
172 | struct PrivateMove { |
173 | PrivateMove &operator=(const PrivateMove &) = default; |
174 | private: |
175 | PrivateMove &operator=(PrivateMove &&); |
176 | friend class Access; |
177 | }; |
178 | static_assert(__is_trivially_assignable(PrivateMove, const PrivateMove &), ""); |
179 | static_assert(!__is_trivially_assignable(PrivateMove, PrivateMove &&), ""); |
180 | |
181 | struct NoAccess { |
182 | PrivateMove pm; |
183 | // NoAccess's move would be deleted, so is suppressed, |
184 | // so moves of it use PrivateMove's copy ctor, which is trivial. |
185 | }; |
186 | static_assert(__is_trivially_assignable(NoAccess, const NoAccess &), ""); |
187 | static_assert(__is_trivially_assignable(NoAccess, NoAccess &&), ""); |
188 | struct TopNoAccess : NoAccess {}; |
189 | static_assert(__is_trivially_assignable(TopNoAccess, const TopNoAccess &), ""); |
190 | static_assert(__is_trivially_assignable(TopNoAccess, TopNoAccess &&), ""); |
191 | |
192 | struct Access { |
193 | PrivateMove pm; |
194 | // NoAccess's move would *not* be deleted, so is *not* suppressed, |
195 | // so moves of it use PrivateMove's move ctor, which is not trivial. |
196 | }; |
197 | static_assert(__is_trivially_assignable(Access, const Access &), ""); |
198 | static_assert(!__is_trivially_assignable(Access, Access &&), ""); |
199 | struct TopAccess : Access {}; |
200 | static_assert(__is_trivially_assignable(TopAccess, const TopAccess &), ""); |
201 | static_assert(!__is_trivially_assignable(TopAccess, TopAccess &&), ""); |
202 | } |
203 | |