if (flag_concepts)
{
tree tmpl_reqs = NULL_TREE;
- if (processing_template_decl > template_class_depth (ctype))
+ tree ctx = friendp ? current_class_type : ctype;
+ bool memtmpl = (processing_template_decl > template_class_depth (ctx));
+ if (memtmpl)
tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
tree ci = build_constraints (tmpl_reqs, decl_reqs);
if (concept_p && ci)
error_at (location, "a function concept cannot be constrained");
ci = NULL_TREE;
}
+ /* C++20 CA378: Remove non-templated constrained functions. */
+ if (ci && !flag_concepts_ts
+ && (!processing_template_decl
+ || (friendp && !memtmpl && !funcdef_flag)))
+ {
+ error_at (location, "constraints on a non-templated function");
+ ci = NULL_TREE;
+ }
set_constraints (decl, ci);
}
auto g0 = []<False T>(T t) { return t; };
auto g1 = []<typename T> requires False<T> (T t) { return t; };
auto g2 = []<typename T>(T t) requires False<decltype(t)> { return t; };
- auto g3 = [](int t) requires False<decltype(t)> { return t; };
+ auto g3 = [](int t) requires False<decltype(t)> { return t; }; // { dg-error "non-templated" }
auto g4 = [](False auto t) { return t; };
auto g5 = [](auto t) requires False<decltype(t)> { return t; };
- auto g6 = [](int t) requires False<int> { return t; };
- auto g7 = [](int t) requires false { return t; };
+ auto g6 = [](int t) requires False<int> { return t; }; // { dg-error "non-templated" }
+ auto g7 = [](int t) requires false { return t; }; // { dg-error "non-templated" }
g0(0); // { dg-error "no match" }
g1(0); // { dg-error "no match" }
g2(0); // { dg-error "no match" }
- g3(0); // { dg-error "no match" }
+ g3(0);
g4(0); // { dg-error "no match" }
g5(0); // { dg-error "no match" }
- g6(0); // { dg-error "no match" }
- g7(0); // { dg-error "no match" }
+ g6(0);
+ g7(0);
}
void test1()
auto g0 = [&]<False T>(T t) { return t; };
auto g1 = [&]<typename T> requires False<T> (T t) { return t; };
auto g2 = [&]<typename T>(T t) requires False<decltype(t)> { return t; };
- auto g3 = [&](int t) requires False<decltype(t)> { return t; };
+ auto g3 = [&](int t) requires False<decltype(t)> { return t; }; // { dg-error "non-templated" }
auto g4 = [&](False auto t) { return t; };
auto g5 = [&](auto t) requires False<decltype(t)> { return t; };
- auto g6 = [&](int t) requires False<int> { return t; };
- auto g7 = [&](int t) requires false { return t; };
+ auto g6 = [&](int t) requires False<int> { return t; }; // { dg-error "non-templated" }
+ auto g7 = [&](int t) requires false { return t; }; // { dg-error "non-templated" }
g0(0); // { dg-error "no match" }
g1(0); // { dg-error "no match" }
g2(0); // { dg-error "no match" }
- g3(0); // { dg-error "no match" }
+ g3(0);
g4(0); // { dg-error "no match" }
g5(0); // { dg-error "no match" }
- g6(0); // { dg-error "no match" }
- g7(0); // { dg-error "no match" }
+ g6(0);
+ g7(0);
}
void test2()
void test6()
{
- Func f1 = [](int a) requires false { return a; }; // { dg-error "cannot convert" }
+ Func f1 = [](int a) requires false { return a; }; // { dg-error "non-templated" }
Func f2 = [](auto a) requires false { return a; }; // { dg-error "cannot convert" }
}
template<typename T>
concept C = requires { typename T::type; };
-void f1(int a) requires true; // OK
-auto f2(int a) -> bool requires true; // OK
+void f1(int a) requires true; // { dg-error "non-templated" }
+auto f2(int a) -> bool requires true; // { dg-error "non-templated" }
auto f3(int a) requires true -> bool; // { dg-error "" } requires-clause precedes trailing-return-type
typedef void fn_t() requires true; // { dg-error "typedef" }
void (*pf)() requires true; // { dg-error "non-function" }