PR c++/82514 - ICE with local class in generic lambda.
authorJason Merrill <jason@redhat.com>
Fri, 26 Jan 2018 15:25:23 +0000 (10:25 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 26 Jan 2018 15:25:23 +0000 (10:25 -0500)
* pt.c (regenerated_lambda_fn_p): Remove.
(enclosing_instantiation_of): Don't use it.
(tsubst_function_decl): Call enclosing_instantiation_of.

* pt.c (lookup_template_class_1): Add sanity check.
* name-lookup.c (do_pushtag): Don't add closures to local_classes.

From-SVN: r257093

gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1y/lambda-generic-nested2.C [new file with mode: 0644]

index bea42736cfa9b4c394e972e04ca54bc7863f98b3..fd3ff717403d0cb7c6a3516789631e4007863965 100644 (file)
@@ -1,3 +1,13 @@
+2018-01-26  Jason Merrill  <jason@redhat.com>
+
+       PR c++/82514 - ICE with local class in generic lambda.
+       * pt.c (regenerated_lambda_fn_p): Remove.
+       (enclosing_instantiation_of): Don't use it.
+       (tsubst_function_decl): Call enclosing_instantiation_of.
+
+       * pt.c (lookup_template_class_1): Add sanity check.
+       * name-lookup.c (do_pushtag): Don't add closures to local_classes.
+
 2018-01-25  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/84031
index c37e52283e4cfa1938de694fa020042b6f6ce851..d0488c0a17e96dad7728c423bdc343253923c12b 100644 (file)
@@ -6451,7 +6451,8 @@ do_pushtag (tree name, tree type, tag_scope scope)
                 template instantiation rather than in some nested context.  */
              add_decl_expr (decl);
            }
-         else
+         /* Lambdas use LAMBDA_EXPR_DISCRIMINATOR instead.  */
+         else if (!LAMBDA_TYPE_P (type))
            vec_safe_push (local_classes, type);
        }
     }
index abfdbd96ae8d0494033432f9b58c342200884a27..de8ad94200a81061997a7376a2506a06cb5e2965 100644 (file)
@@ -222,6 +222,7 @@ static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree);
 static tree canonicalize_expr_argument (tree, tsubst_flags_t);
 static tree make_argument_pack (tree);
 static void register_parameter_specializations (tree, tree);
+static tree enclosing_instantiation_of (tree tctx);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
@@ -8951,6 +8952,10 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
        }
       else if (CLASS_TYPE_P (template_type))
        {
+         /* Lambda closures are regenerated in tsubst_lambda_expr, not
+            instantiated here.  */
+         gcc_assert (!LAMBDA_TYPE_P (template_type));
+
          t = make_class_type (TREE_CODE (template_type));
          CLASSTYPE_DECLARED_CLASS (t)
            = CLASSTYPE_DECLARED_CLASS (template_type);
@@ -12183,9 +12188,20 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
        return t;
 
       /* Calculate the most general template of which R is a
-        specialization, and the complete set of arguments used to
-        specialize R.  */
+        specialization.  */
       gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
+
+      /* We're substituting a lambda function under tsubst_lambda_expr but not
+        directly from it; find the matching function we're already inside.
+        But don't do this if T is a generic lambda with a single level of
+        template parms, as in that case we're doing a normal instantiation. */
+      if (LAMBDA_FUNCTION_P (t) && !lambda_fntype
+         && (!generic_lambda_fn_p (t)
+             || TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (gen_tmpl)) > 1))
+       return enclosing_instantiation_of (t);
+
+      /* Calculate the complete set of arguments used to
+        specialize R.  */
       argvec = tsubst_template_args (DECL_TI_ARGS
                                     (DECL_TEMPLATE_RESULT
                                      (DECL_TI_TEMPLATE (t))),
@@ -12609,24 +12625,15 @@ lambda_fn_in_template_p (tree fn)
   return CLASSTYPE_TEMPLATE_INFO (closure) != NULL_TREE;
 }
 
-/* True if FN is the op() for a lambda regenerated from a lambda in an
-   uninstantiated template.  */
-
-bool
-regenerated_lambda_fn_p (tree fn)
-{
-  return (LAMBDA_FUNCTION_P (fn)
-         && !DECL_TEMPLATE_INSTANTIATION (fn));
-}
-
 /* We're instantiating a variable from template function TCTX.  Return the
    corresponding current enclosing scope.  This gets complicated because lambda
    functions in templates are regenerated rather than instantiated, but generic
    lambda functions are subsequently instantiated.  */
 
 static tree
-enclosing_instantiation_of (tree tctx)
+enclosing_instantiation_of (tree otctx)
 {
+  tree tctx = otctx;
   tree fn = current_function_decl;
   int lambda_count = 0;
 
@@ -12635,22 +12642,18 @@ enclosing_instantiation_of (tree tctx)
     ++lambda_count;
   for (; fn; fn = decl_function_context (fn))
     {
-      tree lambda = fn;
+      tree ofn = fn;
       int flambda_count = 0;
-      for (; fn && regenerated_lambda_fn_p (fn);
+      for (; flambda_count < lambda_count && fn && LAMBDA_FUNCTION_P (fn);
           fn = decl_function_context (fn))
        ++flambda_count;
       if (DECL_TEMPLATE_INFO (fn)
          ? most_general_template (fn) != most_general_template (tctx)
          : fn != tctx)
        continue;
-      if (lambda_count)
-       {
-         fn = lambda;
-         while (flambda_count-- > lambda_count)
-           fn = decl_function_context (fn);
-       }
-      return fn;
+      gcc_assert (DECL_NAME (ofn) == DECL_NAME (otctx)
+                 || DECL_CONV_FN_P (ofn));
+      return ofn;
     }
   gcc_unreachable ();
 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-nested2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-nested2.C
new file mode 100644 (file)
index 0000000..3dbc5b3
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/82514
+// { dg-do compile { target c++14 } }
+
+void g();
+template <typename h> void i(h) { g(); }
+template <int> void n() {
+  [](auto) {
+    struct p { };
+    i(p{});
+  } ('\n');
+}
+
+auto f = n<1>;