Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.

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).  Removed push_deferring_access_checks.
	(finish_fully_implicit_template): Removed pop_deferring_access_checks.
	(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 parsing 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.

From-SVN: r204714
This commit is contained in:
Adam Butcher 2013-11-12 20:17:33 +00:00 committed by Adam Butcher
parent 27297d2d1b
commit 0dca5025f0
13 changed files with 331 additions and 123 deletions

View File

@ -1,3 +1,9 @@
2013-11-12 Adam Butcher <adam@jessamine.co.uk>
* tree.c (grow_tree_vec_stat): New function ...
* tree.h (grow_tree_vec_stat) (grow_tree_vec): ... and its declaration
and macro front-end.
2013-11-12 Marek Polacek <polacek@redhat.com>
* final.c (update_alignments): Initialize label to NULL_RTX.

View File

@ -1,3 +1,35 @@
2013-11-12 Adam Butcher <adam@jessamine.co.uk>
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). Removed push_deferring_access_checks.
(finish_fully_implicit_template): Removed pop_deferring_access_checks.
(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 parsing 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.
2013-11-12 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/57734

View File

@ -10381,33 +10381,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.

View File

@ -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;
}
@ -8660,12 +8663,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. */
@ -8689,7 +8697,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 ();
@ -14096,7 +14107,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 ();
@ -14398,10 +14409,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:
@ -17980,6 +18014,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. */
@ -18067,7 +18115,6 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
tree *tail = &parameters;
bool saved_in_unbraced_linkage_specification_p;
int index = 0;
int implicit_template_parms = 0;
/* Assume all will go well. */
*is_error = false;
@ -18095,18 +18142,11 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
deprecated_state = DEPRECATED_SUPPRESS;
if (parameter)
{
decl = grokdeclarator (parameter->declarator,
&parameter->decl_specifiers,
PARM,
parameter->default_argument != NULL_TREE,
&parameter->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,
&parameter->decl_specifiers,
PARM,
parameter->default_argument != NULL_TREE,
&parameter->decl_specifiers.attributes);
deprecated_state = DEPRECATED_NORMAL;
@ -18194,10 +18234,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;
}
@ -22461,6 +22503,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;
@ -22533,6 +22584,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);
@ -31116,7 +31174,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);
}
@ -31130,110 +31188,138 @@ 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;
/* 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. */
bool become_template =
fn_parms_scope->level_chain->kind != sk_template_parms;
cp_binding_level *const entry_scope = current_binding_level;
size_t synth_count = 0;
bool become_template = false;
cp_binding_level *parent_scope = 0;
/* 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;
/* 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;
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. */
/* 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. */
gcc_assert (current_template_parms);
cp_binding_level *scope = entry_scope;
/* Pop the innermost template parms into TPARMS. */
tree inner_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms);
current_template_parms = TREE_CHAIN (current_template_parms);
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 (scope->kind != sk_template_parms)
{
/* Introduce a new template parameter list for implicit template
parameters. */
if (!generic_type_ptr)
continue;
become_template = true;
++synth_count;
parser->implicit_template_scope
= begin_scope (sk_template_parms, NULL);
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);
++processing_template_decl;
/* 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. */
tree& cur_type = TREE_TYPE (generic_type_ptr);
tree new_type = TREE_TYPE (getdecls ());
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. */
@ -31251,7 +31337,6 @@ finish_fully_implicit_template (cp_parser *parser, tree member_decl_opt)
DECL_VIRTUAL_P (member_decl_opt) = false;
}
pop_deferring_access_checks ();
if (member_decl_opt)
member_decl_opt = finish_member_template_decl (member_decl_opt);
end_template_decl ();

View File

@ -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 */

View File

@ -1,3 +1,16 @@
2013-11-12 Adam Butcher <adam@jessamine.co.uk>
PR c++/58534
PR c++/58536
PR c++/58548
PR c++/58549
PR c++/58637
* g++.dg/cpp1y/pr58534.C: New testcase.
* g++.dg/cpp1y/pr58536.C: New testcase.
* g++.dg/cpp1y/pr58548.C: New testcase.
* g++.dg/cpp1y/pr58549.C: New testcase.
* g++.dg/cpp1y/pr58637.C: New testcase.
2013-11-12 Joseph Myers <joseph@codesourcery.com>
* gcc.dg/c90-thread-local-1.c, gcc.dg/c99-thread-local-1.c,

View File

@ -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...) {}

View File

@ -0,0 +1,12 @@
// { dg-do compile }
// { dg-options "-std=gnu++1y" }
// PR c++/58536
struct A
{
A(auto);
};
A::A(auto) {}

View File

@ -0,0 +1,10 @@
// { dg-do compile }
// { dg-options "-std=gnu++1y" }
// PR c++/58548
void foo(auto)
{
struct A { int i; };
}

View File

@ -0,0 +1,10 @@
// { dg-do compile }
// { dg-options "-std=gnu++1y" }
// PR c++/58549
void foo(auto)
{
void bar();
}

View File

@ -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" }

View File

@ -1864,6 +1864,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;
}
/* Return 1 if EXPR is the integer constant zero or a complex constant
of zero. */

View File

@ -3430,6 +3430,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 *. */