From patchwork Tue Aug 27 19:42:53 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Butcher X-Patchwork-Id: 270212 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "www.sourceware.org", Issuer "StartCom Class 1 Primary Intermediate Server CA" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 02F592C008E for ; Wed, 28 Aug 2013 05:44:04 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=GXnLlsQ3EHUHxY+NtVDjBTTIg7+cpeZFhZuOlMSt5oxZYHzo6zMzQ GEcJ8lp/sHosp0bCrLrG1x5/UYLwkeVHkwccUcdYBKZBjhPnvaKCysx5Xn78KlWu WRz0eMON9Rugb/XRquA8gnGTCNMB3YiSpgvpDfNxhvRzr7xqMxhp3M= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=PlSThakjATnc2bbfJBaFq+729xo=; b=TAHzO7QPst743xGif+Zr iKM/IrRrWx2i+3Te+IXHECdRMT5CxJKKOp5LJCPbjra/NGpfhafwQlszQG9yqU4d qX5h46tET7vZYSSPaJjYGkGqk/fSv2LQMV7tLuF8AnGbHrOMSXuBMnd44Xy/aZnB ciAkbd4rppSTrBudTfd1ggo= Received: (qmail 16392 invoked by alias); 27 Aug 2013 19:43:13 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 16350 invoked by uid 89); 27 Aug 2013 19:43:13 -0000 Received: from mail-wi0-f172.google.com (HELO mail-wi0-f172.google.com) (209.85.212.172) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Tue, 27 Aug 2013 19:43:13 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.8 required=5.0 tests=ALL_TRUSTED, AWL, BAYES_00, FREEMAIL_FROM, KHOP_THREADED autolearn=ham version=3.3.2 X-HELO: mail-wi0-f172.google.com Received: by mail-wi0-f172.google.com with SMTP id ex4so2808269wid.5 for ; Tue, 27 Aug 2013 12:43:08 -0700 (PDT) X-Received: by 10.180.91.167 with SMTP id cf7mr3657wib.1.1377632588029; Tue, 27 Aug 2013 12:43:08 -0700 (PDT) Received: from sphere.lan (munkyhouse.force9.co.uk. [84.92.244.81]) by mx.google.com with ESMTPSA id ff5sm28553968wib.2.1969.12.31.16.00.00 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 27 Aug 2013 12:43:07 -0700 (PDT) From: Adam Butcher To: Jason Merrill Cc: gcc-patches@gcc.gnu.org, Gabriel Dos Reis , Andrew Sutton , Adam Butcher Subject: [PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter. Date: Tue, 27 Aug 2013 20:42:53 +0100 Message-Id: <1377632573-14453-5-git-send-email-adam@jessamine.co.uk> In-Reply-To: <1377632573-14453-1-git-send-email-adam@jessamine.co.uk> References: <1377632573-14453-1-git-send-email-adam@jessamine.co.uk> * cp-tree.h (type_uses_auto_or_concept): Declare. (is_auto_or_concept): Declare. * decl.c (grokdeclarator): Allow 'auto' parameters with -std=gnu++1y or -std=c++1y. * type-utils.h: New header defining ... (find_type_usage): ... this new template 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_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. --- gcc/cp/cp-tree.h | 2 + gcc/cp/decl.c | 7 +- gcc/cp/parser.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++-- gcc/cp/parser.h | 6 ++ gcc/cp/pt.c | 35 +++++----- gcc/cp/type-utils.h | 56 ++++++++++++++++ 6 files changed, 264 insertions(+), 24 deletions(-) create mode 100644 gcc/cp/type-utils.h diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 876a72a..8d4ac94 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5453,10 +5453,12 @@ extern tree make_auto (void); extern tree make_decltype_auto (void); extern tree do_auto_deduction (tree, tree, tree); extern tree type_uses_auto (tree); +extern tree type_uses_auto_or_concept (tree); extern void append_type_to_template_for_access_check (tree, tree, tree, location_t); extern tree splice_late_return_type (tree, tree); extern bool is_auto (const_tree); +extern bool is_auto_or_concept (const_tree); extern tree process_template_parm (tree, location_t, tree, bool, bool); extern tree end_template_parm_list (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4076a24..df44a6e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10325,9 +10325,12 @@ grokdeclarator (const cp_declarator *declarator, if (ctype || in_namespace) error ("cannot use %<::%> in parameter declaration"); - if (type_uses_auto (type)) + if (type_uses_auto (type) && cxx_dialect < cxx1y) { - error ("parameter declared %"); + pedwarn (location_of (type), 0, + "use of % in parameter declaration " + "only available with " + "-std=c++1y or -std=gnu++1y"); type = error_mark_node; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1f0c2c2..7147bfa 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "plugin.h" #include "tree-pretty-print.h" #include "parser.h" +#include "type-utils.h" /* The lexer. */ @@ -2063,6 +2064,11 @@ static vec *cp_parser_initializer_list 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 @@ -3385,6 +3391,9 @@ cp_parser_new (void) /* 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; } @@ -8549,10 +8558,12 @@ 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; 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. */ @@ -8576,6 +8587,7 @@ 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; } pop_deferring_access_checks (); @@ -8920,6 +8932,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) 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); @@ -16790,8 +16804,10 @@ cp_parser_direct_declarator (cp_parser* parser, /* 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); @@ -17889,6 +17905,7 @@ 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; @@ -17916,11 +17933,18 @@ 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); + { + 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; @@ -18008,6 +18032,11 @@ 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); + return parameters; } @@ -20014,7 +20043,11 @@ cp_parser_member_declaration (cp_parser* parser) 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. */ @@ -20030,6 +20063,8 @@ cp_parser_member_declaration (cp_parser* parser) 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. */ @@ -22297,6 +22332,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, = 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; } @@ -28842,4 +28880,134 @@ c_parse_file (void) 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; + tree tparms = NULL_TREE; + + // 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; + + 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 // extend current template parameter list + { + 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); + for (size_t n = 0, end = TREE_VEC_LENGTH (inner_vec); n < end; ++n) + tparms = chainon (tparms, 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" diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 3d8bb74..ffdddaf 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -341,6 +341,12 @@ typedef struct GTY(()) cp_parser { /* The number of template parameter lists that apply directly to the current declaration. */ unsigned num_template_parameter_lists; + + /* 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; + } cp_parser; /* In parser.c */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ba841ca..22087fb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see #include "toplev.h" #include "timevar.h" #include "tree-iterator.h" +#include "type-utils.h" /* The type of functions taking a tree, and some additional data, and returning an int. */ @@ -21098,31 +21099,35 @@ is_auto (const_tree type) return false; } -/* Returns true iff TYPE contains a use of 'auto'. Since auto can only - appear as a type-specifier for the declaration in question, we don't - have to look through the whole type. */ +/* Returns the TEMPLATE_TYPE_PARM in TYPE representing `auto' iff TYPE contains + a use of `auto'. Returns NULL_TREE otherwise. */ tree type_uses_auto (tree type) { - enum tree_code code; - if (is_auto (type)) - return type; + return find_type_usage (type, is_auto); +} - code = TREE_CODE (type); +/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto', + 'decltype(auto)' or a concept. */ - if (code == POINTER_TYPE || code == REFERENCE_TYPE - || code == OFFSET_TYPE || code == FUNCTION_TYPE - || code == METHOD_TYPE || code == ARRAY_TYPE) - return type_uses_auto (TREE_TYPE (type)); +bool +is_auto_or_concept (const_tree type) +{ + return is_auto (type); // or concept +} - if (TYPE_PTRMEMFUNC_P (type)) - return type_uses_auto (TREE_TYPE (TREE_TYPE - (TYPE_PTRMEMFUNC_FN_TYPE (type)))); +/* Returns the TEMPLATE_TYPE_PARM in TYPE representing a generic type (`auto' or + a concept identifier) iff TYPE contains a use of a generic type. Returns + NULL_TREE otherwise. */ - return NULL_TREE; +tree +type_uses_auto_or_concept (tree type) +{ + return find_type_usage (type, is_auto_or_concept); } + /* For a given template T, return the vector of typedefs referenced in T for which access check is needed at T instantiation time. T is either a FUNCTION_DECL or a RECORD_TYPE. diff --git a/gcc/cp/type-utils.h b/gcc/cp/type-utils.h new file mode 100644 index 0000000..db5b1e2 --- /dev/null +++ b/gcc/cp/type-utils.h @@ -0,0 +1,56 @@ +/* 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 +. */ + +#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. */ + +template +inline tree +find_type_usage (tree t, TreePredicate pred) +{ + 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