llvm/clang/test/SemaTemplate/concepts-out-of-line-def.cpp

// RUN: %clang_cc1 -std=c++20 -verify %s

static constexpr int PRIMARY = 0;
static constexpr int SPECIALIZATION_CONCEPT = 1;
static constexpr int SPECIALIZATION_REQUIRES = 2;

template <class T>
concept Concept = (sizeof(T) >= 2 * sizeof(int));

struct XY {
  int x;
  int y;
};

namespace members {

template <class T, class U> struct S {
  static constexpr int primary();
};

template <class T, class U> constexpr int S<T, U>::primary() {
  return PRIMARY;
};

template <Concept C, class U> struct S<C, U> {
  static constexpr int specialization();
};

template <class T, class U>
  requires(sizeof(T) == sizeof(int))
struct S<T, U> {
  static constexpr int specialization();
};

template <Concept C, class U> constexpr int S<C, U>::specialization() {
  return SPECIALIZATION_CONCEPT;
}

template <class T, class U>
  requires(sizeof(T) == sizeof(int))
constexpr int S<T, U>::specialization() {
  return SPECIALIZATION_REQUIRES;
}

static_assert(S<char, double>::primary() == PRIMARY);
static_assert(S<XY, double>::specialization() == SPECIALIZATION_CONCEPT);
static_assert(S<int, double>::specialization() == SPECIALIZATION_REQUIRES);

} // namespace members

namespace enumerations {

template <class T, class U> struct S {
  enum class E : int;
};

template <class T, class U> enum class S<T, U>::E { Value = PRIMARY };

template <Concept C, class U> struct S<C, U> {
  enum class E : int;
};

template <Concept C, class U>
enum class S<C, U>::E {
  Value = SPECIALIZATION_CONCEPT
};

template <class T, class U>
  requires(sizeof(T) == sizeof(int))
struct S<T, U> {
  enum class E : int;
};

template <class T, class U>
  requires(sizeof(T) == sizeof(int))
enum class S<T, U>::E {
  Value = SPECIALIZATION_REQUIRES
};

static_assert(static_cast<int>(S<char, double>::E::Value) == PRIMARY);
static_assert(static_cast<int>(S<XY, double>::E::Value) ==
              SPECIALIZATION_CONCEPT);
static_assert(static_cast<int>(S<int, double>::E::Value) ==
              SPECIALIZATION_REQUIRES);

} // namespace  enumerations

namespace multiple_template_parameter_lists {

template <class Outer>
struct S {
  template <class Inner>
  static constexpr int primary(Inner);
};

template <class Outer>
template <class Inner>
constexpr int S<Outer>::primary(Inner) {
  return PRIMARY;
};

template <Concept Outer>
struct S<Outer> {
  template <class Inner>
  static constexpr int specialization(Inner);
};

template <Concept Outer>
template <class Inner>
constexpr int S<Outer>::specialization(Inner) { return SPECIALIZATION_CONCEPT; }

template <class Outer>
  requires(sizeof(Outer) == sizeof(int))
struct S<Outer> {
  template <class Inner>
  static constexpr int specialization(Inner);
};

template <class Outer>
  requires(sizeof(Outer) == sizeof(int))
template <class Inner>
constexpr int S<Outer>::specialization(Inner) { return SPECIALIZATION_REQUIRES; }

static_assert(S<char>::primary("str") == PRIMARY);
static_assert(S<XY>::specialization("str") == SPECIALIZATION_CONCEPT);
static_assert(S<int>::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 <int>
struct S {
  template <Concept C>
  static constexpr int constrained_method();
};

template <>
template <Concept C>
constexpr int S<1>::constrained_method() { return CONSTRAINED_METHOD_1; }

template <>
template <Concept C>
constexpr int S<2>::constrained_method() { return CONSTRAINED_METHOD_2; }

static_assert(S<1>::constrained_method<XY>() == CONSTRAINED_METHOD_1);
static_assert(S<2>::constrained_method<XY>() == CONSTRAINED_METHOD_2);


template <class T1, class T2>
concept ConceptT1T2 = true;

template<typename T3>
struct S12 {
  template<ConceptT1T2<T3> T4>
  static constexpr int constrained_method();
};

template<>
template<ConceptT1T2<int> T5>
constexpr int S12<int>::constrained_method() { return CONSTRAINED_METHOD_1; }

template<>
template<ConceptT1T2<double> T5>
constexpr int S12<double>::constrained_method() { return CONSTRAINED_METHOD_2; }

static_assert(S12<int>::constrained_method<XY>() == CONSTRAINED_METHOD_1);
static_assert(S12<double>::constrained_method<XY>() == CONSTRAINED_METHOD_2);

} // namespace constrained members

namespace constrained_members_of_nested_types {

template <int>
struct S {
  struct Inner0 {
    struct Inner1 {
      template <Concept C>
      static constexpr int constrained_method();
    };
  };
};

template <>
template <Concept C>
constexpr int S<1>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; }

template <>
template <Concept C>
constexpr int S<2>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; }

