Message ID | 20190227215408.21678-1-jason@redhat.com |
---|---|
State | New |
Headers | show |
Series | [C++] PR c++/86969 - ICE with constexpr if and recursive generic lambdas. | expand |
On Wed, Feb 27, 2019 at 4:54 PM Jason Merrill <jason@redhat.com> wrote: > > Immediately capturing a VLA means we need to create a dependent VLA capture > type, and not in the context of the lambda op(), since trying to look up the > instantiation of the op() while we're substituting into the capture list > would crash. So I force TYPE_CONTEXT and the binding level out to the > enclosing function before pushtag, avoid adding a TAG_DEFN, and instead > force the type to be complete in tsubst_lambda_expr. ...or we could delay doing the special VLA handling until its type becomes non-dependent, which is a lot simpler and less kludgey. Tested x86_64-pc-linux-gnu, applying to trunk. commit eb6c46bbc819c27e1730c935248a23e3a6746a9b Author: Jason Merrill <jason@redhat.com> Date: Thu Feb 28 16:10:12 2019 -0500 PR c++/86969 - ICE with constexpr if and recursive generic lambdas. * class.c, lambda.c, pt.c: Revert earlier change. * lambda.c (add_capture): Don't special-case capture of dependent VLA. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 830ede56af8..f44acfd62b5 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -7246,7 +7246,6 @@ finish_struct (tree t, tree attributes) error ("trying to finish struct, but kicked out due to previous parse errors"); if (processing_template_decl && at_function_scope_p () - && TYPE_CONTEXT (t) == current_function_decl /* Lambdas are defined by the LAMBDA_EXPR. */ && !LAMBDA_TYPE_P (t)) add_stmt (build_min (TAG_DEFN, t)); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index c25df2fbc0e..e7f0fda65be 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -479,31 +479,9 @@ static GTY(()) tree max_id; an array of runtime length. */ static tree -vla_capture_type (tree array_type, tree lambda) +vla_capture_type (tree array_type) { - tree closure = LAMBDA_EXPR_CLOSURE (lambda); - tree type = make_class_type (RECORD_TYPE); - cp_binding_level *slev = current_binding_level; - if (closure) - { - /* If we're already inside the lambda body, force the capture type out - into the enclosing context, so we don't crash trying to instantiate - the capture field in tsubst_lambda_expr. We won't have a TAG_DEFN - from finish_struct in the enclosing context, which we work around in - tsubst_lambda_expr. */ - TYPE_CONTEXT (type) = TYPE_CONTEXT (closure); - cp_binding_level *b = current_binding_level; - for (;; b = b->level_chain) - if (b->this_entity == closure) - { - while (b->this_entity == closure) - b = b->level_chain; - break; - } - current_binding_level = b; - } - type = pushtag (make_anon_name (), type, ts_current); - current_binding_level = slev; + tree type = xref_tag (record_type, make_anon_name (), ts_current, false); xref_basetypes (type, NULL_TREE); type = begin_class_definition (type); if (!ptr_id) @@ -549,7 +527,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, if (type == error_mark_node) return error_mark_node; - if (array_of_runtime_bound_p (type)) + if (!dependent_type_p (type) && array_of_runtime_bound_p (type)) { vla = true; if (!by_reference_p) @@ -563,7 +541,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, initializer = build_constructor_va (init_list_type_node, 2, NULL_TREE, build_address (elt), NULL_TREE, array_type_nelts (type)); - type = vla_capture_type (type, lambda); + type = vla_capture_type (type); } else if (!dependent_type_p (type) && variably_modified_type_p (type, NULL_TREE)) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 673ea8e2258..d678e278078 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17989,10 +17989,6 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (PACK_EXPANSION_P (ofield)) ofield = PACK_EXPANSION_PATTERN (ofield); tree field = tsubst_decl (ofield, args, complain); - if (DECL_VLA_CAPTURE_P (ofield)) - /* The type of a VLA capture might not have a TAG_DEFN in the enclosing - context, so complete it here. */ - complete_type (TREE_TYPE (field)); if (DECL_PACK_P (ofield) && !DECL_NORMAL_CAPTURE_P (ofield)) {
diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f44acfd62b5..830ede56af8 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -7246,6 +7246,7 @@ finish_struct (tree t, tree attributes) error ("trying to finish struct, but kicked out due to previous parse errors"); if (processing_template_decl && at_function_scope_p () + && TYPE_CONTEXT (t) == current_function_decl /* Lambdas are defined by the LAMBDA_EXPR. */ && !LAMBDA_TYPE_P (t)) add_stmt (build_min (TAG_DEFN, t)); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index d178f15a4da..c25df2fbc0e 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -479,9 +479,31 @@ static GTY(()) tree max_id; an array of runtime length. */ static tree -vla_capture_type (tree array_type) +vla_capture_type (tree array_type, tree lambda) { - tree type = xref_tag (record_type, make_anon_name (), ts_current, false); + tree closure = LAMBDA_EXPR_CLOSURE (lambda); + tree type = make_class_type (RECORD_TYPE); + cp_binding_level *slev = current_binding_level; + if (closure) + { + /* If we're already inside the lambda body, force the capture type out + into the enclosing context, so we don't crash trying to instantiate + the capture field in tsubst_lambda_expr. We won't have a TAG_DEFN + from finish_struct in the enclosing context, which we work around in + tsubst_lambda_expr. */ + TYPE_CONTEXT (type) = TYPE_CONTEXT (closure); + cp_binding_level *b = current_binding_level; + for (;; b = b->level_chain) + if (b->this_entity == closure) + { + while (b->this_entity == closure) + b = b->level_chain; + break; + } + current_binding_level = b; + } + type = pushtag (make_anon_name (), type, ts_current); + current_binding_level = slev; xref_basetypes (type, NULL_TREE); type = begin_class_definition (type); if (!ptr_id) @@ -541,7 +563,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, initializer = build_constructor_va (init_list_type_node, 2, NULL_TREE, build_address (elt), NULL_TREE, array_type_nelts (type)); - type = vla_capture_type (type); + type = vla_capture_type (type, lambda); } else if (!dependent_type_p (type) && variably_modified_type_p (type, NULL_TREE)) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d678e278078..673ea8e2258 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17989,6 +17989,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (PACK_EXPANSION_P (ofield)) ofield = PACK_EXPANSION_PATTERN (ofield); tree field = tsubst_decl (ofield, args, complain); + if (DECL_VLA_CAPTURE_P (ofield)) + /* The type of a VLA capture might not have a TAG_DEFN in the enclosing + context, so complete it here. */ + complete_type (TREE_TYPE (field)); if (DECL_PACK_P (ofield) && !DECL_NORMAL_CAPTURE_P (ofield)) { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index da814bdd655..d1a378acd98 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3469,10 +3469,12 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use) = decl_function_context (containing_function); } - /* In a lambda within a template, wait until instantiation - time to implicitly capture a dependent type. */ + /* In a lambda within a template, wait until instantiation time to implicitly + capture a parameter pack. We want to wait because we don't know if we're + capturing the whole pack or a single element, and it's OK to wait because + find_parameter_packs_r walks into the lambda body. */ if (context == containing_function - && dependent_type_p (TREE_TYPE (decl))) + && DECL_PACK_P (decl)) return decl; if (lambda_expr && VAR_P (decl) diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C new file mode 100644 index 00000000000..a1a6e0b78f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if27.C @@ -0,0 +1,22 @@ +// PR c++/86969 +// { dg-do compile { target c++17 } } + +auto compose = [](auto... fs) { + if constexpr (sizeof...(fs) == 0) { + return [](auto x) { return x; }; + } else { + auto fn = [](auto self, auto f, auto... fs) { + if constexpr (sizeof...(fs) == 0) return f; + else return [=](auto x) { + return f(self(self, fs...)(x)); + }; + }; + return fn(fn, fs...); + } +}; + +static_assert(compose( + [](auto x) { return x * 3; }, + [](auto x) { return x + 1; }, + [](auto x) { return x / 2; } + )(6) == 12); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a2d16e15b4a..e4d876b4c0b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2019-02-27 Jason Merrill <jason@redhat.com> + + PR c++/86969 - ICE with constexpr if and recursive generic lambdas. + * semantics.c (process_outer_var_ref): Do capture dependent vars. + * class.c (finish_struct): Only add TAG_DEFN if T is in + current_function_decl. + * lambda.c (vla_capture_type): Force the capture type out into the + lambda's enclosing function. + (add_capture): Pass in the lambda. + * pt.c (tsubst_lambda_expr): complete_type a VLA capture type. + 2019-02-27 Marek Polacek <polacek@redhat.com> PR c++/89511 - ICE with using-declaration and unscoped enumerator.