Re: [PATCH 3/3] Support dumping type bindings in lambda diagnostics.
Hi Jason, Was just about to compose a mail to gcc-patches... Been busy, then ill, now just about ready to submit a new set of diffs. On 27.08.2013 17:47, Jason Merrill wrote: This patch doesn't seem to depend on the others; go ahead and apply it. Okay. As it stands, it means that you get an additional 'const' in diagnostics for lambda's not declared 'mutable'. I didn't think this to be necessarily a bad thing (distinguishing between 'mutable' and 'plain' lambdas and pointing at the cause for possible user error attempting to write to by-value captures) but it's probably contentious. Do you want me to ditch the 'const' output prior to pushing? Cheers, Adam
[PATCH 1/4] Support lambda templates.
* parser.c (cp_parser_lambda_declarator_opt): Accept template parameter list with std=c++1y or std=gnu++1y. (cp_parser_lambda_body): Don't call 'expand_or_defer_fn' for lambda call operator template to avoid adding template result to symbol table. * lambda.c (lambda_function): Return template result if call operator is a template. (maybe_add_lambda_conv_op): Support conversion of a non-capturing lambda template to a function pointer. * decl2.c (check_member_template): Don't reject lambda call operator template in local [lambda] class. * pt.c (instantiate_class_template_1): Don't instantiate lambda call operator template when instantiating lambda class. --- gcc/cp/decl2.c | 5 ++-- gcc/cp/lambda.c | 87 - gcc/cp/parser.c | 40 -- gcc/cp/pt.c | 4 ++- 4 files changed, 110 insertions(+), 26 deletions(-) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index d5d2912..ac9dbd7 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -507,8 +507,9 @@ check_member_template (tree tmpl) || (TREE_CODE (decl) == TYPE_DECL && MAYBE_CLASS_TYPE_P (TREE_TYPE (decl { - /* The parser rejects template declarations in local classes. */ - gcc_assert (!current_function_decl); + /* The parser rejects template declarations in local classes +(with the exception of generic lambdas). */ + gcc_assert (!current_function_decl || LAMBDA_FUNCTION_P (decl)); /* The parser rejects any use of virtual in a function template. */ gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl))); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index a53e692..e9bc7c5 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -196,7 +196,7 @@ lambda_function (tree lambda) /*protect=*/0, /*want_type=*/false, tf_warning_or_error); if (lambda) -lambda = BASELINK_FUNCTIONS (lambda); +lambda = STRIP_TEMPLATE (get_first_fn (lambda)); return lambda; } @@ -759,6 +759,10 @@ maybe_add_lambda_conv_op (tree type) if (processing_template_decl) return; + bool generic_lambda_p += (DECL_TEMPLATE_INFO (callop) +&& DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop); + if (DECL_INITIAL (callop) == NULL_TREE) { /* If the op() wasn't instantiated due to errors, give up. */ @@ -766,7 +770,54 @@ maybe_add_lambda_conv_op (tree type) return; } - stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)), + tree fn_result = TREE_TYPE (TREE_TYPE (callop)); + tree fn_args = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop))); + + if (generic_lambda_p) +{ + /* Construct the dependent member call for the static member function +'_FUN' and remove 'auto' from its return type to allow for simple +implementation of the conversion operator. */ + + tree instance = build_nop (type, null_pointer_node); + argvec = make_tree_vector (); + for (arg = fn_args; arg; arg = DECL_CHAIN (arg)) + { + mark_exp_read (arg); + vec_safe_push (argvec, convert_from_reference (arg)); + } + + tree objfn = build_min (COMPONENT_REF, NULL_TREE, + instance, DECL_NAME (callop), NULL_TREE); + call = build_nt_call_vec (objfn, argvec); + + if (type_uses_auto (fn_result)) + { + ++processing_template_decl; + fn_result = finish_decltype_type + (call, /*id_expression_or_member_access_p=*/false, +tf_warning_or_error); + --processing_template_decl; + } +} + else +{ + arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)), + null_pointer_node); + argvec = make_tree_vector (); + argvec->quick_push (arg); + for (arg = fn_args; arg; arg = DECL_CHAIN (arg)) + { + mark_exp_read (arg); + vec_safe_push (argvec, arg); + } + call = build_call_a (callop, argvec->length (), argvec->address ()); + CALL_FROM_THUNK_P (call) = 1; + if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call))) + call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error); +} + + stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop)); /* First build up the conversion op. */ @@ -794,6 +845,9 @@ maybe_add_lambda_conv_op (tree type) if (nested) DECL_INTERFACE_KNOWN (fn) = 1; + if (generic_lambda_p) +fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop)); + add_method (type, fn, NULL_TREE); /* Generic thunk code fails for varargs; we'll complain in mark_used if @@ -820,8 +874,8 @@ maybe_add_lambda_conv_op (tree type) DECL_NOT_REALLY_EXTERN (fn) = 1; DECL_DECLARED_INLINE_P (fn) = 1; DECL_STATIC_FUNCTION
Re: Lambda templates and implicit function templates.
Hi Jason, Here's an updated patch set. The fully_implicit_function_template_p field has been moved into cp_parser and the other comments addressed. I've done some testing with parameter packs also. They work okay with the explicit template parameter syntax for lambdas. Unfortunately, due to errors being thrown 'early' in grokdeclarator, I haven't been able to get 'auto...' (or reference/qualified variants) working yet. I think I need to defer processing the parameter pack internals of grokdeclarator until I have the synthesized template parameter (or generate one on the fly in-place --- but that's returning to the old 'on-demand' implementation which we moved away from). I don't know if it's the correct thing to do but the implementation currently omits the conversion to function pointer operator if the argument list contains a parameter pack. One other thing, assuming the 'auto...' syntax can be made to work, bug 41933 needs to be resolved for the expansion returned by the generic lambda in N3690 5.1.2.5 to compile. Currently (transforming the 'auto&&...' to an explicit ' T&&...') appears to yield the bug. In particular I get: error: expansion pattern ‘ts’ contains no argument packs sorry, unimplemented: use of ‘type_pack_expansion’ in template http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41933#c8 You look to have done some work on it. Any direction as to where to go from there? If the solution requires reworking variadics somehow might that perhaps alleviate my problems implementing 'auto...'? Wishful thinking probably! Cheers, Adam Patch summary (4): Support lambda templates. Don't generate lambda conversion op if arglist has parameter pack. Support dumping type bindings in lambda diagnostics. Support using 'auto' in a function parameter list to introduce an implicit template parameter. gcc/cp/cp-tree.h| 2 + gcc/cp/decl.c | 7 +- gcc/cp/decl2.c | 5 +- gcc/cp/error.c | 22 +++--- gcc/cp/lambda.c | 115 ++- gcc/cp/parser.c | 222 +--- gcc/cp/parser.h | 6 ++ gcc/cp/pt.c | 39 + gcc/cp/type-utils.h | 56 + 9 files changed, 413 insertions(+), 61 deletions(-) create mode 100644 gcc/cp/type-utils.h -- 1.8.4
[PATCH 2/4] Don't generate lambda conversion op if arglist has parameter pack.
* lambda.c (maybe_add_lambda_conv_op): Optimize argvec building and early out if CALLOP contains a function parameter pack. --- gcc/cp/lambda.c | 60 ++--- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index e9bc7c5..4d76f82 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -770,8 +770,51 @@ maybe_add_lambda_conv_op (tree type) return; } + argvec = make_tree_vector (); + + /* Non-template conversion operators are defined directly. Templates are + deferred. In the non-template case, the nullptr instance of the stateless + lambda type is added to ARGVEC for build_call_a. In the template case it + is bound via build_min. */ + if (!generic_lambda_p) +{ + arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)), + null_pointer_node); + argvec->quick_push (arg); +} + + /* Copy CALLOP's argument list (as per 'copy_list') as FN_ARGS in order to + declare the static member function "_FUN" below. For each arg append to + ARGVEC (converting from reference in the template call op case). Early out + if a parameter pack is found; conversion to function pointer is not + supported in this case. */ + tree fn_args = NULL_TREE; + { +tree src = DECL_CHAIN (DECL_ARGUMENTS (callop)); +tree tgt; + +while (src) + { + if (FUNCTION_PARAMETER_PACK_P (src)) + return; + + if (!fn_args) + fn_args = tgt = copy_node (src); + else + { + TREE_CHAIN (tgt) = copy_node (src); + tgt = TREE_CHAIN (tgt); + } + + mark_exp_read (tgt); + vec_safe_push (argvec, + generic_lambda_p ? convert_from_reference (tgt) : tgt); + + src = TREE_CHAIN (src); + } + } + tree fn_result = TREE_TYPE (TREE_TYPE (callop)); - tree fn_args = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop))); if (generic_lambda_p) { @@ -780,12 +823,6 @@ maybe_add_lambda_conv_op (tree type) implementation of the conversion operator. */ tree instance = build_nop (type, null_pointer_node); - argvec = make_tree_vector (); - for (arg = fn_args; arg; arg = DECL_CHAIN (arg)) - { - mark_exp_read (arg); - vec_safe_push (argvec, convert_from_reference (arg)); - } tree objfn = build_min (COMPONENT_REF, NULL_TREE, instance, DECL_NAME (callop), NULL_TREE); @@ -802,15 +839,6 @@ maybe_add_lambda_conv_op (tree type) } else { - arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)), - null_pointer_node); - argvec = make_tree_vector (); - argvec->quick_push (arg); - for (arg = fn_args; arg; arg = DECL_CHAIN (arg)) - { - mark_exp_read (arg); - vec_safe_push (argvec, arg); - } call = build_call_a (callop, argvec->length (), argvec->address ()); CALL_FROM_THUNK_P (call) = 1; if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call))) -- 1.8.4
[PATCH 3/4] Support dumping type bindings in lambda diagnostics.
* error.c (dump_function_decl): Use standard diagnostic flow to dump a lambda diagnostic, albeit without stating the function name or duplicating the parameter spec (which is dumped as part of the type). --- gcc/cp/error.c | 22 +++--- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index c82a0ce..27ff962 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1380,14 +1380,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME); tree exceptions; vec *typenames = NULL; - - if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) -{ - /* A lambda's signature is essentially its "type", so defer. */ - gcc_assert (LAMBDA_TYPE_P (DECL_CONTEXT (t))); - dump_type (pp, DECL_CONTEXT (t), flags); - return; -} + bool lambda_p = false; flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME); if (TREE_CODE (t) == TEMPLATE_DECL) @@ -1449,16 +1442,23 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) else if (cname) { dump_type (pp, cname, flags); - pp_cxx_colon_colon (pp); + if (LAMBDA_TYPE_P (cname)) + lambda_p = true; + else + pp_cxx_colon_colon (pp); } else dump_scope (pp, CP_DECL_CONTEXT (t), flags); - dump_function_name (pp, t, flags); + /* A lambda's signature is essentially its "type", which has already been + dumped. */ + if (!lambda_p) +dump_function_name (pp, t, flags); if (!(flags & TFF_NO_FUNCTION_ARGUMENTS)) { - dump_parameters (pp, parmtypes, flags); + if (!lambda_p) + dump_parameters (pp, parmtypes, flags); if (TREE_CODE (fntype) == METHOD_TYPE) { -- 1.8.4
[PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
* 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_func
[PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
* error.c (dump_function_decl): Use standard diagnostic flow to dump a lambda diagnostic, albeit without stating the function name or duplicating the parameter spec (which is dumped as part of the type). Rather than qualifying the diagnostic with 'const' for plain lambdas, qualify with 'mutable' if non-const. --- Okay to commit? --- gcc/cp/error.c | 27 +++ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index c82a0ce..a8ca269 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1380,14 +1380,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME); tree exceptions; vec *typenames = NULL; - - if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) -{ - /* A lambda's signature is essentially its "type", so defer. */ - gcc_assert (LAMBDA_TYPE_P (DECL_CONTEXT (t))); - dump_type (pp, DECL_CONTEXT (t), flags); - return; -} + bool lambda_p = false; flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME); if (TREE_CODE (t) == TEMPLATE_DECL) @@ -1449,21 +1442,31 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) else if (cname) { dump_type (pp, cname, flags); - pp_cxx_colon_colon (pp); + if (LAMBDA_TYPE_P (cname)) + lambda_p = true; + else + pp_cxx_colon_colon (pp); } else dump_scope (pp, CP_DECL_CONTEXT (t), flags); - dump_function_name (pp, t, flags); + /* A lambda's signature is essentially its "type", which has already been + dumped. */ + if (!lambda_p) +dump_function_name (pp, t, flags); if (!(flags & TFF_NO_FUNCTION_ARGUMENTS)) { - dump_parameters (pp, parmtypes, flags); + if (!lambda_p) + dump_parameters (pp, parmtypes, flags); if (TREE_CODE (fntype) == METHOD_TYPE) { pp->padding = pp_before; - pp_cxx_cv_qualifier_seq (pp, class_of_this_parm (fntype)); + if (!lambda_p) + pp_cxx_cv_qualifier_seq (pp, class_of_this_parm (fntype)); + else if (!(TYPE_QUALS (class_of_this_parm (fntype)) & TYPE_QUAL_CONST)) + pp_c_ws_string (pp, "mutable"); dump_ref_qualifier (pp, fntype, flags); } -- 1.8.4
[PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
* error.c (dump_lambda_function): New function, dependent on ... (maybe_dump_template_bindings): ... this new function, factored out of ... (dump_function_decl): ... here. Updated to early-out with call to dump_lambda_function after determining template bindings. --- Reworked as requested. Okay to commit? --- gcc/cp/error.c | 60 ++ 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index c82a0ce..1edfa0b 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1363,6 +1363,39 @@ find_typenames (tree t) return ft.typenames; } +static void +maybe_dump_template_bindings (cxx_pretty_printer *pp, + tree t, tree template_parms, tree template_args, + int flags) +{ + if (template_parms != NULL_TREE && template_args != NULL_TREE + && !(flags & TFF_NO_TEMPLATE_BINDINGS)) +{ + vec *typenames = find_typenames (t); + pp_cxx_whitespace (pp); + pp_cxx_left_bracket (pp); + pp_cxx_ws_string (pp, M_("with")); + pp_cxx_whitespace (pp); + dump_template_bindings (pp, template_parms, template_args, typenames); + pp_cxx_right_bracket (pp); +} +} + +static void +dump_lambda_function (cxx_pretty_printer *pp, + tree fn, tree template_parms, tree template_args, + int flags) +{ + /* A lambda's signature is essentially its "type". */ + dump_type (pp, DECL_CONTEXT (fn), flags); + if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST)) +{ + pp->padding = pp_before; + pp_c_ws_string (pp, "mutable"); +} + maybe_dump_template_bindings (pp, fn, template_parms, template_args, flags); +} + /* Pretty print a function decl. There are several ways we want to print a function declaration. The TFF_ bits in FLAGS tells us how to behave. As error can only apply the '#' flag once to give 0 and 1 for V, there @@ -1379,15 +1412,6 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS; int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME); tree exceptions; - vec *typenames = NULL; - - if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) -{ - /* A lambda's signature is essentially its "type", so defer. */ - gcc_assert (LAMBDA_TYPE_P (DECL_CONTEXT (t))); - dump_type (pp, DECL_CONTEXT (t), flags); - return; -} flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME); if (TREE_CODE (t) == TEMPLATE_DECL) @@ -1409,10 +1433,13 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) { template_parms = DECL_TEMPLATE_PARMS (tmpl); t = tmpl; - typenames = find_typenames (t); } } + if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) +return dump_lambda_function (pp, t, template_parms, template_args, +flags); + fntype = TREE_TYPE (t); parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t); @@ -1476,17 +1503,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) if (show_return) dump_type_suffix (pp, TREE_TYPE (fntype), flags); - /* If T is a template instantiation, dump the parameter binding. */ - if (template_parms != NULL_TREE && template_args != NULL_TREE - && !(flags & TFF_NO_TEMPLATE_BINDINGS)) - { - pp_cxx_whitespace (pp); - pp_cxx_left_bracket (pp); - pp_cxx_ws_string (pp, M_("with")); - pp_cxx_whitespace (pp); - dump_template_bindings (pp, template_parms, template_args, typenames); - pp_cxx_right_bracket (pp); - } + maybe_dump_template_bindings (pp, t, template_parms, template_args, + flags); } else if (template_args) { -- 1.8.4
Re: [PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
On 29.08.2013 16:25, Gabriel Dos Reis wrote: On Thu, Aug 29, 2013 at 9:20 AM, Adam Butcher wrote: * error.c (dump_lambda_function): New function, dependent on ... (maybe_dump_template_bindings): ... this new function, factored out of ... (dump_function_decl): ... here. Updated to early-out with call to dump_lambda_function after determining template bindings. --- Reworked as requested. Okay to commit? Document the new functions. Use pp->translate_string ("with") instead of pp_cxx_ws_string (pp, M_("with")). Done. In documenting 'maybe_dump_template_bindings' and reviewing it again I'm not sure it's got the right name. It wraps 'dump_template_bindings' in "[with " and "]". So it does more than just filter a call to 'dump_template_bindings'. Any suggestions? What do you think of 'maybe_dump_with_clause' or something similar? Cheers, Adam Thanks, -- Gaby +static void +maybe_dump_template_bindings (cxx_pretty_printer *pp, + tree t, tree template_parms, tree template_args, + int flags) +{ + if (template_parms != NULL_TREE && template_args != NULL_TREE + && !(flags & TFF_NO_TEMPLATE_BINDINGS)) +{ + vec *typenames = find_typenames (t); + pp_cxx_whitespace (pp); + pp_cxx_left_bracket (pp); + pp_cxx_ws_string (pp, M_("with")); + pp_cxx_whitespace (pp); + dump_template_bindings (pp, template_parms, template_args, typenames); + pp_cxx_right_bracket (pp); +} +} + +static void +dump_lambda_function (cxx_pretty_printer *pp, + tree fn, tree template_parms, tree template_args, + int flags) +{ + /* A lambda's signature is essentially its "type". */ + dump_type (pp, DECL_CONTEXT (fn), flags); + if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST)) +{ + pp->padding = pp_before; + pp_c_ws_string (pp, "mutable"); +} + maybe_dump_template_bindings (pp, fn, template_parms, template_args, flags); +} + /* Pretty print a function decl. There are several ways we want to print a function declaration. The TFF_ bits in FLAGS tells us how to behave. As error can only apply the '#' flag once to give 0 and 1 for V, there @@ -1379,15 +1412,6 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS; int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME); tree exceptions; - vec *typenames = NULL; - - if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) -{ - /* A lambda's signature is essentially its "type", so defer. */ - gcc_assert (LAMBDA_TYPE_P (DECL_CONTEXT (t))); - dump_type (pp, DECL_CONTEXT (t), flags); - return; -} flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME); if (TREE_CODE (t) == TEMPLATE_DECL) @@ -1409,10 +1433,13 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) { template_parms = DECL_TEMPLATE_PARMS (tmpl); t = tmpl; - typenames = find_typenames (t); } } + if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) +return dump_lambda_function (pp, t, template_parms, template_args, +flags); + fntype = TREE_TYPE (t); parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t); @@ -1476,17 +1503,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) if (show_return) dump_type_suffix (pp, TREE_TYPE (fntype), flags); - /* If T is a template instantiation, dump the parameter binding. */ - if (template_parms != NULL_TREE && template_args != NULL_TREE - && !(flags & TFF_NO_TEMPLATE_BINDINGS)) - { - pp_cxx_whitespace (pp); - pp_cxx_left_bracket (pp); - pp_cxx_ws_string (pp, M_("with")); - pp_cxx_whitespace (pp); - dump_template_bindings (pp, template_parms, template_args, typenames); - pp_cxx_right_bracket (pp); - } + maybe_dump_template_bindings (pp, t, template_parms, template_args, + flags); } else if (template_args) { -- 1.8.4
Re: [PATCH] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
* error.c (dump_lambda_function): New function, dependent on ... (maybe_dump_with_clause): ... this new function, factored out of ... (subst_to_string): ... here and ... (dump_function_decl): ... here. Updated to early-out with call to dump_lambda_function after determining template bindings. --- Hi Gaby, On 29.08.2013 18:04, Adam Butcher wrote: > On 29.08.2013 16:25, Gabriel Dos Reis wrote: > > > > Document the new functions. > > Use pp->translate_string ("with") instead of > > pp_cxx_ws_string (pp, M_("with")). > > > Done. In documenting 'maybe_dump_template_bindings' and reviewing > it again I'm not sure it's got the right name. It wraps > 'dump_template_bindings' in "[with " and "]". So it does more than > just filter a call to 'dump_template_bindings'. > > Any suggestions? What do you think of 'maybe_dump_with_clause' or > something similar? > Here's a diff with the name change (though I'm not all that happy with it) and the docs. I've also reimplemented subst_to_string in terms of the new function as it was duplicating much of the code from dump_function_decl (the only downside of this is some unnecessary tests in the subst_to_string case but I think they should get optimized away if it were inlined -- we're dealing with diagnostics formatting here anyway so performance is probably not a big factor). Cheers, Adam --- gcc/cp/error.c | 73 -- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index c82a0ce..3d1e173 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1363,6 +1363,47 @@ find_typenames (tree t) return ft.typenames; } +/* Output the "[with ...]" clause for a template instantiation T iff + TEMPLATE_PARMS, TEMPLATE_ARGS and FLAGS are suitable. T may be NULL if + formatting a deduction/substitution diagnostic rather than an + instantiation. */ + +static void +maybe_dump_with_clause (cxx_pretty_printer *pp, + tree t, tree template_parms, tree template_args, + int flags) +{ + if (template_parms != NULL_TREE && template_args != NULL_TREE + && !(flags & TFF_NO_TEMPLATE_BINDINGS)) +{ + vec *typenames = t ? find_typenames (t) : NULL; + pp_cxx_whitespace (pp); + pp_cxx_left_bracket (pp); + pp->translate_string ("with"); + pp_cxx_whitespace (pp); + dump_template_bindings (pp, template_parms, template_args, typenames); + pp_cxx_right_bracket (pp); +} +} + +/* Dump the lambda function FN including its 'mutable' qualifier and any + template bindings. */ + +static void +dump_lambda_function (cxx_pretty_printer *pp, + tree fn, tree template_parms, tree template_args, + int flags) +{ + /* A lambda's signature is essentially its "type". */ + dump_type (pp, DECL_CONTEXT (fn), flags); + if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST)) +{ + pp->padding = pp_before; + pp_c_ws_string (pp, "mutable"); +} + maybe_dump_with_clause (pp, fn, template_parms, template_args, flags); +} + /* Pretty print a function decl. There are several ways we want to print a function declaration. The TFF_ bits in FLAGS tells us how to behave. As error can only apply the '#' flag once to give 0 and 1 for V, there @@ -1379,15 +1420,6 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS; int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME); tree exceptions; - vec *typenames = NULL; - - if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) -{ - /* A lambda's signature is essentially its "type", so defer. */ - gcc_assert (LAMBDA_TYPE_P (DECL_CONTEXT (t))); - dump_type (pp, DECL_CONTEXT (t), flags); - return; -} flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME); if (TREE_CODE (t) == TEMPLATE_DECL) @@ -1409,10 +1441,12 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) { template_parms = DECL_TEMPLATE_PARMS (tmpl); t = tmpl; - typenames = find_typenames (t); } } + if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) +return dump_lambda_function (pp, t, template_parms, template_args, flags); + fntype = TREE_TYPE (t); parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t); @@ -1476,17 +1510,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) if (show_return) dump_type_suffix (pp, TREE_TYPE (fntype), flags); - /* If T is a template instantiat
[PATCH, committed] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
From: abutcher * error.c (dump_lambda_function): New function, dependent on ... (dump_substitution): ... this new function, factored out of ... (subst_to_string): ... here and ... (dump_function_decl): ... here. Updated to early-out with call to dump_lambda_function after determining template bindings. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202087 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 8 +++ gcc/cp/error.c | 73 +++- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bf49198..f848b81 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2013-08-29 Adam Butcher + + * error.c (dump_lambda_function): New function, dependent on ... + (dump_substitution): ... this new function, factored out of ... + (subst_to_string): ... here and ... + (dump_function_decl): ... here. Updated to early-out with call to + dump_lambda_function after determining template bindings. + 2013-08-28 Paolo Carlini PR c++/58255 diff --git a/gcc/cp/error.c b/gcc/cp/error.c index c82a0ce..af71000 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1363,6 +1363,47 @@ find_typenames (tree t) return ft.typenames; } +/* Output the "[with ...]" clause for a template instantiation T iff + TEMPLATE_PARMS, TEMPLATE_ARGS and FLAGS are suitable. T may be NULL if + formatting a deduction/substitution diagnostic rather than an + instantiation. */ + +static void +dump_substitution (cxx_pretty_printer *pp, + tree t, tree template_parms, tree template_args, + int flags) +{ + if (template_parms != NULL_TREE && template_args != NULL_TREE + && !(flags & TFF_NO_TEMPLATE_BINDINGS)) +{ + vec *typenames = t ? find_typenames (t) : NULL; + pp_cxx_whitespace (pp); + pp_cxx_left_bracket (pp); + pp->translate_string ("with"); + pp_cxx_whitespace (pp); + dump_template_bindings (pp, template_parms, template_args, typenames); + pp_cxx_right_bracket (pp); +} +} + +/* Dump the lambda function FN including its 'mutable' qualifier and any + template bindings. */ + +static void +dump_lambda_function (cxx_pretty_printer *pp, + tree fn, tree template_parms, tree template_args, + int flags) +{ + /* A lambda's signature is essentially its "type". */ + dump_type (pp, DECL_CONTEXT (fn), flags); + if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST)) +{ + pp->padding = pp_before; + pp_c_ws_string (pp, "mutable"); +} + dump_substitution (pp, fn, template_parms, template_args, flags); +} + /* Pretty print a function decl. There are several ways we want to print a function declaration. The TFF_ bits in FLAGS tells us how to behave. As error can only apply the '#' flag once to give 0 and 1 for V, there @@ -1379,15 +1420,6 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS; int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME); tree exceptions; - vec *typenames = NULL; - - if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) -{ - /* A lambda's signature is essentially its "type", so defer. */ - gcc_assert (LAMBDA_TYPE_P (DECL_CONTEXT (t))); - dump_type (pp, DECL_CONTEXT (t), flags); - return; -} flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME); if (TREE_CODE (t) == TEMPLATE_DECL) @@ -1409,10 +1441,12 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) { template_parms = DECL_TEMPLATE_PARMS (tmpl); t = tmpl; - typenames = find_typenames (t); } } + if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) +return dump_lambda_function (pp, t, template_parms, template_args, flags); + fntype = TREE_TYPE (t); parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t); @@ -1476,17 +1510,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) if (show_return) dump_type_suffix (pp, TREE_TYPE (fntype), flags); - /* If T is a template instantiation, dump the parameter binding. */ - if (template_parms != NULL_TREE && template_args != NULL_TREE - && !(flags & TFF_NO_TEMPLATE_BINDINGS)) - { - pp_cxx_whitespace (pp); - pp_cxx_left_bracket (pp); - pp_cxx_ws_string (pp, M_("with")); - pp_cxx_whitespace (pp); - dump_template_bindings (pp, template_parms, template_args, typenames); - pp_cxx_right_bracket (pp); - } + dump_substitution (pp, t, template_parms, template_args, flags); } else if
Re: [PATCH, committed] Support dumping type bindings and 'mutable' qualifier in lambda diagnostics.
On 29.08.2013 21:59, Gabriel Dos Reis wrote: On Thu, Aug 29, 2013 at 3:57 PM, Adam Butcher wrote: From: abutcher * error.c (dump_lambda_function): New function, dependent on ... (dump_substitution): ... this new function, factored out of ... (subst_to_string): ... here and ... (dump_function_decl): ... here. Updated to early-out with call to dump_lambda_function after determining template bindings. Please go ahead and commit it. You do have SVN commit access, right? Yes, this is the committed patch. I was under the impression that I should ping the list with the commit once pushed. Adam git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202087 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 8 +++ gcc/cp/error.c | 73 +++- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bf49198..f848b81 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2013-08-29 Adam Butcher + + * error.c (dump_lambda_function): New function, dependent on ... + (dump_substitution): ... this new function, factored out of ... + (subst_to_string): ... here and ... + (dump_function_decl): ... here. Updated to early-out with call to + dump_lambda_function after determining template bindings. + 2013-08-28 Paolo Carlini PR c++/58255 diff --git a/gcc/cp/error.c b/gcc/cp/error.c index c82a0ce..af71000 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1363,6 +1363,47 @@ find_typenames (tree t) return ft.typenames; } +/* Output the "[with ...]" clause for a template instantiation T iff + TEMPLATE_PARMS, TEMPLATE_ARGS and FLAGS are suitable. T may be NULL if + formatting a deduction/substitution diagnostic rather than an + instantiation. */ + +static void +dump_substitution (cxx_pretty_printer *pp, + tree t, tree template_parms, tree template_args, + int flags) +{ + if (template_parms != NULL_TREE && template_args != NULL_TREE + && !(flags & TFF_NO_TEMPLATE_BINDINGS)) +{ + vec *typenames = t ? find_typenames (t) : NULL; + pp_cxx_whitespace (pp); + pp_cxx_left_bracket (pp); + pp->translate_string ("with"); + pp_cxx_whitespace (pp); + dump_template_bindings (pp, template_parms, template_args, typenames); + pp_cxx_right_bracket (pp); +} +} + +/* Dump the lambda function FN including its 'mutable' qualifier and any + template bindings. */ + +static void +dump_lambda_function (cxx_pretty_printer *pp, + tree fn, tree template_parms, tree template_args, + int flags) +{ + /* A lambda's signature is essentially its "type". */ + dump_type (pp, DECL_CONTEXT (fn), flags); + if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST)) +{ + pp->padding = pp_before; + pp_c_ws_string (pp, "mutable"); +} + dump_substitution (pp, fn, template_parms, template_args, flags); +} + /* Pretty print a function decl. There are several ways we want to print a function declaration. The TFF_ bits in FLAGS tells us how to behave. As error can only apply the '#' flag once to give 0 and 1 for V, there @@ -1379,15 +1420,6 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS; int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME); tree exceptions; - vec *typenames = NULL; - - if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) -{ - /* A lambda's signature is essentially its "type", so defer. */ - gcc_assert (LAMBDA_TYPE_P (DECL_CONTEXT (t))); - dump_type (pp, DECL_CONTEXT (t), flags); - return; -} flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME); if (TREE_CODE (t) == TEMPLATE_DECL) @@ -1409,10 +1441,12 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) { template_parms = DECL_TEMPLATE_PARMS (tmpl); t = tmpl; - typenames = find_typenames (t); } } + if (DECL_NAME (t) && LAMBDA_FUNCTION_P (t)) +return dump_lambda_function (pp, t, template_parms, template_args, flags); + fntype = TREE_TYPE (t); parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t); @@ -1476,17 +1510,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) if (show_return) dump_type_suffix (pp, TREE_TYPE (fntype), flags); - /* If T is a template instantiation, dump the parameter binding. */ - if (template_parms != NULL_TREE && template_args != NULL_TREE - && !(flags & TFF_NO_TEMPLATE_BINDINGS)) - { - pp_cxx_whitespace (pp); -
Re: Lambda templates and implicit function templates.
On 01.09.2013 21:05, Jason Merrill wrote: On 08/27/2013 03:42 PM, Adam Butcher wrote: I don't know if it's the correct thing to do but the implementation currently omits the conversion to function pointer operator if the argument list contains a parameter pack. I would expect that to work. Does the specification not provide for deduction in that case? It doesn't forbid it as far as I can see. But it also gives no example of a stateless lambda with a variadic parameter. TBH I just couldn't figure out the right implementation so thought it better to omit the conversion operator on the assumption that it is not a common use case rather than ICE . I'll have a rethink based on your follow up to 2/4 and try to get a pack expansion working there. One other thing, assuming the 'auto...' syntax can be made to work, bug 41933 needs to be resolved for the expansion returned by the generic lambda in N3690 5.1.2.5 to compile. Currently (transforming the 'auto&&...' to an explicit ' T&&...') appears to yield the bug. Bug 41933 is specifically about lambda capture; I think you're running into something else. The problem is in expanding the 'ts' capture from the 5.1.2.5. It looks like this: 1 auto vglambda = [](auto printer) { 2 return [=](auto&& ... ts) { // OK: ts is a function parameter pack 3 printer(std::forward(ts)...); 4 return [=]() { 5 printer(ts ...); 6 }; 7 }; 8 }; It is the expansion of the captured 'ts' on line 5 that I think yields the bug. Might be slightly different to 41933 though due to not being explicitly captured as "ts...". Unsure. My point was that in order to conform this issue will need to be fixed as well as getting the 'auto...' syntax to work. Cheers, Adam
Re: [PATCH 1/4] Support lambda templates.
On 01.09.2013 21:22, Jason Merrill wrote: On 08/27/2013 03:42 PM, Adam Butcher wrote: + vec_safe_push (argvec, arg); I bet we want convert_from_reference in the non-generic lambda case, too. OK with that change. I think I had made that change originally to keep the two impls the same and I hit issues with non-generic lambdas. But I can't remember the details. I'll try again. If it works with convert_from_reference in both cases should I push or should I sort out the parameter pack conversion op issue and roll that up into this?
Re: [PATCH 4/4] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
On 01.09.2013 22:20, Jason Merrill wrote: On 08/27/2013 03:42 PM, Adam Butcher wrote: + else // extend current template parameter list + // pop the innermost template parms into tparms Most comments should start with a capital letter and end with a period. Will change. + for (size_t n = 0, end = TREE_VEC_LENGTH (inner_vec); n < end; ++n) + tparms = chainon (tparms, TREE_VEC_ELT (inner_vec, n)); Doing chainon in a loop has bad algorithmic complexity, as it walks through the whole tparms list each iteration. Better to build up a list from inner_vec and then chainon that list as a whole. Okay. +template +inline tree +find_type_usage (tree t, TreePredicate pred) I don't think this needs to be a template, since we know the predicates take a single tree and return bool. I didn't know whether to allow for someone passing in a stateful lambda (or other functor) in future so I avoided the issue by making the predicate a template type param. If we're happy that only c-style functions (or stateless lambdas) will be passed then I'll put it back as 'bool (*) (const_tree)'. I don't see any diagnostic for the implicit function template extension; my earlier comment about not controlling it with -std=c++1y vs gnu++1y didn't mean it should go away entirely. :) Maybe we should call it part of c++1z, or just control the diagnostic with -pedantic. I must confess I was a bit unclear about how to proceed there. I'll reinstate the two messages and go with a specific diagnostic if -pedantic is set in the non-lambda case. Cheers, Adam
Re: [PATCH 1/4] Support lambda templates.
On 02.09.2013 19:34, Jason Merrill wrote: On 09/02/2013 02:30 PM, Adam Butcher wrote: On 01.09.2013 21:22, Jason Merrill wrote: I bet we want convert_from_reference in the non-generic lambda case, too. I think I had made that change originally to keep the two impls the same and I hit issues with non-generic lambdas. But I can't remember the details. I'll try again. Okay, finally got around to trying this again. With convert_from_reference in the non-generic case, the code compiles okay but SEGVs on the attempt to branch to '_FUN'. │105 auto lf0 = [] (float& a, int const& b) { return a += b; }; │106 │107 INVOKEi (lf, float, 7, 0); >│108 AS_FUNi (lf, float, 7, 0); │109 AS_PTRi (lf, float, int, 7, 0); │0x404500 mov%eax,-0x4bc(%rbp) │0x404506 mov0x36f0(%rip),%eax# 0x407bfc │0x40450c mov%eax,-0x4c0(%rbp) │0x404512 movl $0x7,-0x2a4(%rbp) │0x40451c lea-0x2a4(%rbp),%rdx │0x404523 lea-0x4bc(%rbp),%rax │0x40452a mov%rdx,%rsi │0x40452d mov%rax,%rdi >│0x404530 callq 0x400934 <const&)>::_FUN(float &, const int &)> If it works with convert_from_reference in both cases should I push or should I sort out the parameter pack conversion op issue and roll that up into this? I think roll them together, since that patch rewrites parts of this one. Will assume, for now, that the convert_from_reference call is not wanted in the non-generic case (maybe something to do with using 'build_call_a' instead of 'build_nt_call_vec' or the convert_from_reference on the call itself?) and will focus on the parameter pack stuff (when I get a chance). Cheers, Adam
Re: [PATCH 1/4] Support lambda templates.
On 03.09.2013 04:50, Jason Merrill wrote: On 09/02/2013 05:18 PM, Adam Butcher wrote: > will focus on the parameter pack stuff (when I get a chance). > Sounds good. I had a quick hack at getting pack expansion working for the conversion op. The syntactic side seems to be okay. It gets all the way to finalizing the tu. It generates suitable diagnostics if I force warnings in various places in my testcase. I've done what amounts to the following (diff hand edited to removing noisy debug logging and temporaries): -- @@ -795,20 +794,39 @@ maybe_add_lambda_conv_op (tree type) while (src) { - if (FUNCTION_PARAMETER_PACK_P (src)) - return; + tree new_node = copy_node (src); if (!fn_args) - fn_args = tgt = copy_node (src); + fn_args = tgt = new_node; else { - TREE_CHAIN (tgt) = copy_node (src); - tgt = TREE_CHAIN (tgt); + TREE_CHAIN (tgt) = new_node; + tgt = new_node; } mark_exp_read (tgt); + + if (FUNCTION_PARAMETER_PACK_P (tgt)) + vec_safe_push (argvec, make_pack_expansion (tgt)); + else vec_safe_push (argvec, generic_lambda_p ? convert_from_reference (tgt) : tgt); src = TREE_CHAIN (src); } -- Problem is that no RTL is set for the incoming parms in the instantiation of the expansion. It ICEs in gimple_expand_cfg because 'DECL_RTL_IF_SET (var)' returns nullptr for the incoming parms resulting in a failed assertion that SA.partition_to_pseudo[i] is non-null. What follows below is basically a dump of various info that may help you to point me in the right direction or may be completely useless or unnecessary to you. Any ideas appreciated. Cheers, Adam The error diagnostic is: /home/ajb/t7-variadic-ptr.cpp: In static member function ‘static decltype (((main()::...)>)0u).operator()(main::__lambda1::_FUN:: ...)) main()_FUN(P ...) [with P = {double, double, double}; decltype (((main()::...)>)0u).operator()(main::__lambda1::_FUN:: ...)) = float]’: /home/ajb/t7-variadic-ptr.cpp:13:37: internal compiler error: in gimple_expand_cfg, at cfgexpand.c:4649 auto g = [] (P...) { return 3.f; }; ^ This only occurs if I instantiate the conversion op. I added the following tracing to gimple_expand_cfg: -- @@ -4635,9 +4635,17 @@ gimple_expand_cfg (void) { tree var = SSA_NAME_VAR (partition_to_var (SA.map, i)); + debug_tree (var); + + if (TREE_CODE (var) != VAR_DECL) +fprintf (stderr, "SA.partition_to_pseudo[%d] == %p\n", i, SA.partition_to_pseudo[i]); + if (TREE_CODE (var) != VAR_DECL && !SA.partition_to_pseudo[i]) + { SA.partition_to_pseudo[i] = DECL_RTL_IF_SET (var); + fprintf (stderr, "SA.partition_to_pseudo[%d] => %p\n", i, SA.partition_to_pseudo[i]); + } gcc_assert (SA.partition_to_pseudo[i]); /* If this decl was marked as living in multiple places, reset -- I expected the instantiated parm_decl for the pack expansion parms to look similar to this (from a 'normal' non-pack parm) ... unit size align 32 symtab 0 alias set -1 canonical type 0x7f3833f83f18 precision 32 pointer_to_this > used SF file /home/ajb/t7-variadic-ptr.cpp line 12 col 30 size unit size align 32 context (mem/c:SF (plus:DI (reg/f:DI 70 virtual-stack-vars) (const_int -20 [0xffec])) [0 D.2134+0 S4 A32]) arg-type incoming-rtl (reg:SF 21 xmm0 [ D.2134 ])> ... but instead it looks like this: unit size align 64 symtab 0 alias set -1 canonical type 0x7f3833f8d000 precision 64 pointer_to_this > used VOID file /home/ajb/t7-variadic-ptr.cpp line 13 col 34 align 8 arg-type chain 0x7f38340e4680 D.2146>> Everything under the tree type seems to be 'default' and I note that context has gone (it is there in the pack expansion expression prior to instantiation). I'm not sure if this is relevant. (note I was passing 3 doubles into the variadic template and a float into the 'plain' single arg template) Here's some dumps of the expansion creation from maybe_add_lambda_conv_op: SRC => > type_0 type_6 VOID align 8 symtab 0 alias set -1 structural equality> decl_1 VOID file /home/ajb/t7-variadic-ptr.cpp line 13 col 34 align 8 context > NEW_NODE => > type_0 type_6 VOID align 8 symtab 0 alias set -1 structural equality> decl_1 VOID file /home/ajb/t7-variadic-ptr.cpp line 13 col 34 align 8 context > MAKE_PACK_EXPANSION => > type_0 type_6 VOID align 8 symtab 0 alias set -1
Re: [PATCH] [lambda] Extract lambda functions from semantics.c.
On 04.09.2013 03:41, Gabriel Dos Reis wrote: On Tue, Sep 3, 2013 at 9:33 PM, Mike Stump wrote: On Jul 12, 2013, at 11:18 PM, Adam Butcher wrote: * gcc/cp/semantics.c (build_lambda_expr), (build_lambda_object), (begin_lambda_type), (lambda_return_type), (lambda_function), (lambda_capture_field_type), (is_capture_proxy), (is_normal_capture_proxy), (insert_capture_proxy), (insert_pending_capture_proxies), (lambda_proxy_type), (build_capture_proxy), (vla_capture_type), (register_capture_members), (add_default_capture), (lambda_expr_this_capture), (maybe_resolve_dummy), (nonlambda_method_basetype), (maybe_add_lambda_conv_op) and (is_lambda_ignored_entity): Moved definitions into ... * gcc/cp/lambda.c: ... this new file. This can cause an incremental build failure because there are no dependencies: diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 2c1774f..65dfe08 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -351,6 +351,7 @@ cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \ cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h $(PARAMS_H) \ $(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h pointer-set.h +cp/lambda.o: cp/lambda.c $(CXX_TREE_H) $(CGRAPH_H) $(VEC_H) $(SYSTEM_H) coretypes.h cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) \ $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H) tree-pretty-print.h When tree codes are added or moved, the check is then against the wrong number, and this will kill the build. I'm still looking forward to the day when all the dependancies are unceremoniously ripped out, until then... Ok? OK. Eek. I didn't realize dependencies had to be manually specified. That's prompted me to update a more recent patchset I'm working on where I've introduced a new header. Is anyone working on using some use, perhaps filtered, of -MD (or -MDD) to generate deps on the fly? I haven't looked into the GCC makefile system in any detail but I assume dependency handling is more complex than the standard usage pattern for -MD or I guess someone would have done it already. Or are maintainers worried that auto deps will slow the build down too much? In our team's experience with using -MD the overhead is negligible; especially when weighed up against the effort required to manually maintain deps. It just takes make a little longer to start actually building anything.
Re: [PATCH] [lambda] Extract lambda functions from semantics.c.
On 04.09.2013 20:39, Gabriel Dos Reis wrote: On Wed, Sep 4, 2013 at 12:55 PM, Adam Butcher wrote: Is anyone working on using some use, perhaps filtered, of -MD (or -MDD) to generate deps on the fly? See Tom's patch series. Ah, yes. Cool. I guess it's just waiting on approval for each part; I note that a few front ends have already been OK'd.
Re: [PATCH 1/4] Support lambda templates.
On 03.09.2013 22:25, Jason Merrill wrote: On 09/03/2013 03:50 PM, Adam Butcher wrote: Problem is that no RTL is set for the incoming parms in the instantiation of the expansion. It ICEs in gimple_expand_cfg because 'DECL_RTL_IF_SET (var)' returns nullptr for the incoming parms resulting in a failed assertion that SA.partition_to_pseudo[i] is non-null. Sounds like a problem with how _FUN's parameters are instantiated. I'm not sure why it would be special. Does using a function parameter pack in the lambda body work currently? If so, how are the expanded parameters different? Yes it does work. And I think (hope) I've cracked it; make_pack_expansion needs to be called in the body of the thunk (i.e. after start_preparsed_function). If I butcher the implementation so that I rewrite any parameter packs with their expansion prior to building the call in return statement, it seems to work. Certainly the following does what I expect it to, the trees look right and, more importantly, it doesn't ICE! auto g = [] (P...) -> float { return 3.f; }; float (*pg3) (double, double, double) = g; return pg3(1,2,3); I'll try to clean up what I've got then submit a rolled up patch. Cheers, Adam
Re: [PATCH 1/4] Support lambda templates.
On 05.09.2013 20:14, Adam Butcher wrote: On 03.09.2013 22:25, Jason Merrill wrote: On 09/03/2013 03:50 PM, Adam Butcher wrote: Problem is that no RTL is set for the incoming parms in the instantiation of the expansion. It ICEs in gimple_expand_cfg because 'DECL_RTL_IF_SET (var)' returns nullptr for the incoming parms resulting in a failed assertion that SA.partition_to_pseudo[i] is non-null. Sounds like a problem with how _FUN's parameters are instantiated. I'm not sure why it would be special. Does using a function parameter pack in the lambda body work currently? If so, how are the expanded parameters different? Yes it does work. And I think (hope) I've cracked it; make_pack_expansion needs to be called in the body of the thunk (i.e. after start_preparsed_function). Okay, this worked because it had the side effect of setting PACK_EXPANSION_LOCAL_P on the expansion. Doing that at the top, in the existing code seems to have the same effect. Cheers, Adam
Re: [PATCH 1/4] Support lambda templates.
Hi Jason, I've attached a patch that handles parameter packs in the conversion op. I thought it best to get this reviewed independently before rolling up into the 'Support lambda templates' patch. Do you think it's the right idea? It seems to work okay but I've reworked the way the template op call is built (and built a separate call for the decltype expression). Cheers, Adam commit 29891189d498f5c6e3aabac72db14b94a200182c Author: Adam Butcher Date: Thu Aug 15 20:21:38 2013 +0100 [Intended for rollup into 1/4]: Handle parameter packs in lambda conversion op. * lambda.c (maybe_add_lambda_conv_op): Move decls to point of use. * TODO: parm pack changelog to be merged with PATCH 1/4. diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index e9bc7c5..3d17948 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -741,6 +741,22 @@ nonlambda_method_basetype (void) return TYPE_METHOD_BASETYPE (TREE_TYPE (fn)); } +/* Helper function for maybe_add_lambda_conv_op; build a CALL_EXPR with + indicated FN, and NARGS, but do not initialize the return type or any of the + argument slots. */ + +static tree +prepare_op_call (tree fn, int nargs) +{ + tree t; + + t = build_vl_exp (CALL_EXPR, nargs + 3); + CALL_EXPR_FN (t) = fn; + CALL_EXPR_STATIC_CHAIN (t) = NULL; + + return t; +} + /* If the closure TYPE has a static op(), also add a conversion to function pointer. */ @@ -749,9 +765,6 @@ maybe_add_lambda_conv_op (tree type) { bool nested = (current_function_decl != NULL_TREE); tree callop = lambda_function (type); - tree rettype, name, fntype, fn, body, compound_stmt; - tree thistype, stattype, statfn, convfn, call, arg; - vec *argvec; if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE) return; @@ -759,7 +772,7 @@ maybe_add_lambda_conv_op (tree type) if (processing_template_decl) return; - bool generic_lambda_p + bool const generic_lambda_p = (DECL_TEMPLATE_INFO (callop) && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop); @@ -770,63 +783,127 @@ maybe_add_lambda_conv_op (tree type) return; } + /* Non-template conversion operators are defined directly with build_call_a + and using DIRECT_ARGVEC for arguments (including 'this'). Templates are + deferred and the CALL is built in-place. In the case of a deduced return + call op, the decltype expression used as a substitute for the return type, + DECLTYPE_CALL is also built in-place. The arguments of DECLTYPE_CALL in + the return expression may differ in flags from those in body CALL. In + particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in + the body CALL, but not in DECLTYPE_CALL. */ + + vec *direct_argvec; + tree decltype_call = 0, call; tree fn_result = TREE_TYPE (TREE_TYPE (callop)); - tree fn_args = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop))); if (generic_lambda_p) { - /* Construct the dependent member call for the static member function -'_FUN' and remove 'auto' from its return type to allow for simple + /* Prepare the dependent member call for the static member function +'_FUN' and, potentially, prepare another call to be used in a decltype +return expression for a deduced return call op to allow for simple implementation of the conversion operator. */ tree instance = build_nop (type, null_pointer_node); - argvec = make_tree_vector (); - for (arg = fn_args; arg; arg = DECL_CHAIN (arg)) - { - mark_exp_read (arg); - vec_safe_push (argvec, convert_from_reference (arg)); - } - tree objfn = build_min (COMPONENT_REF, NULL_TREE, instance, DECL_NAME (callop), NULL_TREE); - call = build_nt_call_vec (objfn, argvec); + int nargs = list_length (DECL_ARGUMENTS (callop)) - 1; + call = prepare_op_call (objfn, nargs); if (type_uses_auto (fn_result)) + decltype_call = prepare_op_call (objfn, nargs); +} + else +{ + direct_argvec = make_tree_vector (); + direct_argvec->quick_push (build1 (NOP_EXPR, +TREE_TYPE (DECL_ARGUMENTS (callop)), +null_pointer_node)); +} + + /* Copy CALLOP's argument list (as per 'copy_list') as FN_ARGS in order to + declare the static member function "_FUN" below. For each arg append to + DIRECT_ARGVEC (for the non-template case) or populate the pre-allocated + call args (for the template case). If a parameter pack is found, expand + it, flagging it as PACK_EXPANSION_LOCAL_P for the body call. */ + + tree fn_args = NULL_TREE; + { +int ix = 0; +tree src = DECL_CHAIN (DECL_ARGUMENTS (callop)); +tree tgt; + +while (src) + { + tree
[PATCH V4 2/2] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
* 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. --- gcc/cp/Make-lang.in | 5 +- gcc/cp/cp-tree.h| 2 + gcc/cp/decl.c | 14 +++- gcc/cp/parser.c | 195 ++-- gcc/cp/parser.h | 6 ++ gcc/cp/pt.c | 35 ++ gcc/cp/type-utils.h | 55 +++ 7 files changed, 286 insertions(+), 26 deletions(-) create mode 100644 gcc/cp/type-utils.h diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 65dfe08..e8d4913 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -320,7 +320,7 @@ cp/except.o: cp/except.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \ cp/expr.o: cp/expr.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) $(TM_P_H) cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h cp/cp-objcp-common.h \ toplev.h $(TREE_INLINE_H) pointer-set.h gt-cp-pt.h intl.h \ - c-family/c-objc.h + c-family/c-objc.h cp/type-utils.h cp/error.o: cp/error.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_H) \ $(FLAGS_H) $(REAL_H) $(LANGHOOKS_DEF_H) $(CXX_PRETTY_PRINT_H) \ tree-diagnostic.h tree-pretty-print.h pointer-set.h c-family/c-objc.h @@ -339,7 +339,8 @@ cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) $(REAL_H) \ gt-cp-mangle.h $(TARGET_H) $(TM_P_H) $(CGRAPH_H) cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_CORE_H) \ gt-cp-parser.h $(TARGET_H) $(PLUGIN_H) intl.h cp/decl.h \ - c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H) + c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H) \ + cp/type-utils.h cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \ $(TM_H) coretypes.h pointer-set.h tree-iterator.h $(SPLAY_TREE_H) cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3e4f188..b68562d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5455,10 +5455,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 b4223aa..8b67ec8 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10320,8 +10320,18 @@ grokdeclarator (const cp_declarator *declarator, if (type_uses_auto (type)) { - error ("parameter declared %"); - type = error_mark_node; + if (current_class_type && LAMBDA_TYPE_P (current_class_type)) + { + if (cxx_dialect < cxx1y) + pedwarn (location_of (type), 0, +"use of % in lambda par
[PATCH V4 1/2] Support lambda templates.
* parser.c (cp_parser_lambda_declarator_opt): Accept template parameter list with std=c++1y or std=gnu++1y. (cp_parser_lambda_body): Don't call 'expand_or_defer_fn' for lambda call operator template to avoid adding template result to symbol table. * lambda.c (lambda_function): Return template result if call operator is a template. (maybe_add_lambda_conv_op): Move declarations to point of use. Refactor operator call building in order to support conversion of a non-capturing lambda template to a function pointer with help from ... (prepare_op_call): ... this new function. * decl2.c (check_member_template): Don't reject lambda call operator template in local [lambda] class. * pt.c (instantiate_class_template_1): Don't instantiate lambda call operator template when instantiating lambda class. --- gcc/cp/decl2.c | 5 +- gcc/cp/lambda.c | 189 ++-- gcc/cp/parser.c | 40 +++- gcc/cp/pt.c | 4 +- 4 files changed, 200 insertions(+), 38 deletions(-) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index d5d2912..ac9dbd7 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -507,8 +507,9 @@ check_member_template (tree tmpl) || (TREE_CODE (decl) == TYPE_DECL && MAYBE_CLASS_TYPE_P (TREE_TYPE (decl { - /* The parser rejects template declarations in local classes. */ - gcc_assert (!current_function_decl); + /* The parser rejects template declarations in local classes +(with the exception of generic lambdas). */ + gcc_assert (!current_function_decl || LAMBDA_FUNCTION_P (decl)); /* The parser rejects any use of virtual in a function template. */ gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl))); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index a53e692..2d20333 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -196,7 +196,7 @@ lambda_function (tree lambda) /*protect=*/0, /*want_type=*/false, tf_warning_or_error); if (lambda) -lambda = BASELINK_FUNCTIONS (lambda); +lambda = STRIP_TEMPLATE (get_first_fn (lambda)); return lambda; } @@ -741,6 +741,22 @@ nonlambda_method_basetype (void) return TYPE_METHOD_BASETYPE (TREE_TYPE (fn)); } +/* Helper function for maybe_add_lambda_conv_op; build a CALL_EXPR with + indicated FN and NARGS, but do not initialize the return type or any of the + argument slots. */ + +static tree +prepare_op_call (tree fn, int nargs) +{ + tree t; + + t = build_vl_exp (CALL_EXPR, nargs + 3); + CALL_EXPR_FN (t) = fn; + CALL_EXPR_STATIC_CHAIN (t) = NULL; + + return t; +} + /* If the closure TYPE has a static op(), also add a conversion to function pointer. */ @@ -749,9 +765,6 @@ maybe_add_lambda_conv_op (tree type) { bool nested = (current_function_decl != NULL_TREE); tree callop = lambda_function (type); - tree rettype, name, fntype, fn, body, compound_stmt; - tree thistype, stattype, statfn, convfn, call, arg; - vec *argvec; if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE) return; @@ -759,6 +772,10 @@ maybe_add_lambda_conv_op (tree type) if (processing_template_decl) return; + bool const generic_lambda_p += (DECL_TEMPLATE_INFO (callop) +&& DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop); + if (DECL_INITIAL (callop) == NULL_TREE) { /* If the op() wasn't instantiated due to errors, give up. */ @@ -766,16 +783,127 @@ maybe_add_lambda_conv_op (tree type) return; } - stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)), - FUNCTION_ARG_CHAIN (callop)); + /* Non-template conversion operators are defined directly with build_call_a + and using DIRECT_ARGVEC for arguments (including 'this'). Templates are + deferred and the CALL is built in-place. In the case of a deduced return + call op, the decltype expression, DECLTYPE_CALL, used as a substitute for + the return type is also built in-place. The arguments of DECLTYPE_CALL in + the return expression may differ in flags from those in the body CALL. In + particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in + the body CALL, but not in DECLTYPE_CALL. */ + + vec *direct_argvec; + tree decltype_call = 0, call; + tree fn_result = TREE_TYPE (TREE_TYPE (callop)); + + if (generic_lambda_p) +{ + /* Prepare the dependent member call for the static member function +'_FUN' and, potentially, prepare another call to be used in a decltype +return expression for a deduced return call op to allow for simple +implementation of the conversion operator. */ + + tree instance = build_nop (type, null_pointer_node); + tree objfn = build_min (COMPONENT_REF,
V4 Lambda templates and implicit function templates.
Hi Jason, Here's the latest patch set; reduced to two patches now. Remaining issues: - Instantiation of generic conversion op ICEs if the call op contains declarations and hasn't already been instantiated. - Still haven't figured out a clean way to make 'auto...' work. Cheers, Adam Patch summary (2): Support lambda templates. Support using 'auto' in a function parameter list to introduce an implicit template parameter. gcc/cp/Make-lang.in | 5 +- gcc/cp/cp-tree.h| 2 + gcc/cp/decl.c | 14 +++- gcc/cp/decl2.c | 5 +- gcc/cp/lambda.c | 189 +++--- gcc/cp/parser.c | 235 +--- gcc/cp/parser.h | 6 ++ gcc/cp/pt.c | 39 + gcc/cp/type-utils.h | 55 9 files changed, 486 insertions(+), 64 deletions(-) create mode 100644 gcc/cp/type-utils.h -- 1.8.4
Re: V4 Lambda templates and implicit function templates.
On 10.09.2013 03:19, Adam Butcher wrote: - Instantiation of generic conversion op ICEs if the call op contains declarations and hasn't already been instantiated. This is not a complete enough description. It only ICEs instantiating the call op through the decltype return of the conversion op if the return type of the call op is a deduced one (i.e. unspecified or specified explicitly as 'auto'). If the lambda call op is instantiated explicitly (i.e. the lambda is called) prior to using the conversion op then all is well. It seems to only occur if there are variables declared within the lambda body or accessible via the lambda's 'this'. Specifically, the ICE is in tsubst_decl (cp/pt.c:10839) asserting 'gcc_unreachable' due to being 'cp_unevaluated_operand'. The instantiation chain starts from attempting to 'mark_used' the call op in the decltype expression. The same ICE can be caused in user code by attempting to take get decltype of a generic lambda call having a deduced return type and declarations: This is fine: auto f = [] (T) {}; decltype (f (4.f)) *p; This is not; it ICEs doing 'tsubst_decl' on the declaration 'x'. auto f = [] (T) { int x; }; decltype (f (4.f)) *p; The conversion op is clearly not a factor here but can be removed from the equation completely by adding a capture. The ICE still occurs. In this case it occurs trying to do 'tsubst_decl' on the capture decl 'i'. int i = 0; auto f = [i] (T) {}; decltype (f (4.f)) *p; ice.cpp: In instantiation of ‘main():: [with T = float]’: ice.cpp:5:20: required from here ice.cpp:4:34: internal compiler error: in tsubst_decl, at cp/pt.c:10839 auto f = [i] (T) {}; ^ Any ideas? Looks like it's something to do with how the call operator is defined. Is there some flag I'm missing in the generic case? Cheers, Adam
Re: V4 Lambda templates and implicit function templates.
On 11.09.2013 16:25, Jason Merrill wrote: On 09/11/2013 10:42 AM, Jason Merrill wrote: Sounds like the problem is that the compiler is trying to instantiate a function while cp_unevaluated_operand is set. But that shouldn't be an issue because push_to_top_level clears cp_unevaluated_operand. How does it come to be set when instantiating the local variable? Ah, I see: it's because instantiate_decl doesn't push_to_top_level for function-local templates. We still need to save/restore cp_unevaluated_operand in that case, and let's also do c_inhibit_evaluation_warnings. Great, that fixes it. Hadn't noticed it didn't happen a namespace scope. Okay for the attached to go to trunk with suitable changelog? diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 22087fb..16e57b5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -18947,6 +18947,8 @@ instantiate_decl (tree d, int defer_ok, tree gen_tmpl; bool pattern_defined; location_t saved_loc = input_location; + int saved_unevaluated_operand = cp_unevaluated_operand; + int saved_inhibit_evaluation_warnings = c_inhibit_evaluation_warnings; bool external_p; tree fn_context; bool nested; @@ -19158,8 +19160,13 @@ instantiate_decl (tree d, int defer_ok, nested = (current_function_decl != NULL_TREE); if (!fn_context) push_to_top_level (); - else if (nested) -push_function_context (); + else +{ + if (nested) + push_function_context (); + cp_unevaluated_operand = 0; + c_inhibit_evaluation_warnings = 0; +} /* Mark D as instantiated so that recursive calls to instantiate_decl do not try to instantiate it again. */ @@ -19283,6 +19290,8 @@ instantiate_decl (tree d, int defer_ok, out: input_location = saved_loc; + cp_unevaluated_operand = saved_unevaluated_operand; + c_inhibit_evaluation_warnings = saved_inhibit_evaluation_warnings; pop_deferring_access_checks (); pop_tinst_level ();
Re: [PATCH V4 2/2] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
On 11.09.2013 17:02, Jason Merrill wrote: On 09/09/2013 10:19 PM, Adam Butcher wrote: + if (current_class_type && LAMBDA_TYPE_P (current_class_type)) + { + if (cxx_dialect < cxx1y) + pedwarn (location_of (type), 0, +"use of % in lambda parameter declaration " +"only available with " +"-std=c++1y or -std=gnu++1y"); + } + else + pedwarn (location_of (type), OPT_Wpedantic, +"ISO C++ forbids use of % in parameter " +"declaration"); I think we want to limit the implicit template extension to C++1y mode as well. OK. Do you think we should mark 'type' as 'error_mark_node' in the pre-C++1y cases to reject the user program or just stick to the pedwarn 0? I.e. this: if (current_class_type && LAMBDA_TYPE_P (current_class_type)) { if (cxx_dialect < cxx1y) { pedwarn (location_of (type), 0, "use of % in lambda parameter declaration " "only available with " "-std=c++1y or -std=gnu++1y"); type = error_mark_node; } } else if (cxx_dialect < cxx1y) { pedwarn (location_of (type), 0, "use of % in parameter declaration " "only available with " "-std=c++1y or -std=gnu++1y"); type = error_mark_node; } else pedwarn (location_of (type), OPT_Wpedantic, "ISO C++ forbids use of % in parameter " "declaration"); or the same but without the "type = error_mark_node;" lines?
[PATCH, committed] Support decl instantiation in function-local templates.
From: abutcher * pt.c (instantiate_decl): Save/restore cp_unevaluated_operand and c_inhibit_evaluation_warnings. Reset if instantiating within a function-local template. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202538 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 6 ++ gcc/cp/pt.c | 13 +++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9c99970..cbad022 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2013-09-12 Adam Butcher + + * pt.c (instantiate_decl): Save/restore cp_unevaluated_operand and + c_inhibit_evaluation_warnings. Reset if instantiating within a + function-local template. + 2013-09-12 Paolo Carlini * semantics.c (finish_pseudo_destructor_expr): Add location_t diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e4ae4b7..3ae679a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -18947,6 +18947,8 @@ instantiate_decl (tree d, int defer_ok, tree gen_tmpl; bool pattern_defined; location_t saved_loc = input_location; + int saved_unevaluated_operand = cp_unevaluated_operand; + int saved_inhibit_evaluation_warnings = c_inhibit_evaluation_warnings; bool external_p; tree fn_context; bool nested; @@ -19158,8 +19160,13 @@ instantiate_decl (tree d, int defer_ok, nested = (current_function_decl != NULL_TREE); if (!fn_context) push_to_top_level (); - else if (nested) -push_function_context (); + else +{ + if (nested) + push_function_context (); + cp_unevaluated_operand = 0; + c_inhibit_evaluation_warnings = 0; +} /* Mark D as instantiated so that recursive calls to instantiate_decl do not try to instantiate it again. */ @@ -19283,6 +19290,8 @@ instantiate_decl (tree d, int defer_ok, out: input_location = saved_loc; + cp_unevaluated_operand = saved_unevaluated_operand; + c_inhibit_evaluation_warnings = saved_inhibit_evaluation_warnings; pop_deferring_access_checks (); pop_tinst_level (); -- 1.8.4
[PATCH, committed] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
From: abutcher * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202540 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog| 32 + gcc/cp/Make-lang.in | 5 +- gcc/cp/cp-tree.h| 2 + gcc/cp/decl.c | 19 - gcc/cp/parser.c | 195 ++-- gcc/cp/parser.h | 6 ++ gcc/cp/pt.c | 35 ++ gcc/cp/type-utils.h | 55 +++ 8 files changed, 323 insertions(+), 26 deletions(-) create mode 100644 gcc/cp/type-utils.h diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 66869d2..470fa1f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,37 @@ 2013-09-12 Adam Butcher + * 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 + * parser.c (cp_parser_lambda_declarator_opt): Accept template parameter list with std=c++1y or std=gnu++1y. (cp_parser_lambda_body): Don't call 'expand_or_defer_fn' for lambda call diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 65dfe08..e8d4913 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -320,7 +320,7 @@ cp/except.o: cp/except.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \ cp/expr.o: cp/expr.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) $(TM_P_H) cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h cp/cp-objcp-common.h \ toplev.h $(TREE
[PATCH, committed] Support lambda templates.
From: abutcher * parser.c (cp_parser_lambda_declarator_opt): Accept template parameter list with std=c++1y or std=gnu++1y. (cp_parser_lambda_body): Don't call 'expand_or_defer_fn' for lambda call operator template to avoid adding template result to symbol table. * lambda.c (lambda_function): Return template result if call operator is a template. (maybe_add_lambda_conv_op): Move declarations to point of use. Refactor operator call building in order to support conversion of a non-capturing lambda template to a function pointer with help from ... (prepare_op_call): ... this new function. * decl2.c (check_member_template): Don't reject lambda call operator template in local [lambda] class. * pt.c (instantiate_class_template_1): Don't instantiate lambda call operator template when instantiating lambda class. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202539 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 17 + gcc/cp/decl2.c | 5 +- gcc/cp/lambda.c | 189 +-- gcc/cp/parser.c | 40 +++- gcc/cp/pt.c | 4 +- 5 files changed, 217 insertions(+), 38 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index cbad022..66869d2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,22 @@ 2013-09-12 Adam Butcher + * parser.c (cp_parser_lambda_declarator_opt): Accept template parameter + list with std=c++1y or std=gnu++1y. + (cp_parser_lambda_body): Don't call 'expand_or_defer_fn' for lambda call + operator template to avoid adding template result to symbol table. + * lambda.c (lambda_function): Return template result if call operator is + a template. + (maybe_add_lambda_conv_op): Move declarations to point of use. Refactor + operator call building in order to support conversion of a non-capturing + lambda template to a function pointer with help from ... + (prepare_op_call): ... this new function. + * decl2.c (check_member_template): Don't reject lambda call operator + template in local [lambda] class. + * pt.c (instantiate_class_template_1): Don't instantiate lambda call + operator template when instantiating lambda class. + +2013-09-12 Adam Butcher + * pt.c (instantiate_decl): Save/restore cp_unevaluated_operand and c_inhibit_evaluation_warnings. Reset if instantiating within a function-local template. diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index d5d2912..ac9dbd7 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -507,8 +507,9 @@ check_member_template (tree tmpl) || (TREE_CODE (decl) == TYPE_DECL && MAYBE_CLASS_TYPE_P (TREE_TYPE (decl { - /* The parser rejects template declarations in local classes. */ - gcc_assert (!current_function_decl); + /* The parser rejects template declarations in local classes +(with the exception of generic lambdas). */ + gcc_assert (!current_function_decl || LAMBDA_FUNCTION_P (decl)); /* The parser rejects any use of virtual in a function template. */ gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl))); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index a53e692..2d20333 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -196,7 +196,7 @@ lambda_function (tree lambda) /*protect=*/0, /*want_type=*/false, tf_warning_or_error); if (lambda) -lambda = BASELINK_FUNCTIONS (lambda); +lambda = STRIP_TEMPLATE (get_first_fn (lambda)); return lambda; } @@ -741,6 +741,22 @@ nonlambda_method_basetype (void) return TYPE_METHOD_BASETYPE (TREE_TYPE (fn)); } +/* Helper function for maybe_add_lambda_conv_op; build a CALL_EXPR with + indicated FN and NARGS, but do not initialize the return type or any of the + argument slots. */ + +static tree +prepare_op_call (tree fn, int nargs) +{ + tree t; + + t = build_vl_exp (CALL_EXPR, nargs + 3); + CALL_EXPR_FN (t) = fn; + CALL_EXPR_STATIC_CHAIN (t) = NULL; + + return t; +} + /* If the closure TYPE has a static op(), also add a conversion to function pointer. */ @@ -749,9 +765,6 @@ maybe_add_lambda_conv_op (tree type) { bool nested = (current_function_decl != NULL_TREE); tree callop = lambda_function (type); - tree rettype, name, fntype, fn, body, compound_stmt; - tree thistype, stattype, statfn, convfn, call, arg; - vec *argvec; if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE) return; @@ -759,6 +772,10 @@ maybe_add_lambda_conv_op (tree type) if (processing_template_decl) return; + bool const generic_lambda_p += (DECL_TEMPLATE_INFO (callop) +&& DECL_TEMPLATE_RESULT (DECL_TI_
Re: [PATCH, committed] Support lambda templates.
On 12.09.2013 23:44, Andrew MacLeod wrote: On 09/12/2013 06:41 PM, Andrew MacLeod wrote: On 09/12/2013 05:55 PM, Tobias Burnus wrote: Adam Butcher wrote: From: abutcher * lambda.c (lambda_function): Return template result if call operator is a template. I believe that that patch causes the following build failure of cp/lambda.c: In file included from ../../gcc/tree-core.h:27:0, from ../../gcc/tree.h:23, from ../../gcc/cp/lambda.c:27: ../../gcc/vec.h: In function 'void maybe_add_lambda_conv_op(tree)': ../../gcc/vec.h:626:44: error: 'direct_argvec' may be used uninitialized in this function [-Werror=maybe-uninitialized] vec_safe_space (const vec *v, unsigned nelems) ^ ../../gcc/cp/lambda.c:795:21: note: 'direct_argvec' was declared here vec *direct_argvec; Tobias PS: I am not positive since I use a patched tree and I haven't bisected. I have verified that is the patch set causing the same issue for me. I backed out that revision and everything is fine. Andrew Only locally of course to verify... :-P Sorry about this. I had built without -Werror. I believed this warning to be a false-positive with the maybe-uninitialized code which I thought might be fixed later. I will commit a fix to initialize these pointers to 0.
[PATCH, committed] Fix uninitialized variables causing breakage with -Werror.
From: abutcher * lambda.c (maybe_add_lambda_conv_op): Initialize direct_argvec and call to nullptr to avoid breakage with -Werror. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202554 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 5 + gcc/cp/lambda.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 68c8ea4..80e0d96 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2013-09-13 Adam Butcher + + * lambda.c (maybe_add_lambda_conv_op): Initialize direct_argvec and call + to nullptr to avoid breakage with -Werror. + 2013-09-12 Brooks Moses PR driver/42955 diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 2d20333..0da22fd 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -792,8 +792,8 @@ maybe_add_lambda_conv_op (tree type) particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in the body CALL, but not in DECLTYPE_CALL. */ - vec *direct_argvec; - tree decltype_call = 0, call; + vec *direct_argvec = 0; + tree decltype_call = 0, call = 0; tree fn_result = TREE_TYPE (TREE_TYPE (callop)); if (generic_lambda_p) -- 1.8.4
Re: [PATCH, committed] Support lambda templates.
On 13.09.2013 07:17, Adam Butcher wrote: On 12.09.2013 23:44, Andrew MacLeod wrote: On 09/12/2013 06:41 PM, Andrew MacLeod wrote: On 09/12/2013 05:55 PM, Tobias Burnus wrote: Adam Butcher wrote: From: abutcher * lambda.c (lambda_function): Return template result if call operator is a template. I believe that that patch causes the following build failure of cp/lambda.c: In file included from ../../gcc/tree-core.h:27:0, from ../../gcc/tree.h:23, from ../../gcc/cp/lambda.c:27: ../../gcc/vec.h: In function 'void maybe_add_lambda_conv_op(tree)': ../../gcc/vec.h:626:44: error: 'direct_argvec' may be used uninitialized in this function [-Werror=maybe-uninitialized] vec_safe_space (const vec *v, unsigned nelems) ^ ../../gcc/cp/lambda.c:795:21: note: 'direct_argvec' was declared here vec *direct_argvec; Tobias PS: I am not positive since I use a patched tree and I haven't bisected. I have verified that is the patch set causing the same issue for me. I backed out that revision and everything is fine. Andrew Only locally of course to verify... :-P Sorry about this. I had built without -Werror. I believed this warning to be a false-positive with the maybe-uninitialized code which I thought might be fixed later. I will commit a fix to initialize these pointers to 0. Fixed in 202554.
Re: [PATCH, committed] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
On 13.09.2013 13:26, Andreas Schwab wrote: FAIL: g++.dg/cpp0x/auto3.C -std=c++11 (test for errors, line 24) FAIL: g++.dg/cpp0x/auto3.C -std=c++11 (test for excess errors) Excess errors: : error: use of 'auto' in parameter declaration only available with -std=c++1y or -std=gnu++1y I'm on it. Specifically, I am looking into the following on the assumption that it is my commits that stuffed them: FAIL: g++.dg/cpp0x/auto3.C -std=c++11 (test for errors, line 24) FAIL: g++.dg/cpp0x/auto3.C -std=c++11 (test for errors, line 24) FAIL: g++.dg/cpp0x/auto3.C -std=c++11 (test for excess errors) FAIL: g++.dg/cpp0x/auto3.C -std=c++11 (test for excess errors) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 115) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 115) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 120) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 120) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 121) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 121) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 82) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 82) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 83) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 83) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 84) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 84) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 85) FAIL: g++.dg/cpp0x/auto9.C (test for errors, line 85) FAIL: g++.dg/cpp0x/auto9.C (test for excess errors) FAIL: g++.dg/cpp0x/auto9.C (test for excess errors) FAIL: g++.dg/cpp0x/lambda/lambda-conv4.C (internal compiler error) FAIL: g++.dg/cpp0x/lambda/lambda-conv4.C (internal compiler error) FAIL: g++.dg/cpp0x/lambda/lambda-conv4.C (test for excess errors) FAIL: g++.dg/cpp0x/lambda/lambda-conv4.C (test for excess errors) FAIL: g++.dg/cpp0x/lambda/lambda-eh2.C execution test FAIL: g++.dg/cpp0x/lambda/lambda-eh2.C execution test FAIL: g++.dg/cpp0x/lambda/lambda-nested4.C (internal compiler error) FAIL: g++.dg/cpp0x/lambda/lambda-nested4.C (internal compiler error) FAIL: g++.dg/cpp0x/lambda/lambda-nested4.C (test for excess errors) FAIL: g++.dg/cpp0x/lambda/lambda-nested4.C (test for excess errors) FAIL: g++.dg/cpp0x/lambda/lambda-template11.C -std=c++11 (internal compiler error) FAIL: g++.dg/cpp0x/lambda/lambda-template11.C -std=c++11 (internal compiler error) FAIL: g++.dg/cpp0x/lambda/lambda-template11.C -std=c++11 (test for excess errors) FAIL: g++.dg/cpp0x/lambda/lambda-template11.C -std=c++11 (test for excess errors) Apologies for not doing before-and-after test run prior to pushing. Cheers, Adam
Generic lambda and implicit function template commits reverted
r202570 | abutcher | 2013-09-13 17:14:15 +0100 (Fri, 13 Sep 2013) | 7 lines Revert r202554, r202540 and r202539. - r202554: Fix uninitialized variables causing breakage with -Werror. - r202540: Support using 'auto' in a function parameter list to introduce an implicit template parameter. - r202539: Support lambda templates. There's some additional work needed before these are ready for trunk. Specifically, I need to make sure there are no test regressions. Cheers, Adam
Re: Generic lambda and implicit function template commits reverted
Hi Jason, Could you cast your eyes over these changes please? I intend to roll them up into the appropriate patches. I will make sure I bootstrap and "before-and-after" the g++.dg testsuite before pushing next time! [PATCH 1/5] Fix uninitialized variables causing breakage with -Werror. Not actually sure that this should be necessary. Initialization of 'direct_argvec' and 'call' and subsequent references are behind '!generic_lambda_p' and 'generic_lambda_p' tests respectively. 'generic_lambda_p' is declared 'const bool'. To pacify -Wmaybe-uninitialized, I have initialized them to 0. [PATCH 2/5] Don't accept 'auto' as the 'type' of a template parameter. The implicit function template code was incorrectly firing in a template parameter list. [PATCH 3/5] Fix location diagnostics by returning to the deprecated 'input_location' global; must be a better fix for this. Don't know why 'location_of (type)' gave ":" rather than "file:line:col:". My current workaround is to return to using 'input_location'. This gives the correct result but I doubt it is acceptable. [PATCH 4/5] Lift CALL_FROM_THUNK_P setting to above the potential 'build_cplus_new' call to prevent ICE due to unexpected tree type. Plain old bug which I introduced when reorganizing the conversion op code. [PATCH 5/5] Handle forward declaration of implicit function templates. Previously kept template parameter types in scope. Another bug. Template parameter list erroneously left in scope. Cheers, Adam [PATCH 1/5] Fix uninitialized variables causing breakage with -Werror. --- diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 2d20333..0da22fd 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -792,8 +792,8 @@ maybe_add_lambda_conv_op (tree type) particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in the body CALL, but not in DECLTYPE_CALL. */ - vec *direct_argvec; - tree decltype_call = 0, call; + vec *direct_argvec = 0; + tree decltype_call = 0, call = 0; tree fn_result = TREE_TYPE (TREE_TYPE (callop)); if (generic_lambda_p) -- [PATCH 2/5] Don't accept 'auto' as the 'type' of a template parameter. --- diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e6e24f8..6a4e863 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10323,7 +10323,12 @@ grokdeclarator (const cp_declarator *declarator, if (type_uses_auto (type)) { - if (current_class_type && LAMBDA_TYPE_P (current_class_type)) + if (template_parm_flag) + { + error ("template parameter declared %"); + type = error_mark_node; + } + else if (current_class_type && LAMBDA_TYPE_P (current_class_type)) { if (cxx_dialect < cxx1y) pedwarn (location_of (type), 0, -- [PATCH 3/5] Fix location diagnostics by returning to the deprecated 'input_location' global; must be a better fix for this. Using 'location_of (type)' yields ": " rather than "file:line:col: " --- diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6a4e863..a948580 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10331,18 +10331,18 @@ grokdeclarator (const cp_declarator *declarator, else if (current_class_type && LAMBDA_TYPE_P (current_class_type)) { if (cxx_dialect < cxx1y) - pedwarn (location_of (type), 0, + pedwarn (input_location, 0, "use of % in lambda parameter declaration " "only available with " "-std=c++1y or -std=gnu++1y"); } else if (cxx_dialect < cxx1y) - pedwarn (location_of (type), 0, + pedwarn (input_location, 0, "use of % in parameter declaration " "only available with " "-std=c++1y or -std=gnu++1y"); else - pedwarn (location_of (type), OPT_Wpedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids use of % in parameter " "declaration"); } -- [PATCH 4/5] Lift CALL_FROM_THUNK_P setting to above the potential 'build_cplus_new' call to prevent ICE due to unexpected tree type. --- diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 0da22fd..0154840 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -883,16 +883,17 @@ maybe_add_lambda_conv_op (tree type) tf_warning_or_error); --processing_template_decl; } + CALL_FROM_THUNK_P (call) = 1; } else { call = build_call_a (callop, direct_argvec->length (), direct_argvec->address ()); + CALL_FROM_THUNK_P (call) = 1; if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call))) call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error); } - CALL_FROM_THUNK_P (call
Re: Generic lambda and implicit function template commits reverted
On 15.09.2013 15:45, Jason Merrill wrote: On 09/15/2013 06:22 AM, Adam Butcher wrote: [PATCH 1/5] Fix uninitialized variables causing breakage with -Werror. [PATCH 2/5] Don't accept 'auto' as the 'type' of a template parameter. OK. I've also added a case for rejecting 'auto' in a catch parameter. [PATCH 3/5] Fix location diagnostics by returning to the deprecated 'input_location' global; must be a better fix for this. Don't know why 'location_of (type)' gave ":" rather than "file:line:col:". My current workaround is to return to using 'input_location'. This gives the correct result but I doubt it is acceptable. This seems to be because make_auto_1 sets the location of the auto type to BUILTINS_LOCATION; I don't remember why I did that. Changing it to use input_location seems appropriate. Thanks. Doing that makes this patch unnecessary. [PATCH 4/5] Lift CALL_FROM_THUNK_P setting to above the potential 'build_cplus_new' call to prevent ICE due to unexpected tree type. Rather than this, I've moved the call to 'build_cplus_new' back down to after 'start_preparsed_function' as I needed to call 'set_flags_from_callee' prior to it but within function scope to prevent regression of 49260 and 47263. Deltas below. No regressions in g++.dg with these updates. Cheers, Adam Subject: [PATCH] * pt.c (make_auto_1): Use input_location rather than BUILTINS_LOCATION. --- diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 58f920e..70f13bb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20925,7 +20925,7 @@ static tree make_auto_1 (tree name) { tree au = cxx_make_type (TEMPLATE_TYPE_PARM); - TYPE_NAME (au) = build_decl (BUILTINS_LOCATION, + TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au); TYPE_STUB_DECL (au) = TYPE_NAME (au); TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index -- [PATCH] Move 'build_cplus_new' call to after 'start_preparsed_function' and call 'set_flags_from_callee' prior to prevent ICE due to unexpected tree type and fix exception handling. --- diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 0da22fd..c9118d8 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -885,13 +885,10 @@ maybe_add_lambda_conv_op (tree type) } } else -{ call = build_call_a (callop, direct_argvec->length (), direct_argvec->address ()); - if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call))) - call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error); -} + CALL_FROM_THUNK_P (call) = 1; tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop)); @@ -987,6 +984,12 @@ maybe_add_lambda_conv_op (tree type) } tree body = begin_function_body (); tree compound_stmt = begin_compound_stmt (0); + if (!generic_lambda_p) +{ + set_flags_from_callee (call); + if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call))) + call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error); +} call = convert_from_reference (call); finish_return_stmt (call); -- [PATCH] Don't allow 'auto' in type of catch parameter. --- diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6a4e863..80ceca1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10328,6 +10328,11 @@ grokdeclarator (const cp_declarator *declarator, error ("template parameter declared %"); type = error_mark_node; } + else if (decl_context == CATCHPARM) + { + error ("catch parameter declared %"); + type = error_mark_node; + } else if (current_class_type && LAMBDA_TYPE_P (current_class_type)) { if (cxx_dialect < cxx1y) -- [PATCH] cpp0x/auto9.C: Downgrade expected error to expected pedwarn. --- diff --git a/gcc/testsuite/g++.dg/cpp0x/auto9.C b/gcc/testsuite/g++.dg/cpp0x/auto9.C index 190bfa6..f357f2b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/auto9.C +++ b/gcc/testsuite/g++.dg/cpp0x/auto9.C @@ -117,8 +117,8 @@ template struct G {}; // { dg-error "auto" } template struct H { H (); ~H (); }; H h; // { dg-error "invalid" } -void qq (auto);// { dg-error "auto" } -void qr (auto*); // { dg-error "auto" } +void qq (auto);// { dg-warning "auto" } +void qr (auto*); // { dg-warning "auto" } // PR c++/46145 typedef auto autot;// { dg-error "auto" } --
[PATCH, committed] * pt.c (make_auto_1): Use input_location rather than BUILTINS_LOCATION.
--- gcc/cp/pt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2ef160a..ed08dca 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -21041,7 +21041,7 @@ static tree make_auto_1 (tree name) { tree au = cxx_make_type (TEMPLATE_TYPE_PARM); - TYPE_NAME (au) = build_decl (BUILTINS_LOCATION, + TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au); TYPE_STUB_DECL (au) = TYPE_NAME (au); TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index -- 1.8.4
[PATCH, re-committed] Support lambda templates.
From: abutcher * parser.c (cp_parser_lambda_declarator_opt): Accept template parameter list with std=c++1y or std=gnu++1y. (cp_parser_lambda_body): Don't call 'expand_or_defer_fn' for lambda call operator template to avoid adding template result to symbol table. * lambda.c (lambda_function): Return template result if call operator is a template. (maybe_add_lambda_conv_op): Move declarations to point of use. Refactor operator call building in order to support conversion of a non-capturing lambda template to a function pointer with help from ... (prepare_op_call): ... this new function. * decl2.c (check_member_template): Don't reject lambda call operator template in local [lambda] class. * pt.c (instantiate_class_template_1): Don't instantiate lambda call operator template when instantiating lambda class. --- gcc/cp/decl2.c | 5 +- gcc/cp/lambda.c | 188 +++- gcc/cp/parser.c | 40 +++- gcc/cp/pt.c | 4 +- 4 files changed, 201 insertions(+), 36 deletions(-) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index c518551..4ac9445 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -502,8 +502,9 @@ check_member_template (tree tmpl) || (TREE_CODE (decl) == TYPE_DECL && MAYBE_CLASS_TYPE_P (TREE_TYPE (decl { - /* The parser rejects template declarations in local classes. */ - gcc_assert (!current_function_decl); + /* The parser rejects template declarations in local classes +(with the exception of generic lambdas). */ + gcc_assert (!current_function_decl || LAMBDA_FUNCTION_P (decl)); /* The parser rejects any use of virtual in a function template. */ gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl))); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 1af301d..b04448b 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -196,7 +196,7 @@ lambda_function (tree lambda) /*protect=*/0, /*want_type=*/false, tf_warning_or_error); if (lambda) -lambda = BASELINK_FUNCTIONS (lambda); +lambda = STRIP_TEMPLATE (get_first_fn (lambda)); return lambda; } @@ -775,6 +775,22 @@ nonlambda_method_basetype (void) return TYPE_METHOD_BASETYPE (TREE_TYPE (fn)); } +/* Helper function for maybe_add_lambda_conv_op; build a CALL_EXPR with + indicated FN and NARGS, but do not initialize the return type or any of the + argument slots. */ + +static tree +prepare_op_call (tree fn, int nargs) +{ + tree t; + + t = build_vl_exp (CALL_EXPR, nargs + 3); + CALL_EXPR_FN (t) = fn; + CALL_EXPR_STATIC_CHAIN (t) = NULL; + + return t; +} + /* If the closure TYPE has a static op(), also add a conversion to function pointer. */ @@ -783,9 +799,6 @@ maybe_add_lambda_conv_op (tree type) { bool nested = (current_function_decl != NULL_TREE); tree callop = lambda_function (type); - tree rettype, name, fntype, fn, body, compound_stmt; - tree thistype, stattype, statfn, convfn, call, arg; - vec *argvec; if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE) return; @@ -793,6 +806,10 @@ maybe_add_lambda_conv_op (tree type) if (processing_template_decl) return; + bool const generic_lambda_p += (DECL_TEMPLATE_INFO (callop) +&& DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop); + if (DECL_INITIAL (callop) == NULL_TREE) { /* If the op() wasn't instantiated due to errors, give up. */ @@ -800,16 +817,124 @@ maybe_add_lambda_conv_op (tree type) return; } - stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)), - FUNCTION_ARG_CHAIN (callop)); + /* Non-template conversion operators are defined directly with build_call_a + and using DIRECT_ARGVEC for arguments (including 'this'). Templates are + deferred and the CALL is built in-place. In the case of a deduced return + call op, the decltype expression, DECLTYPE_CALL, used as a substitute for + the return type is also built in-place. The arguments of DECLTYPE_CALL in + the return expression may differ in flags from those in the body CALL. In + particular, parameter pack expansions are marked PACK_EXPANSION_LOCAL_P in + the body CALL, but not in DECLTYPE_CALL. */ + + vec *direct_argvec = 0; + tree decltype_call = 0, call = 0; + tree fn_result = TREE_TYPE (TREE_TYPE (callop)); + + if (generic_lambda_p) +{ + /* Prepare the dependent member call for the static member function +'_FUN' and, potentially, prepare another call to be used in a decltype +return expression for a deduced return call op to allow for simple +implementation of the conversion operator. */ + + tree instance = build_nop (type, null_pointer_node); + tree objfn =
[PATCH, re-committed] Support using 'auto' in a function parameter list to introduce an implicit template parameter.
From: abutcher gcc/cp/ * 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_init_declarator): Likewise. (cp_parser_function_definition_after_declarator): Likewise. (cp_parser_member_declaration): Likewise. * Make-lang.in (cp/pt.o): Add dependency on type-utils.h. (cp/parser.o): Likewise. gcc/testsuite/ g++.dg/cpp0x/auto9.C: Downgrade two previously expected errors (now interpreted as implicit templates) to be expected pedwarns instead. --- gcc/cp/Make-lang.in| 5 +- gcc/cp/cp-tree.h | 2 + gcc/cp/decl.c | 29 +++- gcc/cp/parser.c| 289 ++--- gcc/cp/parser.h| 6 + gcc/cp/pt.c| 35 +++-- gcc/cp/type-utils.h| 55 +++ gcc/testsuite/g++.dg/cpp0x/auto9.C | 4 +- 8 files changed, 353 insertions(+), 72 deletions(-) create mode 100644 gcc/cp/type-utils.h diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 9a80434..985f22b 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -312,7 +312,7 @@ cp/except.o: cp/except.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \ cp/expr.o: cp/expr.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) $(TM_P_H) cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h cp/cp-objcp-common.h \ toplev.h $(TREE_INLINE_H) pointer-set.h gt-cp-pt.h intl.h \ - c-family/c-objc.h + c-family/c-objc.h cp/type-utils.h cp/error.o: cp/error.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_H) \ $(FLAGS_H) $(REAL_H) $(LANGHOOKS_DEF_H) $(CXX_PRETTY_PRINT_H) \ tree-diagnostic.h tree-pretty-print.h pointer-set.h c-family/c-objc.h @@ -331,7 +331,8 @@ cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) $(REAL_H) \ gt-cp-mangle.h $(TARGET_H) $(TM_P_H) $(CGRAPH_H) cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_CORE_H) \ gt-cp-parser.h $(TARGET_H) $(PLUGIN_H) intl.h cp/decl.h \ - c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H) + c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H) \ + cp/type-utils.h cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \ $(TM_H) coretypes.h pointer-set.h tree-iterator.h $(SPLAY_TREE_H) cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4680053..d7840af 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 f193676..80ceca1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10323,8 +10323,33 @@ grokdeclarator (const cp_declar
Re: C++ PATCH for c++/41933 (variadic lambda capture)
Excellent. This now supports the variadic generic lambda from the spec (albeit without the auto parameter pack) auto vglambda = [](auto printer) { // TODO: return [=](auto&& ... ts) // OK: ts is a function parameter pack return [=] (T&& ... ts) // OK: ts is a function parameter pack { printer(std::forward(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 Just need to get 'auto...' working now for C++14 generic lambda conformance. (I'm still trying!) Cheers, Adam
Re: [PATCH, committed] * pt.c (make_auto_1): Use input_location rather than BUILTINS_LOCATION.
On 16.09.2013 09:02, Eric Botcazou wrote: --- gcc/cp/pt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2ef160a..ed08dca 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -21041,7 +21041,7 @@ static tree make_auto_1 (tree name) { tree au = cxx_make_type (TEMPLATE_TYPE_PARM); - TYPE_NAME (au) = build_decl (BUILTINS_LOCATION, + TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au); TYPE_STUB_DECL (au) = TYPE_NAME (au); TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index That's not a valid post to gcc-patches though. You need to explain what the patch does in a few words, post a ChangeLog entry and say how you tested it. See all the other messages on the list... Apologies if this was out of context. This was a change suggested and reviewed by Jason (http://gcc.gnu.org/ml/gcc-patches/2013-09/msg01114.html). It has been commited. The changelog happened to be a one liner which folded into the subject line.
Re: [PATCH, committed] * pt.c (make_auto_1): Use input_location rather than BUILTINS_LOCATION.
On 16.09.2013 17:54, Eric Botcazou wrote: Apologies if this was out of context. This was a change suggested and reviewed by Jason (http://gcc.gnu.org/ml/gcc-patches/2013-09/msg01114.html). Then don't repost it on gcc-patches, it is already available on gcc-cvs: http://gcc.gnu.org/ml/gcc-cvs/2013-09/msg00473.html For some reason I had got it into my head that I should post to gcc-patches after any commit. After rereading "Write access policies" and "Checking in a change" I now realize I was mistaken. Sorry for the noise.
[C++1y] [PATCH 2/4] Support nested generic lambdas.
* lambda.c (maybe_add_lambda_conv_op): Don't check for instantiated callop in the case of generic lambdas. --- gcc/cp/lambda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index b04448b..2ffa7e0 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -810,7 +810,7 @@ maybe_add_lambda_conv_op (tree type) = (DECL_TEMPLATE_INFO (callop) && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop); - if (DECL_INITIAL (callop) == NULL_TREE) + if (!generic_lambda_p && DECL_INITIAL (callop) == NULL_TREE) { /* If the op() wasn't instantiated due to errors, give up. */ gcc_assert (errorcount || sorrycount); -- 1.8.4
[C++1y] [PATCH 0/4] Fixes and enhancements to generic lambdas and implicit function templates.
Hi all, The following series contain a few miscellaneous updates to generic lambdas and implicit function templates. [1/4]: Use translation-unit-global rather than parameter-list-local counter for generic type names to facilitate nested implicit function templates. Using function-local counter means that nested generic lambdas generate duplicate (conflicting) template type parameters. [2/4]: Support nested generic lambdas. Bug fix; remove assertion not applicable to generic lambdas. [3/4]: Ensure implicit template parameters have distinct canonical types. Unsure on my solution here. I tinkered with externalizing 'canonical_type_parameter' from pt.c but was not sure whether it was necessary. It seemed sufficient to simply make TYPE_CANONICAL be distinct for each parameter so I simply made it point to the generate template parameter type. [4/4]: Generate more intuitive name for 'auto' parameters. Potentially contentious. This makes the names generated for implicit template parameter types to be of the form '' rather than '__GenN'. The former, IMHO, look better in diagnostics. A better solution might be to make the transformation in the diagnostic code rather than relabel the type but this appears to work in my simplistic test cases. On the subject of test cases; I'm trying to put together a set to test all features of the generic lambda and implicit function template updates. This is taking longer than I'd hoped as I'm only getting a few minutes here and there to spend on this at the moment. Cheers, Adam gcc/cp/lambda.c | 2 +- gcc/cp/parser.c | 30 ++ 2 files changed, 19 insertions(+), 13 deletions(-) -- 1.8.4
[C++1y] [PATCH 3/4] Ensure implicit template parameters have distinct canonical types.
* parser.c (add_implicit_template_parms): Set the canonical type of a generic parameter to be that of the newly generated type such that it is unique. --- gcc/cp/parser.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7e9ade2..148e2f2 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -29005,6 +29005,9 @@ add_implicit_template_parms (cp_parser *parser, size_t expect_count, cur_type = cp_build_qualified_type (new_type, TYPE_QUALS (cur_type)); else cur_type = new_type; + + /* Make the canonical type of the parameter distinct. */ + TYPE_CANONICAL (TREE_TYPE (TREE_VALUE (p))) = cur_type; } gcc_assert (synth_count == expect_count); -- 1.8.4
[C++1y] [PATCH 4/4] Generate more intuitive name for 'auto' parameters.
* parser.c (make_generic_type_name): Spell generic type names '' rather than '__GenN'. --- gcc/cp/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 148e2f2..a54496a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -28902,7 +28902,7 @@ make_generic_type_name () { char buf[32]; static int i = 0; - sprintf (buf, "__GenT%d", i); + sprintf (buf, "", ++i); return get_identifier (buf); } -- 1.8.4
[C++1y] [PATCH 1/4] Use translation-unit-global rather than parameter-list-local counter for generic type names to facilitate nested implicit function templates.
* parser.c (make_generic_type_name): Use static count rather than parameter and ... (add_implicit_template_parms): ... propagate interface change here. --- gcc/cp/parser.c | 25 ++--- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 2cd60f0..7e9ade2 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -28898,9 +28898,10 @@ c_parse_file (void) template parameter implied by `auto' or a concept identifier). */ static tree -make_generic_type_name (int i) +make_generic_type_name () { char buf[32]; + static int i = 0; sprintf (buf, "__GenT%d", i); return get_identifier (buf); } @@ -28915,14 +28916,14 @@ 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. */ +/* 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. */ tree -add_implicit_template_parms (cp_parser *parser, size_t count, tree parameters) +add_implicit_template_parms (cp_parser *parser, size_t expect_count, +tree parameters) { gcc_assert (current_binding_level->kind == sk_function_parms); @@ -28931,7 +28932,7 @@ add_implicit_template_parms (cp_parser *parser, size_t count, tree parameters) bool become_template = fn_parms_scope->level_chain->kind != sk_template_parms; - size_t synth_idx = 0; + size_t synth_count = 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 @@ -28973,7 +28974,7 @@ add_implicit_template_parms (cp_parser *parser, size_t count, tree parameters) ++processing_template_parmlist; } - for (tree p = parameters; p && synth_idx < count; p = TREE_CHAIN (p)) + 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); @@ -28981,7 +28982,9 @@ add_implicit_template_parms (cp_parser *parser, size_t count, tree parameters) if (!generic_type_ptr) continue; - tree synth_id = make_generic_type_name (synth_idx++); + ++synth_count; + + 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 @@ -29004,7 +29007,7 @@ add_implicit_template_parms (cp_parser *parser, size_t count, tree parameters) cur_type = new_type; } - gcc_assert (synth_idx == count); + gcc_assert (synth_count == expect_count); push_binding_level (fn_parms_scope); -- 1.8.4
Re: [C++1y] [PATCH 1/4] Use translation-unit-global rather than parameter-list-local counter for generic type names to facilitate nested implicit function templates.
On 20.09.2013 18:46, Jason Merrill wrote: On 09/19/2013 02:37 PM, Adam Butcher wrote: + static int i = 0; I think this needs to be global and GTY so that it works properly with PCH. Didn't consider PCH. This delta OK? --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -28897,12 +28897,12 @@ c_parse_file (void) /* Create an identifier for a generic parameter type (a synthesized template parameter implied by `auto' or a concept identifier). */ +static GTY(()) int generic_parm_count; static tree make_generic_type_name () { char buf[32]; - static int i = 0; - sprintf (buf, "", ++i); + sprintf (buf, "", ++generic_parm_count); return get_identifier (buf); }
Re: [C++1y] [PATCH 3/4] Ensure implicit template parameters have distinct canonical types.
On 20.09.2013 18:47, Jason Merrill wrote: Why is canonical_type_parameter not doing the right thing here? I don't see a reason we should need to treat these differently from normal template parms. The issue only happens with indirect parms. The type 'auto' is given a canonical type in make_auto_1. When the parm type is plain unqualified 'auto', the implicit template code replaces it with the generated type and all's well. When the parm is 'auto&' the implicit template code only replaces the template_type_parm 'auto' with the generated type, the wrapping reference_type is left with the canonical type of 'auto&'. Example of two parm types in the same list (chain field removed): > unsigned DI size <...> unit size <...> align 64 symtab 0 alias set -1 canonical type 0x7f27b2ff3150> > unsigned DI size <...> unit size <...> align 64 symtab 0 alias set -1 canonical type 0x7f27b2ff3150> After replacement: VOID align 8 symtab 0 alias set -1 canonical type 0x7f27b2ff3540 index 1 level 1 orig_level 1>> unsigned DI size <...> unit size <...> align 64 symtab 0 alias set -1 canonical type 0x7f27b2ff3150> VOID align 8 symtab 0 alias set -1 canonical type 0x7f27b2ff35e8 index 2 level 1 orig_level 1>> unsigned DI size <...> unit size <...> align 64 symtab 0 alias set -1 canonical type 0x7f27b2ff3150> Looks like I'll need to expose canonical_type_parameter and push it through from the top of the parameter rather than just replace the template_type_parm. Or leave this as is and arrange for this scenario to never occur. I guess this wouldn't happen if we were replacing on the fly. Maybe make_auto_1 could differ in behavior when in a parameter list (would not setting a canonical type get us anywhere?) or just call a different function? I'll have a further look when I get some more time. Cheers, Adam
Re: [C++1y] [PATCH 3/4] Ensure implicit template parameters have distinct canonical types.
On 22.09.2013 14:07, Adam Butcher wrote: On 20.09.2013 18:47, Jason Merrill wrote: Why is canonical_type_parameter not doing the right thing here? I don't see a reason we should need to treat these differently from normal template parms. The issue only happens with indirect parms. The type 'auto' is given a canonical type in make_auto_1. When the parm type is plain unqualified 'auto', the implicit template code replaces it with the generated type and all's well. When the parm is 'auto&' the implicit template code only replaces the template_type_parm 'auto' with the generated type, the wrapping reference_type is left with the canonical type of 'auto&'. Example of two parm types in the same list (chain field removed): > unsigned DI size <...> unit size <...> align 64 symtab 0 alias set -1 canonical type 0x7f27b2ff3150> > unsigned DI size <...> unit size <...> align 64 symtab 0 alias set -1 canonical type 0x7f27b2ff3150> After replacement: VOID align 8 symtab 0 alias set -1 canonical type 0x7f27b2ff3540 index 1 level 1 orig_level 1>> unsigned DI size <...> unit size <...> align 64 symtab 0 alias set -1 canonical type 0x7f27b2ff3150> VOID align 8 symtab 0 alias set -1 canonical type 0x7f27b2ff35e8 index 2 level 1 orig_level 1>> unsigned DI size <...> unit size <...> align 64 symtab 0 alias set -1 canonical type 0x7f27b2ff3150> Looks like I'll need to expose canonical_type_parameter and push it through from the top of the parameter rather than just replace the template_type_parm. Or leave this as is and arrange for this scenario to never occur. I guess this wouldn't happen if we were replacing on the fly. Maybe make_auto_1 could differ in behavior when in a parameter list (would not setting a canonical type get us anywhere?) or just call a different function? I'll have a further look when I get some more time. The following solves the canonical type issue in the general case (pointers and refs) and makes it equivalent to the explicit template case -- in terms of canonical type at least. for (tree t = TREE_TYPE (TREE_VALUE (p)); t; t = TREE_CHAIN (t)) TYPE_CANONICAL (t) = t; But I'm not necessarily proposing it as a good final solution. It is yet another type chain loop, and I'm not sure about preserving other fields that are set in the explicit template case (e.g. reference_to_this). So far test cases appear to work as expected but I'm thinking that getting the 'auto' replaced earlier might solve these issues more naturally (and others such as auto... packs) Cheers, Adam
[C++1y] [Implicit Fix instantiation of implicit function template forward declarations.
Hi Jason, I noticed that, although implicit function template declarations were accepted. They weren't setup correctly and didn't instantiate properly. The following patch fixes this by moving finish_fully_implicit_template to the end of cp_parser_init_declarator. OK to go with the others? Cheers, Adam Fix instantiation of implicit function template forward declarations. * parser.c (cp_parser_init_declarator): Defer calling finish_fully_implicit_template for forward declarations until after other decl processing is complete. Cleanup for clarity: Extract 'else' case after 'if' containing unconditional return. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 82abf7c..f3133f3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16318,8 +16318,7 @@ cp_parser_init_declarator (cp_parser* parser, "a function-definition is not allowed here"); return error_mark_node; } - else - { + location_t func_brace_location = cp_lexer_peek_token (parser->lexer)->location; @@ -16357,9 +16356,6 @@ cp_parser_init_declarator (cp_parser* parser, return decl; } } - else if (parser->fully_implicit_function_template_p) - decl = finish_fully_implicit_template (parser, decl); -} /* [dcl.dcl] @@ -16581,6 +16577,15 @@ cp_parser_init_declarator (cp_parser* parser, if (!friend_p && pushed_scope) pop_scope (pushed_scope); + if (function_declarator_p (declarator) + && parser->fully_implicit_function_template_p) +{ + if (member_p) + decl = finish_fully_implicit_template (parser, decl); + else + finish_fully_implicit_template (parser, /*member_decl_opt=*/0); +} + return decl; }
[C++1y] [PATCH] Fix PR c++/58500
Hi, This fixes using 'auto' in the return type of a function pointer to introduce an implicit function template parameter. Note that this doesn't mean that 'auto' parameters in a function ptr will be treated the same; I think we need a special case for this in the implicit template parameter introduction code (or refactor to generate template parm types on the fly). Cheers, Adam gcc/cp/ PR c++/58500 * type-utils.h (find_type_usage) Only traverse one type level into member function pointers. gcc/testsuite/ PR c++/58500 * g++.dg/cpp1y/pr58500.C: New testcase. diff --git a/gcc/cp/type-utils.h b/gcc/cp/type-utils.h index 3e82ca4..2febce7 100644 --- a/gcc/cp/type-utils.h +++ b/gcc/cp/type-utils.h @@ -47,7 +47,7 @@ find_type_usage (tree t, bool (*pred) (const_tree)) if (TYPE_PTRMEMFUNC_P (t)) return find_type_usage - (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (t))), pred); + (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (t)), pred); return NULL_TREE; } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58500.C b/gcc/testsuite/g++.dg/cpp1y/pr58500.C new file mode 100644 index 000..b9d4a26 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr58500.C @@ -0,0 +1,8 @@ +// { dg-do compile } +// { dg-options "-std=gnu++1y" } + +// PR c++/58500 + +struct A {}; + +void foo(auto (A::*)());
Re: [C++1y] [PATCH 3/4] Ensure implicit template parameters have distinct canonical types.
On 22.09.2013 18:57, Adam Butcher wrote: The following solves the canonical type issue in the general case (pointers and refs) and makes it equivalent to the explicit template case -- in terms of canonical type at least. for (tree t = TREE_TYPE (TREE_VALUE (p)); t; t = TREE_CHAIN (t)) TYPE_CANONICAL (t) = t; The above is insufficient; the traversal doesn't handle function pointers. Currently, to get my local testcases passing, I have the following workaround that abuses find_type_usage. I intend for this to be replaced with a better solution but it will at least mean that people can start experimenting with this feature now (as they appear to be doing http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58500). This supports that testcase also. Cheers, Adam Workaround implicit function template parameter canonical type issue. * parser.c (add_implicit_template_parms): Workaround to fix up canonical type references left over from before substation of 'auto'. Better solution needed but this makes test cases functional. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index f3133f3..4171476 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -28987,6 +28987,25 @@ add_implicit_template_parms (cp_parser *parser, size_t expect_count, if (!generic_type_ptr) continue; + /* Make the canonical type of each part of the parameter distinct. +FIXME: A better solution is needed for this. Not least the abuse of +find_type_usage. Need foreach_type or similar for proper mutable +access. If something like this does turn out to be necessary then the +find_type_usage loop above can be replaced by a foreach_type that fixes +up the canonical types on the way to finding the 'auto'. */ + + struct helper { static bool fixup_canonical_types (tree t) { + t = TREE_TYPE (t); + if (!t) + return false; + if (is_auto_or_concept (t)) + return true; + TYPE_CANONICAL (t) = t; + return false; + }}; + find_type_usage (TREE_VALUE (p), (bool (*)(const_tree)) + helper::fixup_canonical_types); + ++synth_count; tree synth_id = make_generic_type_name ();
Re: [C++1y] [Implicit Fix instantiation of implicit function template forward declarations.
On 23.09.2013 19:03, Jason Merrill wrote: On 09/23/2013 01:53 AM, Adam Butcher wrote: + if (member_p) +decl = finish_fully_implicit_template (parser, decl); + else +finish_fully_implicit_template (parser, /*member_decl_opt=*/0); Why don't we want to return the template for the non-member case? If the decl is passed to finish_fully_implicit_template it is considered to be a member and the finished member returned. In the non-member case, nullptr is returned.
Re: [C++1y] [PATCH] Fix PR c++/58500
On 23.09.2013 19:02, Jason Merrill wrote: On 09/23/2013 02:08 AM, Adam Butcher wrote: Note that this doesn't mean that 'auto' parameters in a function ptr will be treated the same; I think we need a special case for this in the implicit template parameter introduction code (or refactor to generate template parm types on the fly). It is seeming like generating the types on the fly will make various things simpler; otherwise we need to deal with rewriting arbitrarily complex types later on. Agreed. We can arrange for the parm trees to be as if the user had explicitly specified the template and then subsequent logic will proceed 'naturally'. I'll look into it.
Re: [C++1y] [PATCH 3/4] ... canonical type workaround and refactoring
On 23.09.2013 08:15, Adam Butcher wrote: On 22.09.2013 18:57, Adam Butcher wrote: The following solves the canonical type issue in the general case (pointers and refs) and makes it equivalent to the explicit template case -- in terms of canonical type at least. for (tree t = TREE_TYPE (TREE_VALUE (p)); t; t = TREE_CHAIN (t)) TYPE_CANONICAL (t) = t; The above is insufficient; the traversal doesn't handle function pointers. Currently, to get my local testcases passing, I have the following workaround that abuses find_type_usage. I intend for this to be replaced with a better solution but it will at least mean that people can start experimenting with this feature now (as they appear to be doing http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58500). This supports that testcase also. Shall I push the patch below to trunk as an intermediate workaround whilst I get to refactoring to support on-the-fly template parm synthesis? On the subject of on-the-fly synthesis: I haven't started yet but I'm thinking to trigger in 'cp_parser_simple_type_specifier' when 'current_binding_level->kind == sk_function_parms'. I can foresee a potential issue with packs in that, upon reading the 'auto' (potentially nested in some other type), a plain template parm will be synthesized; but it may need to be a pack parm type if '...' is found later. My initial testcase is: template struct X { T m(int, float); }; auto f(X, auto (X::*) (auto...)) { char* s = "warn"; } int main() { X x; f(x, &X::m); } where f should be translated as similar to: template auto f(X, A2 (X::*) (A4...)) { char* s = "warn"; } In the case of something like: auto f(X&&...) the translation would need to be: template auto f(X&&...) I'm thinking that getting that to happen correctly might be tricky (but haven't tried yet). The 'auto' would trigger plain template parameter synthesis. Perhaps a 'could_be_parameter_pack_p' on the template_type_parm? Though I don't know how the following could be handled as implicit template auto f(X&&...) It would not be possible to infer which of the template parms to make the pack. auto f(X&&...) Probably multiple generic-type pack expansions should be forbidden. I'll see what happens when I get there but any guidance/thoughts you have on the subject will be valuable. Cheers, Adam Workaround implicit function template parameter canonical type issue. * parser.c (add_implicit_template_parms): Workaround to fix up canonical type references left over from before substation of 'auto'. Better solution needed but this makes test cases functional. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index f3133f3..4171476 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -28987,6 +28987,25 @@ add_implicit_template_parms (cp_parser *parser, size_t expect_count, if (!generic_type_ptr) continue; + /* Make the canonical type of each part of the parameter distinct. +FIXME: A better solution is needed for this. Not least the abuse of +find_type_usage. Need foreach_type or similar for proper mutable +access. If something like this does turn out to be necessary then the +find_type_usage loop above can be replaced by a foreach_type that fixes +up the canonical types on the way to finding the 'auto'. */ + + struct helper { static bool fixup_canonical_types (tree t) { + t = TREE_TYPE (t); + if (!t) + return false; + if (is_auto_or_concept (t)) + return true; + TYPE_CANONICAL (t) = t; + return false; + }}; + find_type_usage (TREE_VALUE (p), (bool (*)(const_tree)) + helper::fixup_canonical_types); + ++synth_count; tree synth_id = make_generic_type_name ();
[SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
Hi Jason, I did intend to break this up but as I've completed the first pass at refactoring implicit function templates and along the way fixed the 5 bugs submitted by Volker I thought I'd post the rolled up patch for you to peruse. It (should) support arbitrarily complex use of 'auto' in a parameter list to introduce template parameters. Implicit pack expansion parameters containing a single 'auto' are handled by tentatively assuming a single 'auto' might be a pack then reverting the flag if found not to be. This now fully supports the current C++14 generic lambda examples. No new regressions on trunk as of this morning. Any feedback appreciated. Diff attached with -w -b. Cheers, Adam TODO: Changelog post review. PR c++/58534 PR c++/58536 PR c++/58548 PR c++/58549 PR c++/58637 gcc/cp/decl.c| 30 +--- gcc/cp/parser.c | 312 ++- gcc/cp/parser.h | 15 ++ 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 + 8 files changed, 299 insertions(+), 106 deletions(-) commit 90c77cdd87eb63617719a9ad129803a2048761ff Author: Adam Butcher Date: Wed Sep 18 17:39:40 2013 +0100 Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637. TODO: Changelog post review. PR c++/58534 PR c++/58536 PR c++/58548 PR c++/58549 PR c++/58637 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 81ed409..8095eca 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10323,34 +10323,12 @@ grokdeclarator (const cp_declarator *declarator, if (type_uses_auto (type)) { - if (template_parm_flag) - { - error ("template parameter declared %"); - type = error_mark_node; - } - else if (decl_context == CATCHPARM) - { - error ("catch parameter declared %"); + if (cxx_dialect >= cxx1y) + error ("% parameter not permitted in this context"); + else + error ("parameter declared %"); 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 % 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 % 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 % in parameter " - "declaration"); - } /* A parameter declared as an array of T is really a pointer to T. One declared as a function is really a pointer to a function. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 90c1775..8c8be4c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -245,6 +245,19 @@ static FILE *cp_lexer_debug_stream; sizeof, typeof, or alignof. */ int cp_unevaluated_operand; +/* Nonzero if parsing a context where 'auto' in a parameter list should not + trigger an implicit template parameter. Specifically, 'auto' should not + introduce a new template type parameter in explicit specializations, trailing + return types or exception specifiers. */ +int cp_disable_auto_as_implicit_function_template_parm; + +/* Track the number of implicit template parameters introduced by the + current function parameter and, for handling implicit parameter packs, track + the most recently synthesized type. These are reset prior to parsing in + cp_parameter_declarator and updated in synthesize_implicit_template_parm. */ +int cp_num_implicit_template_type_parms; +tree cp_last_implicit_template_type_parm; + /* Dump up to NUM tokens in BUFFER to FILE starting with token START_TOKEN. If START_TOKEN is NULL, the dump starts with the first token in BUFFER. If NUM is 0, dump all the tokens. If @@ -2064,8 +2077,8 @@ 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 synthesize_implicit_template_parm + (cp_parser *parser); static tree finish_fully_implicit_template (cp_parser *, tree); @@ -3393,6 +3406,8 @@ cp_parser_new (void) /* Not declaring an implicit function template. */ parser->fully_implicit_function_template_p = false; + parser->implicit_template_parms = 0; + parser->implicit_template_scope = 0; ret
Re: [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
On 2013-10-09 4:37, Jason Merrill wrote: On 10/07/2013 05:14 AM, Adam Butcher wrote: + /* Forbid ambiguous implicit pack expansions by only allowing +a single generic type in such a parameter. +XXX: Maybe allow if explicitly specified template +XXX: 'typename...' account for all expansions? Though this +XXX: could be tricky or slow. This seems wrong. The standard says, The invented type template-parameter is a parameter pack if the corresponding parameter-declaration de- clares a function parameter pack (8.3.5). So if we have a function parameter pack, any generic type parameters in the type are packs. Of course; makes sense. I had confused myself. Not that it's a function parameter pack, but presumably you would expect auto f(tuple p) to be supported? This doesn't work with my existing impl since I only generate a variadic type on the declaration of a function parameter pack. I think the following cases should also work auto g1(std::tuple, std::tuple> p) auto g2(std::tuple, std::tuple...>> p) In both cases, the first generic type is a plain type and the second is a type pack. Making the parameter a function parameter pack should also work auto h1(std::tuple, std::tuple>... v) auto h2(std::tuple, std::tuple...>>... v) The first 'auto' is a pack expanded by 'v' and the second is expanded within the second tuple (and required to be consistent among all 'v' arguments). + /* If there is only one generic type in the parameter, tentatively + assume that that it is a parameter pack. If it turns out, after +grokdeclarator, that the parameter does not contain a pack +expansion, then reset it be a non-pack type. */ + if (cp_num_implicit_template_type_parms == 1) + TEMPLATE_PARM_PARAMETER_PACK + (TEMPLATE_TYPE_PARM_INDEX + (cp_last_implicit_template_type_parm)) = true; This will cause problems with type comparison, since TYPE_CANONICAL of the implicit parm doesn't have TEMPLATE_PARM_PARAMETER_PACK set. Indeed it does. That's why I was talking about using tsubst to replace a non-pack with a pack. Will do. + parser->implicit_template_scope = class_scope; + else + parser->implicit_template_scope = fn_parms_scope; + current_binding_level = parser->implicit_template_scope->level_chain; Why not make implicit_template_scope the actual template scope, rather than the function/class? It looks like all the users immediately take the level_chain. My original intent was to store the actual template parm scope but I changed it to the containing scope to make the comparison in cp_parser_parameter_declaration_list; It determines the completion point of the implicit template scope. It is terminated once current_binding_level returns to the initiating scope. I'll have another look to reduce level_chain traversal. +/* Nonzero if parsing a context where 'auto' in a parameter list should not + trigger an implicit template parameter. Specifically, 'auto' should not + introduce a new template type parameter in explicit specializations, trailing + return types or exception specifiers. */ +int cp_disable_auto_as_implicit_function_template_parm; Can we put this in cp_parser, invert the sense of the flag, and only set it during cp_parser_parameter_declaration_clause? Done. But it still needs a flag to disable in the case of explicit template specialization. At the moment I've replaced the explicit_specialization_p parm of cp_parser_single_declaration with a global cp_parsing_explicit_function_specialization but not sure if that's the best solution. I'll post an update once I get some time to rework the pack stuff. Cheers, Adam
Re: [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
On 2013-10-11 3:26, Jason Merrill wrote: Can we put this in cp_parser, invert the sense of the flag, and only set it during cp_parser_parameter_declaration_clause? Done. But it still needs a flag to disable in the case of explicit template specialization. Can't you just check processing_specialization? Yep. That's much cleaner. Cheers, Adam
Re: [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
On Wed, 25 Sep 2013 11:01:26 -0500, Jason Merrill wrote: On 09/24/2013 02:05 AM, Adam Butcher wrote: > On the subject of on-the-fly synthesis: I haven't started yet but I'm > thinking to trigger in 'cp_parser_simple_type_specifier' when > 'current_binding_level->kind == sk_function_parms'. > This is working out quite well. And I've cleaned up and optimized synthesize_implicit_template_parm to update current_template_parms directly. Implicitly packs are still a problem though. > I can foresee a > potential issue with packs in that, upon reading the 'auto' (potentially > nested in some other type), a plain template parm will be synthesized; > but it may need to be a pack parm type if '...' is found later. Hmm, good point. I think there are two options: 1) Build up the type as normal and use tsubst to replace the non-pack template parameter with a pack if needed. The problem I've hit with this (and other hacks I've tried that involve finishing the type first and rewriting afterward) is that, with parm types such as "pair...", the specialization "pair" is indexed in pt.c by hash_specialization into type_specializations before the '...' is seen. In an explicit template, the template type parms are already marked as packs so are hashed as such and are distinct from non-pack template type parms. The issue occurs in cases such as: auto a = [] (auto, pair v) { return sizeof (v); }; auto b = [] (auto, pair... v) { return sizeof... (v); }; a(1, pair()); b(2, pair(), pair()); If the declarations of a and b are reversed, it works as expected. I cannot find a way to prevent picking up the non-pack "pair" type on the way through parsing "pair...". I've tried a few hacks to prevent hashing if an 'auto' is present in the current type but ended up with canonical type issues. I also tried rehashing after pack replacement but still hit the same issue. My conclusion is that the 'auto' needs to synthesize a pack type from the start for parameter packs. Which leads to: 2) If we see 'auto', scan ahead (possibly via tentative parsing) to see if there's a ... My current preferred option. The problem with it is that, ideally, I only want to look ahead for '...' in the parm decl if an 'auto' is seen. But I'm not sure how to do this in the case where the first 'auto' is nested in a template parameter (or other complex type). E.g. auto f(pair, auto>... v) ^ From the 'auto' I'd need to unwind to the fn parm scope and then try to tentatively parse the ellipsis. To unwind and look ahead for '...' needs the full parser mechanics but without any side-effects. I don't think I can do it with the lexer alone as I think there may be ambiguity with scanning <, <<, >, >> tokens. Look-ahead seems like the right way to go (unless there's a way to defer type hashing) but I'm not sure how to achieve it. Any suggestions? Cheers, Adam
Re: [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
On 2013-10-15 22:21, Adam Butcher wrote: On Wed, 25 Sep 2013 11:01:26 -0500, Jason Merrill wrote: > > 2) If we see 'auto', scan ahead (possibly via tentative parsing) to see if there's a ... > My current preferred option. The problem with it is that, ideally, I only want to look ahead for '...' in the parm decl if an 'auto' is seen. But I'm not sure how to do this in the case where the first 'auto' is nested in a template parameter (or other complex type). E.g. auto f(pair, auto>... v) ^ From the 'auto' I'd need to unwind to the fn parm scope and then try to tentatively parse the ellipsis. To unwind and look ahead for '...' needs the full parser mechanics but without any side-effects. I don't think I can do it with the lexer alone as I think there may be ambiguity with scanning <, <<, >, >> tokens. Look-ahead seems like the right way to go (unless there's a way to defer type hashing) but I'm not sure how to achieve it. I've got a [potential] [partial] solution to this. It doesn't handle edge cases but I believe it will handle the majority of cases. By maintaining a nesting counter of calls to cp_parser_enclosed_template_argument_list we can determine, for a particular parm, what level of template-id were are parsing when we see an 'auto'. A tentative skip parse handling < << ( [ ] ) >> > can be done until reaching an ellipsis or, if <> nesting count drops to zero, a closing paren or comma terminating the parm. Mismatches would also be considered as terminating the parm. In the ellipsis case we assume some sort of pack. If the <> nesting count is zero when an ellipsis is found, we assume a function parameter pack and flag that all 'auto's in the parm should be type packs and don't need to do the look-ahead again for this parm. If the <> nesting count is non-zero when an ellipsis is found, then only the 'auto's within that level of template argument list are considered type packs and look-ahead will be done for 'auto' found in subsequent template argument lists within the parm. The latter case implements the implicit type pack extension supporting, for example, the following: f(tuple,tuple> t) This doesn't handle cases where < << >> > are used as operators within the parm but I think that's an edge case and it would only affect whether the 'auto' was considered an implicit type pack or not. I haven't gone all the way with this theory yet, but it could be a plausible solution. Let me know what you think. Cheers, Adam
[C++ PATCH 2/3] Support implicit parameter packs.
* 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
Re: [SKETCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
Hi Jason, I've got the tsubst solution for implicit parameter packs working now. I've also improved the efficiency of incremental template parameter synthesis and added some testcases. All C++14 generic lambda examples pass and no new regressions. Cheers, Adam Patch summary (3): Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637. Support implicit parameter packs. Add some generic lambda test cases. gcc/cp/decl.c | 30 +- gcc/cp/parser.c| 331 +++-- gcc/cp/parser.h| 19 ++ 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 ++ 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 + 19 files changed, 561 insertions(+), 114 deletions(-) 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 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 -- 1.8.4
[C++ PATCH 3/3] Add some generic lambda test cases.
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 000..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 000..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 + +int main() +{ + auto f = [] (T const& s) mutable { +typename T::N x; +return x.test (); + }; + auto g = [] (auto const& s) { +typename std::decay::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 000..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 = [] (T a, auto b) { return a + b; }; + auto g = [] (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 000..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 \ +
[C++ PATCH 1/3] 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). (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 '' 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 %"); - type = error_mark_node; - } - else if (decl_context == CATCHPARM) - { - error ("catch parameter declared %"); - 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 % 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 % in parameter declaration " -"only available with " -"-std=c++1y or -std=gnu++1y"); + if (cxx_dialect >= cxx1y) + error ("% parameter not permitted in this context"); else - pedwarn (location_of (type), OPT_Wpedantic, -"ISO C++ forbids use of % in parameter " -"declaration"); + error ("parameter declared %"); + 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 decla
[PATCH] PR c++/69139
PR c++/69139 * cp/parser.c (cp_parser_simple_type_specifier): Don't mistake 'auto' in trailing return function pointer types as an implicit template parameter. PR c++/69139 * g++.dg/cpp0x/trailing12.C: New test. --- gcc/cp/parser.c | 22 ++ gcc/testsuite/g++.dg/cpp0x/trailing12.C | 6 ++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/trailing12.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d03b0c9..c1a9674 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16029,8 +16029,11 @@ cp_parser_simple_type_specifier (cp_parser* parser, maybe_warn_cpp0x (CPP0X_AUTO); if (parser->auto_is_implicit_function_template_parm_p) { - /* The 'auto' might be the placeholder return type for a function decl -with trailing return type. */ + /* The 'auto' might be the placeholder return type for a function type +with trailing return type. Look for a '->' after parameter list. +Handle pointer-to-function, function reference and +pointer-to-member-function by tentatively consuming two pairs of +parens before testing for '->'. */ bool have_trailing_return_fn_decl = false; if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_PAREN) @@ -16042,8 +16045,19 @@ cp_parser_simple_type_specifier (cp_parser* parser, /*recovering*/false, /*or_comma*/false, /*consume_paren*/true)) - have_trailing_return_fn_decl - = cp_lexer_next_token_is (parser->lexer, CPP_DEREF); + { + if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) + have_trailing_return_fn_decl = true; + else if ((cp_lexer_consume_token (parser->lexer)->type + == CPP_OPEN_PAREN) + && (cp_parser_skip_to_closing_parenthesis + (parser, + /*recovering*/false, + /*or_comma*/false, + /*consume_paren*/true))) + have_trailing_return_fn_decl + = cp_lexer_next_token_is (parser->lexer, CPP_DEREF); + } cp_parser_abort_tentative_parse (parser); } diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing12.C b/gcc/testsuite/g++.dg/cpp0x/trailing12.C new file mode 100644 index 000..f3e02a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/trailing12.C @@ -0,0 +1,6 @@ +// PR c++/69139 +// { dg-do compile { target c++11 } } + +auto get(int) -> int { return {}; } +template int f(auto (*)(int) -> R) { return {}; } +int i = f(get); -- 2.7.0
[PATCH] Re: PR c++/69139
The following fixes up the handling of trailing returns with cv/ref specifiers mentioned by TC in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69139#c3. I've added handling of exception and transaction specs too. --- gcc/cp/parser.c | 12 ++-- gcc/testsuite/g++.dg/cpp0x/trailing12.C | 10 ++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c1a9674..f51fac4 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16055,8 +16055,16 @@ cp_parser_simple_type_specifier (cp_parser* parser, /*recovering*/false, /*or_comma*/false, /*consume_paren*/true))) - have_trailing_return_fn_decl - = cp_lexer_next_token_is (parser->lexer, CPP_DEREF); + { + /* Consume any cv-qualifier-seq, ref-qualifier, +tx-qualifier and/or exception specifier. */ + cp_parser_cv_qualifier_seq_opt (parser); + cp_parser_ref_qualifier_opt (parser); + cp_parser_tx_qualifier_opt (parser); + cp_parser_exception_specification_opt (parser); + have_trailing_return_fn_decl + = cp_lexer_next_token_is (parser->lexer, CPP_DEREF); + } } cp_parser_abort_tentative_parse (parser); } diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing12.C b/gcc/testsuite/g++.dg/cpp0x/trailing12.C index f3e02a8..707b753 100644 --- a/gcc/testsuite/g++.dg/cpp0x/trailing12.C +++ b/gcc/testsuite/g++.dg/cpp0x/trailing12.C @@ -4,3 +4,13 @@ auto get(int) -> int { return {}; } template int f(auto (*)(int) -> R) { return {}; } int i = f(get); + +struct X { + auto get(int) const & throw() -> int { return {}; } + auto get(int) && -> long { return {}; } +}; + +template auto f(auto (X::*)(int) const & -> R) -> R {} + +using I = decltype(f(&X::get)); +using I = int; -- 2.7.0
Re: [PATCH] PR c++/69139
On 2016-02-08 19:14, Patrick Palka wrote: On Mon, 8 Feb 2016, Jason Merrill wrote: On 02/08/2016 11:43 AM, Patrick Palka wrote: BTW, last month I posted a patch for this PR that handles all kinds of specifiers as well __attribute__ specifiers. Patch is at: https://gcc.gnu.org/ml/gcc-patches/2016-01/msg02004.html -- it makes the parser arbitrarily look ahead (while skipping over pairs of parens) until it finds a DEREF, a COMMA, a CLOSE_PAREN or an EQ. If it first finds a DEREF then have_trailing_return_fn_decl is set. Dunno if it's better to have this kind of "dumb" lookahead, or to be more explicit about one expects to consume like your followup patch does. Hmm, I think I prefer your approach [snip] Me too. I was worried that the cases handled in the explicit solution might get longer, more complex and repeat large amounts of other parser code. Providing this approach gives us no false positives I would say it's superior.
[PATCH] Fix PR c++/59635
* cp/lambda.c (maybe_add_lambda_conv_op): Handle marking conversion function as unimplemented for generic lambdas with varargs. * g++.dg/opt/pr59635.C: New testcase. --- gcc/cp/lambda.c | 2 +- gcc/testsuite/g++.dg/cpp1y/pr59635.C | 9 + 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr59635.C diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 1855716..8bb820d 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -970,7 +970,7 @@ maybe_add_lambda_conv_op (tree type) the conversion op is used. */ if (varargs_function_p (callop)) { - DECL_DELETED_FN (fn) = 1; + DECL_DELETED_FN (STRIP_TEMPLATE (fn)) = 1; return; } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr59635.C b/gcc/testsuite/g++.dg/cpp1y/pr59635.C new file mode 100644 index 000..07bd6c4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr59635.C @@ -0,0 +1,9 @@ +// { dg-do compile } +// { dg-options "-std=c++1y" } + +// PR c++/59635 + +auto f = [] (auto, ...) { return 0; }; + +int (*p) (int, ...) = f; // { dg-error "unimplemented" } + -- 1.8.5.2
[PATCH] Fix PR c++/59636
* cp/parser.c (cp_parser_template_parameter): Early out with error_mark_node if parameter declaration was not parsed. * g++.dg/cpp1y/pr59636.C: New testcase. --- gcc/cp/parser.c | 12 ++-- gcc/testsuite/g++.dg/cpp1y/pr59636.C | 7 +++ 2 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr59636.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 35dcefd..4f737df 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -12981,20 +12981,21 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type, = cp_parser_parameter_declaration (parser, /*template_parm_p=*/true, /*parenthesized_p=*/NULL); + if (!parameter_declarator) +return error_mark_node; + /* If the parameter declaration is marked as a parameter pack, set *IS_PARAMETER_PACK to notify the caller. Also, unmark the declarator's PACK_EXPANSION_P, otherwise we'll get errors from grokdeclarator. */ - if (parameter_declarator - && parameter_declarator->declarator + if (parameter_declarator->declarator && parameter_declarator->declarator->parameter_pack_p) { *is_parameter_pack = true; parameter_declarator->declarator->parameter_pack_p = false; } - if (parameter_declarator - && parameter_declarator->default_argument) + if (parameter_declarator->default_argument) { /* Can happen in some cases of erroneous input (c++/34892). */ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) @@ -13018,8 +13019,7 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type, /* We might end up with a pack expansion as the type of the non-type template parameter, in which case this is a non-type template parameter pack. */ - else if (parameter_declarator - && parameter_declarator->decl_specifiers.type + else if (parameter_declarator->decl_specifiers.type && PACK_EXPANSION_P (parameter_declarator->decl_specifiers.type)) { *is_parameter_pack = true; diff --git a/gcc/testsuite/g++.dg/cpp1y/pr59636.C b/gcc/testsuite/g++.dg/cpp1y/pr59636.C new file mode 100644 index 000..f2ca5b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr59636.C @@ -0,0 +1,7 @@ +// { dg-do compile } +// { dg-options "-std=c++1y" } + +// PR c++/59636 + +auto f = []() { return []<>() {}; }; // { dg-error "expected identifier" } + -- 1.8.5.2
Re: [PATCH] Fix PR c++/59635
On 2014-01-03 21:45, Adam Butcher wrote: * g++.dg/opt/pr59635.C: New testcase. s/opt/cpp1y/ +int (*p) (int, ...) = f; // { dg-error "unimplemented" } s/dg-error/dg-message/
[PATCH] Fix PR c++/59629
* cp/parser.c (cp_parser_lambda_expression): Save/reset/restore auto_is_implicit_function_template_parm_p around lambda body. * g++.dg/cpp1y/pr59629.C: New testcase. --- gcc/cp/parser.c | 5 + gcc/testsuite/g++.dg/cpp1y/pr59629.C | 7 +++ 2 files changed, 12 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr59629.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4f737df..0e013b9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8740,6 +8740,8 @@ cp_parser_lambda_expression (cp_parser* parser) = parser->fully_implicit_function_template_p; tree implicit_template_parms = parser->implicit_template_parms; cp_binding_level* implicit_template_scope = parser->implicit_template_scope; +bool auto_is_implicit_function_template_parm_p += parser->auto_is_implicit_function_template_parm_p; parser->num_template_parameter_lists = 0; parser->in_statement = 0; @@ -8747,6 +8749,7 @@ cp_parser_lambda_expression (cp_parser* parser) parser->fully_implicit_function_template_p = false; parser->implicit_template_parms = 0; parser->implicit_template_scope = 0; +parser->auto_is_implicit_function_template_parm_p = false; /* By virtue of defining a local class, a lambda expression has access to the private variables of enclosing classes. */ @@ -8774,6 +8777,8 @@ cp_parser_lambda_expression (cp_parser* parser) = fully_implicit_function_template_p; parser->implicit_template_parms = implicit_template_parms; parser->implicit_template_scope = implicit_template_scope; +parser->auto_is_implicit_function_template_parm_p + = auto_is_implicit_function_template_parm_p; } pop_deferring_access_checks (); diff --git a/gcc/testsuite/g++.dg/cpp1y/pr59629.C b/gcc/testsuite/g++.dg/cpp1y/pr59629.C new file mode 100644 index 000..a0c9209 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr59629.C @@ -0,0 +1,7 @@ +// { dg-do compile } +// { dg-options "-std=c++1y" } + +// PR c++/59629 + +void foo(int i = []{ auto 0; }()); // { dg-error "expected|could not convert" } + -- 1.8.5.2
[PATCH] Fix PR c++/59638
* cp/parser.c (cp_parser_init_declarator): Undo fully implicit template parameter list when declarator is not a function. * g++.dg/cpp1y/pr59638.C: New testcase. --- gcc/cp/parser.c | 8 gcc/testsuite/g++.dg/cpp1y/pr59638.C | 16 2 files changed, 24 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr59638.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0e013b9..991588d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16784,6 +16784,14 @@ cp_parser_init_declarator (cp_parser* parser, warning (OPT_Wattributes, "attributes after parenthesized initializer ignored"); + /* Declarations involving function parameter lists containing implicit + template parameters will have been made into implicit templates. If they + do not turn out to be actual function declarations then finish the + template declaration here. */ + if (parser->fully_implicit_function_template_p) +if (!function_declarator_p (declarator)) + finish_fully_implicit_template (parser, /*member_decl_opt=*/0); + /* For an in-class declaration, use `grokfield' to create the declaration. */ if (member_p) diff --git a/gcc/testsuite/g++.dg/cpp1y/pr59638.C b/gcc/testsuite/g++.dg/cpp1y/pr59638.C new file mode 100644 index 000..cd9dcdf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr59638.C @@ -0,0 +1,16 @@ +// { dg-do compile } +// { dg-options "-std=gnu++1y" } + +// PR c++/59638 + + +void (*a)(auto); // { dg-error "template declaration" } + +void (*b)(auto) = 0; // { dg-error "template declaration" } + +typedef void (*f)(auto); // { dg-error "template declaration" } + +struct A +{ + int i; +}; -- 1.8.5.2
Re: [PATCH] Fix PR c++/59638
On 2014-01-06 14:36, Jason Merrill wrote: On 01/04/2014 04:54 AM, Adam Butcher wrote: + /* Declarations involving function parameter lists containing implicit + template parameters will have been made into implicit templates. If they + do not turn out to be actual function declarations then finish the + template declaration here. */ This will always be an error, right? Please mention that in the comment. OK with that change. Yes I think so. Will commit with this mod: diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 991588d..68f81b7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16784,10 +16784,11 @@ cp_parser_init_declarator (cp_parser* parser, warning (OPT_Wattributes, "attributes after parenthesized initializer ignored"); - /* Declarations involving function parameter lists containing implicit - template parameters will have been made into implicit templates. If they - do not turn out to be actual function declarations then finish the - template declaration here. */ + /* A non-template declaration involving a function parameter list containing + an implicit template parameter will have been made into a template. If it + turns out that the resulting declaration is not an actual function then + finish the template declaration here. An error message will already have + been issued. */ if (parser->fully_implicit_function_template_p) if (!function_declarator_p (declarator)) finish_fully_implicit_template (parser, /*member_decl_opt=*/0);
Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
On 2013-11-08 18:50, Jason Merrill wrote: On 10/31/2013 05:47 AM, Adam Butcher wrote: + become_template = true; + push_deferring_access_checks (dk_deferred); Why is this call here? I don't see anything in the rest of the function that would trigger an access check, or a matching pop. This is only in the 'fully implicit function template' case; and the matching pop is in finish_fully_implicit_template. It was in the original impl which was trying to do all the things that beginning and ending an explicit template parameter list did. Maybe this is unnecessary. I'll see if anything breaks if I remove it. + /* 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); Is this changing anything? I'm not sure if we need to copy the decl or if we can just reuse it, but either way we need to set the type of TEMPLATE_TYPE_DECL (t) to t. I think it (or at least one of the assignments) is necessary. It is derived from some similar code in tsubst. I'll have another look into it and add TREE_TYPE (TEMPLATE_TYPE_DECL (t)) = t also. What problem will be caused by not setting the latter; is it a consistency issue? I have not seen any probs in testing so far. + SET_TYPE_STRUCTURAL_EQUALITY (t); Why not TYPE_CANONICAL (t) = canonical_type_parameter (t); ? Only for the sake of not exposing this (currently static) function from pt.c (or moving the pack convert function into pt.c). My original impl did extern canonical_type_parameter and use that and I think it worked as expected. Would that be preferred? Cheers, Adam
Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
On 2013-11-09 13:21, Adam Butcher wrote: On 2013-11-08 18:50, Jason Merrill wrote: On 10/31/2013 05:47 AM, Adam Butcher wrote: + become_template = true; + push_deferring_access_checks (dk_deferred); Why is this call here? I don't see anything in the rest of the function that would trigger an access check, or a matching pop. This is only in the 'fully implicit function template' case; and the matching pop is in finish_fully_implicit_template. It was in the original impl which was trying to do all the things that beginning and ending an explicit template parameter list did. Maybe this is unnecessary. I'll see if anything breaks if I remove it. + /* 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); Is this changing anything? I'm not sure if we need to copy the decl or if we can just reuse it, but either way we need to set the type of TEMPLATE_TYPE_DECL (t) to t. I think it (or at least one of the assignments) is necessary. It is derived from some similar code in tsubst. I'll have another look into it and add TREE_TYPE (TEMPLATE_TYPE_DECL (t)) = t also. What problem will be caused by not setting the latter; is it a consistency issue? I have not seen any probs in testing so far. + SET_TYPE_STRUCTURAL_EQUALITY (t); Why not TYPE_CANONICAL (t) = canonical_type_parameter (t); ? Only for the sake of not exposing this (currently static) function from pt.c (or moving the pack convert function into pt.c). My original impl did extern canonical_type_parameter and use that and I think it worked as expected. Would that be preferred? The following update appears to work. Cheers, Adam diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index be799a0..aba4a09 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -31270,8 +31270,6 @@ synthesize_implicit_template_parm (cp_parser *parser) become_template = true; - push_deferring_access_checks (dk_deferred); - parser->implicit_template_scope = begin_scope (sk_template_parms, NULL); @@ -31362,10 +31360,12 @@ convert_generic_types_to_packs (tree parm, parameter. */ tree t = copy_type (TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i; + TREE_TYPE (TEMPLATE_TYPE_DECL (t)) = t; 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); + extern tree canonical_type_parameter (tree); + TYPE_CANONICAL (t) = canonical_type_parameter (t); TREE_VEC_ELT (replacement, i) = t; } @@ -31406,7 +31406,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 (); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8c1553f..d3047cb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3546,7 +3546,7 @@ build_template_parm_index (int index, parameter. Returns the canonical type parameter, which may be TYPE if no such parameter existed. */ -static tree +tree canonical_type_parameter (tree type) { tree list;
Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
On 2013-11-10 6:10, Jason Merrill wrote: Hmm, actually I think messing with the non-pack's decl is dangerous, and we should come up with a new decl for the pack instead. I think you can use reduce_template_parm_level with a "levels" argument of 0 to build a new decl and parm index. I actually did this in one of my experiments and it worked fine. Although I also had to update the template parm list with new decl: TREE_VALUE (TREE_VEC_ELT (current, i)) = TREE_CHAIN (t); At that point I had the convert function in pt.c an operating directly on current_template_parms (also having direct access to the two statics required; reduce_template_parm_level and canonical_type_parameter). I can't think of a case where we'd want to make this substitution in anything but the current_template_parms so maybe moving the convert function back into to pt.c and removing the 'current' parm from it might be best? And if we're doing that, setting TYPE_STUB_DECL and TYPE_NAME is indeed necessary. Only for the sake of not exposing this (currently static) function from pt.c (or moving the pack convert function into pt.c). My original impl did extern canonical_type_parameter and use that and I think it worked as expected. Would that be preferred? Yes. Please declare it in cp-tree.h rather than within the function. Will do. Unless, as suggested above, we go for moving convert_generic_types_to_packs into pt.c in which case exposing these internals won't be necessary. Cheers, Adam
Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
On 2013-11-10 10:38, Adam Butcher wrote: On 2013-11-10 6:10, Jason Merrill wrote: Hmm, actually I think messing with the non-pack's decl is dangerous, and we should come up with a new decl for the pack instead. I think you can use reduce_template_parm_level with a "levels" argument of 0 to build a new decl and parm index. I actually did this in one of my experiments and it worked fine. Although I also had to update the template parm list with new decl: TREE_VALUE (TREE_VEC_ELT (current, i)) = TREE_CHAIN (t); At that point I had the convert function in pt.c an operating directly on current_template_parms (also having direct access to the two statics required; reduce_template_parm_level and canonical_type_parameter). I can't think of a case where we'd want to make this substitution in anything but the current_template_parms so maybe moving the convert function back into to pt.c and removing the 'current' parm from it might be best? And if we're doing that, setting TYPE_STUB_DECL and TYPE_NAME is indeed necessary. Only for the sake of not exposing this (currently static) function from pt.c (or moving the pack convert function into pt.c). My original impl did extern canonical_type_parameter and use that and I think it worked as expected. Would that be preferred? Yes. Please declare it in cp-tree.h rather than within the function. Will do. Unless, as suggested above, we go for moving convert_generic_types_to_packs into pt.c in which case exposing these internals won't be necessary. With the convert function in pt.c, PATCH 2/3 now looks as follows: Support implicit parameter packs. * pt.c (convert_generic_types_to_packs): New function to transform a range of implicitly introduced non-pack template parms to be parameter packs. * cp-tree.h (convert_generic_types_to_packs): Declare. * parser.c (cp_parser_parameter_declaration_list): If a function parameter pack contains generic types, convert them to packs prior to grokdeclarator. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fd79adb..e30922a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5469,6 +5469,7 @@ 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 convert_generic_types_to_packs (tree, int, int); extern tree splice_late_return_type (tree, tree); extern bool is_auto(const_tree); extern bool is_auto_or_concept (const_tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c48952a..eaad8e4 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18131,6 +18131,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, @@ -18142,11 +18146,29 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error) deprecated_state = DEPRECATED_SUPPRESS; if (parameter) + { + /* 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, + 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; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8c1553f..360d8a3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -21629,6 +21629,56 @@ append_type_to_template_for_access_check (tree templ, scope, location); } +/* Convert the generic type parameters in PARM that match the types given in the + range [START_IDX, END_IDX) from the current_template_parms into generic type + packs. */ + +tree +convert_generic_types_to_packs (tree parm, int start_idx, int end_idx) +{ + tree current = current_template_parms; + int depth = TMPL_PARMS_DEPTH (current); + current = INNERMOST_TEMPLATE_PARMS (current); + tree replacem
Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
On 2013-11-10 18:49, Jason Merrill wrote: On 11/10/2013 08:10 AM, Adam Butcher wrote: + /* Build up a tree vec of empty tree vecs up to the inner substitution +args built above. */ I think we want to copy the enclosing args; see existing uses of add_outermost_template_args. OK. I had that originally but I was concerned that it was wasteful which is why I ended up using nullptrs for non-subst'd types in the inner level and empty tree vecs for the prior levels. It seemed to work as expected; I assumed that tsubst simply doesn't do anything with a null tree substitution (i.e. it is an identity op). There will be an additional, seemingly unnecessary, cost of copying these and the loop above will presumably be required to set the non-subst'd types rather than leave them as nullptr also. Since we are tsubsting the declaration here and we only want to adjust the template parameter types themselves at their declaration is this really necessary? I've no problem with implementing this if it truly is necessary but I don't want to add unnecessary cycles if not. One other thing, by 'copy' I take it you mean copy the tree vecs of the enclosing levels only, not also the types within them. And I also assume that I'll need to set the currently unset types in the inner level also? Cheers Adam
Re: [C++ PATCH] Refactor implicit function template implementation and fix 58534, 58536, 58548, 58549 and 58637.
On 2013-11-10 23:21, Jason Merrill wrote: On 11/10/2013 02:39 PM, Adam Butcher wrote: I assumed that tsubst simply doesn't do anything with a null tree substitution (i.e. it is an identity op). Substituting NULL_TREE for a template parameter gives a template parameter with a reduced level; this happens during partial instantiation. Ah, OK. Since we are tsubsting the declaration here and we only want to adjust the template parameter types themselves at their declaration is this really necessary? I've no problem with implementing this if it truly is necessary but I don't want to add unnecessary cycles if not. The difference between setting copying a pointer to a vec versus setting it to null seems completely negligible to me. Sure. I was more concerned with allocating vecs for each outer list and copying the parms over versus allocating a 'null' placeholder list for each level which we're not concerned about. No worries though, I've proceeded with your suggestion below. I think it is necessary in case the function parameter type involves template parameters from the enclosing context as well as implicit template parameters. One other thing, by 'copy' I take it you mean copy the tree vecs of the enclosing levels only, not also the types within them. Yes, using add_outermost_template_args. I have done this (diff -w -b follows). The route to this seems even more costly though; current_template_parms needs to first be converted to a vec by current_template_args() then the last nesting level is thrown away and replaced with the one we're working on. It's all working but I'm wondering whether a custom loop here would be better. And I also assume that I'll need to set the currently unset types in the inner level also? Can you have explicit template parameters at the same level as the implicit ones? Yes. If so, then their places in the vec will need to be set appropriately in case they are used in the function parameter type. OK. I had testcases that appeared to pass OK with the previous NULL_TREE tsubst but maybe I wasn't checking something (perhaps a combination of an explicit template parm type and an auto in a single parm). End result is that everything looks OK though so we might be able to get the C++14 lambda support marked as "in 4.9" soon hopefully. Cheers, Adam diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 360d8a3..69c7688 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -21641,6 +21641,10 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx) current = INNERMOST_TEMPLATE_PARMS (current); tree replacement = make_tree_vec (TREE_VEC_LENGTH (current)); + for (int i = 0; i < start_idx; ++i) +TREE_VEC_ELT (replacement, i) + = TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i))); + for (int i = start_idx; i < end_idx; ++i) { /* Create a distinct parameter pack type from the current parm and add it @@ -21662,18 +21666,15 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx) TREE_VALUE (TREE_VEC_ELT (current, i)) = TREE_CHAIN (t); } + for (int i = end_idx, e = TREE_VEC_LENGTH (current); i < e; ++i) +TREE_VEC_ELT (replacement, i) + = TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (current, i))); + 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; -} +replacement = add_outermost_template_args (current_template_args (), + replacement); return tsubst (parm, replacement, tf_none, NULL_TREE); }
[PATCH] Fix c++/59112 and c++/59113: Disallow implicit function templates in local functions unless defining a lambda.
gcc/cp/ PR c++/59112 PR c++/59113 * parser.c (cp_parser_parameter_declaration_clause): Disallow implicit function templates in local functions unless defining a lambda. gcc/testsuite/ PR c++/59112 PR c++/59113 g++.dg/cpp1y/pr58533.C: Updated testcase. g++.dg/cpp1y/pr59112.C: New testcase. g++.dg/cpp1y/pr59113.C: New testcase. --- gcc/cp/parser.c | 4 +++- gcc/testsuite/g++.dg/cpp1y/pr58533.C | 2 +- gcc/testsuite/g++.dg/cpp1y/pr59112.C | 12 gcc/testsuite/g++.dg/cpp1y/pr59113.C | 11 +++ 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr59112.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr59113.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index eaad8e4..1a26811 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18026,7 +18026,9 @@ cp_parser_parameter_declaration_clause (cp_parser* parser) (void) cleanup; if (!processing_specialization) -parser->auto_is_implicit_function_template_parm_p = true; +if (!current_function_decl + || (current_class_type && LAMBDA_TYPE_P (current_class_type))) + parser->auto_is_implicit_function_template_parm_p = true; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58533.C b/gcc/testsuite/g++.dg/cpp1y/pr58533.C index e1855d7..9bcd771 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr58533.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr58533.C @@ -3,5 +3,5 @@ void foo() { - void (*fp)(auto); // { dg-error "template" } + void (*fp)(auto); // { dg-error "auto|not permitted" } } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr59112.C b/gcc/testsuite/g++.dg/cpp1y/pr59112.C new file mode 100644 index 000..e7326ac --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr59112.C @@ -0,0 +1,12 @@ +// { dg-do compile } +// { dg-options "-std=gnu++1y" } + +// PR c++/59112 + +void foo() +{ + struct A + { +A(auto) {} // { dg-error "auto|not permitted" } + }; +} diff --git a/gcc/testsuite/g++.dg/cpp1y/pr59113.C b/gcc/testsuite/g++.dg/cpp1y/pr59113.C new file mode 100644 index 000..f909a76 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr59113.C @@ -0,0 +1,11 @@ +// { dg-do compile } +// { dg-options "-std=gnu++1y" } + +// PR c++/59113 + +void foo() +{ + void bar(auto) {} // { dg-error "function-definition|auto|not permitted" } +} + +auto i = 0; -- 1.8.4
[PATCH] Fix PR c++/61537
* parser.c (cp_parser_elaborated_type_specifier): Only consider template parameter lists outside of function parameter scope. * g++.dg/cpp1y/pr61537.C: New testcase. --- gcc/cp/parser.c | 28 +++- gcc/testsuite/g++.dg/cpp1y/pr61537.C | 24 2 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr61537.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 41200a0..736d012 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -15081,6 +15081,15 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, return cp_parser_make_typename_type (parser, parser->scope, identifier, token->location); + + /* Template parameter lists apply only if we are not within a +function parameter list. */ + bool template_parm_lists_apply + = parser->num_template_parameter_lists; + for (cp_binding_level *s = current_binding_level; s; s = s->level_chain) + if (s->kind == sk_function_parms) + template_parm_lists_apply = false; + /* Look up a qualified name in the usual way. */ if (parser->scope) { @@ -15123,7 +15132,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, decl = (cp_parser_maybe_treat_template_as_class (decl, /*tag_name_p=*/is_friend -&& parser->num_template_parameter_lists)); +&& template_parm_lists_apply)); if (TREE_CODE (decl) != TYPE_DECL) { @@ -15136,9 +15145,9 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, if (TREE_CODE (TREE_TYPE (decl)) != TYPENAME_TYPE) { - bool allow_template = (parser->num_template_parameter_lists - || DECL_SELF_REFERENCE_P (decl)); - type = check_elaborated_type_specifier (tag_type, decl, + bool allow_template = (template_parm_lists_apply +|| DECL_SELF_REFERENCE_P (decl)); + type = check_elaborated_type_specifier (tag_type, decl, allow_template); if (type == error_mark_node) @@ -15224,15 +15233,16 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, ts = ts_global; template_p = - (parser->num_template_parameter_lists + (template_parm_lists_apply && (cp_parser_next_token_starts_class_definition_p (parser) || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))); /* An unqualified name was used to reference this type, so there were no qualifying templates. */ - if (!cp_parser_check_template_parameters (parser, - /*num_templates=*/0, - token->location, - /*declarator=*/NULL)) + if (template_parm_lists_apply + && !cp_parser_check_template_parameters (parser, + /*num_templates=*/0, + token->location, + /*declarator=*/NULL)) return error_mark_node; type = xref_tag (tag_type, identifier, ts, template_p); } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr61537.C b/gcc/testsuite/g++.dg/cpp1y/pr61537.C new file mode 100644 index 000..55761cd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr61537.C @@ -0,0 +1,24 @@ +// PR c++/61537 +// { dg-do compile { target c++1y } } +// { dg-options "" } + +struct A {}; + +template +struct B +{ + template + void f(U, struct A); +}; + +template +template +void B::f(U, struct A) +{ +} + +int main() +{ + B b; + b.f(42, A()); +} -- 2.0.0
Re: [PATCH] Fix PR c++/61537
On 2014-06-24 23:22, Paolo Carlini wrote: On 06/24/2014 01:40 AM, Adam Butcher wrote: +// { dg-do compile { target c++1y } } I don't think this is a C++1y specific issue... You're right. I'm so used to creating pr testcases in that g++.dg/cpp1y dir, I automatically added the test there without engaging my brain! +// { dg-options "" } Also, likely minor detail, could you please explain why you need this? Don't think I do; it was a copy from the most recent test in the cpp1y dir (another bad habit). Same issue as before; need to engage brain. :) I've fixed these issues up in my tree and moved the test to g++.dg. Cheers, Adam diff --git a/gcc/testsuite/g++.dg/cpp1y/pr61537.C b/gcc/testsuite/g++.dg/pr61537.C similarity index 79% rename from gcc/testsuite/g++.dg/cpp1y/pr61537.C rename to gcc/testsuite/g++.dg/pr61537.C index 55761cd..12aaf58 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr61537.C +++ b/gcc/testsuite/g++.dg/pr61537.C @@ -1,6 +1,5 @@ // PR c++/61537 -// { dg-do compile { target c++1y } } -// { dg-options "" } +// { dg-do compile } struct A {};
Re: [PATCH] Fix PR c++/61537
* parser.c (cp_parser_elaborated_type_specifier): Only consider template parameter lists outside of function parameter scope. * g++.dg/template/pr61537.C: New testcase. --- gcc/cp/parser.c | 31 ++- gcc/testsuite/g++.dg/template/pr61537.C | 23 +++ 2 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/pr61537.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 41200a0..c440c99 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -15081,6 +15081,18 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, return cp_parser_make_typename_type (parser, parser->scope, identifier, token->location); + + /* Template parameter lists apply only if we are not within a +function parameter list. */ + bool template_parm_lists_apply + = parser->num_template_parameter_lists; + if (template_parm_lists_apply) + for (cp_binding_level *s = current_binding_level; +s && s->kind != sk_template_parms; +s = s->level_chain) + if (s->kind == sk_function_parms) + template_parm_lists_apply = false; + /* Look up a qualified name in the usual way. */ if (parser->scope) { @@ -15123,7 +15135,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, decl = (cp_parser_maybe_treat_template_as_class (decl, /*tag_name_p=*/is_friend -&& parser->num_template_parameter_lists)); +&& template_parm_lists_apply)); if (TREE_CODE (decl) != TYPE_DECL) { @@ -15136,9 +15148,9 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, if (TREE_CODE (TREE_TYPE (decl)) != TYPENAME_TYPE) { - bool allow_template = (parser->num_template_parameter_lists - || DECL_SELF_REFERENCE_P (decl)); - type = check_elaborated_type_specifier (tag_type, decl, + bool allow_template = (template_parm_lists_apply +|| DECL_SELF_REFERENCE_P (decl)); + type = check_elaborated_type_specifier (tag_type, decl, allow_template); if (type == error_mark_node) @@ -15224,15 +15236,16 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, ts = ts_global; template_p = - (parser->num_template_parameter_lists + (template_parm_lists_apply && (cp_parser_next_token_starts_class_definition_p (parser) || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))); /* An unqualified name was used to reference this type, so there were no qualifying templates. */ - if (!cp_parser_check_template_parameters (parser, - /*num_templates=*/0, - token->location, - /*declarator=*/NULL)) + if (template_parm_lists_apply + && !cp_parser_check_template_parameters (parser, + /*num_templates=*/0, + token->location, + /*declarator=*/NULL)) return error_mark_node; type = xref_tag (tag_type, identifier, ts, template_p); } diff --git a/gcc/testsuite/g++.dg/template/pr61537.C b/gcc/testsuite/g++.dg/template/pr61537.C new file mode 100644 index 000..12aaf58 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/pr61537.C @@ -0,0 +1,23 @@ +// PR c++/61537 +// { dg-do compile } + +struct A {}; + +template +struct B +{ + template + void f(U, struct A); +}; + +template +template +void B::f(U, struct A) +{ +} + +int main() +{ + B b; + b.f(42, A()); +} -- 2.0.0
Re: [PATCH] Fix PR c++/61537
On 2014-06-25 21:57, Jason Merrill wrote: OK, thanks. Do you want me to apply to 4.9 too?
Re: [PATCH 1/2] PR c++/61636
On 2015-04-17 20:58, Jason Merrill wrote: On 04/09/2015 11:31 PM, Adam Butcher wrote: + /* For generic lambdas, resolve default captured 'this' now. */ This isn't quite right. We don't want to capture 'this' any time we see a member function call, as overload resolution might choose a static member function that doesn't need 'this'. The special handling we want is for the case where the call depends on a generic lambda parameter, in which case we capture 'this' because the call "names [this] in a potentially-evaluated expression (3.2) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression." Good point. I'll look into it. So for a nullary member call we will always capture 'this', but for N-ary, we only capture if we find one of the lambda's parameters (or a parameter from an enclosing generic lambda?) in the call's arguments right? Cheers, Adam
Re: [PATCH 1/2] PR c++/61636
On 2015-04-17 22:06, Adam Butcher wrote: On 2015-04-17 20:58, Jason Merrill wrote: On 04/09/2015 11:31 PM, Adam Butcher wrote: + /* For generic lambdas, resolve default captured 'this' now. */ This isn't quite right. We don't want to capture 'this' any time we see a member function call, as overload resolution might choose a static member function that doesn't need 'this'. The special handling we want is for the case where the call depends on a generic lambda parameter, in which case we capture 'this' because the call "names [this] in a potentially-evaluated expression (3.2) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression." Good point. I'll look into it. So for a nullary member call we will always capture 'this', but for N-ary, we only capture if we find one of the lambda's parameters (or a parameter from an enclosing generic lambda?) in the call's arguments right? Test like this? /* { dg-do run { target c++14 } } */ /* { dg-final { scan-assembler-not "..." } } */ struct X { int f (int, double) { return 255; } static int f (int, int) { return 65535; } auto m1 () { return [=] (auto a) { return f (7, a); }; } auto m2 () { return [=] (auto a) { return f (9, 10) + a; }; } }; #include int main() { X x; assert (x.m1 () (42.0) == 255); assert (x.m1 () (42) == 65535); assert (x.m2 () (42.0) == (65535 + 42)); assert (x.m2 () (42) == (65535 + 42)); assert (sizeof x.m2 () < sizeof x.m1 ()); }
Re: [PATCH 1/2] PR c++/61636
On 2015-04-18 18:53, Adam Butcher wrote: Test like this? /* { dg-do run { target c++14 } } */ /* { dg-final { scan-assembler-not "..." } } */ struct X { int f (int, double) { return 255; } static int f (int, int) { return 65535; } auto m1 () { return [=] (auto a) { return f (7, a); }; } auto m2 () { return [=] (auto a) { return f (9, 10) + a; }; } And this: auto m3 () { return [=] (auto a) { return f (11, 12.0) + a; }; } Currently we don't capture 'this' here despite the call not being dependent on any lambda parameter and resolving to a non-static member function. I think I need to resolve a member call within a generic lambda as if it were not in template context to determine whether it unambiguously resolves to a static member function. If it does, then no capture required. Otherwise, 'this' should be captured because either a) the call is to a non-static member function without any dependent parameters or b) because it may resolve to a non-static member function at callop instantiate time. No sure whether I can do all this at my current patch site in cp_parser_postfix_expression or whether it needs to be later. Adam
Re: [PATCH 1/2] ?PR c++/61636
On 2015-04-20 11:25, Marek Polacek wrote: On Sat, Apr 18, 2015 at 06:53:28PM +0100, Adam Butcher wrote: Test like this? /* { dg-do run { target c++14 } } */ /* { dg-final { scan-assembler-not "..." } } */ What is this dg-final supposed to do here? It was a placeholder for making sure that, once fixed, the lambda depending on only the static member function does not capture 'this'. I didn't get around to seeing whether that was possible from the asm output and if it were, what symbol I should check for the absence of. For now I have sizeof assertions but I suppose I could use an sfinae test for existence (or otherwise in this case) of the placeholder '__this'.
[PATCH 1/2] PR c++/61636 * cp/parser.c (cp_parser_postfix_expression): Resolve default captured 'this' early for generic lambdas.
PR c++/61636 * g++.dg/cpp1y/pr61636.C: New test. --- gcc/cp/parser.c | 16 gcc/testsuite/g++.dg/cpp1y/pr61636.C | 19 +++ 2 files changed, 35 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr61636.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4d6b479..ac91976 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -6321,6 +6321,22 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, tree instance = TREE_OPERAND (postfix_expression, 0); tree fn = TREE_OPERAND (postfix_expression, 1); + /* For generic lambdas, resolve default captured 'this' now. */ + if (processing_template_decl + && is_dummy_object (instance) + && current_class_type + && CLASSTYPE_LAMBDA_EXPR (current_class_type)) + if (tree callop = lambda_function (current_class_type)) + if (DECL_TEMPLATE_INFO (callop) + && (DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) + == callop) + && TREE_TYPE (instance) != current_class_type + && DERIVED_FROM_P (TREE_TYPE (instance), + current_nonlambda_class_type ())) + TREE_OPERAND (postfix_expression, 0) + = instance + = maybe_resolve_dummy (instance, true); + if (processing_template_decl && (type_dependent_expression_p (instance) || (!BASELINK_P (fn) diff --git a/gcc/testsuite/g++.dg/cpp1y/pr61636.C b/gcc/testsuite/g++.dg/cpp1y/pr61636.C new file mode 100644 index 000..5694675 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr61636.C @@ -0,0 +1,19 @@ +// PR c++/61636 +// { dg-do compile { target c++1y } } + +struct X +{ + void f(int) {} + + auto defer_f() + { + return [&] (auto x) { + return f(x); + }; + } +}; + +int main() +{ + X().defer_f()(2); +} -- 2.3.5
[PATCH 2/2] PR c++/64382 * cp/parser.c (parsing_default_capturing_generic_lambda_in_template): New function. * cp/cp-tree.h: Declare it. * cp/semantics.c (finish_id_expression): Resolve names wit
PR c++/64382 * g++.dg/cpp1y/pr64382.C: New test. --- gcc/cp/cp-tree.h | 1 + gcc/cp/parser.c | 21 + gcc/cp/semantics.c | 8 +--- gcc/testsuite/g++.dg/cpp1y/pr64382.C | 23 +++ 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr64382.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2a904a5..484f352 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5645,6 +5645,7 @@ extern bool maybe_clone_body (tree); /* In parser.c */ extern tree cp_convert_range_for (tree, tree, tree, bool); extern bool parsing_nsdmi (void); +extern bool parsing_default_capturing_generic_lambda_in_template (void); extern void inject_this_parameter (tree, cp_cv_quals); /* in pt.c */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ac91976..74b55df 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18339,6 +18339,27 @@ parsing_nsdmi (void) return false; } +/* Return true iff our current scope is a default capturing generic lambda + defined within a template. */ + +bool +parsing_default_capturing_generic_lambda_in_template (void) +{ + if (processing_template_decl && current_class_type) +if (tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type)) + if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE) + if (tree callop = lambda_function (lam)) + if (DECL_TEMPLATE_INFO (callop) + && (DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) + == callop) + && ((current_nonlambda_class_type () + && CLASSTYPE_TEMPLATE_INFO (current_nonlambda_class_type ())) + || ((current_nonlambda_function () + && DECL_TEMPLATE_INFO (current_nonlambda_function ()) + return true; + return false; +} + /* Parse a late-specified return type, if any. This is not a separate non-terminal, but part of a function declarator, which looks like diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 74af7e8..f1ab183 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3450,9 +3450,11 @@ finish_id_expression (tree id_expression, } } - /* If the name was dependent on a template parameter, we will -resolve the name at instantiation time. */ - if (dependent_p) + /* If the name was dependent on a template parameter and we're not in a +default capturing generic lambda within a template, we will resolve the +name at instantiation time. */ + if (dependent_p + && !parsing_default_capturing_generic_lambda_in_template ()) { /* Create a SCOPE_REF for qualified names, if the scope is dependent. */ diff --git a/gcc/testsuite/g++.dg/cpp1y/pr64382.C b/gcc/testsuite/g++.dg/cpp1y/pr64382.C new file mode 100644 index 000..ff552ac --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr64382.C @@ -0,0 +1,23 @@ +// PR c++/64382 +// { dg-do compile { target c++1y } } + +template +struct my_queue +{ + void push(T) + { + } + void ice() + { +auto L = [=](auto &&v) { + push(v); +}; +trav(L); + } + template + void trav(F &&f) + { +f(T()); + } +}; +template struct my_queue; -- 2.3.5
[PATCH] [PR c++/61636 and c++/64382] Fix default capture in generic lambdas
Hi Jason, I finally scraped some time together to look into these two generic lambda default capture bugs and believe I have a solution. Still have to run tests but I thought I'd get these out for your perusal whilst I rebase onto origin/master and run the testsuite. Cheers, Adam
Re: [PATCH 2/2] PR c++/64382 * cp/parser.c (parsing_default_capturing_generic_lambda_in_template): New function. * cp/cp-tree.h: Declare it. * cp/semantics.c (finish_id_expression): Resolve names
On 2015-04-14 8:26, Jakub Jelinek wrote: I'd say best would be to just use separate ifs with return false. Done.
Re: [PATCH 2/2] PR c++/64382 * cp/parser.c (parsing_default_capturing_generic_lambda_in_template)...
On 2015-04-10 4:31, Adam Butcher wrote: +parsing_default_capturing_generic_lambda_in_template (void) I'm wondering whether we should cache this as a bool on the parser. Currently it is called once per id-expression and will always return the same result for any given lambda.
[PATCH] PR c++/65750
* cp/parser.c (cp_parser_simple_type_specifier): Don't synthesize implicit template parm if 'auto' is a placeholder for trailing return type. --- gcc/cp/parser.c | 23 +++ gcc/testsuite/g++.dg/cpp1y/pr65750.C | 12 2 files changed, 35 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr65750.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4611be9..511ec85 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -14949,6 +14949,29 @@ cp_parser_simple_type_specifier (cp_parser* parser, maybe_warn_cpp0x (CPP0X_AUTO); if (parser->auto_is_implicit_function_template_parm_p) { + /* The 'auto' might be the placeholder return type for a function decl +with trailing return type. */ + bool have_trailing_return_fn_decl = false; + if (cp_lexer_peek_nth_token (parser->lexer, 2)->type + == CPP_OPEN_PAREN) + { + cp_parser_parse_tentatively (parser); + cp_lexer_consume_token (parser->lexer); + if (cp_parser_skip_to_closing_parenthesis (parser, +/*recovering*/false, +/*or_comma*/false, +/*consume_paren*/true)) + have_trailing_return_fn_decl + = cp_lexer_next_token_is (parser->lexer, CPP_DEREF); + cp_parser_abort_tentative_parse (parser); + } + + if (have_trailing_return_fn_decl) + { + type = make_auto (); + break; + } + if (cxx_dialect >= cxx14) type = synthesize_implicit_template_parm (parser); else diff --git a/gcc/testsuite/g++.dg/cpp1y/pr65750.C b/gcc/testsuite/g++.dg/cpp1y/pr65750.C new file mode 100644 index 000..798d13b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr65750.C @@ -0,0 +1,12 @@ +// PR c++/65750 +// { dg-do compile { target c++14 } } + +template struct F { }; + +class a +{ + virtual auto f( F< void () > ) -> void; + virtual auto g( F< auto () -> void > ) -> void; +}; + +auto main() -> int { } -- 2.3.5
Re: [PATCH] PR c++/65750
On 2015-04-10 15:57, Adam Butcher wrote: + cp_lexer_consume_token (parser->lexer); Actually there should be two of these as the 'auto' isn't consumed yet.
Re: [C++ Patch] Remove is_auto_or_concept, etc
Sorry for not getting back to your original post Paolo. I haven't been picking up mails for a while. On 2017-05-01 16:56, Jason Merrill wrote: On Thu, Apr 27, 2017 at 2:02 PM, Paolo Carlini wrote: On 26/04/2017 12:32, Paolo Carlini wrote: in 2013 (2013-09-16) Adam added two slightly obscure functions and I can't find much around in terms of rationale, etc: is_auto_or_concept (const_tree type) type_uses_auto_or_concept (tree type) I don't think they were there in the original 2009 version on the old lambdas branch -- but it stagnated somewhat and when I remade it against mainline (4.something) it was around the time that concepts were showing similar semantics (in terms of implicit/abbrievated templates). I made a cardinal sin and introduced an overly-generic function name expecting that a future concepts implementation would need to trigger at the same point of the parse too. I.e. if a concept name or 'auto' is seen we inject an implicit template parameter (or make the "plain" function into a template at that point). That intent was not well documented or published (other than in the API name) and, since -fconcepts is now working without any calls to this function, it's clearly not been necessary or has been more naturally done in a different way. The latter seems completely unused (it's meant for debugging purposes?); Quite possibly for debugging though maybe some refactoring got rid of the need for it and neglected to bin it. the former evidently simply forwards to is_auto, and we end up in the front-end with uses of both, which in fact are equivalent, which seems weird: IMHO, if they are actually equivalent in our implementation we should clearly explain that in the comment and have only one. Or what? ... replying to myself, in practice we could do the below, which certainly passes testing, and in fact now seems to me even more obvious than I thought a couple of days ago... Definitely OK to bin. No point in having dead or confusing code; it's complicated enough as it is. :)
[PATCH] Fix PR c++/64382
Hi Jason, I've reopened 64382 and unhooked it from 61636 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64382#c6). This is a rebase of my original patch for 64382 from April 2015 against latest master. My query about caching parsing_default_capturing_generic_lambda_in_template() still applies. It is currently called once for each id-expression that is dependent but its result will be consistent within a particular lambda body. It feels like we should compute the state once when entering a lambda body and refer to the cached state thereafter (resetting/restoring it on descent/return from each lambda we come across). Cheers, Adam PR c++/64382 * cp/parser.c (parsing_default_capturing_generic_lambda_in_template): New function. * cp/cp-tree.h: Declare it. * cp/semantics.c (finish_id_expression): Resolve names within a default capturing generic lambda defined within a template prior to instantiation to allow for captures to be added to the closure type. PR c++/64382 * g++.dg/cpp1y/pr64382.C: New test. --- gcc/cp/cp-tree.h | 1 + gcc/cp/parser.c | 25 + gcc/cp/semantics.c | 8 +--- gcc/testsuite/g++.dg/cpp1y/pr64382.C | 23 +++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr64382.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9c4436710dd..77d20d4d3dc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6110,6 +6110,7 @@ extern bool maybe_clone_body (tree); /* In parser.c */ extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool); extern bool parsing_nsdmi (void); +extern bool parsing_default_capturing_generic_lambda_in_template (void); extern void inject_this_parameter (tree, cp_cv_quals); /* in pt.c */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 29dcfea283f..5cc0ddacc2b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -20450,6 +20450,31 @@ parsing_nsdmi (void) return false; } +/* Return true iff our current scope is a default capturing generic lambda + defined within a template. */ + +bool +parsing_default_capturing_generic_lambda_in_template (void) +{ + if (!processing_template_decl || !current_class_type) +return false; + + tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type); + if (!lam || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE) +return false; + + tree callop = lambda_function (lam); + if (!callop) +return false; + + return (DECL_TEMPLATE_INFO (callop) + && (DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop) + && ((current_nonlambda_class_type () + && CLASSTYPE_TEMPLATE_INFO (current_nonlambda_class_type ())) + || ((current_nonlambda_function () + && DECL_TEMPLATE_INFO (current_nonlambda_function ()); +} + /* Parse a late-specified return type, if any. This is not a separate non-terminal, but part of a function declarator, which looks like diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 42024755e4f..3c0bd7e751c 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3562,9 +3562,11 @@ finish_id_expression (tree id_expression, ? CP_ID_KIND_UNQUALIFIED_DEPENDENT : CP_ID_KIND_UNQUALIFIED))); - /* If the name was dependent on a template parameter, we will -resolve the name at instantiation time. */ - if (dependent_p) + /* If the name was dependent on a template parameter and we're not in a +default capturing generic lambda within a template, we will resolve the +name at instantiation time. */ + if (dependent_p + && !parsing_default_capturing_generic_lambda_in_template ()) { if (DECL_P (decl) && any_dependent_type_attributes_p (DECL_ATTRIBUTES (decl))) diff --git a/gcc/testsuite/g++.dg/cpp1y/pr64382.C b/gcc/testsuite/g++.dg/cpp1y/pr64382.C new file mode 100644 index 000..8f2e931e048 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr64382.C @@ -0,0 +1,23 @@ +// PR c++/64382 +// { dg-do compile { target c++14 } } + +template +struct my_queue +{ + void push(T) + { + } + void ice() + { +auto L = [=](auto &&v) { + push(v); +}; +trav(L); + } + template + void trav(F &&f) + { +f(T()); + } +}; +template struct my_queue; -- 2.11.0