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);
+}

Reply via email to