static_assert(S<1>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_1);
static_assert(S<2>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_2);


template <class T1, class T2>
concept ConceptT1T2 = true;

template<typename T3>
struct S12 {
  struct Inner0 {
    struct Inner1 {
      template<ConceptT1T2<T3> T4>
      static constexpr int constrained_method();
    };
  };
};

template<>
template<ConceptT1T2<int> T5>
constexpr int S12<int>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; }

template<>
template<ConceptT1T2<double> T5>
constexpr int S12<double>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; }

static_assert(S12<int>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_1);
static_assert(S12<double>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_2);

} // namespace constrained_members_of_nested_types

namespace constrained_member_sfinae {

template<int N> struct S {
  template<class T>
  static constexpr int constrained_method() requires (sizeof(int[N * 1073741824 + 4]) == 16) { // expected-warning {{variable length arrays in C++ are a Clang extension}} \
                                                                                                  expected-note {{value 4294967296 is outside the range of representable values of type 'int'}} \
                                                                                                  expected-note {{while calculating associated constraint of template 'constrained_method' here}}
    return CONSTRAINED_METHOD_1;
  }

  template<class T>
  static constexpr int constrained_method() requires (sizeof(int[N]) == 16);
};

template<>
template<typename T>
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<double>() == CONSTRAINED_METHOD_2);

} // namespace constrained_member_sfinae

namespace requires_expression_references_members {

void accept1(int x);
void accept2(XY xy);

template <class T> struct S {
  T Field = T();

  constexpr int constrained_method()
      requires requires { accept1(Field); };

  constexpr int constrained_method()
      requires requires { accept2(Field); };
};

template <class T>
constexpr int S<T>::constrained_method()
  requires requires { accept1(Field); } {
  return CONSTRAINED_METHOD_1;
}

template <class T>
constexpr int S<T>::constrained_method()
  requires requires { accept2(Field); } {
  return CONSTRAINED_METHOD_2;
}

static_assert(S<int>().constrained_method() == CONSTRAINED_METHOD_1);
static_assert(S<XY>().constrained_method() == CONSTRAINED_METHOD_2);

} // namespace requires_expression_references_members

namespace GH60231 {

template<typename T0> concept C = true;

template <typename T1>
struct S {
  template <typename F1> requires C<S<T1>>
  void foo1(F1 f);

  template <typename F2>
  void foo2(F2 f) requires C<S<T1>>;

  template <typename F3> requires C<F3>
  void foo3(F3 f);
};

template <typename T2>
template <typename F4> requires C<S<T2>>
void S<T2>::foo1(F4 f) {}

template <typename T3>
template <typename F5>
void S<T3>::foo2(F5 f) requires C<S<T3>> {}

template <typename T4>
template <typename F6> requires C<F6>
void S<T4>::foo3(F6 f) {}

} // namespace GH60231

