1 // RUN: %clang_cc1 -std=c++20 -verify %s 2 // expected-no-diagnostics 3 4 static constexpr int PRIMARY = 0; 5 static constexpr int SPECIALIZATION_CONCEPT = 1; 6 static constexpr int SPECIALIZATION_REQUIRES = 2; 7 8 template <class T> 9 concept Concept = (sizeof(T) >= 2 * sizeof(int)); 10 11 struct XY { 12 int x; 13 int y; 14 }; 15 16 namespace members { 17 18 template <class T, class U> struct S { 19 static constexpr int primary(); 20 }; 21 22 template <class T, class U> constexpr int S<T, U>::primary() { 23 return PRIMARY; 24 }; 25 26 template <Concept C, class U> struct S<C, U> { 27 static constexpr int specialization(); 28 }; 29 30 template <class T, class U> 31 requires(sizeof(T) == sizeof(int)) 32 struct S<T, U> { 33 static constexpr int specialization(); 34 }; 35 36 template <Concept C, class U> constexpr int S<C, U>::specialization() { 37 return SPECIALIZATION_CONCEPT; 38 } 39 40 template <class T, class U> 41 requires(sizeof(T) == sizeof(int)) 42 constexpr int S<T, U>::specialization() { 43 return SPECIALIZATION_REQUIRES; 44 } 45 46 static_assert(S<char, double>::primary() == PRIMARY); 47 static_assert(S<XY, double>::specialization() == SPECIALIZATION_CONCEPT); 48 static_assert(S<int, double>::specialization() == SPECIALIZATION_REQUIRES); 49 50 } // namespace members 51 52 namespace enumerations { 53 54 template <class T, class U> struct S { 55 enum class E : int; 56 }; 57 58 template <class T, class U> enum class S<T, U>::E { Value = PRIMARY }; 59 60 template <Concept C, class U> struct S<C, U> { 61 enum class E : int; 62 }; 63 64 template <Concept C, class U> 65 enum class S<C, U>::E { 66 Value = SPECIALIZATION_CONCEPT 67 }; 68 69 template <class T, class U> 70 requires(sizeof(T) == sizeof(int)) 71 struct S<T, U> { 72 enum class E : int; 73 }; 74 75 template <class T, class U> 76 requires(sizeof(T) == sizeof(int)) 77 enum class S<T, U>::E { 78 Value = SPECIALIZATION_REQUIRES 79 }; 80 81 static_assert(static_cast<int>(S<char, double>::E::Value) == PRIMARY); 82 static_assert(static_cast<int>(S<XY, double>::E::Value) == 83 SPECIALIZATION_CONCEPT); 84 static_assert(static_cast<int>(S<int, double>::E::Value) == 85 SPECIALIZATION_REQUIRES); 86 87 } // namespace enumerations 88 89 namespace multiple_template_parameter_lists { 90 91 template <class Outer> 92 struct S { 93 template <class Inner> 94 static constexpr int primary(Inner); 95 }; 96 97 template <class Outer> 98 template <class Inner> 99 constexpr int S<Outer>::primary(Inner) { 100 return PRIMARY; 101 }; 102 103 template <Concept Outer> 104 struct S<Outer> { 105 template <class Inner> 106 static constexpr int specialization(Inner); 107 }; 108 109 template <Concept Outer> 110 template <class Inner> 111 constexpr int S<Outer>::specialization(Inner) { return SPECIALIZATION_CONCEPT; } 112 113 template <class Outer> 114 requires(sizeof(Outer) == sizeof(int)) 115 struct S<Outer> { 116 template <class Inner> 117 static constexpr int specialization(Inner); 118 }; 119 120 template <class Outer> 121 requires(sizeof(Outer) == sizeof(int)) 122 template <class Inner> 123 constexpr int S<Outer>::specialization(Inner) { return SPECIALIZATION_REQUIRES; } 124 125 static_assert(S<char>::primary("str") == PRIMARY); 126 static_assert(S<XY>::specialization("str") == SPECIALIZATION_CONCEPT); 127 static_assert(S<int>::specialization("str") == SPECIALIZATION_REQUIRES); 128 129 } // namespace multiple_template_parameter_lists 130 131 static constexpr int CONSTRAINED_METHOD_1 = 1; 132 static constexpr int CONSTRAINED_METHOD_2 = 2; 133 134 namespace constrained_members { 135 136 template <int> 137 struct S { 138 template <Concept C> 139 static constexpr int constrained_method(); 140 }; 141 142 template <> 143 template <Concept C> 144 constexpr int S<1>::constrained_method() { return CONSTRAINED_METHOD_1; } 145 146 template <> 147 template <Concept C> 148 constexpr int S<2>::constrained_method() { return CONSTRAINED_METHOD_2; } 149 150 static_assert(S<1>::constrained_method<XY>() == CONSTRAINED_METHOD_1); 151 static_assert(S<2>::constrained_method<XY>() == CONSTRAINED_METHOD_2); 152 153 154 template <class T1, class T2> 155 concept ConceptT1T2 = true; 156 157 template<typename T3> 158 struct S12 { 159 template<ConceptT1T2<T3> T4> 160 static constexpr int constrained_method(); 161 }; 162 163 template<> 164 template<ConceptT1T2<int> T5> 165 constexpr int S12<int>::constrained_method() { return CONSTRAINED_METHOD_1; } 166 167 template<> 168 template<ConceptT1T2<double> T5> 169 constexpr int S12<double>::constrained_method() { return CONSTRAINED_METHOD_2; } 170 171 static_assert(S12<int>::constrained_method<XY>() == CONSTRAINED_METHOD_1); 172 static_assert(S12<double>::constrained_method<XY>() == CONSTRAINED_METHOD_2); 173 174 } // namespace constrained members 175 176 namespace constrained_members_of_nested_types { 177 178 template <int> 179 struct S { 180 struct Inner0 { 181 struct Inner1 { 182 template <Concept C> 183 static constexpr int constrained_method(); 184 }; 185 }; 186 }; 187 188 template <> 189 template <Concept C> 190 constexpr int S<1>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; } 191 192 template <> 193 template <Concept C> 194 constexpr int S<2>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; } 195 196 static_assert(S<1>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_1); 197 static_assert(S<2>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_2); 198 199 200 template <class T1, class T2> 201 concept ConceptT1T2 = true; 202 203 template<typename T3> 204 struct S12 { 205 struct Inner0 { 206 struct Inner1 { 207 template<ConceptT1T2<T3> T4> 208 static constexpr int constrained_method(); 209 }; 210 }; 211 }; 212 213 template<> 214 template<ConceptT1T2<int> T5> 215 constexpr int S12<int>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; } 216 217 template<> 218 template<ConceptT1T2<double> T5> 219 constexpr int S12<double>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; } 220 221 static_assert(S12<int>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_1); 222 static_assert(S12<double>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_2); 223 224 } // namespace constrained_members_of_nested_types 225 226 namespace constrained_member_sfinae { 227 228 template<int N> struct S { 229 template<class T> 230 static constexpr int constrained_method() requires (sizeof(int[N * 1073741824 + 4]) == 16) { 231 return CONSTRAINED_METHOD_1; 232 } 233 234 template<class T> 235 static constexpr int constrained_method() requires (sizeof(int[N]) == 16); 236 }; 237 238 template<> 239 template<typename T> 240 constexpr int S<4>::constrained_method() requires (sizeof(int[4]) == 16) { 241 return CONSTRAINED_METHOD_2; 242 } 243 244 // Verify that there is no amiguity in this case. 245 static_assert(S<4>::constrained_method<double>() == CONSTRAINED_METHOD_2); 246 247 } // namespace constrained_member_sfinae 248 249 namespace requires_expression_references_members { 250 251 void accept1(int x); 252 void accept2(XY xy); 253 254 template <class T> struct S { 255 T Field = T(); 256 257 constexpr int constrained_method() 258 requires requires { accept1(Field); }; 259 260 constexpr int constrained_method() 261 requires requires { accept2(Field); }; 262 }; 263 264 template <class T> 265 constexpr int S<T>::constrained_method() 266 requires requires { accept1(Field); } { 267 return CONSTRAINED_METHOD_1; 268 } 269 270 template <class T> 271 constexpr int S<T>::constrained_method() 272 requires requires { accept2(Field); } { 273 return CONSTRAINED_METHOD_2; 274 } 275 276 static_assert(S<int>().constrained_method() == CONSTRAINED_METHOD_1); 277 static_assert(S<XY>().constrained_method() == CONSTRAINED_METHOD_2); 278 279 } // namespace requires_expression_references_members 280 281 namespace GH60231 { 282 283 template<typename T0> concept C = true; 284 285 template <typename T1> 286 struct S { 287 template <typename F1> requires C<S<T1>> 288 void foo1(F1 f); 289 290 template <typename F2> 291 void foo2(F2 f) requires C<S<T1>>; 292 293 template <typename F3> requires C<F3> 294 void foo3(F3 f); 295 }; 296 297 template <typename T2> 298 template <typename F4> requires C<S<T2>> 299 void S<T2>::foo1(F4 f) {} 300 301 template <typename T3> 302 template <typename F5> 303 void S<T3>::foo2(F5 f) requires C<S<T3>> {} 304 305 template <typename T4> 306 template <typename F6> requires C<F6> 307 void S<T4>::foo3(F6 f) {} 308 309 } // namespace GH60231 310 311 namespace GH62003 { 312 313 template <typename T0> concept Concept = true; 314 315 template <class T1> 316 struct S1 { 317 template <Concept C1> 318 static constexpr int foo(); 319 }; 320 template <class T2> 321 template <Concept C2> 322 constexpr int S1<T2>::foo() { return 1; } 323 324 template <Concept C3> 325 struct S2 { 326 template <class T3> 327 static constexpr int foo(); 328 }; 329 template <Concept C4> 330 template <class T4> 331 constexpr int S2<C4>::foo() { return 2; } 332 333 template <Concept C5> 334 struct S3 { 335 template <Concept C6> 336 static constexpr int foo(); 337 }; 338 template <Concept C7> 339 template <Concept C8> 340 constexpr int S3<C7>::foo() { return 3; } 341 342 static_assert(S1<int>::foo<int>() == 1); 343 static_assert(S2<int>::foo<int>() == 2); 344 static_assert(S3<int>::foo<int>() == 3); 345 346 } // namespace GH62003 347 348 namespace MultilevelTemplateWithPartialSpecialization { 349 template <typename> 350 concept Concept = true; 351 352 namespace two_level { 353 template <typename T1, int> 354 struct W0 { 355 template <typename T2> 356 requires (Concept<T2>) 357 void f(const T2 &); 358 }; 359 360 template <typename T3> 361 struct W0<T3, 0> { 362 template <typename T4> 363 requires (Concept<T4>) 364 void f(const T4 &); 365 }; 366 367 template <typename T3> 368 template <typename T4> 369 requires (Concept<T4>) 370 inline void W0<T3, 0>::f(const T4 &) {} 371 } // namespace two_level 372 373 namespace three_level { 374 template <typename T1, int> 375 struct W0 { 376 template <typename T2> 377 struct W1 { 378 template <typename T3> 379 requires (Concept<T3>) 380 void f(const T3 &); 381 }; 382 }; 383 384 template <typename T4> 385 struct W0<T4, 0> { 386 template <typename T5> 387 struct W1 { 388 template <typename T6> 389 requires (Concept<T6>) 390 void f(const T6 &); 391 }; 392 }; 393 394 template <typename T7> 395 template <typename T8> 396 template <typename T9> 397 requires (Concept<T9>) 398 inline void W0<T7, 0>::W1<T8>::f(const T9 &) {} 399 } // namespace three_level 400 401 } // namespace MultilevelTemplateWithPartialSpecialization 402 403 namespace PR62697 { 404 template<typename> 405 concept c = true; 406 407 template<typename T> 408 struct s { 409 void f() requires c<void(T)>; 410 }; 411 412 template<typename T> 413 void s<T>::f() requires c<void(T)> { } 414 } 415