xref: /llvm-project/clang/test/SemaTemplate/concepts-recursive-inst.cpp (revision 42667563721e139a93ab886119ea2780ebc3fecc)
1 // RUN: %clang_cc1 -std=c++20 -verify %s
2 namespace GH53213 {
3 template<typename T>
4 concept c = requires(T t) { f(t); }; // #CDEF
5 
6 auto f(c auto); // #FDEF
7 
g()8 void g() {
9   f(0);
10   // expected-error@-1{{no matching function for call to 'f'}}
11   // expected-note@#FDEF{{constraints not satisfied}}
12   // expected-note@#FDEF{{because 'int' does not satisfy 'c'}}
13   // expected-note@#CDEF{{because 'f(t)' would be invalid: no matching function for call to 'f'}}
14 }
15 } // namespace GH53213
16 
17 namespace GH45736 {
18 struct constrained;
19 
20 template<typename T>
21   struct type {
22   };
23 template<typename T>
f(type<T>)24   constexpr bool f(type<T>) {
25       return true;
26   }
27 
28 template<typename T>
29   concept matches = f(type<T>());
30 
31 
32 struct constrained {
33     template<typename U> requires matches<U>
constrainedGH45736::constrained34         explicit constrained(U value) {
35             }
36 };
37 
f(constrained const &)38 bool f(constrained const &) {
39     return true;
40 }
41 
42 struct outer {
43     constrained state;
44 };
45 
f(outer const & x)46 bool f(outer const & x) {
47     return f(x.state);
48 }
49 } // namespace GH45736
50 
51 namespace DirectRecursiveCheck {
52 template<class T>
53 concept NotInf = true;
54 template<class T>
55 concept Inf = requires(T& v){ // #INF_REQ
56   {begin(v)}; // #INF_BEGIN_EXPR
57 };
58 
begin(NotInf auto & v)59 void begin(NotInf auto& v){ } // #NOTINF_BEGIN
60 // This lookup should fail, since it results in a recursive check.
61 // However, this is a 'hard failure'(not a SFINAE failure or constraints
62 // violation), so it needs to cause the entire lookup to fail.
begin(Inf auto & v)63 void begin(Inf auto& v){ } // #INF_BEGIN
64 
65 struct my_range{
66 } rng;
67 
baz()68 void baz() {
69 auto it = begin(rng); // #BEGIN_CALL
70 // expected-error@#INF_BEGIN {{satisfaction of constraint 'Inf<Inf auto>' depends on itself}}
71 // expected-note@#INF_BEGIN {{while substituting template arguments into constraint expression here}}
72 // expected-note@#INF_BEGIN_EXPR {{while checking constraint satisfaction for template 'begin<DirectRecursiveCheck::my_range>' required here}}
73 // expected-note@#INF_BEGIN_EXPR {{while substituting deduced template arguments into function template 'begin'}}
74 // expected-note@#INF_BEGIN_EXPR {{in instantiation of requirement here}}
75 // expected-note@#INF_REQ {{while substituting template arguments into constraint expression here}}
76 // expected-note@#INF_BEGIN {{while checking the satisfaction of concept 'Inf<DirectRecursiveCheck::my_range>' requested here}}
77 // expected-note@#INF_BEGIN {{while substituting template arguments into constraint expression here}}
78 // expected-note@#BEGIN_CALL {{while checking constraint satisfaction for template 'begin<DirectRecursiveCheck::my_range>' required here}}
79 // expected-note@#BEGIN_CALL {{in instantiation of function template specialization}}
80 
81 // Fallout of the failure is failed lookup, which is necessary to stop odd
82 // cascading errors.
83 // expected-error@#BEGIN_CALL {{no matching function for call to 'begin'}}
84 // expected-note@#NOTINF_BEGIN {{candidate function}}
85 // expected-note@#INF_BEGIN{{candidate template ignored: constraints not satisfied}}
86 }
87 } // namespace DirectRecursiveCheck
88 
89 namespace GH50891 {
90   template <typename T>
91   concept Numeric = requires(T a) { // #NUMERIC
92       foo(a); // #FOO_CALL
93     };
94 
95   struct Deferred {
96     friend void foo(Deferred);
97     template <Numeric TO> operator TO(); // #OP_TO
98   };
99 
100   static_assert(Numeric<Deferred>); // #STATIC_ASSERT
101   // expected-error@#NUMERIC{{satisfaction of constraint 'requires (T a) { foo(a); }' depends on itself}}
102   // expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
103   // expected-note@#OP_TO {{while checking the satisfaction of concept 'Numeric<GH50891::Deferred>' requested here}}
104   // expected-note@#OP_TO {{while substituting template arguments into constraint expression here}}
105   // expected-note@#FOO_CALL {{while checking constraint satisfaction for template}}
106   // expected-note@#FOO_CALL {{in instantiation of function template specialization}}
107   // expected-note@#FOO_CALL {{in instantiation of requirement here}}
108   // expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
109 
110   // expected-error@#STATIC_ASSERT {{static assertion failed}}
111   // expected-note@#STATIC_ASSERT{{while checking the satisfaction of concept 'Numeric<GH50891::Deferred>' requested here}}
112   // expected-note@#STATIC_ASSERT{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
113 
114 } // namespace GH50891
115 
116 
117 namespace GH60323 {
118   // This should not diagnose, as it does not depend on itself.
119   struct End {
120         template<class T>
goGH60323::End121               void go(T t) { }
122 
123             template<class T>
endparensGH60323::End124                   auto endparens(T t)
125                           requires requires { go(t); }
126                 { return go(t); }
127   };
128 
129   struct Size {
130         template<class T>
goGH60323::Size131               auto go(T t)
132                   { return End().endparens(t); }
133 
134             template<class T>
sizeparensGH60323::Size135                   auto sizeparens(T t)
136                           requires requires { go(t); }
137                 { return go(t); }
138   };
139 
f()140   int f()
141   {
142         int i = 42;
143             Size().sizeparens(i);
144   }
145 }
146