1 // { dg-do run { target c++17 } }
2 // { dg-options "-fconcepts" }
3 
4 #include <cassert>
5 
6 template<typename T>
C()7   concept bool C() { return __is_class(T); }
8 
9 template<typename T>
D()10   concept bool D() { return __is_empty(T); }
11 
12 struct X { } x;
13 struct Y { int n; } y;
14 
15 int called = 0;
16 
17 // Test constrained member definitions
18 template<typename T>
19   struct S1 {
f1S120     void f1() requires C<T>() { }
21 
f2S122     void f2() requires C<T>() { called = 1; }
f2S123     void f2() requires not C<T>() { called = 2; }
24 
f3S125     void f3() { called = 1; }
f3S126     void f3() requires C<T>() { called = 2; }
f3S127     void f3() requires C<T>() and D<T>() { called = 3; }
28 
29     void g1() requires C<T>() and true;
30 
31     void g2() requires C<T>();
32     void g2() requires not C<T>();
33 
34     void g3();
35     void g3() requires C<T>();
36     void g3() requires C<T>() and D<T>();
37 
h1S138     template<C U> void h1(U u) { called = 1; }
39     template<C U> void h2(U u);
40     template<C U> void h3(U u) requires D<U>();
41   };
42 
43 template<C T>
44   struct S2 {
45     void f(T) requires D<T>();
46   };
47 
48 
main()49 int main() {
50   S1<X> sx;
51   S1<Y> sy;
52   S1<int> si;
53 
54   // Defined in-class
55   sx.f1();
56   sx.f2(); assert(called == 1);
57   sx.f3(); assert(called == 3);
58 
59   sy.f1();
60   sy.f2(); assert(called == 1);
61   sy.f3(); assert(called == 2);
62 
63   si.f2(); assert(called == 2);
64   si.f3(); assert(called == 1);
65 
66   // Member function template tests
67   S1<int> s1i;
68   s1i.h1(x); assert(called == 1);
69   s1i.h2(x); assert(called == 2);
70   s1i.h3(x); assert(called == 3);
71 
72   // Defined out of class.
73   sx.g1();
74   sx.g2(); assert(called == 1);
75   sx.g3(); assert(called == 3);
76 
77   sy.g1();
78   sy.g2(); assert(called == 1);
79   sy.g3(); assert(called == 2);
80 
81   si.g2(); assert(called == 2);
82   si.g3(); assert(called == 1);
83 }
84 
85 template<typename T>
g1()86   void S1<T>::g1() requires C<T>() and true { }
87 
88 template<typename T>
g2()89   void S1<T>::g2() requires C<T>() { called = 1; }
90 
91 template<typename T>
g2()92   void S1<T>::g2() requires not C<T>() { called = 2; }
93 
94 template<typename T>
g3()95   void S1<T>::g3() { called = 1; }
96 
97 template<typename T>
g3()98   void S1<T>::g3() requires C<T>() { called = 2; }
99 
100 template<typename T>
g3()101   void S1<T>::g3() requires C<T>() and D<T>() { called = 3; }
102 
103 template<typename T>
104   template<C U>
h2(U u)105     void S1<T>::h2(U u) { called = 2; }
106 
107 template<typename T>
108   template<C U>
h3(U u)109       void S1<T>::h3(U u) requires D<U>() { called = 3; }
110 
111 template<C T>
f(T t)112   void S2<T>::f(T t) requires D<T>() { called = 4; }
113