aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2018-11-01 22:10:31 +0000
committerMarek Polacek <mpolacek@gcc.gnu.org>2018-11-01 22:10:31 +0000
commit5d9a0e3b99e31a2167f6b6ab2473feb58f7c77e8 (patch)
tree37c5dd82ef0aa75d2a14f04e83a976603e23d193
parent3af0c6bce5e4343a6099ba07e9dbfc3288de40a6 (diff)
downloadgcc-5d9a0e3b99e31a2167f6b6ab2473feb58f7c77e8.zip
gcc-5d9a0e3b99e31a2167f6b6ab2473feb58f7c77e8.tar.gz
gcc-5d9a0e3b99e31a2167f6b6ab2473feb58f7c77e8.tar.bz2
Implement P0846R0, ADL and function templates.
* decl.c (grokfndecl): Allow FUNCTION_DECL in assert. * lex.c (unqualified_fn_lookup_error): Handle TEMPLATE_ID_EXPR. * parser.c (cp_parser_postfix_expression): Do ADL for a template-name. (cp_parser_template_id): Give errors if parsing the template argument list didn't go well. Allow FUNCTION_DECL in assert. (cp_parser_template_name): Consider a name to refer to a template if it is an unqualified-id followed by a <. Don't return the identifier if the decl is a function and dependent. * pt.c (tsubst_copy) <case OVERLOAD>: Remove assert. * g++.dg/addr_builtin-1.C: Adjust dg-error. * g++.dg/cpp2a/fn-template1.C: New test. * g++.dg/cpp2a/fn-template10.C: New test. * g++.dg/cpp2a/fn-template11.C: New test. * g++.dg/cpp2a/fn-template12.C: New test. * g++.dg/cpp2a/fn-template13.C: New test. * g++.dg/cpp2a/fn-template14.C: New test. * g++.dg/cpp2a/fn-template15.C: New test. * g++.dg/cpp2a/fn-template16.C: New test. * g++.dg/cpp2a/fn-template2.C: New test. * g++.dg/cpp2a/fn-template3.C: New test. * g++.dg/cpp2a/fn-template4.C: New test. * g++.dg/cpp2a/fn-template5.C: New test. * g++.dg/cpp2a/fn-template6.C: New test. * g++.dg/cpp2a/fn-template7.C: New test. * g++.dg/cpp2a/fn-template8.C: New test. * g++.dg/cpp2a/fn-template9.C: New test. * g++.dg/parse/fn-template1.C: New test. * g++.dg/parse/fn-template2.C: New test. * g++.dg/parse/template19.C: Adjust dg-error. * g++.dg/template/pr61745.C: Add target to dg-error. From-SVN: r265734
-rw-r--r--gcc/cp/ChangeLog13
-rw-r--r--gcc/cp/decl.c4
-rw-r--r--gcc/cp/lex.c3
-rw-r--r--gcc/cp/parser.c72
-rw-r--r--gcc/cp/pt.c4
-rw-r--r--gcc/testsuite/ChangeLog25
-rw-r--r--gcc/testsuite/g++.dg/addr_builtin-1.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template1.C37
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template10.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template11.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template12.C33
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template13.C32
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template14.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template15.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template16.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template2.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template3.C29
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template4.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template5.C32
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template6.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template7.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template8.C34
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/fn-template9.C21
-rw-r--r--gcc/testsuite/g++.dg/parse/fn-template1.C15
-rw-r--r--gcc/testsuite/g++.dg/parse/fn-template2.C17
-rw-r--r--gcc/testsuite/g++.dg/parse/template19.C2
-rw-r--r--gcc/testsuite/g++.dg/template/pr61745.C4
27 files changed, 507 insertions, 18 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b567d65..b27ae1a 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,16 @@
+2018-11-01 Marek Polacek <polacek@redhat.com>
+
+ Implement P0846R0, ADL and function templates.
+ * decl.c (grokfndecl): Allow FUNCTION_DECL in assert.
+ * lex.c (unqualified_fn_lookup_error): Handle TEMPLATE_ID_EXPR.
+ * parser.c (cp_parser_postfix_expression): Do ADL for a template-name.
+ (cp_parser_template_id): Give errors if parsing the template argument
+ list didn't go well. Allow FUNCTION_DECL in assert.
+ (cp_parser_template_name): Consider a name to refer to a template if
+ it is an unqualified-id followed by a <. Don't return the identifier
+ if the decl is a function and dependent.
+ * pt.c (tsubst_copy) <case OVERLOAD>: Remove assert.
+
2018-11-01 Nathan Sidwell <nathan@acm.org>
* cp-tree.h (struct lang_function): Delete x_local_names field.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 23fcf6b0..f0033dd 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8857,7 +8857,9 @@ grokfndecl (tree ctype,
the information in the TEMPLATE_ID_EXPR. */
SET_DECL_IMPLICIT_INSTANTIATION (decl);
- gcc_assert (identifier_p (fns) || TREE_CODE (fns) == OVERLOAD);
+ gcc_assert (identifier_p (fns)
+ || TREE_CODE (fns) == OVERLOAD
+ || TREE_CODE (fns) == FUNCTION_DECL);
DECL_TEMPLATE_INFO (decl) = build_template_info (fns, args);
for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t))
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 410dfd1..26ec52f 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -541,6 +541,9 @@ unqualified_fn_lookup_error (cp_expr name_expr)
if (loc == UNKNOWN_LOCATION)
loc = input_location;
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+ name = TREE_OPERAND (name, 0);
+
if (processing_template_decl)
{
/* In a template, it is invalid to write "f()" or "f(3)" if no
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 206ceb0..d01c924 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -7195,7 +7195,11 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
if (idk == CP_ID_KIND_UNQUALIFIED
|| idk == CP_ID_KIND_TEMPLATE_ID)
{
- if (identifier_p (postfix_expression))
+ if (identifier_p (postfix_expression)
+ /* In C++2A, we may need to perform ADL for a template
+ name. */
+ || (TREE_CODE (postfix_expression) == TEMPLATE_ID_EXPR
+ && identifier_p (TREE_OPERAND (postfix_expression, 0))))
{
if (!args->is_empty ())
{
@@ -16029,6 +16033,37 @@ cp_parser_template_id (cp_parser *parser,
}
/* Parse the arguments. */
arguments = cp_parser_enclosed_template_argument_list (parser);
+
+ if ((cxx_dialect > cxx17)
+ && (TREE_CODE (templ) == FUNCTION_DECL || identifier_p (templ))
+ && !template_keyword_p
+ && (cp_parser_error_occurred (parser)
+ || cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)))
+ {
+ /* This didn't go well. */
+ if (TREE_CODE (templ) == FUNCTION_DECL)
+ {
+ /* C++2A says that "function-name < a;" is now ill-formed. */
+ if (cp_parser_error_occurred (parser))
+ {
+ error_at (token->location, "invalid template-argument-list");
+ inform (token->location, "function name as the left hand "
+ "operand of %<<%> is ill-formed in C++2a; wrap the "
+ "function name in %<()%>");
+ }
+ else
+ /* We expect "f<targs>" to be followed by "(args)". */
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "expected %<(%> after template-argument-list");
+ if (start_of_id)
+ /* Purge all subsequent tokens. */
+ cp_lexer_purge_tokens_after (parser->lexer, start_of_id);
+ }
+ else
+ cp_parser_simulate_error (parser);
+ pop_deferring_access_checks ();
+ return error_mark_node;
+ }
}
/* Set the location to be of the form:
@@ -16085,6 +16120,7 @@ cp_parser_template_id (cp_parser *parser,
a function-template. */
gcc_assert ((DECL_FUNCTION_TEMPLATE_P (templ)
|| TREE_CODE (templ) == OVERLOAD
+ || TREE_CODE (templ) == FUNCTION_DECL
|| BASELINK_P (templ)));
template_id = lookup_template_function (templ, arguments);
@@ -16287,6 +16323,10 @@ cp_parser_template_name (cp_parser* parser,
}
}
+ /* cp_parser_lookup_name clears OBJECT_TYPE. */
+ const bool scoped_p = ((parser->scope ? parser->scope
+ : parser->context->object_type) != NULL_TREE);
+
/* Look up the name. */
decl = cp_parser_lookup_name (parser, identifier,
tag_type,
@@ -16319,6 +16359,27 @@ cp_parser_template_name (cp_parser* parser,
if (TREE_CODE (*iter) == TEMPLATE_DECL)
found = true;
+ if (!found
+ && (cxx_dialect > cxx17)
+ && !scoped_p
+ && cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+ {
+ /* [temp.names] says "A name is also considered to refer to a template
+ if it is an unqualified-id followed by a < and name lookup finds
+ either one or more functions or finds nothing." */
+
+ /* The "more functions" case. Just use the OVERLOAD as normally.
+ We don't use is_overloaded_fn here to avoid considering
+ BASELINKs. */
+ if (TREE_CODE (decl) == OVERLOAD
+ /* Name lookup found one function. */
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ found = true;
+ /* Name lookup found nothing. */
+ else if (decl == error_mark_node)
+ return identifier;
+ }
+
if (!found)
{
/* The name does not name a template. */
@@ -16327,15 +16388,6 @@ cp_parser_template_name (cp_parser* parser,
}
}
- /* If DECL is dependent, and refers to a function, then just return
- its name; we will look it up again during template instantiation. */
- if (DECL_FUNCTION_TEMPLATE_P (decl) || !DECL_P (decl))
- {
- tree scope = ovl_scope (decl);
- if (TYPE_P (scope) && dependent_type_p (scope))
- return identifier;
- }
-
return decl;
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2dc0cb1..4226d4d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15538,10 +15538,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return t;
case OVERLOAD:
- /* An OVERLOAD will always be a non-dependent overload set; an
- overload set from function scope will just be represented with an
- IDENTIFIER_NODE, and from class scope with a BASELINK. */
- gcc_assert (!uses_template_parms (t));
/* We must have marked any lookups as persistent. */
gcc_assert (!OVL_LOOKUP_P (t) || OVL_USED_P (t));
return t;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f206f8b..98703db 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,28 @@
+2018-11-01 Marek Polacek <polacek@redhat.com>
+
+ Implement P0846R0, ADL and function templates.
+ * g++.dg/addr_builtin-1.C: Adjust dg-error.
+ * g++.dg/cpp2a/fn-template1.C: New test.
+ * g++.dg/cpp2a/fn-template10.C: New test.
+ * g++.dg/cpp2a/fn-template11.C: New test.
+ * g++.dg/cpp2a/fn-template12.C: New test.
+ * g++.dg/cpp2a/fn-template13.C: New test.
+ * g++.dg/cpp2a/fn-template14.C: New test.
+ * g++.dg/cpp2a/fn-template15.C: New test.
+ * g++.dg/cpp2a/fn-template16.C: New test.
+ * g++.dg/cpp2a/fn-template2.C: New test.
+ * g++.dg/cpp2a/fn-template3.C: New test.
+ * g++.dg/cpp2a/fn-template4.C: New test.
+ * g++.dg/cpp2a/fn-template5.C: New test.
+ * g++.dg/cpp2a/fn-template6.C: New test.
+ * g++.dg/cpp2a/fn-template7.C: New test.
+ * g++.dg/cpp2a/fn-template8.C: New test.
+ * g++.dg/cpp2a/fn-template9.C: New test.
+ * g++.dg/parse/fn-template1.C: New test.
+ * g++.dg/parse/fn-template2.C: New test.
+ * g++.dg/parse/template19.C: Adjust dg-error.
+ * g++.dg/template/pr61745.C: Add target to dg-error.
+
2017-11-01 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/54613
diff --git a/gcc/testsuite/g++.dg/addr_builtin-1.C b/gcc/testsuite/g++.dg/addr_builtin-1.C
index e8ba31f..0c282b1 100644
--- a/gcc/testsuite/g++.dg/addr_builtin-1.C
+++ b/gcc/testsuite/g++.dg/addr_builtin-1.C
@@ -108,7 +108,7 @@ static F* test_taking_address_of_gcc_builtin ()
a = p - __builtin_trap; // { dg-error "built-in" }
// Relational operators. Ill-formed but allowed with -fpermissive.
- a = __builtin_trap < p; // { dg-error "built-in" }
+ a = __builtin_trap < p; // { dg-error "built-in|invalid template-argument-list" }
a = p < __builtin_trap; // { dg-error "built-in" }
a = __builtin_trap <= p; // { dg-error "built-in" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template1.C b/gcc/testsuite/g++.dg/cpp2a/fn-template1.C
new file mode 100644
index 0000000..2492d9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template1.C
@@ -0,0 +1,37 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+int h;
+void g();
+void e();
+void e(int);
+void e(int, int);
+
+namespace N {
+ struct A { };
+ template <class T> int f(T);
+ template <class T> int g(T);
+ template <class T> int h(T);
+ template <class T> int e(T);
+}
+
+int v = e<N::A>(N::A());
+int x = f<N::A>(N::A());
+int y = g<N::A>(N::A());
+int z = h<N::A>(N::A()); // { dg-error "expected" }
+
+template<class>
+void fn ()
+{
+ int v = e<N::A>(N::A());
+ int x = f<N::A>(N::A());
+ int y = g<N::A>(N::A());
+ int z = h<N::A>(N::A()); // { dg-error "expected" }
+}
+
+void
+test ()
+{
+ fn<int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template10.C b/gcc/testsuite/g++.dg/cpp2a/fn-template10.C
new file mode 100644
index 0000000..c69d48f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template10.C
@@ -0,0 +1,22 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+int h;
+void g();
+void e();
+void e(int);
+void e(int, int);
+
+namespace N {
+ struct A { };
+ template <class T> static int f(T) { return 1; }
+ template <class T> static int g(T) { return 2; }
+ template <class T> static int h(T);
+ template <class T> static int e(T) { return 3; }
+}
+
+int v = e<N::A>(N::A());
+int x = f<N::A>(N::A());
+int y = g<N::A>(N::A());
+int z = h<N::A>(N::A()); // { dg-error "expected" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template11.C b/gcc/testsuite/g++.dg/cpp2a/fn-template11.C
new file mode 100644
index 0000000..1a6b688
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template11.C
@@ -0,0 +1,11 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+int nonconst ();
+
+int foo ()
+{
+ return blah < // { dg-error "not declared" }
+ nonconst (), nonconst (); // { dg-error "call to non-.constexpr. function" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template12.C b/gcc/testsuite/g++.dg/cpp2a/fn-template12.C
new file mode 100644
index 0000000..fc72fd0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template12.C
@@ -0,0 +1,33 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S {
+ template<typename T> int foo(T);
+ template<typename T> int foo(T, T);
+ template<typename T> int foo(T, T, T);
+};
+
+template<typename T>
+struct W {
+ template<typename U> T foo(U);
+ template<typename U> T foo(U, U);
+ template<typename U> T foo(U, U, U);
+};
+
+void
+test ()
+{
+ S s;
+ s.foo<int>(1);
+ s.foo<int>(1, 2);
+ s.foo<int>(1, 2, 3);
+
+ W<int> w;
+ w.foo<int>(1);
+ w.foo<int>(1, 2);
+ w.foo<int>(1, 2, 3);
+
+ w.nothere<int>(1); // { dg-error "has no member|expected" }
+ s.nothere<int>(1); // { dg-error "has no member|expected" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template13.C b/gcc/testsuite/g++.dg/cpp2a/fn-template13.C
new file mode 100644
index 0000000..ece6d15
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template13.C
@@ -0,0 +1,32 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct A {
+ template<typename T>
+ int foo (T a, T b) { return a + b; }
+};
+
+int
+bar (A* pa, int (A::*pm)(int, int))
+{
+ return (pa->*pm)(1, 2);
+}
+
+int
+baz (A pa, int (A::*pm)(int, int))
+{
+ return (pa.*pm)(1, 2);
+}
+
+int
+main ()
+{
+ A a;
+ int i = bar (&a, &A::foo<int>);
+ if (i != 3)
+ __builtin_abort ();
+ i = baz (a, &A::foo<int>);
+ if (i != 3)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template14.C b/gcc/testsuite/g++.dg/cpp2a/fn-template14.C
new file mode 100644
index 0000000..96d9267
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template14.C
@@ -0,0 +1,9 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+template<typename> struct B
+{
+ template<typename> int foo() { return 0; }
+ int i = foo<int>();
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template15.C b/gcc/testsuite/g++.dg/cpp2a/fn-template15.C
new file mode 100644
index 0000000..20e4801
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template15.C
@@ -0,0 +1,23 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+// Don't get confused by these valid cases.
+
+template <class>
+class A {
+ template <bool> void b();
+ void m_fn1();
+};
+
+template <class T>
+void A<T>::m_fn1() { b<>(0); }
+
+
+template <int> struct X {
+ X() { fn<>(0); }
+ template <int> void fn();
+};
+
+
+template <typename> void a() { a<int>; }
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template16.C b/gcc/testsuite/g++.dg/cpp2a/fn-template16.C
new file mode 100644
index 0000000..becaff1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template16.C
@@ -0,0 +1,20 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct undeclared<int> { }; // { dg-error "not a class template" }
+
+int
+main ()
+{
+ int foo ();
+ int foo (int);
+ int foo (int, int);
+ int a, b = 10;
+ a = foo<; // { dg-error "" }
+ a = foo < b; // { dg-error "" }
+ a = foo<b>; // { dg-error "" }
+ a = foo<b>(; // { dg-error "expected" }
+ a = foo<b>(1; // { dg-error "expected" }
+ a = foo<b>(1); // { dg-error "no matching" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template2.C b/gcc/testsuite/g++.dg/cpp2a/fn-template2.C
new file mode 100644
index 0000000..f974c8c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template2.C
@@ -0,0 +1,16 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct A { };
+bool operator <(void (*fp)(), A) { return false; }
+void f() {}
+
+int
+main ()
+{
+ A a;
+ f < a; // { dg-error "invalid" }
+ bool b = f < a; // { dg-error "invalid" }
+ (f) < a;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template3.C b/gcc/testsuite/g++.dg/cpp2a/fn-template3.C
new file mode 100644
index 0000000..f801625
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template3.C
@@ -0,0 +1,29 @@
+// P0846R0
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+void g();
+void e();
+void e(int);
+void e(int, int);
+
+namespace N {
+ struct A { };
+ template <class T> int f(T) { return 1; }
+ template <class T> int g(T) { return 2; }
+ template <class T> int e(T) { return 3; }
+}
+
+int
+main ()
+{
+ int v = e<N::A>(N::A());
+ if (v != 3)
+ __builtin_abort ();
+ int x = f<N::A>(N::A());
+ if (x != 1)
+ __builtin_abort ();
+ int y = g<N::A>(N::A());
+ if (y != 2)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template4.C b/gcc/testsuite/g++.dg/cpp2a/fn-template4.C
new file mode 100644
index 0000000..9259c2e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template4.C
@@ -0,0 +1,11 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+template <typename T> void foo() { }
+template <typename T> void bar(int) { }
+int main()
+{
+ foo<float>();
+ bar<int>(1);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template5.C b/gcc/testsuite/g++.dg/cpp2a/fn-template5.C
new file mode 100644
index 0000000..33477c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template5.C
@@ -0,0 +1,32 @@
+// P0846R0
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+int g() { return 11; }
+int e() { return 12; }
+int e(int) { return 13; }
+int e(int, int) { return 14; }
+
+namespace N {
+ struct A { };
+ template <class T> int f(T) { return 1; }
+ template <class T> int g(T) { return 2; }
+ template <class T> int e(T) { return 3; }
+}
+
+int
+main ()
+{
+ int v = e(1);
+ if (v != 13)
+ __builtin_abort ();
+ int x = e(1, 2);
+ if (x != 14)
+ __builtin_abort ();
+ int y = g();
+ if (y != 11)
+ __builtin_abort ();
+ int z = e();
+ if (z != 12)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template6.C b/gcc/testsuite/g++.dg/cpp2a/fn-template6.C
new file mode 100644
index 0000000..63b2377
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template6.C
@@ -0,0 +1,16 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+template<class>
+struct X {
+ int first = 0;
+};
+
+int
+f ()
+{
+ X<int> x, y;
+ bool b = x.first < y.first;
+ return b;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template7.C b/gcc/testsuite/g++.dg/cpp2a/fn-template7.C
new file mode 100644
index 0000000..d048606
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template7.C
@@ -0,0 +1,18 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct undeclared<int> { }; // { dg-error "not a class template" }
+
+int
+main ()
+{
+ int foo ();
+ int a, b = 10;
+ a = foo<; // { dg-error "invalid template-argument-list|invalid" }
+ a = foo < b; // { dg-error "invalid template-argument-list|invalid" }
+ a = foo<b>; // { dg-error "after template-argument-list|invalid" }
+ a = foo<b>(; // { dg-error "expected" }
+ a = foo<b>(1; // { dg-error "expected" }
+ a = foo<b>(1); // { dg-error "no matching" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template8.C b/gcc/testsuite/g++.dg/cpp2a/fn-template8.C
new file mode 100644
index 0000000..9cd28ee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template8.C
@@ -0,0 +1,34 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+const unsigned long arr[10] = { 2 };
+template<class T> struct S { int n; };
+
+template <class T>
+int fn1 (S<T>* s)
+{
+ int i = 1;
+ return s->n < arr[i + 1];
+}
+
+template <class T>
+int fn2 (S<T> s)
+{
+ int i = 1;
+ return s.n < arr[i + 1];
+}
+
+template <class T>
+int fn3 (S<T>* s)
+{
+ int i = 1;
+ return s->template n < 1; // { dg-error "parse error in template argument list" }
+}
+
+template <class T>
+int fn4 (S<T> s)
+{
+ int i = 1;
+ return s.template n < 1; // { dg-error "parse error in template argument list" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template9.C b/gcc/testsuite/g++.dg/cpp2a/fn-template9.C
new file mode 100644
index 0000000..19c960c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template9.C
@@ -0,0 +1,21 @@
+// P0846R0
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+namespace N1 {
+ struct S {};
+ template<int X> void f(S);
+}
+
+namespace N2 {
+ template<class T> void f(T t);
+}
+
+void
+g (N1::S s)
+{
+ f<3>(s);
+
+ using N2::f;
+ f<3>(s);
+}
diff --git a/gcc/testsuite/g++.dg/parse/fn-template1.C b/gcc/testsuite/g++.dg/parse/fn-template1.C
new file mode 100644
index 0000000..00f8b49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/fn-template1.C
@@ -0,0 +1,15 @@
+// P0846R0
+// { dg-do compile }
+
+struct A { };
+bool operator <(void (*fp)(), A) { return false; }
+void f() {}
+
+int
+main ()
+{
+ A a;
+ f < a; // { dg-error "invalid" "" { target c++2a } }
+ bool b = f < a; // { dg-error "invalid" "" { target c++2a } }
+ (f) < a;
+}
diff --git a/gcc/testsuite/g++.dg/parse/fn-template2.C b/gcc/testsuite/g++.dg/parse/fn-template2.C
new file mode 100644
index 0000000..c56694e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/fn-template2.C
@@ -0,0 +1,17 @@
+// P0846R0
+// { dg-do compile }
+
+namespace N1 {
+ struct S {};
+ template<int X> void f(S);
+}
+
+namespace N2 {
+ template<class T> void f(T t);
+}
+
+void
+g (N1::S s)
+{
+ f<3>(s); // { dg-error "was not declared" "" { target c++17_down } }
+}
diff --git a/gcc/testsuite/g++.dg/parse/template19.C b/gcc/testsuite/g++.dg/parse/template19.C
index dc1a673..fba4f6d 100644
--- a/gcc/testsuite/g++.dg/parse/template19.C
+++ b/gcc/testsuite/g++.dg/parse/template19.C
@@ -6,6 +6,6 @@ template<int> struct A
{
template<int> void foo()
{
- foo<0>::; // { dg-error "before" }
+ foo<0>::; // { dg-error "before|function template-id" }
}
};
diff --git a/gcc/testsuite/g++.dg/template/pr61745.C b/gcc/testsuite/g++.dg/template/pr61745.C
index 0f7c280..da5973e 100644
--- a/gcc/testsuite/g++.dg/template/pr61745.C
+++ b/gcc/testsuite/g++.dg/template/pr61745.C
@@ -18,5 +18,7 @@ public:
// this compiles only if the following definition is moved
// AFTER the friend declaration
Zp operator-() const { return Zp(p-val); }
- friend Zp<INT,P> operator- <>(const Zp<INT,P>& a, const Zp<INT,P>& b); // { dg-error "declaration|expected" }
+ // In C++2A, we have an unqualified-id (operator-) followed by
+ // '<', and name lookup found a function.
+ friend Zp<INT,P> operator- <>(const Zp<INT,P>& a, const Zp<INT,P>& b); // { dg-error "declaration|expected" "" { target c++17_down } }
};