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