From fe23b12a23e357103a40fda08df33f3547f112e6 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 1 Feb 2018 21:07:09 -0500 Subject: [PATCH] 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. From-SVN: r257325 --- gcc/cp/ChangeLog | 10 ++++++ gcc/cp/constexpr.c | 2 +- gcc/cp/cp-tree.h | 1 + gcc/cp/expr.c | 4 +-- gcc/cp/lambda.c | 32 +++++++++++++++---- gcc/cp/semantics.c | 2 +- .../g++.dg/cpp0x/lambda/lambda-variadic6.C | 12 +++++++ 7 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic6.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5b6c75a83f5..728597599c5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2018-02-01 Jason Merrill + + 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 PR c++/84125 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); +} -- 2.30.2