https://gcc.gnu.org/g:5f39aa74f2217e04d2868f2110523b2a0ed41165
commit r16-6277-g5f39aa74f2217e04d2868f2110523b2a0ed41165 Author: Jason Merrill <[email protected]> Date: Fri Dec 19 15:20:13 2025 +0700 c++: lambda template arg in abbreviated template [PR117034] A lambda used as a non-type template argument to a type-constraint in the first parameter of an abbreviated function template was wrapped in a TARGET_EXPR because we hadn't opened the implicit template scope yet. After r16-5115 changed convert_template_argument to call instantiate_non_dependent_expr_internal on non-dependent expressions, these TARGET_EXPRs began hitting the default case in tsubst_expr, causing an ICE. So let's enter implicit template scope as soon as we see the concept-name; at that point we know we're declaring an abbreviated template. PR c++/117034 gcc/cp/ChangeLog: * parser.cc (maybe_start_implicit_template): Split out from... (synthesize_implicit_template_parm): ...here. (cp_parser_template_id): Call it. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-template-pr117034.C: New test. Co-authored-by: Egas Ribeiro <[email protected]> Diff: --- gcc/cp/parser.cc | 104 +++++++++++---------- .../g++.dg/cpp2a/lambda-template-pr117034.C | 12 +++ 2 files changed, 66 insertions(+), 50 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 89d2b9e692f2..b3bf0703d3d2 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -277,6 +277,7 @@ static tree omp_start_variant_function (cp_declarator *, tree); static int omp_finish_variant_function (cp_parser *, tree, tree, tree, bool, bool); +static void maybe_start_implicit_template (cp_parser *parser); /* Manifest constants. */ #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token)) @@ -20293,6 +20294,13 @@ cp_parser_template_id (cp_parser *parser, if (templ == error_mark_node || is_identifier) return templ; + /* If we see a concept name in a parameter-list, it's a type-constraint in an + abbreviated function template, so enter template scope before parsing the + template arguments. */ + if (parser->auto_is_implicit_function_template_parm_p + && concept_definition_p (templ)) + maybe_start_implicit_template (parser); + /* Since we're going to preserve any side-effects from this parse, set up a firewall to protect our callers from cp_parser_commit_to_tentative_parse in the template arguments. */ @@ -56323,38 +56331,14 @@ make_generic_type_name () return get_identifier (buf); } -/* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS - (creating a new template parameter list if necessary). Returns the newly - created template type parm. */ +/* We're declaring an abbreviated function template, make sure that + parser->implicit_template_scope is set. */ -static tree -synthesize_implicit_template_parm (cp_parser *parser, tree constr) +static void +maybe_start_implicit_template (cp_parser *parser) { - /* A requires-clause is not a function and cannot have placeholders. */ - if (current_binding_level->requires_expression) - { - error ("placeholder type not allowed in this context"); - return error_mark_node; - } - - gcc_assert (current_binding_level->kind == sk_function_parms); - - /* We are either continuing a function template that already contains implicit - template parameters, creating a new fully-implicit function template, or - extending an existing explicit function template with implicit template - parameters. */ - - cp_binding_level *const entry_scope = current_binding_level; - - bool become_template = false; - cp_binding_level *parent_scope = 0; - if (parser->implicit_template_scope) - { - gcc_assert (parser->implicit_template_parms); - - current_binding_level = parser->implicit_template_scope; - } + return; else { /* Roll back to the existing template parameter scope (in the case of @@ -56363,7 +56347,9 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) in the case of out-of-line member definitions). The function scope is added back after template parameter synthesis below. */ + cp_binding_level *const entry_scope = current_binding_level; cp_binding_level *scope = entry_scope; + cp_binding_level *parent_scope = nullptr; while (scope->kind == sk_function_parms) { @@ -56416,8 +56402,6 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) /* Introduce a new template parameter list for implicit template parameters. */ - become_template = true; - parser->implicit_template_scope = begin_scope (sk_template_parms, NULL); @@ -56425,6 +56409,12 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) parser->fully_implicit_function_template_p = true; ++parser->num_template_parameter_lists; + + parent_scope->level_chain = current_binding_level; + + current_template_parms + = tree_cons (size_int (current_template_depth + 1), + make_tree_vec (0), current_template_parms); } else { @@ -56439,7 +56429,36 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) parser->implicit_template_parms = TREE_VEC_ELT (v, TREE_VEC_LENGTH (v) - 1); } + + current_binding_level = entry_scope; } +} + +/* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS + (creating a new template parameter list if necessary). Returns the newly + created template type parm. */ + +static tree +synthesize_implicit_template_parm (cp_parser *parser, tree constr) +{ + /* A requires-clause is not a function and cannot have placeholders. */ + if (current_binding_level->requires_expression) + { + error ("placeholder type not allowed in this context"); + return error_mark_node; + } + + gcc_assert (current_binding_level->kind == sk_function_parms); + + /* We are either continuing a function template that already contains implicit + template parameters, creating a new fully-implicit function template, or + extending an existing explicit function template with implicit template + parameters. */ + + cp_binding_level *const entry_scope = current_binding_level; + + maybe_start_implicit_template (parser); + current_binding_level = parser->implicit_template_scope; /* Synthesize a new template parameter and track the current template parameter chain with implicit_template_parms. */ @@ -56452,10 +56471,6 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) gcc_assert(!proto || TREE_CODE (proto) == TYPE_DECL); tree synth_tmpl_parm = finish_template_type_parm (class_type_node, synth_id); - if (become_template) - current_template_parms = tree_cons (size_int (current_template_depth + 1), - NULL_TREE, current_template_parms); - /* Attach the constraint to the parm before processing. */ tree node = build_tree_list (NULL_TREE, synth_tmpl_parm); TREE_TYPE (node) = constr; @@ -56495,21 +56510,10 @@ synthesize_implicit_template_parm (cp_parser *parser, tree constr) template parameter list with this synthesized type, otherwise grow the current template parameter list. */ - if (become_template) - { - parent_scope->level_chain = current_binding_level; - - tree new_parms = make_tree_vec (1); - TREE_VEC_ELT (new_parms, 0) = parser->implicit_template_parms; - TREE_VALUE (current_template_parms) = new_parms; - } - else - { - tree& new_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms); - int new_parm_idx = TREE_VEC_LENGTH (new_parms); - new_parms = grow_tree_vec (new_parms, new_parm_idx + 1); - TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms; - } + tree& new_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms); + int new_parm_idx = TREE_VEC_LENGTH (new_parms); + new_parms = grow_tree_vec (new_parms, new_parm_idx + 1); + TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms; /* If the new parameter was constrained, we need to add that to the constraints in the template parameter list. */ diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-template-pr117034.C b/gcc/testsuite/g++.dg/cpp2a/lambda-template-pr117034.C new file mode 100644 index 000000000000..842e2dcffec2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-template-pr117034.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++20 } } +// PR c++/117034 + +template<typename, auto> +concept A = true; + +void f(A<[] {}> auto) {} + +int main() +{ + f(42); +}
