PR c++/82882 - ICE with lambda in template default argument.
authorJason Merrill <jason@redhat.com>
Fri, 15 Jun 2018 20:22:44 +0000 (16:22 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 15 Jun 2018 20:22:44 +0000 (16:22 -0400)
* lambda.c (record_null_lambda_scope): New.
* pt.c (tsubst_lambda_expr): Use it.
* name-lookup.c (do_pushtag): Don't give a lambda DECL_CONTEXT of a
function that isn't open.

From-SVN: r261654

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/lambda.c
gcc/cp/name-lookup.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg8.C [new file with mode: 0644]

index 2679ca6..f6c6908 100644 (file)
@@ -1,5 +1,11 @@
 2018-06-15  Jason Merrill  <jason@redhat.com>
 
+       PR c++/82882 - ICE with lambda in template default argument.
+       * lambda.c (record_null_lambda_scope): New.
+       * pt.c (tsubst_lambda_expr): Use it.
+       * name-lookup.c (do_pushtag): Don't give a lambda DECL_CONTEXT of a
+       function that isn't open.
+
        * tree.c (maybe_warn_parm_abi): Inform the location of the class.
 
 2018-06-14  Marek Polacek  <polacek@redhat.com>
index 9a50d66..3566668 100644 (file)
@@ -7018,6 +7018,7 @@ extern tree finish_builtin_launder                (location_t, tree,
                                                 tsubst_flags_t);
 extern void start_lambda_scope                 (tree);
 extern void record_lambda_scope                        (tree);
+extern void record_null_lambda_scope           (tree);
 extern void finish_lambda_scope                        (void);
 extern tree start_lambda_function              (tree fn, tree lambda_expr);
 extern void finish_lambda_function             (tree body);
index 231490f..3776d6b 100644 (file)
@@ -1380,6 +1380,24 @@ record_lambda_scope (tree lambda)
   LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++;
 }
 
+/* This lambda is an instantiation of a lambda in a template default argument
+   that got no LAMBDA_EXPR_EXTRA_SCOPE, so this shouldn't either.  But we do
+   need to use and increment the global count to avoid collisions.  */
+
+void
+record_null_lambda_scope (tree lambda)
+{
+  if (vec_safe_is_empty (lambda_scope_stack))
+    record_lambda_scope (lambda);
+  else
+    {
+      tree_int *p = lambda_scope_stack->begin();
+      LAMBDA_EXPR_EXTRA_SCOPE (lambda) = p->t;
+      LAMBDA_EXPR_DISCRIMINATOR (lambda) = p->i++;
+    }
+  gcc_assert (LAMBDA_EXPR_EXTRA_SCOPE (lambda) == NULL_TREE);
+}
+
 void
 finish_lambda_scope (void)
 {
index 8d1748a..7990029 100644 (file)
@@ -6542,6 +6542,14 @@ do_pushtag (tree name, tree type, tag_scope scope)
        {
          tree cs = current_scope ();
 
+         /* Avoid setting the lambda context to a current_function_decl that
+            we aren't actually inside, e.g. one set by push_access_scope
+            during tsubst_default_argument.  */
+         if (cs && TREE_CODE (cs) == FUNCTION_DECL
+             && LAMBDA_TYPE_P (type)
+             && !at_function_scope_p ())
+           cs = DECL_CONTEXT (cs);
+
          if (scope == ts_current
              || (cs && TREE_CODE (cs) == FUNCTION_DECL))
            context = cs;
index ba78d2e..ed634dd 100644 (file)
@@ -17530,7 +17530,11 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
 
   if (LAMBDA_EXPR_EXTRA_SCOPE (t) == NULL_TREE)
-    LAMBDA_EXPR_EXTRA_SCOPE (r) = NULL_TREE;
+    /* A lambda in a default argument outside a class gets no
+       LAMBDA_EXPR_EXTRA_SCOPE, as specified by the ABI.  But
+       tsubst_default_argument calls start_lambda_scope, so we need to
+       specifically ignore it here, and use the global scope.  */
+    record_null_lambda_scope (r);
   else
     record_lambda_scope (r);
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg8.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg8.C
new file mode 100644 (file)
index 0000000..cf842ad
--- /dev/null
@@ -0,0 +1,24 @@
+// PR c++/82282
+// { dg-do compile { target c++14 } }
+
+template<typename = int>
+void f(const char* a =
+       ([](int = []{ static int i; return 42; }()) {
+         static int i;
+         return "";
+       }()));
+
+template<typename = int>
+struct X {
+  void f(const char* a =
+        ([](int = [] { static int i; return 42; }()) { 
+           enum { Size = 42 - 1 };
+           return "";
+         }()));
+};
+
+void g()
+{
+  f();
+  X<int>().f();
+}