// RUN: %clang_cc1 -std=c++20 -verify %s // expected-no-diagnostics static constexpr int PRIMARY = 0; static constexpr int SPECIALIZATION_CONCEPT = 1; static constexpr int SPECIALIZATION_REQUIRES = 2; template concept Concept = (sizeof(T) >= 2 * sizeof(int)); struct XY { int x; int y; }; namespace members { template struct S { static constexpr int primary(); }; template constexpr int S::primary() { return PRIMARY; }; template struct S { static constexpr int specialization(); }; template requires(sizeof(T) == sizeof(int)) struct S { static constexpr int specialization(); }; template constexpr int S::specialization() { return SPECIALIZATION_CONCEPT; } template requires(sizeof(T) == sizeof(int)) constexpr int S::specialization() { return SPECIALIZATION_REQUIRES; } static_assert(S::primary() == PRIMARY); static_assert(S::specialization() == SPECIALIZATION_CONCEPT); static_assert(S::specialization() == SPECIALIZATION_REQUIRES); } // namespace members namespace enumerations { template struct S { enum class E : int; }; template enum class S::E { Value = PRIMARY }; template struct S { enum class E : int; }; template enum class S::E { Value = SPECIALIZATION_CONCEPT }; template requires(sizeof(T) == sizeof(int)) struct S { enum class E : int; }; template requires(sizeof(T) == sizeof(int)) enum class S::E { Value = SPECIALIZATION_REQUIRES }; static_assert(static_cast(S::E::Value) == PRIMARY); static_assert(static_cast(S::E::Value) == SPECIALIZATION_CONCEPT); static_assert(static_cast(S::E::Value) == SPECIALIZATION_REQUIRES); } // namespace enumerations namespace multiple_template_parameter_lists { template struct S { template static constexpr int primary(Inner); }; template template constexpr int S::primary(Inner) { return PRIMARY; }; template struct S { template static constexpr int specialization(Inner); }; template template constexpr int S::specialization(Inner) { return SPECIALIZATION_CONCEPT; } template requires(sizeof(Outer) == sizeof(int)) struct S { template static constexpr int specialization(Inner); }; template requires(sizeof(Outer) == sizeof(int)) template constexpr int S::specialization(Inner) { return SPECIALIZATION_REQUIRES; } static_assert(S::primary("str") == PRIMARY); static_assert(S::specialization("str") == SPECIALIZATION_CONCEPT); static_assert(S::specialization("str") == SPECIALIZATION_REQUIRES); } // namespace multiple_template_parameter_lists static constexpr int CONSTRAINED_METHOD_1 = 1; static constexpr int CONSTRAINED_METHOD_2 = 2; namespace constrained_members { template struct S { template static constexpr int constrained_method(); }; template <> template constexpr int S<1>::constrained_method() { return CONSTRAINED_METHOD_1; } template <> template constexpr int S<2>::constrained_method() { return CONSTRAINED_METHOD_2; } static_assert(S<1>::constrained_method() == CONSTRAINED_METHOD_1); static_assert(S<2>::constrained_method() == CONSTRAINED_METHOD_2); template concept ConceptT1T2 = true; template struct S12 { template T4> static constexpr int constrained_method(); }; template<> template T5> constexpr int S12::constrained_method() { return CONSTRAINED_METHOD_1; } template<> template T5> constexpr int S12::constrained_method() { return CONSTRAINED_METHOD_2; } static_assert(S12::constrained_method() == CONSTRAINED_METHOD_1); static_assert(S12::constrained_method() == CONSTRAINED_METHOD_2); } // namespace constrained members namespace constrained_members_of_nested_types { template struct S { struct Inner0 { struct Inner1 { template static constexpr int constrained_method(); }; }; }; template <> template constexpr int S<1>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; } template <> template constexpr int S<2>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; } static_assert(S<1>::Inner0::Inner1::constrained_method() == CONSTRAINED_METHOD_1); static_assert(S<2>::Inner0::Inner1::constrained_method() == CONSTRAINED_METHOD_2); template concept ConceptT1T2 = true; template struct S12 { struct Inner0 { struct Inner1 { template T4> static constexpr int constrained_method(); }; }; }; template<> template T5> constexpr int S12::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; } template<> template T5> constexpr int S12::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; } static_assert(S12::Inner0::Inner1::constrained_method() == CONSTRAINED_METHOD_1); static_assert(S12::Inner0::Inner1::constrained_method() == CONSTRAINED_METHOD_2); } // namespace constrained_members_of_nested_types namespace constrained_member_sfinae { template struct S { template static constexpr int constrained_method() requires (sizeof(int[N * 1073741824 + 4]) == 16) { return CONSTRAINED_METHOD_1; } template static constexpr int constrained_method() requires (sizeof(int[N]) == 16); }; template<> template constexpr int S<4>::constrained_method() requires (sizeof(int[4]) == 16) { return CONSTRAINED_METHOD_2; } // Verify that there is no amiguity in this case. static_assert(S<4>::constrained_method() == CONSTRAINED_METHOD_2); } // namespace constrained_member_sfinae namespace requires_expression_references_members { void accept1(int x); void accept2(XY xy); template struct S { T Field = T(); constexpr int constrained_method() requires requires { accept1(Field); }; constexpr int constrained_method() requires requires { accept2(Field); }; }; template constexpr int S::constrained_method() requires requires { accept1(Field); } { return CONSTRAINED_METHOD_1; } template constexpr int S::constrained_method() requires requires { accept2(Field); } { return CONSTRAINED_METHOD_2; } static_assert(S().constrained_method() == CONSTRAINED_METHOD_1); static_assert(S().constrained_method() == CONSTRAINED_METHOD_2); } // namespace requires_expression_references_members namespace GH60231 { template concept C = true; template struct S { template requires C> void foo1(F1 f); template void foo2(F2 f) requires C>; template requires C void foo3(F3 f); }; template template requires C> void S::foo1(F4 f) {} template template void S::foo2(F5 f) requires C> {} template template requires C void S::foo3(F6 f) {} } // namespace GH60231 namespace GH62003 { template concept Concept = true; template struct S1 { template static constexpr int foo(); }; template template constexpr int S1::foo() { return 1; } template struct S2 { template static constexpr int foo(); }; template template constexpr int S2::foo() { return 2; } template struct S3 { template static constexpr int foo(); }; template template constexpr int S3::foo() { return 3; } static_assert(S1::foo() == 1); static_assert(S2::foo() == 2); static_assert(S3::foo() == 3); } // namespace GH62003 namespace MultilevelTemplateWithPartialSpecialization { template concept Concept = true; namespace two_level { template struct W0 { template requires (Concept) void f(const T2 &); }; template struct W0 { template requires (Concept) void f(const T4 &); }; template template requires (Concept) inline void W0::f(const T4 &) {} } // namespace two_level namespace three_level { template struct W0 { template struct W1 { template requires (Concept) void f(const T3 &); }; }; template struct W0 { template struct W1 { template requires (Concept) void f(const T6 &); }; }; template template template requires (Concept) inline void W0::W1::f(const T9 &) {} } // namespace three_level } // namespace MultilevelTemplateWithPartialSpecialization namespace PR62697 { template concept c = true; template struct s { void f() requires c; }; template void s::f() requires c { } }