diff mbox series

C++ PATCH for c++/84160, ICE with nested variadic lambda capture

Message ID CADzB+2nvM25sHC_uLwaMhBpb_mo=WUKK8iTe_MVQfLhUPb5K0A@mail.gmail.com
State New
Headers show
Series C++ PATCH for c++/84160, ICE with nested variadic lambda capture | expand

Commit Message

Jason Merrill Feb. 2, 2018, 2:06 a.m. UTC
In dealing with variadic capture, we've historically not bothered
trying to track the capture proxies and just dealt with the
COMPONENT_REFs directly.  This was breaking the new DECL_CAPTURED_VAR
code.  The simplest solution for now is to make an exception for this
case; this doesn't actually cause any problems because the primary use
of DECL_CAPTURED_VAR is looking up the value of a constant variable,
and a function parameter pack is never a constant variable.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 35c8dba74b3dac15cc440e060e2e7f829202e85c
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Feb 1 17:34:42 2018 -0500

            PR c++/84160 - ICE with nested variadic capture.
    
            * lambda.c (is_capture_proxy_with_ref): New.
            (insert_capture_proxy): Don't set DECL_CAPTURED_VARIABLE from a
            COMPONENT_REF.
            * expr.c (mark_use): Use is_capture_proxy_with_ref.
            * constexpr.c (potential_constant_expression_1): Likewise.
            * semantics.c (process_outer_var_ref): Likewise.
diff mbox series

Patch

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 1390405c416..171c389515a 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5369,7 +5369,7 @@  potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case VAR_DECL:
       if (DECL_HAS_VALUE_EXPR_P (t))
 	{
-	  if (now && is_normal_capture_proxy (t))
+	  if (now && is_capture_proxy_with_ref (t))
 	    {
 	      /* -- in a lambda-expression, a reference to this or to a
 		 variable with automatic storage duration defined outside that
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5f14e514638..a53f4fd9c03 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6901,6 +6901,7 @@  extern void insert_capture_proxy		(tree);
 extern void insert_pending_capture_proxies	(void);
 extern bool is_capture_proxy			(tree);
 extern bool is_normal_capture_proxy             (tree);
+extern bool is_capture_proxy_with_ref           (tree);
 extern void register_capture_members		(tree);
 extern tree lambda_expr_this_capture            (tree, bool);
 extern void maybe_generic_this_capture		(tree, tree);
diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c
index 2e679868970..b2c8cfaf88c 100644
--- a/gcc/cp/expr.c
+++ b/gcc/cp/expr.c
@@ -111,7 +111,7 @@  mark_use (tree expr, bool rvalue_p, bool read_p,
     {
     case VAR_DECL:
     case PARM_DECL:
-      if (rvalue_p && is_normal_capture_proxy (expr))
+      if (rvalue_p && is_capture_proxy_with_ref (expr))
 	{
 	  /* Look through capture by copy.  */
 	  tree cap = DECL_CAPTURED_VARIABLE (expr);
@@ -154,7 +154,7 @@  mark_use (tree expr, bool rvalue_p, bool read_p,
 	{
 	  /* Try to look through the reference.  */
 	  tree ref = TREE_OPERAND (expr, 0);
-	  if (rvalue_p && is_normal_capture_proxy (ref))
+	  if (rvalue_p && is_capture_proxy_with_ref (ref))
 	    {
 	      /* Look through capture by reference.  */
 	      tree cap = DECL_CAPTURED_VARIABLE (ref);
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index e1caaef6fe9..ff8236ad316 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -290,13 +290,24 @@  is_normal_capture_proxy (tree decl)
   return DECL_NORMAL_CAPTURE_P (val);
 }
 
+/* Returns true iff DECL is a capture proxy for which we can use
+   DECL_CAPTURED_VARIABLE.  In effect, this is a normal proxy other than a
+   nested capture of a function parameter pack.  */
+
+bool
+is_capture_proxy_with_ref (tree var)
+{
+  return (is_normal_capture_proxy (var) && DECL_LANG_SPECIFIC (var)
+	  && DECL_CAPTURED_VARIABLE (var));
+}
+
 /* VAR is a capture proxy created by build_capture_proxy; add it to the
    current function, which is the operator() for the appropriate lambda.  */
 
 void
 insert_capture_proxy (tree var)
 {
-  if (is_normal_capture_proxy (var))
+  if (is_capture_proxy_with_ref (var))
     {
       tree cap = DECL_CAPTURED_VARIABLE (var);
       if (CHECKING_P)
@@ -443,11 +454,20 @@  build_capture_proxy (tree member, tree init)
 	    init = TREE_OPERAND (init, 0);
 	  STRIP_NOPS (init);
 	}
-      gcc_assert (VAR_P (init) || TREE_CODE (init) == PARM_DECL);
-      while (is_normal_capture_proxy (init))
-	init = DECL_CAPTURED_VARIABLE (init);
-      retrofit_lang_decl (var);
-      DECL_CAPTURED_VARIABLE (var) = init;
+
+      if (TREE_CODE (init) == COMPONENT_REF)
+	/* We're capturing a capture of a function parameter pack, and have
+	   lost track of the original variable.  It's not important to have
+	   DECL_CAPTURED_VARIABLE in this case, since a function parameter pack
+	   isn't a constant variable, so don't bother trying to set it.  */;
+      else
+	{
+	  gcc_assert (VAR_P (init) || TREE_CODE (init) == PARM_DECL);
+	  while (is_normal_capture_proxy (init))
+	    init = DECL_CAPTURED_VARIABLE (init);
+	  retrofit_lang_decl (var);
+	  DECL_CAPTURED_VARIABLE (var) = init;
+	}
     }
 
   if (name == this_identifier)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 76160345882..ea92da37625 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3321,7 +3321,7 @@  process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
     {
       /* Check whether we've already built a proxy.  */
       tree var = decl;
-      while (is_normal_capture_proxy (var))
+      while (is_capture_proxy_with_ref (var))
 	var = DECL_CAPTURED_VARIABLE (var);
       tree d = retrieve_local_specialization (var);
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic6.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic6.C
new file mode 100644
index 00000000000..d9707d05c70
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic6.C
@@ -0,0 +1,12 @@ 
+// PR c++/84160
+// { dg-do compile { target c++11 } }
+
+template < typename ... T > void f (T ... a) 
+{
+  [a ...] { [a ...] {}; };
+}
+
+void g ()
+{
+  f < int > (0);
+}