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