summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/CXX/class.derived/class.virtual/p6.cpp21
-rw-r--r--clang/test/CXX/dcl/dcl.decl/p3.cpp35
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.id/mixed-constraints.cpp18
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp58
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp20
-rw-r--r--clang/test/CXX/over/over.match/over.match.best/p1-2a.cpp114
-rw-r--r--clang/test/CXX/over/over.match/over.match.viable/p3.cpp63
-rw-r--r--clang/test/CXX/over/over.over/p4-2a.cpp61
-rw-r--r--clang/test/CXX/temp/temp.constr/temp.constr.constr/function-templates.cpp5
-rw-r--r--clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp16
-rw-r--r--clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp12
-rw-r--r--clang/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp12
-rw-r--r--clang/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp10
-rw-r--r--clang/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp8
-rw-r--r--clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp21
-rw-r--r--clang/test/CXX/temp/temp.constr/temp.constr.order/function-templates.cpp10
-rw-r--r--clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp8
-rw-r--r--clang/test/CXX/temp/temp.explicit/p8.cpp22
-rw-r--r--clang/test/Parser/cxx-concepts-ambig-constraint-expr.cpp24
-rw-r--r--clang/test/Parser/cxx-concepts-requires-clause.cpp99
-rw-r--r--clang/test/SemaTemplate/instantiate-requires-clause.cpp31
21 files changed, 592 insertions, 76 deletions
diff --git a/clang/test/CXX/class.derived/class.virtual/p6.cpp b/clang/test/CXX/class.derived/class.virtual/p6.cpp
new file mode 100644
index 00000000000..63a4313de55
--- /dev/null
+++ b/clang/test/CXX/class.derived/class.virtual/p6.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+template<typename T>
+class A {
+ virtual void f1() requires (sizeof(T) == 0);
+ // expected-error@-1{{virtual function cannot have a requires clause}}
+ virtual void f2() requires (sizeof(T) == 1);
+ // expected-error@-1{{virtual function cannot have a requires clause}}
+};
+
+template<typename T>
+class B : A<T> {
+ virtual void f1() requires (sizeof(T) == 0) override {}
+ // expected-error@-1{{virtual function cannot have a requires clause}}
+};
+
+template<typename T> struct C : T {void f() requires true; };
+// expected-error@-1{{virtual function cannot have a requires clause}}
+struct D { virtual void f(); };
+template struct C<D>;
+// expected-note@-1{{in instantiation of template class 'C<D>' requested here}} \ No newline at end of file
diff --git a/clang/test/CXX/dcl/dcl.decl/p3.cpp b/clang/test/CXX/dcl/dcl.decl/p3.cpp
new file mode 100644
index 00000000000..eec0aa2043a
--- /dev/null
+++ b/clang/test/CXX/dcl/dcl.decl/p3.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+template<typename T, typename U>
+constexpr bool is_same_v = false;
+
+template<typename T>
+constexpr bool is_same_v<T, T> = true;
+
+void f1(int a) requires true; // OK
+auto f2(int a) -> bool requires true; // OK
+auto f3(int a) -> bool (*)(int b) requires true; // OK
+auto f4(int a) requires true -> bool; // expected-error{{trailing return type must appear before trailing requires clause}}
+int f5(int a) requires; // expected-error{{expected expression}}
+int f6(int a) requires {} // expected-error{{expected expression}}
+void (f7()) requires true;
+void (f8() requires true); // expected-error{{trailing requires clause should be placed outside parentheses}}
+void (*(f9 requires (true)))(); // expected-error{{trailing requires clause should be placed outside parentheses}}
+static_assert(is_same_v<decltype(f9), void (*)()>);
+void (*pf)() requires true; // expected-error{{trailing requires clause can only be used when declaring a function}}
+void g1(int (*dsdads)() requires false); // expected-error{{trailing requires clause can only be used when declaring a function}}
+void g2(int (*(*dsdads)())() requires true); // expected-error{{trailing requires clause can only be used when declaring a function}}
+void g3(int (*(*dsdads)(int) requires true)() ); // expected-error{{trailing requires clause should be placed outside parentheses}}
+using T = void ();
+T x requires true;
+struct S {
+ T m1 requires true, m2 requires true;
+};
+
+template<typename T>
+struct R {
+ R(T t);
+};
+
+template<typename T>
+R(T) -> R<T> requires true; // expected-error{{deduction guide cannot have a requires clause}}
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/mixed-constraints.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/mixed-constraints.cpp
new file mode 100644
index 00000000000..fafb3f7b35d
--- /dev/null
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/mixed-constraints.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+template<typename T> requires (sizeof(T) >= 4 && sizeof(T) <= 10)
+// expected-note@-1{{because 'sizeof(char [20]) <= 10' (20 <= 10) evaluated to false}}
+// expected-note@-2{{because 'sizeof(char) >= 4' (1 >= 4) evaluated to false}}
+void foo() requires (sizeof(T) <= 8) {}
+// expected-note@-1{{candidate template ignored: constraints not satisfied [with T = char]}}
+// expected-note@-2{{candidate template ignored: constraints not satisfied [with T = char [9]]}}
+// expected-note@-3{{candidate template ignored: constraints not satisfied [with T = char [20]]}}
+// expected-note@-4{{because 'sizeof(char [9]) <= 8' (9 <= 8) evaluated to false}}
+
+void bar() {
+ foo<char>(); // expected-error{{no matching function for call to 'foo'}}
+ foo<int>();
+ foo<unsigned long long int>();
+ foo<char[9]>(); // expected-error{{no matching function for call to 'foo'}}
+ foo<char[20]>(); // expected-error{{no matching function for call to 'foo'}}
+} \ No newline at end of file
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp
new file mode 100644
index 00000000000..f13ab279da3
--- /dev/null
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+namespace functions
+{
+ void foo(int) requires false {}
+ // expected-note@-1 3{{because 'false' evaluated to false}}
+ // expected-note@-2 {{candidate function not viable: constraints not satisfied}}
+ void bar(int) requires true {}
+
+ void a(int);
+ void a(double);
+
+ void baz() {
+ foo(1); // expected-error{{no matching function for call to 'foo'}}
+ bar(1);
+ void (*p1)(int) = foo; // expected-error{{invalid reference to function 'foo': constraints not satisfied}}
+ void (*p3)(int) = bar;
+ decltype(foo)* a1 = nullptr; // expected-error{{invalid reference to function 'foo': constraints not satisfied}}
+ decltype(bar)* a2 = nullptr;
+ }
+}
+
+namespace methods
+{
+ template<typename T>
+ struct A {
+ static void foo(int) requires (sizeof(T) == 1) {} // expected-note 3{{because 'sizeof(char [2]) == 1' (2 == 1) evaluated to false}}
+ static void bar(int) requires (sizeof(T) == 2) {} // expected-note 3{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}}
+ };
+
+ void baz() {
+ A<char>::foo(1);
+ A<char>::bar(1); // expected-error{{invalid reference to function 'bar': constraints not satisfied}}
+ A<char[2]>::foo(1); // expected-error{{invalid reference to function 'foo': constraints not satisfied}}
+ A<char[2]>::bar(1);
+ void (*p1)(int) = A<char>::foo;
+ void (*p2)(int) = A<char>::bar; // expected-error{{invalid reference to function 'bar': constraints not satisfied}}
+ void (*p3)(int) = A<char[2]>::foo; // expected-error{{invalid reference to function 'foo': constraints not satisfied}}
+ void (*p4)(int) = A<char[2]>::bar;
+ decltype(A<char>::foo)* a1 = nullptr;
+ decltype(A<char>::bar)* a2 = nullptr; // expected-error{{invalid reference to function 'bar': constraints not satisfied}}
+ decltype(A<char[2]>::foo)* a3 = nullptr; // expected-error{{invalid reference to function 'foo': constraints not satisfied}}
+ decltype(A<char[2]>::bar)* a4 = nullptr;
+ }
+}
+
+namespace operators
+{
+ template<typename T>
+ struct A {
+ A<T> operator-(A<T> b) requires (sizeof(T) == 1) { return b; } // expected-note{{because 'sizeof(int) == 1' (4 == 1) evaluated to false}}
+ };
+
+ void baz() {
+ auto* x = &A<int>::operator-; // expected-error{{invalid reference to function 'operator-': constraints not satisfied}}
+ auto y = &A<char>::operator-;
+ }
+} \ No newline at end of file
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp
new file mode 100644
index 00000000000..942280e1059
--- /dev/null
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+auto l1 = [] (auto x) requires (sizeof(decltype(x)) == 1) { return x; };
+// expected-note@-1{{candidate template ignored: constraints not satisfied [with $0 = int]}}
+// expected-note@-2{{because 'sizeof(decltype(x)) == 1' (4 == 1) evaluated to false}}
+
+auto l1t1 = l1('a');
+auto l1t2 = l1(1);
+// expected-error@-1{{no matching function for call to object of type '(lambda at}}
+
+auto l2 = [] (auto... x) requires ((sizeof(decltype(x)) >= 2) && ...) { return (x + ...); };
+// expected-note@-1{{candidate template ignored: constraints not satisfied [with $0 = <char>]}}
+// expected-note@-2{{candidate template ignored: constraints not satisfied [with $0 = <int, char>]}}
+// expected-note@-3 2{{because 'sizeof(decltype(x)) >= 2' (1 >= 2) evaluated to false}}
+
+auto l2t1 = l2('a');
+// expected-error@-1{{no matching function for call to object of type '(lambda at}}
+auto l2t2 = l2(1, 'a');
+// expected-error@-1{{no matching function for call to object of type '(lambda at}}
+auto l2t3 = l2((short)1, (short)1); \ No newline at end of file
diff --git a/clang/test/CXX/over/over.match/over.match.best/p1-2a.cpp b/clang/test/CXX/over/over.match/over.match.best/p1-2a.cpp
new file mode 100644
index 00000000000..dba2ef204e1
--- /dev/null
+++ b/clang/test/CXX/over/over.match/over.match.best/p1-2a.cpp
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+template<typename T, typename U>
+constexpr static bool is_same_v = false;
+
+template<typename T>
+constexpr static bool is_same_v<T, T> = true;
+
+namespace templates
+{
+ template<typename T>
+ concept AtLeast1 = sizeof(T) >= 1;
+
+ template<typename T>
+ int foo(T t) requires (sizeof(T) == 4) { // expected-note {{candidate function}}
+ return 0;
+ }
+
+ template<typename T>
+ char foo(T t) requires AtLeast1<T> { // expected-note {{candidate function}}
+ return 'a';
+ }
+
+ template<typename T>
+ double foo(T t) requires (AtLeast1<T> && sizeof(T) <= 2) {
+ return 'a';
+ }
+
+ static_assert(is_same_v<decltype(foo(10)), int>); // expected-error {{call to 'foo' is ambiguous}}
+ static_assert(is_same_v<decltype(foo(short(10))), double>);
+
+ template<typename T>
+ void bar() requires (sizeof(T) == 1) { }
+ // expected-note@-1{{similar constraint expressions not considered equivalent}}
+ // expected-note@-2{{candidate function [with T = char]}}
+
+ template<typename T>
+ void bar() requires (sizeof(T) == 1 && sizeof(T) >= 0) { }
+ // expected-note@-1{{candidate function [with T = char]}}
+ // expected-note@-2{{similar constraint expression here}}
+
+ static_assert(is_same_v<decltype(bar<char>()), void>);
+ // expected-error@-1{{call to 'bar' is ambiguous}}
+
+ template<typename T>
+ constexpr int baz() requires AtLeast1<T> { // expected-note {{candidate function}}
+ return 1;
+ }
+
+ template<typename T> requires AtLeast1<T>
+ constexpr int baz() { // expected-note {{candidate function [with T = int]}}
+ return 2;
+ }
+
+ static_assert(baz<int>() == 1); // expected-error {{call to 'baz' is ambiguous}}
+}
+
+namespace non_template
+{
+ template<typename T>
+ concept AtLeast2 = sizeof(T) >= 2;
+
+ template<typename T>
+ concept AtMost8 = sizeof(T) <= 8;
+
+ int foo() requires AtLeast2<long> && AtMost8<long> {
+ return 0;
+ }
+
+ double foo() requires AtLeast2<long> {
+ return 0.0;
+ }
+
+ double baz() requires AtLeast2<long> && AtMost8<long> { // expected-note {{candidate function}}
+ return 0.0;
+ }
+
+ int baz() requires AtMost8<long> && AtLeast2<long> { // expected-note {{candidate function}}
+ return 0.0;
+ }
+
+ void bar() requires (sizeof(long) >= 8) { }
+ // expected-note@-1 {{candidate function}}
+ // expected-note@-2 {{similar constraint expressions not considered equivalent}}
+
+ void bar() requires (sizeof(long) >= 8 && sizeof(int) <= 30) { }
+ // expected-note@-1 {{candidate function}}
+ // expected-note@-2 {{similar constraint expression here}}
+
+ static_assert(is_same_v<decltype(foo()), int>);
+ static_assert(is_same_v<decltype(baz()), int>); // expected-error {{call to 'baz' is ambiguous}}
+ static_assert(is_same_v<decltype(bar()), void>); // expected-error {{call to 'bar' is ambiguous}}
+
+ constexpr int goo(int a) requires AtLeast2<int> && true {
+ return 1;
+ }
+
+ constexpr int goo(const int b) requires AtLeast2<int> {
+ return 2;
+ }
+
+ // Only trailing requires clauses of redeclarations are compared for overload resolution.
+ constexpr int doo(int a, ...) requires AtLeast2<int> && true { // expected-note {{candidate function}}
+ return 1;
+ }
+
+ constexpr int doo(int b) requires AtLeast2<int> { // expected-note {{candidate function}}
+ return 2;
+ }
+
+ static_assert(goo(1) == 1);
+ static_assert(doo(2) == 1); // expected-error {{call to 'doo' is ambiguous}}
+}
+
diff --git a/clang/test/CXX/over/over.match/over.match.viable/p3.cpp b/clang/test/CXX/over/over.match/over.match.viable/p3.cpp
new file mode 100644
index 00000000000..ef752d76ec2
--- /dev/null
+++ b/clang/test/CXX/over/over.match/over.match.viable/p3.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+struct S2 {};
+// expected-note@-1 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'S1' to 'const S2' for 1st argument}}
+// expected-note@-2 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'S1' to 'S2' for 1st argument}}
+// expected-note@-3 {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
+
+struct S1 {
+ void foo() const requires true {}
+ void foo() const requires false {}
+ void bar() const requires false {}
+ // expected-note@-1 {{because 'false' evaluated to false}}
+ operator bool() const requires true { return true; }
+ explicit operator bool() const requires false;
+ explicit operator S2() const requires false;
+ // expected-note@-1 {{candidate function not viable: constraints not satisfied}}
+ // expected-note@-2 {{because 'false' evaluated to false}}
+};
+
+void foo() {
+ S1().foo();
+ S1().bar();
+ // expected-error@-1 {{invalid reference to function 'bar': constraints not satisfied}}
+ (void) static_cast<bool>(S1());
+ (void) static_cast<S2>(S1());
+ // expected-error@-1 {{no matching conversion for static_cast from 'S1' to 'S2'}}
+}
+
+// Test that constraints are checked before implicit conversions are formed.
+
+template<typename T>
+struct invalid_template { using X = typename T::non_existant; };
+struct A {
+ template<typename T, bool=invalid_template<T>::aadasas>
+ operator T() {}
+};
+
+void foo(int) requires false;
+void foo(A) requires true;
+
+struct S {
+ void foo(int) requires false;
+ void foo(A) requires true;
+ S(A) requires false;
+ S(double) requires true;
+ ~S() requires false;
+ // expected-note@-1 2{{because 'false' evaluated to false}}
+ ~S() requires true;
+ operator int() requires true;
+ operator int() requires false;
+};
+
+void bar() {
+ foo(A{});
+ S{1.}.foo(A{});
+ // expected-error@-1{{invalid reference to function '~S': constraints not satisfied}}
+ // Note - this behavior w.r.t. constrained dtors is a consequence of current
+ // wording, which does not invoke overload resolution when a dtor is called.
+ // P0848 is set to address this issue.
+ S s = 1;
+ // expected-error@-1{{invalid reference to function '~S': constraints not satisfied}}
+ int a = s;
+} \ No newline at end of file
diff --git a/clang/test/CXX/over/over.over/p4-2a.cpp b/clang/test/CXX/over/over.over/p4-2a.cpp
new file mode 100644
index 00000000000..a5d7a110992
--- /dev/null
+++ b/clang/test/CXX/over/over.over/p4-2a.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+template<typename T, typename U>
+constexpr static bool is_same_v = false;
+
+template<typename T>
+constexpr static bool is_same_v<T, T> = true;
+
+template<typename T>
+concept AtLeast2 = sizeof(T) >= 2;
+
+template<typename T>
+concept AtMost8 = sizeof(T) <= 8;
+
+int foo() requires AtLeast2<long> && AtMost8<long> {
+ return 0;
+}
+
+double foo() requires AtLeast2<char> {
+ return 0.0;
+}
+
+char bar() requires AtLeast2<char> { // expected-note {{possible target for call}}
+ return 1.0;
+}
+
+short bar() requires AtLeast2<long> && AtMost8<long> {
+// expected-note@-1{{possible target for call}}
+// expected-note@-2{{candidate function}}
+ return 0.0;
+}
+
+int bar() requires AtMost8<long> && AtLeast2<long> {
+// expected-note@-1{{possible target for call}}
+// expected-note@-2{{candidate function}}
+ return 0.0;
+}
+
+char baz() requires AtLeast2<char> {
+ return 1.0;
+}
+
+short baz() requires AtLeast2<long> && AtMost8<long> {
+ return 0.0;
+}
+
+int baz() requires AtMost8<long> && AtLeast2<long> {
+ return 0.0;
+}
+
+long baz() requires AtMost8<long> && AtLeast2<long> && AtLeast2<short> {
+ return 3.0;
+}
+
+void a() {
+ static_assert(is_same_v<decltype(&foo), int(*)()>);
+ static_assert(is_same_v<decltype(&bar), long(*)()>);
+ // expected-error@-1{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}}
+ // expected-error@-2{{call to 'bar' is ambiguous}}
+ static_assert(is_same_v<decltype(&baz), long(*)()>);
+} \ No newline at end of file
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/function-templates.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/function-templates.cpp
index c1a3a27fbea..99de7261a81 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/function-templates.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.constr/function-templates.cpp
@@ -23,14 +23,13 @@ static_assert(is_same_v<decltype(dereference<int*>(nullptr)), int>);
static_assert(is_same_v<decltype(dereference(2)), int>); // expected-error {{no matching function for call to 'dereference'}}
static_assert(is_same_v<decltype(dereference<char>('a')), char>); // expected-error {{no matching function for call to 'dereference'}}
-
-template<typename T> requires T{} + T{} // expected-note {{because substituted constraint expression is ill-formed: invalid operands to binary expression ('A' and 'A')}}
+template<typename T> requires (T{} + T{}) // expected-note {{because substituted constraint expression is ill-formed: invalid operands to binary expression ('A' and 'A')}}
auto foo(T t) { // expected-note {{candidate template ignored: constraints not satisfied [with T = A]}}
return t + t;
}
-template<typename T> requires !((T{} - T{}) && (T{} + T{})) || false
+template<typename T> requires (!((T{} - T{}) && (T{} + T{})) || false)
// expected-note@-1{{because substituted constraint expression is ill-formed: invalid operands to binary expression ('A' and 'A')}}
// expected-note@-2{{and 'false' evaluated to false}}
auto bar(T t) { // expected-note {{candidate template ignored: constraints not satisfied [with T = A]}}
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
index 24caa5063a1..a25b22a9a15 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
-template<typename T> requires sizeof(T) >= 2 // expected-note{{because 'sizeof(char) >= 2' (1 >= 2) evaluated to false}}
+template<typename T> requires (sizeof(T) >= 2) // expected-note{{because 'sizeof(char) >= 2' (1 >= 2) evaluated to false}}
struct A {
static constexpr int value = sizeof(T);
};
@@ -9,8 +9,8 @@ static_assert(A<int>::value == 4);
static_assert(A<char>::value == 1); // expected-error{{constraints not satisfied for class template 'A' [with T = char]}}
template<typename T, typename U>
- requires sizeof(T) != sizeof(U) // expected-note{{because 'sizeof(int) != sizeof(char [4])' (4 != 4) evaluated to false}}
- && sizeof(T) >= 4 // expected-note{{because 'sizeof(char) >= 4' (1 >= 4) evaluated to false}}
+ requires (sizeof(T) != sizeof(U) // expected-note{{because 'sizeof(int) != sizeof(char [4])' (4 != 4) evaluated to false}}
+ && sizeof(T) >= 4) // expected-note{{because 'sizeof(char) >= 4' (1 >= 4) evaluated to false}}
constexpr int SizeDiff = sizeof(T) > sizeof(U) ? sizeof(T) - sizeof(U) : sizeof(U) - sizeof(T);
static_assert(SizeDiff<int, char> == 3);
@@ -44,16 +44,16 @@ static_assert(S<S2>::value);
template<typename T>
struct AA
{
- template<typename U> requires sizeof(U) == sizeof(T) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}}
+ template<typename U> requires (sizeof(U) == sizeof(T)) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}}
struct B
{
static constexpr int a = 0;
};
- template<typename U> requires sizeof(U) == sizeof(T) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}}
+ template<typename U> requires (sizeof(U) == sizeof(T)) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}}
static constexpr int b = 1;
- template<typename U> requires sizeof(U) == sizeof(T) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}}
+ template<typename U> requires (sizeof(U) == sizeof(T)) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}}
static constexpr int getB() { // expected-note{{candidate template ignored: constraints not satisfied [with U = int [2]]}}
return 2;
}
@@ -85,8 +85,8 @@ template<typename T> requires B<T>::type // expected-note{{in instantiation of t
// expected-note@-1{{while substituting template arguments into constraint expression here}}
struct C { };
-template<typename T> requires T{} // expected-error{{atomic constraint must be of type 'bool' (found 'int')}}
+template<typename T> requires (T{}) // expected-error{{atomic constraint must be of type 'bool' (found 'int')}}
struct D { };
static_assert(C<int>{}); // expected-note{{while checking constraint satisfaction for template 'C<int>' required here}}
-static_assert(D<int>{}); // expected-note{{while checking constraint satisfaction for template 'D<int>' required here}} \ No newline at end of file
+static_assert(D<int>{}); // expected-note{{while checking constraint satisfaction for template 'D<int>' required here}}
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
index 47bd2a55076..1ea4da29ee9 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
@@ -2,10 +2,10 @@
namespace class_templates
{
- template<typename T, typename U> requires sizeof(T) >= 4 // expected-note {{because 'sizeof(char) >= 4' (1 >= 4) evaluated to false}}
+ template<typename T, typename U> requires (sizeof(T) >= 4) // expected-note {{because 'sizeof(char) >= 4' (1 >= 4) evaluated to false}}
struct is_same { static constexpr bool value = false; };
- template<typename T> requires sizeof(T*) >= 4 && sizeof(T) >= 4
+ template<typename T> requires (sizeof(T*) >= 4 && sizeof(T) >= 4)
struct is_same<T*, T*> { static constexpr bool value = true; };
static_assert(!is_same<char*, char*>::value);
@@ -23,7 +23,7 @@ namespace class_templates
// expected-note@-1{{while substituting template arguments into constraint expression here}}
struct B<T*> {};
- template<typename T> requires T{} // expected-error{{atomic constraint must be of type 'bool' (found 'int')}}
+ template<typename T> requires (T{}) // expected-error{{atomic constraint must be of type 'bool' (found 'int')}}
struct B<T**> {};
static_assert((B<int**>{}, true)); // expected-note{{while checking constraint satisfaction for class template partial specialization 'B<int *>' required here}}
@@ -35,10 +35,10 @@ namespace class_templates
namespace variable_templates
{
- template<typename T, typename U> requires sizeof(T) >= 4
+ template<typename T, typename U> requires (sizeof(T) >= 4)
constexpr bool is_same_v = false;
- template<typename T> requires sizeof(T*) >= 4 && sizeof(T) >= 4
+ template<typename T> requires (sizeof(T*) >= 4 && sizeof(T) >= 4)
constexpr bool is_same_v<T*, T*> = true;
static_assert(!is_same_v<char*, char*>);
@@ -55,7 +55,7 @@ namespace variable_templates
// expected-note@-1{{while substituting template arguments into constraint expression here}}
constexpr bool v1<T*> = true;
- template<typename T> requires T{} // expected-error{{atomic constraint must be of type 'bool' (found 'int')}}
+ template<typename T> requires (T{}) // expected-error{{atomic constraint must be of type 'bool' (found 'int')}}
constexpr bool v1<T**> = true;
static_assert(v1<int**>); // expected-note{{while checking constraint satisfaction for variable template partial specialization 'v1<int *>' required here}}
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
index 5d5361f9c20..6f7b80e26a6 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
@@ -2,9 +2,9 @@
namespace nodiag {
-template <typename T> requires bool(T())
+template <typename T> requires (bool(T()))
struct A;
-template <typename U> requires bool(U())
+template <typename U> requires (bool(U()))
struct A;
} // end namespace nodiag
@@ -21,7 +21,7 @@ struct B;
template <typename T> requires true // expected-note{{previous template declaration is here}}
struct C;
-template <typename T> requires !0 // expected-error{{requires clause differs in template redeclaration}}
+template <typename T> requires (!0) // expected-error{{requires clause differs in template redeclaration}}
struct C;
} // end namespace diag
@@ -29,15 +29,15 @@ struct C;
namespace nodiag {
struct AA {
- template <typename T> requires someFunc(T())
+ template <typename T> requires (someFunc(T()))
struct A;
};
-template <typename U> requires someFunc(U())
+template <typename U> requires (someFunc(U()))
struct AA::A { };
struct AAF {
- template <typename T> requires someFunc(T())
+ template <typename T> requires (someFunc(T()))
friend struct AA::A;
};
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp
index c83ab26059d..30fbec64eea 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp
@@ -2,9 +2,9 @@
namespace nodiag {
-template <typename T> requires bool(T())
+template <typename T> requires (bool(T()))
int A();
-template <typename U> requires bool(U())
+template <typename U> requires (bool(U()))
int A();
} // end namespace nodiag
@@ -26,7 +26,7 @@ int orig::A();
template <typename T> requires true
int orig::B();
// expected-error@-1{{out-of-line declaration of 'B' does not match any declaration in namespace 'diag::orig'}}
-template <typename T> requires !0
+template <typename T> requires (!0)
int orig::C();
// expected-error@-1{{out-of-line declaration of 'C' does not match any declaration in namespace 'diag::orig'}}
@@ -35,11 +35,11 @@ int orig::C();
namespace nodiag {
struct AA {
- template <typename T> requires someFunc(T())
+ template <typename T> requires (someFunc(T()))
int A();
};
-template <typename T> requires someFunc(T())
+template <typename T> requires (someFunc(T()))
int AA::A() { return sizeof(T); }
} // end namespace nodiag
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp
index cf6874f12d3..eabb636b0bb 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp
@@ -3,11 +3,11 @@
namespace nodiag {
struct B {
- template <typename T> requires bool(T())
+ template <typename T> requires (bool(T()))
static int A;
};
-template <typename U> requires bool(U())
+template <typename U> requires (bool(U()))
int B::A = int(U());
} // end namespace nodiag
@@ -15,11 +15,11 @@ int B::A = int(U());
namespace diag {
struct B {
- template <typename T> requires bool(T()) // expected-note{{previous template declaration is here}}
+ template <typename T> requires (bool(T())) // expected-note{{previous template declaration is here}}
static int A;
};
-template <typename U> requires !bool(U()) // expected-error{{requires clause differs in template redeclaration}}
+template <typename U> requires (!bool(U())) // expected-error{{requires clause differs in template redeclaration}}
int B::A = int(U());
} // end namespace diag \ No newline at end of file
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
index 8c2f5526941..5d41035aa88 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
@@ -1,9 +1,12 @@
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
-template<typename T> requires sizeof(T) >= 4
+template<typename T> requires (sizeof(T) >= 4)
+// expected-note@-1{{similar constraint expressions not considered equivalen}}
class A{}; // expected-note{{template is declared here}}
-template<typename T> requires sizeof(T) >= 4 && sizeof(T) <= 10
+template<typename T> requires (sizeof(T) >= 4 && sizeof(T) <= 10)
+// expected-note@-1{{similar constraint expression here}}
+
class A<T>{}; // expected-error{{class template partial specialization is not more specialized than the primary template}}
template<typename T>
@@ -12,7 +15,7 @@ concept C1 = sizeof(T) >= 4;
template<typename T> requires C1<T>
class B{};
-template<typename T> requires C1<T> && sizeof(T) <= 10
+template<typename T> requires (C1<T> && sizeof(T) <= 10)
class B<T>{};
template<typename T>
@@ -48,3 +51,15 @@ struct F<T>{ enum{ value = 3 }; };
static_assert(F<unsigned>::value == 2);
static_assert(F<char[10]>::value == 3);
static_assert(F<char>::value == 1);
+
+// Make sure atomic constraints subsume each other only if their parameter
+// mappings are identical.
+
+template<typename T, typename U> requires C2<T>
+struct I { }; // expected-note {{template is declared here}}
+
+template<typename T, typename U> requires C2<U>
+struct I<T, U> { }; // expected-error {{class template partial specialization is not more specialized than the primary template}}
+
+template<typename T, typename U> requires C2<T> && C2<U>
+struct I<T, U> { };
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/function-templates.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/function-templates.cpp
index cc578fe0ad6..7f68369d528 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.order/function-templates.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/function-templates.cpp
@@ -1,9 +1,11 @@
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
-template<typename T> requires sizeof(T) >= 4
+template<typename T> requires (sizeof(T) >= 4)
+// expected-note@-1{{similar constraint expressions not considered equivalent}}
bool a() { return false; } // expected-note {{candidate function [with T = unsigned int]}}
-template<typename T> requires sizeof(T) >= 4 && sizeof(T) <= 10
+template<typename T> requires (sizeof(T) >= 4 && sizeof(T) <= 10)
+// expected-note@-1{{similar constraint expression here}}
bool a() { return true; } // expected-note {{candidate function [with T = unsigned int]}}
bool av = a<unsigned>(); // expected-error {{call to 'a' is ambiguous}}
@@ -14,7 +16,7 @@ concept C1 = sizeof(T) >= 4;
template<typename T> requires C1<T>
constexpr bool b() { return false; }
-template<typename T> requires C1<T> && sizeof(T) <= 10
+template<typename T> requires (C1<T> && sizeof(T) <= 10)
constexpr bool b() { return true; }
static_assert(b<int>());
@@ -86,4 +88,4 @@ static_assert(sizeof(g<int>()));
template <unsigned> struct X {};
template <class...> int h(X<0>);
template <unsigned b, class...> int h(X<b>);
-static_assert(sizeof(h(X<0>{}))); \ No newline at end of file
+static_assert(sizeof(h(X<0>{})));
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
index b40c77e70a1..cf88e34036d 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
@@ -1,9 +1,11 @@
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
-template<typename T> requires sizeof(T) >= 4
+template<typename T> requires (sizeof(T) >= 4)
+// expected-note@-1{{similar constraint expressions not considered equivalent}}
bool a = false; // expected-note{{template is declared here}}
-template<typename T> requires sizeof(T) >= 4 && sizeof(T) <= 10
+template<typename T> requires (sizeof(T) >= 4 && sizeof(T) <= 10)
+// expected-note@-1{{similar constraint expression here}}
bool a<T> = true; // expected-error{{variable template partial specialization is not more specialized than the primary template}}
template<typename T>
@@ -12,7 +14,7 @@ concept C1 = sizeof(T) >= 4;
template<typename T> requires C1<T>
bool b = false;
-template<typename T> requires C1<T> && sizeof(T) <= 10
+template<typename T> requires (C1<T> && sizeof(T) <= 10)
bool b<T> = true;
template<typename T>
diff --git a/clang/test/CXX/temp/temp.explicit/p8.cpp b/clang/test/CXX/temp/temp.explicit/p8.cpp
new file mode 100644
index 00000000000..72d22557899
--- /dev/null
+++ b/clang/test/CXX/temp/temp.explicit/p8.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+template<typename T, typename S = char> requires (sizeof(T) + sizeof(S) < 10)
+// expected-note@-1{{because 'sizeof(char [100]) + sizeof(char) < 10' (101 < 10) evaluated to false}}
+void f(T t, S s) requires (sizeof(t) == 1 && sizeof(s) == 1) { };
+// expected-note@-1{{candidate template ignored: constraints not satisfied [with T = int, S = char]}}
+// expected-note@-2{{because 'sizeof (t) == 1' (4 == 1) evaluated to false}}
+// expected-note@-3{{candidate template ignored: constraints not satisfied [with T = char, S = short]}}
+// expected-note@-4{{because 'sizeof (s) == 1' (2 == 1) evaluated to false}}
+// expected-note@-5{{candidate template ignored: constraints not satisfied [with T = char [100], S = char]}}
+
+template<>
+void f<int>(int t, char s) { };
+// expected-error@-1{{no function template matches function template specialization 'f'}}
+
+template<>
+void f<char, short>(char t, short s) { };
+// expected-error@-1{{no function template matches function template specialization 'f'}}
+
+template<>
+void f<char[100]>(char t[100], char s) { };
+// expected-error@-1{{no function template matches function template specialization 'f'}} \ No newline at end of file
diff --git a/clang/test/Parser/cxx-concepts-ambig-constraint-expr.cpp b/clang/test/Parser/cxx-concepts-ambig-constraint-expr.cpp
index 12ab338a6b0..1cd2605ce05 100644
--- a/clang/test/Parser/cxx-concepts-ambig-constraint-expr.cpp
+++ b/clang/test/Parser/cxx-concepts-ambig-constraint-expr.cpp
@@ -5,25 +5,5 @@
// the syntax is consumed without backtracking.
// type-specifier-seq in conversion-type-id
-template <typename T> requires (bool)&T::operator short
-unsigned int foo(); // expected-error {{C++ requires a type specifier for all declarations}}
-
-// type-specifier-seq in new-type-id
-template <typename T> requires (bool)sizeof new (T::f()) short
-unsigned int bar(); // expected-error {{C++ requires a type specifier for all declarations}}
-
-template<typename T> requires (bool)sizeof new (T::f()) unsigned // expected-error {{'struct' cannot be signed or unsigned}}
-struct X { }; // expected-error {{'X' cannot be defined in a type specifier}}
-
-// C-style cast
-// of function call on function-style cast
-template <typename T> requires (bool(T()))
-T (*fp)(); // expected-error {{use of undeclared identifier 'fp'}}
-
-// function-style cast
-// as the callee in a function call
-struct A {
- static int t;
- template <typename T> requires bool(T())
- (A(T (&t))) { } // expected-error {{called object type 'bool' is not a function or function pointer}}
-};
+template <typename T> requires T::operator short
+unsigned int foo(); // expected-error {{C++ requires a type specifier for all declarations}} \ No newline at end of file
diff --git a/clang/test/Parser/cxx-concepts-requires-clause.cpp b/clang/test/Parser/cxx-concepts-requires-clause.cpp
index 01893a94cbc..60e7004e081 100644
--- a/clang/test/Parser/cxx-concepts-requires-clause.cpp
+++ b/clang/test/Parser/cxx-concepts-requires-clause.cpp
@@ -1,13 +1,11 @@
-// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ %s -verify
-// expected-no-diagnostics
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify
// Test parsing of the optional requires-clause in a template-declaration.
template <typename T> requires true
void foo() { }
-
-template <typename T> requires !0
+template <typename T> requires (!0)
struct A {
void foo();
struct AA;
@@ -27,31 +25,30 @@ struct A {
using MQ = M<TT>;
};
-template <typename T> requires !0
+template <typename T> requires (!0)
void A<T>::foo() { }
-template <typename T> requires !0
+template <typename T> requires (!0)
struct A<T>::AA { };
-template <typename T> requires !0
+template <typename T> requires (!0)
enum A<T>::E : int { E0 };
-template <typename T> requires !0
+template <typename T> requires (!0)
int A<T>::x = 0;
-template <typename T> requires !0
+template <typename T> requires (!0)
template <typename> requires true
void A<T>::Mfoo() { }
-template <typename T> requires !0
+template <typename T> requires (!0)
template <typename> requires true
struct A<T>::M { };
-template <typename T> requires !0
+template <typename T> requires (!0)
template <typename> requires true
int A<T>::Mx = 0;
-
template <typename T> requires true
int x = 0;
@@ -80,3 +77,81 @@ struct C::M { };
template <typename> requires true
int C::Mx = 0;
+
+// Test behavior with non-primary-expression requires clauses
+
+template<typename T> requires foo<T>()
+// expected-error@-1{{parentheses are required around this expression in a requires clause}}
+struct B1 { };
+
+int func() { }
+
+template<typename T> requires func()
+// expected-error@-1{{atomic constraint must be of type 'bool' (found '<overloaded function type>')}}
+// expected-note@-2{{parentheses are required around this expression in a requires clause}}
+struct B2 { };
+
+template<typename T> requires (foo<T>())
+struct B3 { };
+
+template<typename T> requires T{}
+// expected-error@-1{{parentheses are required around this expression in a requires clause}}
+struct B4 { };
+
+template<typename T> requires sizeof(T) == 0
+// expected-error@-1{{parentheses are required around this expression in a requires clause}}
+struct B5 { };
+
+template<typename T> requires (sizeof(T)) == 0
+// expected-error@-1{{parentheses are required around this expression in a requires clause}}
+struct B6 { };
+
+template<typename T> requires 0
+// expected-error@-1{{atomic constraint must be of type 'bool' (found 'int')}}
+(int) bar() { };
+
+template<typename T> requires foo<T>
+(int) bar() { };
+// expected-error@-1{{expected '(' for function-style cast or type construction}}
+
+template<typename T>
+void bar() requires foo<T>();
+// expected-error@-1{{parentheses are required around this expression in a requires clause}}
+
+template<typename T>
+void bar() requires (foo<T>());
+
+template<typename T>
+void bar() requires func();
+// expected-error@-1{{atomic constraint must be of type 'bool' (found '<overloaded function type>')}}
+// expected-note@-2{{parentheses are required around this expression in a requires clause}}
+
+template<typename T>
+void bar() requires T{};
+// expected-error@-1{{parentheses are required around this expression in a requires clause}}
+
+template<typename T>
+void bar() requires sizeof(T) == 0;
+// expected-error@-1{{parentheses are required around this expression in a requires clause}}
+
+template<typename T>
+void bar() requires (sizeof(T)) == 0;
+// expected-error@-1{{parentheses are required around this expression in a requires clause}}
+
+void bar(int x, int y) requires (x, y, true);
+
+struct B {
+ int x;
+ void foo(int y) requires (x, this, this->x, y, true);
+ static void bar(int y) requires (x, true);
+ // expected-error@-1{{'this' cannot be implicitly used in a static member function declaration}}
+ static void baz(int y) requires (this, true);
+ // expected-error@-1{{'this' cannot be used in a static member function declaration}}
+};
+
+auto lambda1 = [] (auto x) requires (sizeof(decltype(x)) == 1) { };
+
+auto lambda2 = [] (auto x) constexpr -> int requires (sizeof(decltype(x)) == 1) { return 0; };
+
+auto lambda3 = [] requires (sizeof(char) == 1) { };
+// expected-error@-1{{lambda requires '()' before 'requires' clause}} \ No newline at end of file
diff --git a/clang/test/SemaTemplate/instantiate-requires-clause.cpp b/clang/test/SemaTemplate/instantiate-requires-clause.cpp
new file mode 100644
index 00000000000..f36396b98db
--- /dev/null
+++ b/clang/test/SemaTemplate/instantiate-requires-clause.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify
+
+template <typename... Args> requires ((sizeof(Args) == 1), ...)
+// expected-note@-1 {{because '(sizeof(int) == 1) , (sizeof(char) == 1) , (sizeof(int) == 1)' evaluated to false}}
+void f1(Args&&... args) { }
+// expected-note@-1 {{candidate template ignored: constraints not satisfied [with Args = <int, char, int>]}}
+
+using f11 = decltype(f1('a'));
+using f12 = decltype(f1(1, 'b'));
+using f13 = decltype(f1(1, 'b', 2));
+// expected-error@-1 {{no matching function for call to 'f1'}}
+
+template <typename... Args>
+void f2(Args&&... args) requires ((sizeof(args) == 1), ...) { }
+// expected-note@-1 {{candidate template ignored: constraints not satisfied [with Args = <int, char, int>]}}
+// expected-note@-2 {{because '(sizeof (args) == 1) , (sizeof (args) == 1) , (sizeof (args) == 1)' evaluated to false}}
+
+using f21 = decltype(f2('a'));
+using f22 = decltype(f2(1, 'b'));
+using f23 = decltype(f2(1, 'b', 2));
+// expected-error@-1 {{no matching function for call to 'f2'}}
+
+template <typename... Args> requires ((sizeof(Args) == 1), ...)
+// expected-note@-1 {{because '(sizeof(int) == 1) , (sizeof(char) == 1) , (sizeof(int) == 1)' evaluated to false}}
+void f3(Args&&... args) requires ((sizeof(args) == 1), ...) { }
+// expected-note@-1 {{candidate template ignored: constraints not satisfied [with Args = <int, char, int>]}}
+
+using f31 = decltype(f3('a'));
+using f32 = decltype(f3(1, 'b'));
+using f33 = decltype(f3(1, 'b', 2));
+// expected-error@-1 {{no matching function for call to 'f3'}}
OpenPOWER on IntegriCloud