aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/g++.dg/cpp2a/concepts-fn1.C
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/testsuite/g++.dg/cpp2a/concepts-fn1.C')
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-fn1.C248
1 files changed, 248 insertions, 0 deletions
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-fn1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-fn1.C
new file mode 100644
index 00000000000..33f3a7490bb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-fn1.C
@@ -0,0 +1,248 @@
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept Type = true;
+
+template<typename T>
+concept False = false;
+
+template<typename T>
+concept Class = __is_class(T);
+
+template<typename T>
+concept EmptyClass = Class<T> && __is_empty(T);
+
+template<typename T, typename U>
+concept Classes = __is_class(T) && __is_class (U);
+
+struct empty { };
+
+struct nonempty { int n; };
+
+static_assert(Type<int>);
+static_assert(False<int>); // { dg-error "static assertion failed" }
+
+// Basic checks
+
+template<typename T>
+ requires Type<T>
+int fn1(T t) { return 0; }
+
+template<typename T>
+ requires False<T>
+int fn2(T t) { return 0; }
+
+void driver()
+{
+ fn1(0); // OK
+ fn2(0); // { dg-error "cannot call function" }
+}
+
+// Ordering
+
+template<typename T>
+concept Cf = requires (T t) { t.f(); };
+
+template<typename T>
+concept Cfg = Cf<T> && requires (T t) { t.g(); };
+
+template<typename T>
+concept Cf2 = requires (T t) { t.f(); };
+
+template<typename T>
+constexpr int algo(T t) { return 0; }
+
+template<typename T> requires Cf<T>
+constexpr int algo(T t) { return 1; }
+
+template<typename T> requires Cfg<T>
+constexpr int algo(T t) { return 2; }
+
+template<typename T> requires Cf<T>
+constexpr int ambig(T t) { return 1; }
+
+template<typename T> requires Cf2<T>
+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<typename T>
+struct S
+{
+ void f() requires Class<T> { }
+
+ template<typename U>
+ struct Inner
+ {
+ void g() requires Classes<T, U> { }
+ };
+
+ template<typename U> requires Classes<T, U> void h(U) { }
+};
+
+struct X { };
+
+void driver_1()
+{
+ S<X> s1;
+ s1.f(); // OK
+ s1.h(s1); // OK
+ s1.h(0); // { dg-error "no matching function" }
+
+ S<int> s2;
+ s2.f(); // { dg-error "no matching function" }
+
+ S<X>::Inner<X> si1;
+ si1.g();
+
+ S<X>::Inner<int> si2;
+ si2.g(); // { dg-error "no matching function" }
+}
+
+// Check constraints on non-dependent arguments, even when in a
+// dependent context.
+
+template<typename T> requires Class<T> void f1(T x) { }
+
+// fn1-2.C -- Dependent checks
+template<typename T>
+void caller_1(T x)
+{
+ f1(x); // Unchecked dependent arg.
+ f1(empty{}); // Checked non-dependent arg, but OK
+ f1(0); // { dg-error "cannot call function" }
+}
+
+// fn3.c -- Ordering
+template<typename T>
+ requires Class<T>
+constexpr int f2(T x) { return 1; }
+
+template<typename T>
+ requires EmptyClass<T>
+constexpr int f2(T x) { return 2; }
+
+template<typename T>
+constexpr int f3(T x) requires Class<T> { return 1; }
+
+template<typename T>
+constexpr int f3(T x) requires EmptyClass<T> { 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<typename T> requires Type<T> void ok(T) { }
+template<typename T> requires Class<T> void err(T) { }
+
+auto p1 = &ok<int>;
+auto p2 = &err<int>; // { dg-error "no matches" }
+void (*p3)(int) = &ok<int>;
+void (*p4)(int) = &err<int>; // { dg-error "no matches" }
+void (*p5)(int) = &ok;
+void (*p6)(int) = &err; // { dg-error "no matches" }
+
+template<typename T> void g(T x) { }
+
+void driver_3 ()
+{
+ g(&ok<int>);
+ g(&err<int>); // { dg-error "no matches" }
+}
+
+
+struct S2 {
+ template<typename T> requires Type<T> int ok(T) { return 0; }
+ template<typename T> requires Class<T> int err(T) { return 0; }
+};
+
+auto p7 = &S2::ok<int>;
+auto p8 = &S2::err<int>; // { dg-error "no matches" }
+int (S2::*p9)(int) = &S2::ok<int>;
+int (S2::*p10)(int) = &S2::err<int>; // { 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<typename T>
+ requires Class<T>
+constexpr int fn(T) { return 1; }
+
+template<typename T>
+ requires EmptyClass<T>
+constexpr int fn(T) { return 2; }
+
+struct S3
+{
+ template<typename T>
+ requires Class<T>
+ constexpr int fn(T) const { return 1; }
+
+ template<typename T>
+ requires EmptyClass<T>
+ 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<X>; // Empty f
+ static_assert (p1(x) == 2);
+
+ constexpr auto p2 = &fn<Y>; // Class f
+ static_assert(p2(y) == 1);
+
+ constexpr auto p3 = &S3::fn<X>; // Empty f
+ static_assert((s.*p3)(x) == 2);
+
+ constexpr auto p4 = &S3::fn<Y>; // 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<typename T> requires Type<T> void f3();
+template<typename T> void f3() requires Type<T>;
+
+void driver_4()
+{
+ f3<int>(); // { dg-error "call of overload | ambiguous" }
+}
+
+template<template<typename T> requires true class X> void f4();
+template<template<typename T> class X> void f4(); // OK: different declarations
+
+template<typename T> requires Type<T> void def() { }
+template<typename T> requires Type<T> void def() { } // { dg-error "redefinition" }
+