1// RUN: %clang_cc1 -std=c++11 -verify %s
2
3// expected-no-diagnostics
4
5template<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};
15template<typename T> using trivially_assignable =
16  typename trivially_assignable_check<T, true>::type;
17template<typename T> using not_trivially_assignable =
18  typename trivially_assignable_check<T, false>::type;
19
20struct Trivial {};
21using _ = trivially_assignable<Trivial>;
22
23// A copy/move assignment operator for class X is trivial if it is not user-provided,
24struct UserProvided {
25  UserProvided &operator=(const UserProvided &);
26};
27using _ = not_trivially_assignable<UserProvided>;
28
29// its declared parameter type is the same as if it had been implicitly
30// declared,
31struct NonConstCopy {
32  NonConstCopy &operator=(NonConstCopy &) = default;
33};
34using _ = not_trivially_assignable<NonConstCopy>;
35
36// class X has no virtual functions
37struct VFn {
38  virtual void f();
39};
40using _ = not_trivially_assignable<VFn>;
41
42// and no virtual base classes
43struct VBase : virtual Trivial {};
44using _ = not_trivially_assignable<VBase>;
45
46// and the assignment operator selected to copy/move each [direct subobject] is trivial
47struct TemplateCtor {
48  template<typename T> TemplateCtor operator=(T &);
49};
50using _ = trivially_assignable<TemplateCtor>;
51struct TemplateCtorMember {
52  TemplateCtor tc;
53};
54using _ = trivially_assignable<TemplateCtorMember>;
55struct MutableTemplateCtorMember {
56  mutable TemplateCtor mtc;
57};
58static_assert(!__is_trivially_assignable(MutableTemplateCtorMember, const MutableTemplateCtorMember &), "");
59static_assert(__is_trivially_assignable(MutableTemplateCtorMember, MutableTemplateCtorMember &&), "");
60
61// Both trivial and non-trivial special members.
62struct 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
70static_assert(!__has_trivial_assign(TNT), "lie deliberately for gcc compatibility");
71static_assert(__is_trivially_assignable(TNT, TNT), "");
72static_assert(!__is_trivially_assignable(TNT, TNT &), "");
73static_assert(__is_trivially_assignable(TNT, const TNT &), "");
74static_assert(!__is_trivially_assignable(TNT, volatile TNT &), "");
75static_assert(__is_trivially_assignable(TNT, TNT &&), "");
76static_assert(!__is_trivially_assignable(TNT, const TNT &&), "");
77static_assert(!__is_trivially_assignable(TNT, volatile TNT &&), "");
78
79// This has only trivial special members.
80struct DerivedFromTNT : TNT {};
81
82static_assert(__has_trivial_assign(DerivedFromTNT), "");
83static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT), "");
84static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &), "");
85static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &), "");
86static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &), "");
87static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &&), "");
88static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &&), "");
89static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &&), "");
90
91// This has only trivial special members.
92struct TNTMember {
93  TNT tnt;
94};
95
96static_assert(__has_trivial_assign(TNTMember), "");
97static_assert(__is_trivially_assignable(TNTMember, TNTMember), "");
98static_assert(__is_trivially_assignable(TNTMember, TNTMember &), "");
99static_assert(__is_trivially_assignable(TNTMember, const TNTMember &), "");
100static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &), "");
101static_assert(__is_trivially_assignable(TNTMember, TNTMember &&), "");
102static_assert(__is_trivially_assignable(TNTMember, const TNTMember &&), "");
103static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &&), "");
104
105struct NCCTNT : NonConstCopy, TNT {};
106
107static_assert(!__has_trivial_assign(NCCTNT), "");
108static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT), "");
109static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &), "");
110static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &), "");
111static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &), "");
112static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &&), "");
113static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &&), "");
114static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &&), "");
115
116struct 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
124using _ = trivially_assignable<MultipleTrivial>;
125
126struct RefQualifier {
127  RefQualifier &operator=(const RefQualifier &) & = default;
128  RefQualifier &operator=(const RefQualifier &) &&;
129  RefQualifier &operator=(RefQualifier &&) &;
130  RefQualifier &operator=(RefQualifier &&) && = default;
131};
132struct 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};
140static_assert(__is_trivially_assignable(DerivedFromRefQualifier&, const DerivedFromRefQualifier&), "");
141static_assert(__is_trivially_assignable(DerivedFromRefQualifier&&, const DerivedFromRefQualifier&), "");
142static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&, DerivedFromRefQualifier&&), "");
143static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&&, DerivedFromRefQualifier&&), "");
144
145struct TemplateAssignNoMove {
146  TemplateAssignNoMove &operator=(const TemplateAssignNoMove &) = default;
147  template<typename T> TemplateAssignNoMove &operator=(T &&);
148};
149static_assert(__is_trivially_assignable(TemplateAssignNoMove, const TemplateAssignNoMove &), "");
150static_assert(!__is_trivially_assignable(TemplateAssignNoMove, TemplateAssignNoMove &&), "");
151
152struct UseTemplateAssignNoMove {
153  TemplateAssignNoMove tanm;
154};
155static_assert(__is_trivially_assignable(UseTemplateAssignNoMove, const UseTemplateAssignNoMove &), "");
156static_assert(!__is_trivially_assignable(UseTemplateAssignNoMove, UseTemplateAssignNoMove &&), "");
157
158struct TemplateAssignNoMoveSFINAE {
159  TemplateAssignNoMoveSFINAE &operator=(const TemplateAssignNoMoveSFINAE &) = default;
160  template<typename T, typename U = typename T::error> TemplateAssignNoMoveSFINAE &operator=(T &&);
161};
162static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, const TemplateAssignNoMoveSFINAE &), "");
163static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, TemplateAssignNoMoveSFINAE &&), "");
164
165struct UseTemplateAssignNoMoveSFINAE {
166  TemplateAssignNoMoveSFINAE tanm;
167};
168static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, const UseTemplateAssignNoMoveSFINAE &), "");
169static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, UseTemplateAssignNoMoveSFINAE &&), "");
170
171namespace 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