aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/lambda.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2019-02-27 16:54:25 -0500
committerJason Merrill <jason@gcc.gnu.org>2019-02-27 16:54:25 -0500
commite6df04c105464436e700013e1f665ebf0f94c9f2 (patch)
tree13b41c71195608f85e18e625f3a53dd5ecb4a1ab /gcc/cp/lambda.c
parent5b0a9c7cc1fa723369df61598cd3a8af4d21f5ff (diff)
downloadgcc-e6df04c105464436e700013e1f665ebf0f94c9f2.zip
gcc-e6df04c105464436e700013e1f665ebf0f94c9f2.tar.gz
gcc-e6df04c105464436e700013e1f665ebf0f94c9f2.tar.bz2
PR c++/86969 - ICE with constexpr if and recursive generic lambdas.
Here, the problem was that extract_local_specs wasn't seeing that we use 'self' inside the lambda in the else of the inner constexpr if, because we don't walk into lambda bodies and we didn't capture it in the lambda because 'self' is still dependent. Marek recently changed process_outer_var_ref to do more implicit capture in templates; this example shows that we should always capture non-packs, so that we can continue to not walk into lambda bodies. We do walk into lambda bodies for pack expansions, so we can delay deciding whether we're capturing a single element or the entire pack. 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. * 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. From-SVN: r269265
Diffstat (limited to 'gcc/cp/lambda.c')
-rw-r--r--gcc/cp/lambda.c28
1 files changed, 25 insertions, 3 deletions
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index d178f15..c25df2f 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))