* [C++ PATCH 3/3] Add some generic lambda test cases.
2013-11-02 10:03 [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637 Adam Butcher
@ 2013-11-02 10:03 ` Adam Butcher
2013-11-02 10:03 ` [C++ PATCH 1/3] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637 Adam Butcher
2013-11-02 10:03 ` [C++ PATCH 2/3] Support implicit parameter packs Adam Butcher
2 siblings, 0 replies; 15+ messages in thread
From: Adam Butcher @ 2013-11-02 10:03 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt, Adam Butcher
gcc/testsuite/g++.dg/cpp1y/
* lambda-generic.C: New test case.
* lambda-generic-cfun.C: New test case.
* lambda-generic-dep.C: New test case.
* lambda-generic-udt.C: New test case.
* lambda-generic-variadic.C: New test case.
* lambda-generic-x.C: New test case.
* lambda-generic-xcfun.C: New test case.
* lambda-generic-xudt.C: New test case.
* lambda-generic-mixed.C: New test case.
---
gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C | 25 +++++++++++
gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C | 42 ++++++++++++++++++
gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C | 10 +++++
gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C | 51 ++++++++++++++++++++++
.../g++.dg/cpp1y/lambda-generic-variadic.C | 15 +++++++
gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C | 25 +++++++++++
gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C | 25 +++++++++++
gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C | 4 ++
gcc/testsuite/g++.dg/cpp1y/lambda-generic.C | 23 ++++++++++
9 files changed, 220 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic.C
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C
new file mode 100644
index 0000000..5e51526
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-cfun.C
@@ -0,0 +1,25 @@
+// Generic lambda conversion to function ptr test from N3690 5.1.2.6
+// { dg-options "-std=c++1y" }
+
+void f1(int (*)(int)) { }
+void f2(char (*)(int)) { }
+void g(int (*)(int)) { } // #1
+void g(char (*)(char)) { } // #2
+void h(int (*)(int)) { } // #3
+void h(char (*)(int)) { } // #4
+
+int main()
+{
+ auto glambda = [](auto a) { return a; };
+ int (*fp)(int) = glambda;
+ f1(glambda); // OK
+ f2(glambda); // { dg-error "invalid user-defined conversion" }
+ g(glambda); // { dg-error "ambiguous" }
+ h(glambda); // OK: calls #3 since it is convertible from ID
+ int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
+
+ auto GL = [](auto a) { return a; };
+ int (*GL_int)(int) = GL; // OK: through conversion function template
+ GL_int(3);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C
new file mode 100644
index 0000000..bb68738
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep.C
@@ -0,0 +1,42 @@
+// Generic lambda type dependence test part from N3690 5.1.2.12
+// { dg-options "-std=c++1y" }
+
+void f(int, const int (&)[2] = {}) { } // #1
+void f(const int&, const int (&)[1]) { } // #2
+
+void test()
+{
+ const int x = 17;
+ auto g = [](auto a) {
+ f(x); // OK: calls #1, does not capture x
+ };
+ auto g2 = [=](auto a) {
+ int selector[sizeof(a) == 1 ? 1 : 2]{};
+ f(x, selector); // OK: is a dependent expression, so captures x
+ };
+}
+
+struct S {
+ struct N {
+ auto test () { return 7.f; }
+ };
+};
+
+#include <utility>
+
+int main()
+{
+ auto f = [] <typename T> (T const& s) mutable {
+ typename T::N x;
+ return x.test ();
+ };
+ auto g = [] (auto const& s) {
+ typename std::decay<decltype (s)>::type::N x;
+ return x.test ();
+ };
+
+ S i;
+ f(i);
+ g(i);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C
new file mode 100644
index 0000000..4e26fc5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-mixed.C
@@ -0,0 +1,10 @@
+// Mixed explicit and implicit generic lambda test.
+// { dg-options "-std=c++1y" }
+
+int main()
+{
+ auto f = [] <typename T> (T a, auto b) { return a + b; };
+ auto g = [] <typename T> (auto a, T b) { return a + b; };
+
+ return f (1.0, 3) + g (1.0, 3);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C
new file mode 100644
index 0000000..9f6d45a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C
@@ -0,0 +1,51 @@
+// Ensure that generic lambdas properly construct and destroy user types.
+// { dg-options "-std=c++1y -DUSE_AUTO_SYNTAX" }
+// { dg-do run }
+
+int i = 3;
+
+struct S
+{
+ S () { ++i; }
+ S (S const&) { ++i; }
+ S (S&& old) { old.shadow = true; i += 2; }
+ ~S () { if (shadow) i -= 2; else --i; }
+
+ bool shadow = false;
+};
+
+extern "C" void printf(...);
+#define assert(e) if (e); else \
+ printf ("%s:%d: !(%s)\n", __FILE__, __LINE__, #e), __builtin_abort ();
+
+int main ()
+{
+ assert (i == 3);
+ {
+ S s; assert (i == 4);
+
+ #if USE_AUTO_SYNTAX
+ auto byref = [] (auto& r) { (void) r; };
+ auto bycref = [] (auto const& r) { (void) r; };
+ auto byval = [] (auto v, auto const x) { assert (i == x); (void) v; };
+ auto byrval = [] (auto&& r, auto const x) { S steal (static_cast<S&&>(r));
+ assert (i == x); };
+
+ #elif USE_EXPLICIT_TEMPLATE_SYNTAX
+ auto byref = [] <typename T> (T& r) { (void) r; };
+ auto bycref = [] <typename T> (T const& r) { (void) r; };
+ auto byval = [] <typename T, typename I>
+ (T v, I const x) { assert (i == x); (void) v; };
+ auto byrval = [] <typename T, typename I>
+ (T&& r, I const x) { S steal (static_cast<S&&>(r));
+ assert (i == x); };
+ #endif
+
+ byref (s); assert (i == 4);
+ bycref (s); assert (i == 4);
+ byval (s, 5); assert (i == 4);
+ byrval (static_cast<S&&>(s), 6); assert (i == 5);
+ }
+ assert (i == 3);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic.C
new file mode 100644
index 0000000..bd41b35
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic.C
@@ -0,0 +1,15 @@
+// Basic generic lambda test
+// { dg-options "-std=c++1y" }
+// { dg-do run }
+
+template <typename T, typename U> struct pair {};
+template <typename... T> struct tuple {};
+
+int main()
+{
+ auto a = [] (auto, pair<auto,auto> v) { return sizeof (v); };
+ auto b = [] (auto, pair<pair<auto,auto>,auto>... v) { return sizeof... (v); };
+
+ a(1, pair<int, float>());
+ b(2, pair<pair<short,char>, double>(), pair<pair<float,long>, int>());
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C
new file mode 100644
index 0000000..48a6268
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-x.C
@@ -0,0 +1,25 @@
+// Explicit generic lambda test from N3690 5.1.2.5
+// { dg-options "-std=gnu++1y" }
+
+#include <iostream>
+
+int main()
+{
+ auto glambda = [] <typename A, typename B> (A a, B&& b) { return a < b; };
+ bool b = glambda(3, 3.14); // OK
+ auto vglambda = [] <typename P> (P printer) {
+ return [=] <typename... T> (T&& ... ts) { // OK: ts is a function parameter pack
+ printer(std::forward<decltype(ts)>(ts)...);
+ return [=]() {
+ printer(ts ...);
+ };
+ };
+ };
+ auto p = vglambda( [] <typename A,
+ typename B,
+ typename C> (A v1, B v2, C v3)
+ { std::cout << v1 << v2 << v3; } );
+ auto q = p(1, 'a', 3.14); // OK: outputs 1a3.14
+ q(); // OK: outputs 1a3.14
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C
new file mode 100644
index 0000000..d44b796
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xcfun.C
@@ -0,0 +1,25 @@
+// Explicit generic lambda conversion to function ptr test from N3690 5.1.2.6
+// { dg-options "-std=gnu++1y" }
+
+void f1(int (*)(int)) { }
+void f2(char (*)(int)) { }
+void g(int (*)(int)) { } // #1
+void g(char (*)(char)) { } // #2
+void h(int (*)(int)) { } // #3
+void h(char (*)(int)) { } // #4
+
+int main()
+{
+ auto glambda = [] <typename T> (T a) { return a; };
+ int (*fp)(int) = glambda;
+ f1(glambda); // OK
+ f2(glambda); // { dg-error "invalid user-defined conversion" }
+ g(glambda); // { dg-error "ambiguous" }
+ h(glambda); // OK: calls #3 since it is convertible from ID
+ int& (*fpi)(int*) = [] <typename T> (T* a) -> auto& { return *a; }; // OK
+
+ auto GL = [] <typename T> (T a) { return a; };
+ int (*GL_int)(int) = GL; // OK: through conversion function template
+ GL_int(3);
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C
new file mode 100644
index 0000000..fba864b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-xudt.C
@@ -0,0 +1,4 @@
+// Ensure that generic lambdas properly construct and destroy user types.
+// { dg-options "-std=gnu++1y -DUSE_EXPLICIT_TEMPLATE_SYNTAX" }
+
+#include "lambda-generic-udt.C"
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic.C
new file mode 100644
index 0000000..1f66475
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic.C
@@ -0,0 +1,23 @@
+// Generic lambda test from N3690 5.1.2.5
+// { dg-options "-std=c++1y" }
+
+#include <iostream>
+
+int main()
+{
+ auto glambda = [](auto a, auto&& b) { return a < b; };
+ bool b = glambda(3, 3.14); // OK
+ auto vglambda = [](auto printer) {
+ return [=](auto&& ... ts) { // OK: ts is a function parameter pack
+ printer(std::forward<decltype(ts)>(ts)...);
+ return [=]() {
+ printer(ts ...);
+ };
+ };
+ };
+ auto p = vglambda( [](auto v1, auto v2, auto v3)
+ { std::cout << v1 << v2 << v3; } );
+ auto q = p(1, 'a', 3.14); // OK: outputs 1a3.14
+ q(); // OK: outputs 1a3.14
+}
+
--
1.8.4
^ permalink raw reply [flat|nested] 15+ messages in thread
* [C++ PATCH 1/3] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
2013-11-02 10:03 [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637 Adam Butcher
2013-11-02 10:03 ` [C++ PATCH 3/3] Add some generic lambda test cases Adam Butcher
@ 2013-11-02 10:03 ` Adam Butcher
2013-11-08 19:10 ` [C++ PATCH] " Jason Merrill
2013-11-02 10:03 ` [C++ PATCH 2/3] Support implicit parameter packs Adam Butcher
2 siblings, 1 reply; 15+ messages in thread
From: Adam Butcher @ 2013-11-02 10:03 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt, Adam Butcher
gcc/
* tree.c (grow_tree_vec_stat): New function ...
* tree.h (grow_tree_vec_stat) (grow_tree_vec): ... and its declaration
and macro front-end.
gcc/cp/
PR c++/58534
PR c++/58536
PR c++/58548
PR c++/58549
PR c++/58637
* parser.h (struct cp_parser): New members implicit_template_parms,
implicit_template_scope and auto_is_implicit_function_template_parm_p.
* parser.c (add_implicit_template_parms): Refactor as ...
(synthesize_implicit_template_parm): ... this to append a new template
type parm to the current template parameter list (introducing a new list
if necessary).
(cp_parser_new): Initialize new cp_parser members.
(cp_parser_parameter_declaration_clause): Consider auto as implicit
template parm when parsing a parameter declaration (unless paring an
explicit specialization).
(cp_parser_parameter_declaration_list): Remove local
implicit_template_parms counter and reset cp_parser implicit template
state when complete.
(cp_parser_lambda_expression): Reset implicit template cp_parser members
whilst generating lambda class.
(cp_parser_function_definition_after_declarator): Reset implicit
template cp_parser members whilst parsing function definition.
(make_generic_type_name): Respell '<autoN>' as 'auto:N' which works
better with template diagnostics.
(cp_parser_simple_type_specifier): Synthesize implicit template parm on
parsing 'auto' if auto_is_implicit_function_template_parm_p and provide
diagnostics ...
* decl.c (grokdeclarator): ... that were previously done here.
gcc/testsuite/g++.dg/
* cpp1y/pr58534.C: New testcase.
* cpp1y/pr58536.C: New testcase.
* cpp1y/pr58548.C: New testcase.
* cpp1y/pr58549.C: New testcase.
* cpp1y/pr58637.C: New testcase.
---
gcc/cp/decl.c | 30 +---
gcc/cp/parser.c | 278 +++++++++++++++++++++++------------
gcc/cp/parser.h | 19 +++
gcc/testsuite/g++.dg/cpp1y/pr58534.C | 9 ++
gcc/testsuite/g++.dg/cpp1y/pr58536.C | 12 ++
gcc/testsuite/g++.dg/cpp1y/pr58548.C | 10 ++
gcc/testsuite/g++.dg/cpp1y/pr58549.C | 10 ++
gcc/testsuite/g++.dg/cpp1y/pr58637.C | 7 +
gcc/tree.c | 22 +++
gcc/tree.h | 5 +
10 files changed, 281 insertions(+), 121 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58534.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58536.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58548.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58549.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr58637.C
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 09c1daa..786814c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10375,33 +10375,11 @@ grokdeclarator (const cp_declarator *declarator,
if (type_uses_auto (type))
{
- if (template_parm_flag)
- {
- error ("template parameter declared %<auto%>");
- type = error_mark_node;
- }
- else if (decl_context == CATCHPARM)
- {
- error ("catch parameter declared %<auto%>");
- type = error_mark_node;
- }
- else if (current_class_type && LAMBDA_TYPE_P (current_class_type))
- {
- if (cxx_dialect < cxx1y)
- pedwarn (location_of (type), 0,
- "use of %<auto%> in lambda parameter declaration "
- "only available with "
- "-std=c++1y or -std=gnu++1y");
- }
- else if (cxx_dialect < cxx1y)
- pedwarn (location_of (type), 0,
- "use of %<auto%> in parameter declaration "
- "only available with "
- "-std=c++1y or -std=gnu++1y");
+ if (cxx_dialect >= cxx1y)
+ error ("%<auto%> parameter not permitted in this context");
else
- pedwarn (location_of (type), OPT_Wpedantic,
- "ISO C++ forbids use of %<auto%> in parameter "
- "declaration");
+ error ("parameter declared %<auto%>");
+ type = error_mark_node;
}
/* A parameter declared as an array of T is really a pointer to T.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index bbc8e75..b699ac4 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2107,8 +2107,8 @@ static bool cp_parser_ctor_initializer_opt_and_function_body
static tree cp_parser_late_parsing_omp_declare_simd
(cp_parser *, tree);
-static tree add_implicit_template_parms
- (cp_parser *, size_t, tree);
+static tree synthesize_implicit_template_parm
+ (cp_parser *);
static tree finish_fully_implicit_template
(cp_parser *, tree);
@@ -3443,7 +3443,10 @@ cp_parser_new (void)
parser->num_template_parameter_lists = 0;
/* Not declaring an implicit function template. */
+ parser->auto_is_implicit_function_template_parm_p = false;
parser->fully_implicit_function_template_p = false;
+ parser->implicit_template_parms = 0;
+ parser->implicit_template_scope = 0;
return parser;
}
@@ -8617,12 +8620,17 @@ cp_parser_lambda_expression (cp_parser* parser)
= parser->num_template_parameter_lists;
unsigned char in_statement = parser->in_statement;
bool in_switch_statement_p = parser->in_switch_statement_p;
- bool fully_implicit_function_template_p = parser->fully_implicit_function_template_p;
+ bool fully_implicit_function_template_p
+ = parser->fully_implicit_function_template_p;
+ tree implicit_template_parms = parser->implicit_template_parms;
+ cp_binding_level* implicit_template_scope = parser->implicit_template_scope;
parser->num_template_parameter_lists = 0;
parser->in_statement = 0;
parser->in_switch_statement_p = false;
parser->fully_implicit_function_template_p = false;
+ parser->implicit_template_parms = 0;
+ parser->implicit_template_scope = 0;
/* By virtue of defining a local class, a lambda expression has access to
the private variables of enclosing classes. */
@@ -8646,7 +8654,10 @@ cp_parser_lambda_expression (cp_parser* parser)
parser->num_template_parameter_lists = saved_num_template_parameter_lists;
parser->in_statement = in_statement;
parser->in_switch_statement_p = in_switch_statement_p;
- parser->fully_implicit_function_template_p = fully_implicit_function_template_p;
+ parser->fully_implicit_function_template_p
+ = fully_implicit_function_template_p;
+ parser->implicit_template_parms = implicit_template_parms;
+ parser->implicit_template_scope = implicit_template_scope;
}
pop_deferring_access_checks ();
@@ -14053,7 +14064,7 @@ cp_parser_explicit_specialization (cp_parser* parser)
cp_parser_single_declaration (parser,
/*checks=*/NULL,
/*member_p=*/false,
- /*explicit_specialization_p=*/true,
+ /*explicit_specialization_p=*/true,
/*friend_p=*/NULL);
/* We're done with the specialization. */
end_specialization ();
@@ -14355,10 +14366,33 @@ cp_parser_simple_type_specifier (cp_parser* parser,
case RID_VOID:
type = void_type_node;
break;
-
+
case RID_AUTO:
maybe_warn_cpp0x (CPP0X_AUTO);
- type = make_auto ();
+ if (parser->auto_is_implicit_function_template_parm_p)
+ {
+ type = synthesize_implicit_template_parm (parser);
+
+ if (current_class_type && LAMBDA_TYPE_P (current_class_type))
+ {
+ if (cxx_dialect < cxx1y)
+ pedwarn (location_of (type), 0,
+ "use of %<auto%> in lambda parameter declaration "
+ "only available with "
+ "-std=c++1y or -std=gnu++1y");
+ }
+ else if (cxx_dialect < cxx1y)
+ pedwarn (location_of (type), 0,
+ "use of %<auto%> in parameter declaration "
+ "only available with "
+ "-std=c++1y or -std=gnu++1y");
+ else
+ pedwarn (location_of (type), OPT_Wpedantic,
+ "ISO C++ forbids use of %<auto%> in parameter "
+ "declaration");
+ }
+ else
+ type = make_auto ();
break;
case RID_DECLTYPE:
@@ -17937,6 +17971,20 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
bool ellipsis_p;
bool is_error;
+ struct cleanup {
+ cp_parser* parser;
+ int auto_is_implicit_function_template_parm_p;
+ ~cleanup() {
+ parser->auto_is_implicit_function_template_parm_p
+ = auto_is_implicit_function_template_parm_p;
+ }
+ } cleanup = { parser, parser->auto_is_implicit_function_template_parm_p };
+
+ (void) cleanup;
+
+ if (!processing_specialization)
+ parser->auto_is_implicit_function_template_parm_p = true;
+
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* Check for trivial parameter-declaration-clauses. */
@@ -18024,7 +18072,6 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
tree *tail = ¶meters;
bool saved_in_unbraced_linkage_specification_p;
int index = 0;
- int implicit_template_parms = 0;
/* Assume all will go well. */
*is_error = false;
@@ -18052,18 +18099,11 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
deprecated_state = DEPRECATED_SUPPRESS;
if (parameter)
- {
- decl = grokdeclarator (parameter->declarator,
- ¶meter->decl_specifiers,
- PARM,
- parameter->default_argument != NULL_TREE,
- ¶meter->decl_specifiers.attributes);
-
- if (TREE_TYPE (decl) != error_mark_node
- && parameter->decl_specifiers.type
- && is_auto_or_concept (parameter->decl_specifiers.type))
- ++implicit_template_parms;
- }
+ decl = grokdeclarator (parameter->declarator,
+ ¶meter->decl_specifiers,
+ PARM,
+ parameter->default_argument != NULL_TREE,
+ ¶meter->decl_specifiers.attributes);
deprecated_state = DEPRECATED_NORMAL;
@@ -18151,10 +18191,12 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
parser->in_unbraced_linkage_specification_p
= saved_in_unbraced_linkage_specification_p;
- if (parameters != error_mark_node && implicit_template_parms)
- parameters = add_implicit_template_parms (parser,
- implicit_template_parms,
- parameters);
+ if (cp_binding_level *its = parser->implicit_template_scope)
+ if (current_binding_level->level_chain == its)
+ {
+ parser->implicit_template_parms = 0;
+ parser->implicit_template_scope = 0;
+ }
return parameters;
}
@@ -22406,6 +22448,15 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
bool saved_in_function_body;
unsigned saved_num_template_parameter_lists;
cp_token *token;
+ bool fully_implicit_function_template_p
+ = parser->fully_implicit_function_template_p;
+ parser->fully_implicit_function_template_p = false;
+ tree implicit_template_parms
+ = parser->implicit_template_parms;
+ parser->implicit_template_parms = 0;
+ cp_binding_level* implicit_template_scope
+ = parser->implicit_template_scope;
+ parser->implicit_template_scope = 0;
saved_in_function_body = parser->in_function_body;
parser->in_function_body = true;
@@ -22478,6 +22529,13 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
= saved_num_template_parameter_lists;
parser->in_function_body = saved_in_function_body;
+ parser->fully_implicit_function_template_p
+ = fully_implicit_function_template_p;
+ parser->implicit_template_parms
+ = implicit_template_parms;
+ parser->implicit_template_scope
+ = implicit_template_scope;
+
if (parser->fully_implicit_function_template_p)
finish_fully_implicit_template (parser, /*member_decl_opt=*/0);
@@ -31011,7 +31069,7 @@ static tree
make_generic_type_name ()
{
char buf[32];
- sprintf (buf, "<auto%d>", ++generic_parm_count);
+ sprintf (buf, "auto:%d", ++generic_parm_count);
return get_identifier (buf);
}
@@ -31025,110 +31083,140 @@ tree_type_is_auto_or_concept (const_tree t)
return TREE_TYPE (t) && is_auto_or_concept (TREE_TYPE (t));
}
-/* Add EXPECT_COUNT implicit template parameters gleaned from the generic
- type parameters in PARAMETERS to the CURRENT_TEMPLATE_PARMS (creating a new
- template parameter list if necessary). Returns PARAMETERS suitably rewritten
- to reference the newly created types or ERROR_MARK_NODE on failure. */
+/* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS
+ (creating a new template parameter list if necessary). Returns the newly
+ created template type parm. */
tree
-add_implicit_template_parms (cp_parser *parser, size_t expect_count,
- tree parameters)
+synthesize_implicit_template_parm (cp_parser *parser)
{
gcc_assert (current_binding_level->kind == sk_function_parms);
- cp_binding_level *fn_parms_scope = current_binding_level;
-
- bool become_template =
- fn_parms_scope->level_chain->kind != sk_template_parms;
-
- size_t synth_count = 0;
+ /* We are either continuing a function template that already contains implicit
+ template parameters, creating a new fully-implicit function template, or
+ extending an existing explicit function template with implicit template
+ parameters. */
- /* Roll back a scope level and either introduce a new template parameter list
- or update an existing one. The function scope is added back after template
- parameter synthesis below. */
- current_binding_level = fn_parms_scope->level_chain;
+ cp_binding_level *const entry_scope = current_binding_level;
- /* TPARMS tracks the function's template parameter list. This is either a new
- chain in the case of a fully implicit function template or an extension of
- the function's explicitly specified template parameter list. */
- tree tparms = NULL_TREE;
+ bool become_template = false;
+ cp_binding_level *parent_scope = 0;
- if (become_template)
+ if (parser->implicit_template_scope)
{
- push_deferring_access_checks (dk_deferred);
- begin_template_parm_list ();
+ gcc_assert (parser->implicit_template_parms);
- parser->fully_implicit_function_template_p = true;
- ++parser->num_template_parameter_lists;
+ current_binding_level = parser->implicit_template_scope;
}
else
{
- /* Roll back the innermost template parameter list such that it may be
- extended in the loop below as if it were being explicitly declared. */
-
- gcc_assert (current_template_parms);
+ /* Roll back to the existing template parameter scope (in the case of
+ extending an explicit function template) or introduce a new template
+ parameter scope ahead of the function parameter scope (or class scope
+ in the case of out-of-line member definitions). The function scope is
+ added back after template parameter synthesis below. */
- /* Pop the innermost template parms into TPARMS. */
- tree inner_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms);
- current_template_parms = TREE_CHAIN (current_template_parms);
+ cp_binding_level *scope = entry_scope;
- size_t inner_vec_len = TREE_VEC_LENGTH (inner_vec);
- if (inner_vec_len != 0)
+ while (scope->kind == sk_function_parms)
{
- tree t = tparms = TREE_VEC_ELT (inner_vec, 0);
- for (size_t n = 1; n < inner_vec_len; ++n)
- t = TREE_CHAIN (t) = TREE_VEC_ELT (inner_vec, n);
+ parent_scope = scope;
+ scope = scope->level_chain;
}
+ if (current_class_type && !LAMBDA_TYPE_P (current_class_type)
+ && parser->num_classes_being_defined == 0)
+ while (scope->kind == sk_class)
+ {
+ parent_scope = scope;
+ scope = scope->level_chain;
+ }
- ++processing_template_parmlist;
- }
+ current_binding_level = scope;
- for (tree p = parameters; p && synth_count < expect_count; p = TREE_CHAIN (p))
- {
- tree generic_type_ptr
- = find_type_usage (TREE_VALUE (p), tree_type_is_auto_or_concept);
-
- if (!generic_type_ptr)
- continue;
+ if (scope->kind != sk_template_parms)
+ {
+ /* Introduce a new template parameter list for implicit template
+ parameters. */
- ++synth_count;
+ become_template = true;
- tree synth_id = make_generic_type_name ();
- tree synth_tmpl_parm = finish_template_type_parm (class_type_node,
- synth_id);
- tparms = process_template_parm (tparms, DECL_SOURCE_LOCATION (TREE_VALUE
- (p)),
- build_tree_list (NULL_TREE,
- synth_tmpl_parm),
- /*non_type=*/false,
- /*param_pack=*/false);
+ push_deferring_access_checks (dk_deferred);
- /* Rewrite the type of P to be the template_parm added above (getdecls is
- used to retrieve it since it is the most recent declaration in this
- scope). Qualifiers need to be preserved also. */
+ parser->implicit_template_scope
+ = begin_scope (sk_template_parms, NULL);
- tree& cur_type = TREE_TYPE (generic_type_ptr);
- tree new_type = TREE_TYPE (getdecls ());
+ ++processing_template_decl;
- if (TYPE_QUALS (cur_type))
- cur_type = cp_build_qualified_type (new_type, TYPE_QUALS (cur_type));
+ parser->fully_implicit_function_template_p = true;
+ ++parser->num_template_parameter_lists;
+ }
else
- cur_type = new_type;
+ {
+ /* Synthesize implicit template parameters at the end of the explicit
+ template parameter list. */
+
+ gcc_assert (current_template_parms);
+
+ parser->implicit_template_scope = scope;
+
+ tree v = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+ parser->implicit_template_parms
+ = TREE_VEC_ELT (v, TREE_VEC_LENGTH (v) - 1);
+ }
}
- gcc_assert (synth_count == expect_count);
+ /* Synthesize a new template parameter and track the current template
+ parameter chain with implicit_template_parms. */
- push_binding_level (fn_parms_scope);
+ tree synth_id = make_generic_type_name ();
+ tree synth_tmpl_parm = finish_template_type_parm (class_type_node,
+ synth_id);
+ tree new_parm
+ = process_template_parm (parser->implicit_template_parms,
+ input_location,
+ build_tree_list (NULL_TREE, synth_tmpl_parm),
+ /*non_type=*/false,
+ /*param_pack=*/false);
- end_template_parm_list (tparms);
- return parameters;
+ if (parser->implicit_template_parms)
+ parser->implicit_template_parms
+ = TREE_CHAIN (parser->implicit_template_parms);
+ else
+ parser->implicit_template_parms = new_parm;
+
+ tree new_type = TREE_TYPE (getdecls ());
+
+ /* If creating a fully implicit function template, start the new implicit
+ template parameter list with this synthesized type, otherwise grow the
+ current template parameter list. */
+
+ if (become_template)
+ {
+ parent_scope->level_chain = current_binding_level;
+
+ tree new_parms = make_tree_vec (1);
+ TREE_VEC_ELT (new_parms, 0) = parser->implicit_template_parms;
+ current_template_parms = tree_cons (size_int (processing_template_decl),
+ new_parms, current_template_parms);
+ }
+ else
+ {
+ tree& new_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+ int new_parm_idx = TREE_VEC_LENGTH (new_parms);
+ new_parms = grow_tree_vec_stat (new_parms, new_parm_idx + 1);
+ TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms;
+ }
+
+ current_binding_level = entry_scope;
+
+ return new_type;
}
/* Finish the declaration of a fully implicit function template. Such a
template has no explicit template parameter list so has not been through the
- normal template head and tail processing. add_implicit_template_parms tries
- to do the head; this tries to do the tail. MEMBER_DECL_OPT should be
+ normal template head and tail processing. synthesize_implicit_template_parm
+ tries to do the head; this tries to do the tail. MEMBER_DECL_OPT should be
provided if the declaration is a class member such that its template
declaration can be completed. If MEMBER_DECL_OPT is provided the finished
form is returned. Otherwise NULL_TREE is returned. */
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 75f327b..1024024 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -360,11 +360,30 @@ typedef struct GTY(()) cp_parser {
data structure with everything needed for parsing the clauses. */
cp_omp_declare_simd_data * GTY((skip)) omp_declare_simd;
+ /* Nonzero if parsing a parameter list where 'auto' should trigger an implicit
+ template parameter. */
+ bool auto_is_implicit_function_template_parm_p;
+
/* TRUE if the function being declared was made a template due to its
parameter list containing generic type specifiers (`auto' or concept
identifiers) rather than an explicit template parameter list. */
bool fully_implicit_function_template_p;
+ /* Tracks the function's template parameter list when declaring a function
+ using generic type parameters. This is either a new chain in the case of a
+ fully implicit function template or an extension of the function's existing
+ template parameter list. This is tracked to optimize calls subsequent
+ calls to synthesize_implicit_template_parm during
+ cp_parser_parameter_declaration. */
+ tree implicit_template_parms;
+
+ /* The scope into which an implicit template parameter list has been
+ introduced or an existing template parameter list is being extended with
+ implicit template paramaters. In most cases this is the sk_function_parms
+ scope containing the use of a generic type. In the case of an out-of-line
+ member definition using a generic type, it is the sk_class scope. */
+ cp_binding_level* implicit_template_scope;
+
} cp_parser;
/* In parser.c */
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58534.C b/gcc/testsuite/g++.dg/cpp1y/pr58534.C
new file mode 100644
index 0000000..4aa4f43
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr58534.C
@@ -0,0 +1,9 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// PR c++/58534
+
+template<typename> void foo(const auto&) {}
+
+template<typename, typename...T> void foo(const auto&, T...) {}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58536.C b/gcc/testsuite/g++.dg/cpp1y/pr58536.C
new file mode 100644
index 0000000..8050c19
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr58536.C
@@ -0,0 +1,12 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// PR c++/58536
+
+struct A
+{
+ A(auto);
+};
+
+A::A(auto) {}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58548.C b/gcc/testsuite/g++.dg/cpp1y/pr58548.C
new file mode 100644
index 0000000..0ac2e1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr58548.C
@@ -0,0 +1,10 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// PR c++/58548
+
+void foo(auto)
+{
+ struct A { int i; };
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58549.C b/gcc/testsuite/g++.dg/cpp1y/pr58549.C
new file mode 100644
index 0000000..b71bac9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr58549.C
@@ -0,0 +1,10 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// PR c++/58549
+
+void foo(auto)
+{
+ void bar();
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58637.C b/gcc/testsuite/g++.dg/cpp1y/pr58637.C
new file mode 100644
index 0000000..46200ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr58637.C
@@ -0,0 +1,7 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++1y" }
+
+// PR c++/58637
+
+template<> void foo(auto); // { dg-error "auto|not a template" }
+
diff --git a/gcc/tree.c b/gcc/tree.c
index 332751a..28cbba8 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -1940,6 +1940,28 @@ make_tree_vec_stat (int len MEM_STAT_DECL)
return t;
}
+
+/* Grow a TREE_VEC node to new length LEN. */
+
+tree
+grow_tree_vec_stat (tree v, int len MEM_STAT_DECL)
+{
+ gcc_assert (TREE_CODE (v) == TREE_VEC);
+
+ int oldlen = TREE_VEC_LENGTH (v);
+ gcc_assert (len > oldlen);
+
+ int oldlength = (oldlen - 1) * sizeof (tree) + sizeof (struct tree_vec);
+ int length = (len - 1) * sizeof (tree) + sizeof (struct tree_vec);
+
+ record_node_allocation_statistics (TREE_VEC, length - oldlength);
+
+ v = (tree) ggc_realloc_stat (v, length PASS_MEM_STAT);
+
+ TREE_VEC_LENGTH (v) = len;
+
+ return v;
+}
\f
/* Return 1 if EXPR is the integer constant zero or a complex constant
of zero. */
diff --git a/gcc/tree.h b/gcc/tree.h
index 920ad07..8ca89d9 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3412,6 +3412,11 @@ extern tree make_tree_binfo_stat (unsigned MEM_STAT_DECL);
extern tree make_tree_vec_stat (int MEM_STAT_DECL);
#define make_tree_vec(t) make_tree_vec_stat (t MEM_STAT_INFO)
+/* Grow a TREE_VEC. */
+
+extern tree grow_tree_vec_stat (tree v, int MEM_STAT_DECL);
+#define grow_tree_vec(v, t) grow_tree_vec_stat (v, t MEM_STAT_INFO)
+
/* Return the (unique) IDENTIFIER_NODE node for a given name.
The name is supplied as a char *. */
--
1.8.4
^ permalink raw reply [flat|nested] 15+ messages in thread
* [C++ PATCH 2/3] Support implicit parameter packs.
2013-11-02 10:03 [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637 Adam Butcher
2013-11-02 10:03 ` [C++ PATCH 3/3] Add some generic lambda test cases Adam Butcher
2013-11-02 10:03 ` [C++ PATCH 1/3] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637 Adam Butcher
@ 2013-11-02 10:03 ` Adam Butcher
2 siblings, 0 replies; 15+ messages in thread
From: Adam Butcher @ 2013-11-02 10:03 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches, Volker Reichelt, Adam Butcher
* parser.c (convert_generic_types_to_packs): New function to transform
a range of implicitly introduced non-pack template parms to be parameter
packs.
(cp_parser_parameter_declaration_list): If a function parameter pack
contains generic types, convert them to packs prior to grokdeclarator.
---
gcc/cp/parser.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 74 insertions(+), 7 deletions(-)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b699ac4..10b9f72 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2109,6 +2109,8 @@ static tree cp_parser_late_parsing_omp_declare_simd
static tree synthesize_implicit_template_parm
(cp_parser *);
+static tree convert_generic_types_to_packs
+ (tree, tree, int, int);
static tree finish_fully_implicit_template
(cp_parser *, tree);
@@ -18069,7 +18071,7 @@ static tree
cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
{
tree parameters = NULL_TREE;
- tree *tail = ¶meters;
+ tree *tail = ¶meters;
bool saved_in_unbraced_linkage_specification_p;
int index = 0;
@@ -18078,7 +18080,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
/* The special considerations that apply to a function within an
unbraced linkage specifications do not apply to the parameters
to the function. */
- saved_in_unbraced_linkage_specification_p
+ saved_in_unbraced_linkage_specification_p
= parser->in_unbraced_linkage_specification_p;
parser->in_unbraced_linkage_specification_p = false;
@@ -18088,6 +18090,10 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
cp_parameter_declarator *parameter;
tree decl = error_mark_node;
bool parenthesized_p = false;
+ int template_parm_idx = (parser->num_template_parameter_lists?
+ TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
+ (current_template_parms)) : 0);
+
/* Parse the parameter. */
parameter
= cp_parser_parameter_declaration (parser,
@@ -18099,11 +18105,30 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
deprecated_state = DEPRECATED_SUPPRESS;
if (parameter)
- decl = grokdeclarator (parameter->declarator,
- ¶meter->decl_specifiers,
- PARM,
- parameter->default_argument != NULL_TREE,
- ¶meter->decl_specifiers.attributes);
+ {
+ /* If a function parameter pack was specified and an implicit template
+ parameter was introduced during cp_parser_parameter_declaration,
+ change any implicit parameters introduced into packs. */
+ if (parser->implicit_template_parms
+ && parameter->declarator
+ && parameter->declarator->parameter_pack_p)
+ {
+ int latest_template_parm_idx = TREE_VEC_LENGTH
+ (INNERMOST_TEMPLATE_PARMS (current_template_parms));
+
+ if (latest_template_parm_idx != template_parm_idx)
+ parameter->decl_specifiers.type = convert_generic_types_to_packs
+ (parameter->decl_specifiers.type,
+ current_template_parms,
+ template_parm_idx, latest_template_parm_idx);
+ }
+
+ decl = grokdeclarator (parameter->declarator,
+ ¶meter->decl_specifiers,
+ PARM,
+ parameter->default_argument != NULL_TREE,
+ ¶meter->decl_specifiers.attributes);
+ }
deprecated_state = DEPRECATED_NORMAL;
@@ -31213,6 +31238,48 @@ synthesize_implicit_template_parm (cp_parser *parser)
return new_type;
}
+/* Convert the generic type parameters in PARM that match the types given in the
+ range [START_IDX, END_IDX) from the template parameters CURRENT into generic
+ type packs. */
+
+tree
+convert_generic_types_to_packs (tree parm,
+ tree current, int start_idx, int end_idx)
+{
+ int depth = TMPL_PARMS_DEPTH (current);
+ current = INNERMOST_TEMPLATE_PARMS (current);
+ tree replacement = make_tree_vec (TREE_VEC_LENGTH (current));
+
+ for (int i = start_idx; i < end_idx; ++i)
+ {
+ /* Create a distinct parameter pack type from the current parm and add it
+ to the replacement args to tsubst below into the generic function
+ parameter. */
+
+ tree t = copy_type (TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i))));
+ TYPE_STUB_DECL (t) = TYPE_NAME (t) = TEMPLATE_TYPE_DECL (t);
+ TYPE_MAIN_VARIANT (t) = t;
+ TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ TREE_VEC_ELT (replacement, i) = t;
+ }
+
+ if (depth > 1)
+ {
+ /* Build up a tree vec of empty tree vecs up to the inner substitution
+ args built above. */
+
+ tree inner = replacement;
+ replacement = make_tree_vec (depth);
+ int last = depth - 1;
+ for (int i = 0; i < last; ++i)
+ TREE_VEC_ELT (replacement, i) = make_tree_vec (0);
+ TREE_VEC_ELT (replacement, last) = inner;
+ }
+
+ return tsubst (parm, replacement, tf_none, NULL_TREE);
+}
+
/* Finish the declaration of a fully implicit function template. Such a
template has no explicit template parameter list so has not been through the
normal template head and tail processing. synthesize_implicit_template_parm
--
1.8.4
^ permalink raw reply [flat|nested] 15+ messages in thread