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