namespace GH62003 {

template <typename T0> concept Concept = true;

template <class T1>
struct S1 {
  template <Concept C1>
  static constexpr int foo();
};
template <class T2>
template <Concept C2>
constexpr int S1<T2>::foo() { return 1; }

template <Concept C3>
struct S2 {
  template <class T3>
  static constexpr int foo();
};
template <Concept C4>
template <class T4>
constexpr int S2<C4>::foo() { return 2; }

template <Concept C5>
struct S3 {
  template <Concept C6>
  static constexpr int foo();
};
template <Concept C7>
template <Concept C8>
constexpr int S3<C7>::foo() { return 3; }

static_assert(S1<int>::foo<int>() == 1);
static_assert(S2<int>::foo<int>() == 2);
static_assert(S3<int>::foo<int>() == 3);

} // namespace GH62003

namespace MultilevelTemplateWithPartialSpecialization {
template <typename>
concept Concept = true;

namespace two_level {
template <typename T1, int>
struct W0 {
  template <typename T2>
  requires (Concept<T2>)
  void f(const T2 &);
};

template <typename T3>
struct W0<T3, 0> {
  template <typename T4>
  requires (Concept<T4>)
  void f(const T4 &);
};

template <typename T3>
template <typename T4>
requires (Concept<T4>)
inline void W0<T3, 0>::f(const T4 &) {}
} // namespace two_level

namespace three_level {
template <typename T1, int>
struct W0 {
  template <typename T2>
  struct W1 {
    template <typename T3>
    requires (Concept<T3>)
    void f(const T3 &);
  };
};

template <typename T4>
struct W0<T4, 0> {
  template <typename T5>
  struct W1 {
    template <typename T6>
    requires (Concept<T6>)
    void f(const T6 &);
  };
};

template <typename T7>
template <typename T8>
template <typename T9>
requires (Concept<T9>)
inline void W0<T7, 0>::W1<T8>::f(const T9 &) {}
} // namespace three_level

} // namespace MultilevelTemplateWithPartialSpecialization

namespace PR62697 {
template<typename>
concept c = true;

template<typename T>
struct s {
    void f() requires c<void(T)>;
};

template<typename T>
void s<T>::f() requires c<void(T)> { }
}

namespace GH62272 {
template<typename T> concept A = true;
template<typename T> struct X { A<T> auto f(); };
template<typename T> A<T> auto X<T>::f() {}
}

namespace GH65810 {
template<typename Param>
concept TrivialConcept =
requires(Param param) {
  (void)param;
};

template <typename T>
struct Base {
  class InnerClass;
};

template <typename T>
class Base<T>::InnerClass {
  template <typename Param>
    requires TrivialConcept<Param>
    int func(Param param) const;
};

template <typename T>
template <typename Param>
requires TrivialConcept<Param>
int Base<T>::InnerClass::func(Param param) const {
  return 0;
}

template<typename T>
struct Outermost {
  struct Middle {
    template<typename U>
    struct Innermost {
      template <typename Param>
        requires TrivialConcept<Param>
        int func(Param param) const;
    };
  };
};

template <typename T>
template <typename U>
template <typename Param>
requires TrivialConcept<Param>
int Outermost<T>::Middle::Innermost<U>::func(Param param) const {
  return 0;
}

} // namespace GH65810

namespace GH61763 {
template<typename T, typename U>
concept same_as = true;

template <class = void>
struct Foo {
      template <same_as<void> Param>
            friend struct Bar;
};

template struct Foo<>;

template <same_as<void> Param>
struct Bar {
};


template<typename T>
concept ok = true;

struct outer {
    template<typename T>
        requires ok<T>
          struct foo {};
};

template<typename U>
struct bar {
    template<typename T>
        requires ok<T>
          friend struct outer::foo;
};

bar<int> x;
} // namespace GH61763


