// { dg-do compile { target c++2a } } // { dg-additional-options "-fconcepts-ts" } // Basic tests using function concepts. template concept bool Type() { return true; } template concept bool False() { return false; } template concept bool Class() { return __is_class(T); } template concept bool EmptyClass() { return Class() && __is_empty(T); } template concept bool Classes() { return __is_class(T) && __is_class (U); } struct empty { }; struct nonempty { int n; }; static_assert(Type()); static_assert(False()); // { dg-error "static assertion failed" } // Basic checks template requires (Type()) int fn1(T t) { return 0; } template requires (False()) int fn2(T t) { return 0; } void driver() { fn1(0); // OK fn2(0); // { dg-error "" } } // Ordering template concept bool Cf() { return requires (T t) { t.f(); }; } template concept bool Cfg() { return Cf() && requires (T t) { t.g(); }; } template concept bool Cf2() { return requires (T t) { t.f(); }; } template constexpr int algo(T t) { return 0; } template requires (Cf()) constexpr int algo(T t) { return 1; } template requires (Cfg()) constexpr int algo(T t) { return 2; } template requires (Cf()) constexpr int ambig(T t) { return 1; } template requires (Cf2()) constexpr int ambig(T t) { return 1; } struct T1 { void f() { } }; struct T2 : T1 { void g() { } }; void driver_0() { T1 x; T2 y; static_assert(algo(0) == 0); static_assert(algo(x) == 1); static_assert(algo(y) == 2); ambig(x); // { dg-error "call of overload | is ambiguous" } } template struct S { void f() requires (Class()) { } template struct Inner { void g() requires (Classes()) { } }; template requires (Classes()) void h(U) { } }; struct X { }; void driver_1() { S s1; s1.f(); // OK s1.h(s1); // OK s1.h(0); // { dg-error "no matching function" } S s2; s2.f(); // { dg-error "no matching function" } S::Inner si1; si1.g(); S::Inner si2; si2.g(); // { dg-error "no matching function" } } // Check constraints on non-dependent arguments, even when in a // dependent context. template requires (Class()) void f1(T x) { } // fn1-2.C -- Dependent checks template void caller_1(T x) { f1(x); // Unchecked dependent arg. f1(empty{}); // Checked non-dependent arg, but OK f1(0); // { dg-error "" } } // fn3.c -- Ordering template requires (Class()) constexpr int f2(T x) { return 1; } template requires (EmptyClass()) constexpr int f2(T x) { return 2; } template constexpr int f3(T x) requires (Class()) { return 1; } template constexpr int f3(T x) requires (EmptyClass()) { return 2; } void driver_2() { f2(0); // { dg-error "no matching function" } static_assert (f2(empty{}) == 2); static_assert (f2(nonempty{}) == 1); f3(0); // { dg-error "no matching function" } static_assert (f3(empty{}) == 2); static_assert (f3(nonempty{}) == 1); } // fn8.C -- Address of overloaded functions template requires (Type()) void ok(T) { } template requires (Class()) void err(T) { } auto p1 = &ok; auto p2 = &err; // { dg-error "" } void (*p3)(int) = &ok; void (*p4)(int) = &err; // { dg-error "no matches" } void (*p5)(int) = &ok; void (*p6)(int) = &err; // { dg-error "no matches" } template void g(T x) { } void driver_3 () { g(&ok); g(&err); // { dg-error "no matches" } } struct S2 { template requires (Type()) int ok(T) { return 0; } template requires (Class()) int err(T) { return 0; } }; auto p7 = &S2::ok; auto p8 = &S2::err; // { dg-error "" } int (S2::*p9)(int) = &S2::ok; int (S2::*p10)(int) = &S2::err; // { dg-error "no matches" } int (S2::*p11)(int) = &S2::ok; int (S2::*p12)(int) = &S2::err; // { dg-error "no matches" } // fn9.C -- Ordering with function address template requires (Class()) constexpr int fn(T) { return 1; } template requires (EmptyClass()) constexpr int fn(T) { return 2; } struct S3 { template requires (Class()) constexpr int fn(T) const { return 1; } template requires (EmptyClass()) constexpr int fn(T) const { return 2; } }; void driver_5 () { struct X { }; struct Y { X x; }; constexpr X x; constexpr Y y; constexpr S3 s; constexpr auto p1 = &fn; // Empty f static_assert (p1(x) == 2); constexpr auto p2 = &fn; // Class f static_assert(p2(y) == 1); constexpr auto p3 = &S3::fn; // Empty f static_assert((s.*p3)(x) == 2); constexpr auto p4 = &S3::fn; // Empty f static_assert((s.*p4)(y) == 1); } // Redeclarations // FIXME: This should be a diagnosable error. The programmer has moved // the requirements from the template-head to the declarator. template requires (Type()) void f3(); template void f3() requires (Type()); void driver_4() { f3(); // { dg-error "call of overload | ambiguous" } } template requires true class X> void f4(); template class X> void f4(); // OK: different declarations template requires (Type()) void def() { } template requires (Type()) void def() { } // { dg-error "redefinition" } // fn-concept1.C template concept bool Tuple() { // { dg-error "multiple statements" } static_assert(T::value, ""); return true; } void f(Tuple&);