+2013-09-12 Adam Butcher <adam@jessamine.co.uk>
+
+ * cp-tree.h (type_uses_auto_or_concept): Declare.
+ (is_auto_or_concept): Declare.
+ * decl.c (grokdeclarator): Allow 'auto' parameters in lambdas with
+ -std=gnu++1y or -std=c++1y or, as a GNU extension, in plain functions.
+ * type-utils.h: New header defining ...
+ (find_type_usage): ... this new function based on pt.c (type_uses_auto)
+ for searching a type tree given a predicate.
+ * pt.c (type_uses_auto): Reimplement via type-utils.h (find_type_usage).
+ (is_auto_or_concept): New function.
+ (type_uses_auto_or_concept): New function.
+ * parser.h (struct cp_parser): Add fully_implicit_function_template_p.
+ * parser.c (cp_parser_new): Initialize fully_implicit_function_template_p.
+ (cp_parser_new): Initialize fully_implicit_function_template_p.
+ (cp_parser_lambda_expression): Copy and restore value of
+ fully_implicit_function_template_p as per other parser fields.
+ (cp_parser_parameter_declaration_list): Count generic
+ parameters and call ...
+ (add_implicit_template_parms): ... this new function to synthesize them
+ with help from type-utils.h (find_type_usage), ...
+ (tree_type_is_auto_or_concept): ... this new static function and ...
+ (make_generic_type_name): ... this new static function.
+ (cp_parser_direct_declarator): Account for implicit template parameters.
+ (cp_parser_lambda_declarator_opt): Finish fully implicit template if
+ necessary by calling ...
+ (finish_fully_implicit_template): ... this new function.
+ (cp_parser_member_declaration): Likewise.
+ (cp_parser_function_definition_after_declarator): Likewise.
+ * Make-lang.in (cp/pt.o): Add dependency on type-utils.h.
+ (cp/parser.o): Likewise.
+
2013-09-12 Adam Butcher <adam@jessamine.co.uk>
* parser.c (cp_parser_lambda_declarator_opt): Accept template parameter
#include "plugin.h"
#include "tree-pretty-print.h"
#include "parser.h"
+#include "type-utils.h"
\f
/* The lexer. */
static bool cp_parser_ctor_initializer_opt_and_function_body
(cp_parser *, bool);
+static tree add_implicit_template_parms
+ (cp_parser *, size_t, tree);
+static tree finish_fully_implicit_template
+ (cp_parser *, tree);
+
/* Classes [gram.class] */
static tree cp_parser_class_name
/* No template parameters apply. */
parser->num_template_parameter_lists = 0;
+ /* Not declaring an implicit function template. */
+ parser->fully_implicit_function_template_p = false;
+
return 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;
parser->num_template_parameter_lists = 0;
parser->in_statement = 0;
parser->in_switch_statement_p = false;
+ parser->fully_implicit_function_template_p = false;
/* By virtue of defining a local class, a lambda expression has access to
the private variables of enclosing classes. */
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;
}
pop_deferring_access_checks ();
finish_template_decl (template_param_list);
--parser->num_template_parameter_lists;
}
+ else if (parser->fully_implicit_function_template_p)
+ fco = finish_fully_implicit_template (parser, fco);
}
finish_member_declaration (fco);
/* Parse the parameter-declaration-clause. */
params = cp_parser_parameter_declaration_clause (parser);
+ /* Restore saved template parameter lists accounting for implicit
+ template parameters. */
parser->num_template_parameter_lists
- = saved_num_template_parameter_lists;
+ += saved_num_template_parameter_lists;
/* Consume the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
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;
deprecated_state = DEPRECATED_SUPPRESS;
if (parameter)
- decl = grokdeclarator (parameter->declarator,
- ¶meter->decl_specifiers,
- PARM,
- parameter->default_argument != NULL_TREE,
- ¶meter->decl_specifiers.attributes);
+ {
+ 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;
+ }
deprecated_state = DEPRECATED_NORMAL;
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);
+
return parameters;
}
attributes);
/* If the member was not a friend, declare it here. */
if (!friend_p)
- finish_member_declaration (decl);
+ {
+ if (parser->fully_implicit_function_template_p)
+ decl = finish_fully_implicit_template (parser, decl);
+ finish_member_declaration (decl);
+ }
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If the next token is a semicolon, consume it. */
initializer, /*init_const_expr_p=*/true,
asm_specification,
attributes);
+ if (parser->fully_implicit_function_template_p)
+ decl = finish_fully_implicit_template (parser, decl);
}
/* Reset PREFIX_ATTRIBUTES. */
= saved_num_template_parameter_lists;
parser->in_function_body = saved_in_function_body;
+ if (parser->fully_implicit_function_template_p)
+ finish_fully_implicit_template (parser, /*member_decl_opt=*/0);
+
return fn;
}
the_parser = NULL;
}
+/* Create an identifier for a generic parameter type (a synthesized
+ template parameter implied by `auto' or a concept identifier). */
+
+static tree
+make_generic_type_name (int i)
+{
+ char buf[32];
+ sprintf (buf, "__GenT%d", i);
+ return get_identifier (buf);
+}
+
+/* Predicate that behaves as is_auto_or_concept but matches the parent
+ node of the generic type rather than the generic type itself. This
+ allows for type transformation in add_implicit_template_parms. */
+
+static inline bool
+tree_type_is_auto_or_concept (const_tree t)
+{
+ return TREE_TYPE (t) && is_auto_or_concept (TREE_TYPE (t));
+}
+
+/* Add 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. */
+
+tree
+add_implicit_template_parms (cp_parser *parser, size_t count, tree parameters)
+{
+ 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_idx = 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)
+ {
+ push_deferring_access_checks (dk_deferred);
+ begin_template_parm_list ();
+
+ parser->fully_implicit_function_template_p = true;
+ ++parser->num_template_parameter_lists;
+ }
+ 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);
+
+ /* 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)
+ {
+ 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);
+ }
+
+ ++processing_template_parmlist;
+ }
+
+ for (tree p = parameters; p && synth_idx < 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;
+
+ tree synth_id = make_generic_type_name (synth_idx++);
+ 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);
+
+ /* 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));
+ else
+ cur_type = new_type;
+ }
+
+ gcc_assert (synth_idx == count);
+
+ push_binding_level (fn_parms_scope);
+
+ end_template_parm_list (tparms);
+
+ return parameters;
+}
+
+/* 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
+ 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. */
+
+tree
+finish_fully_implicit_template (cp_parser *parser, tree member_decl_opt)
+{
+ gcc_assert (parser->fully_implicit_function_template_p);
+
+ pop_deferring_access_checks ();
+ if (member_decl_opt)
+ member_decl_opt = finish_member_template_decl (member_decl_opt);
+ end_template_decl ();
+
+ parser->fully_implicit_function_template_p = false;
+ --parser->num_template_parameter_lists;
+
+ return member_decl_opt;
+}
+
#include "gt-cp-parser.h"
--- /dev/null
+/* Utilities for querying and manipulating type trees.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_CP_TYPE_UTILS_H
+#define GCC_CP_TYPE_UTILS_H
+
+/* Returns the first tree within T that is directly matched by PRED. T may be a
+ type or PARM_DECL and is incrementally decomposed toward its type-specifier
+ until a match is found. NULL_TREE is returned if PRED does not match any
+ part of T.
+
+ This is primarily intended for detecting whether T uses `auto' or a concept
+ identifier. Since either of these can only appear as a type-specifier for
+ the declaration in question, only top-level qualifications are traversed;
+ find_type_usage does not look through the whole type. */
+
+inline tree
+find_type_usage (tree t, bool (*pred) (const_tree))
+{
+ enum tree_code code;
+ if (pred (t))
+ return t;
+
+ code = TREE_CODE (t);
+
+ if (code == POINTER_TYPE || code == REFERENCE_TYPE
+ || code == PARM_DECL || code == OFFSET_TYPE
+ || code == FUNCTION_TYPE || code == METHOD_TYPE
+ || code == ARRAY_TYPE)
+ return find_type_usage (TREE_TYPE (t), pred);
+
+ if (TYPE_PTRMEMFUNC_P (t))
+ return find_type_usage
+ (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (t))), pred);
+
+ return NULL_TREE;
+}
+
+#endif // GCC_CP_TYPE_UTILS_H