namespace GH74314 {
template <class T, class U> constexpr bool is_same_v = __is_same(T, U);
template <class T, class U> constexpr bool is_not_same_v = !__is_same(T, U);

template <class Result>
concept something_interesting = requires {
      true;
      requires is_same_v<int, Result>;
};

template <class T>
struct X { // #defined-here
      void foo() requires requires { requires is_not_same_v<T, int>; };
      void bar(decltype(requires { requires is_not_same_v<T, int>; }));
};

template <class T>
void X<T>::foo() requires requires { requires something_interesting<T>; } {}
// expected-error@-1{{definition of 'foo' does not match any declaration}}
// expected-note@#defined-here{{defined here}}
// expected-note@-8{{member declaration nearly matches}}

template <class T>
void X<T>::foo() requires requires { requires is_not_same_v<T, int>; } {} // ok

template <class T>
void X<T>::bar(decltype(requires { requires something_interesting<T>; })) {}
// expected-error@-1{{definition of 'bar' does not match any declaration}}
// expected-note@#defined-here{{defined here}}

template <class T>
void X<T>::bar(decltype(requires { requires is_not_same_v<T, int>; })) {}
} // namespace GH74314

namespace GH56482 {
template <typename SlotMap>
concept slot_map_has_reserve = true;

template <typename T> struct Slot_map {
  constexpr void reserve() const noexcept
    requires slot_map_has_reserve<Slot_map>;

  constexpr void reserve(int) const noexcept
    requires slot_map_has_reserve<Slot_map<T>>;
};

template <typename T>
constexpr void Slot_map<T>::reserve() const noexcept
  requires slot_map_has_reserve<Slot_map<T>>
{}

template <typename T>
constexpr void Slot_map<T>::reserve(int) const noexcept
  requires slot_map_has_reserve<Slot_map>
{}
} // namespace GH56482

namespace GH74447 {
template <typename T> struct S {
  template <typename... U, int V>
  void test(T target, U... value)
    requires requires {
      target;
      sizeof...(value) == 1;
      V == 2;
    };
};

template <typename T>
template <typename... U, int V>
void S<T>::test(T target, U... value)
  requires requires {
    target;
    sizeof...(value) == 1;
    V == 2;
  }
{}
} // namespace GH74447

namespace GH72557 {

template <typename...>
concept IsAnyOf = true;

template <class... DerTs> struct DerivedCollection {
  template <class DerT>
    requires IsAnyOf<DerTs...>
  unsigned long index();
};

template <class... DerTs>
template <class DerT>
  requires IsAnyOf<DerTs...>
unsigned long DerivedCollection<DerTs...>::index() {}

} // namespace GH72557

namespace GH101735 {

template <class, class>
concept True = true;

template <typename T>
class A {
  template <typename... Ts>
  void method(Ts&... ts)
    requires requires (T t) {
      { t.method(static_cast<Ts &&>(ts)...) } -> True<void>;
    };
};

template <typename T>
template <typename... Ts>
void A<T>::method(Ts&... ts)
  requires requires (T t) {
    { t.method(static_cast<Ts &&>(ts)...) } -> True<void>;
  } {}

}

namespace GH63782 {
// GH63782 was also fixed by PR #80594, so let's add a test for it.

template<bool... Vals>
constexpr bool All = (Vals && ...);

template<bool... Bs>
class Class {
  template<typename>
  requires All<Bs...>
  void Foo();
};

template<bool... Bs>
template<typename>
requires All<Bs...>
void Class<Bs...>::Foo() {
};

} // namespace GH63782

namespace eve {
// Reduced from the "eve" project

template <typename... Ts>
struct tuple {
  template <int I0> requires(I0 <= sizeof...(Ts))
  constexpr auto split();
};

template <typename... Ts>
template <int I0>
requires(I0 <= sizeof...(Ts))
constexpr auto tuple<Ts...>::split(){
  return 0;
}

int foo() {
  tuple<int, float> x;
  return x.split<0>();
}

} // namespace eve

namespace GH93099 {

// Issues with sizeof...(expr)

template <typename T = int> struct C {
  template <int... N>
    requires(sizeof...(N) > 0)
  friend class NTTP;

  template <class... Tp>
    requires(sizeof...(Tp) > 0)
  friend class TP;

  template <template <typename> class... TTp>
    requires(sizeof...(TTp) > 0)
  friend class TTP;
};

template <int... N>
  requires(sizeof...(N) > 0)
class NTTP;

template <class... Tp>
  requires(sizeof...(Tp) > 0)
class TP;

template <template <typename> class... TTp>
  requires(sizeof...(TTp) > 0)
class TTP;

C v;

} // namespace GH93099