PR c++/84160 - ICE with nested variadic capture.
authorJason Merrill <jason@redhat.com>
Fri, 2 Feb 2018 02:07:09 +0000 (21:07 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 2 Feb 2018 02:07:09 +0000 (21:07 -0500)
* 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.

From-SVN: r257325

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/expr.c
gcc/cp/lambda.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic6.C [new file with mode: 0644]

index 5b6c75a83f55023a58eac951e15359cc0bc1dd46..728597599c5a3d30a6754ff80a901c4a39606307 100644 (file)
@@ -1,3 +1,13 @@
+2018-02-01  Jason Merrill  <jason@redhat.com>
+
+       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.
+
 2018-02-01  Marek Polacek  <polacek@redhat.com>
 
        PR c++/84125
index 1390405c416c1013fb0ea346e2430c8dc18c095e..171c389515a40ce3816d5d33767547b77257946a 100644 (file)
@@ -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
index 5f14e51463836e340cbdf54059d0b65457d600fa..a53f4fd9c03a13eb0303a77f433695d406e773c3 100644 (file)
@@ -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);
index 2e67986897061d27bbd4b368af888025d76988d6..b2c8cfaf88c7ee1f0620ef60cd059e8fb8eaa96f 100644 (file)
@@ -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);
index e1caaef6fe9b7b6209d29999905b81d9737292cc..ff8236ad316c453ff2f2f7866f69718e1ce016db 100644 (file)
@@ -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)
index 76160345882ed64321d3becf7fbd0c05b34e5b42..ea92da376257ebef5f41d8d2b60e65fd9575028d 100644 (file)
@@ -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 (file)
index 0000000..d9707d0
--- /dev/null
@@ -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);
+}