tree build_capture_proxy (tree member) { tree var, object, fn, closure, name, lam, type; if (PACK_EXPANSION_P (member)) member = PACK_EXPANSION_PATTERN (member); closure = DECL_CONTEXT (member); fn = lambda_function (closure); lam = CLASSTYPE_LAMBDA_EXPR (closure); /* The proxy variable forwards to the capture field. */ object = build_fold_indirect_ref (DECL_ARGUMENTS (fn)); object = finish_non_static_data_member (member, object, NULL_TREE); if (REFERENCE_REF_P (object)) object = TREE_OPERAND (object, 0); /* Remove the __ inserted by add_capture. */ if (DECL_NORMAL_CAPTURE_P (member)) name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2); else name = DECL_NAME (member); type = lambda_proxy_type (object); if (DECL_VLA_CAPTURE_P (member)) { /* Rebuild the VLA type from the pointer and maxindex. */ tree field = next_initializable_field (TYPE_FIELDS (type)); tree ptr = build_simple_component_ref (object, field); field = next_initializable_field (DECL_CHAIN (field)); tree max = build_simple_component_ref (object, field); type = build_cplus_array_type (TREE_TYPE (TREE_TYPE (ptr)), build_index_type (max)); type = build_reference_type (type); REFERENCE_VLA_OK (type) = true; object = convert (type, ptr); } var = build_decl (input_location, VAR_DECL, name, type); SET_DECL_VALUE_EXPR (var, object); DECL_HAS_VALUE_EXPR_P (var) = 1; DECL_ARTIFICIAL (var) = 1; TREE_USED (var) = 1; DECL_CONTEXT (var) = fn; if (name == this_identifier) { gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (lam) == member); LAMBDA_EXPR_THIS_CAPTURE (lam) = var; } if (fn == current_function_decl) insert_capture_proxy (var); else vec_safe_push (LAMBDA_EXPR_PENDING_PROXIES (lam), var); return var; }
void register_capture_members (tree captures) { if (captures == NULL_TREE) return; register_capture_members (TREE_CHAIN (captures)); tree field = TREE_PURPOSE (captures); if (PACK_EXPANSION_P (field)) field = PACK_EXPANSION_PATTERN (field); /* We set this in add_capture to avoid duplicates. */ IDENTIFIER_MARKED (DECL_NAME (field)) = false; finish_member_declaration (field); }
tree add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, bool explicit_init_p) { char *buf; tree type, member, name; bool vla = false; bool variadic = false; tree initializer = orig_init; if (PACK_EXPANSION_P (initializer)) { initializer = PACK_EXPANSION_PATTERN (initializer); variadic = true; } if (TREE_CODE (initializer) == TREE_LIST) initializer = build_x_compound_expr_from_list (initializer, ELK_INIT, tf_warning_or_error); type = TREE_TYPE (initializer); if (type == error_mark_node) return error_mark_node; if (array_of_runtime_bound_p (type)) { vla = true; if (!by_reference_p) error ("array of runtime bound cannot be captured by copy, " "only by reference"); /* For a VLA, we capture the address of the first element and the maximum index, and then reconstruct the VLA for the proxy. */ tree elt = cp_build_array_ref (input_location, initializer, integer_zero_node, tf_warning_or_error); 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); } else if (!dependent_type_p (type) && variably_modified_type_p (type, NULL_TREE)) { error ("capture of variable-size type %qT that is not an N3639 array " "of runtime bound", type); if (TREE_CODE (type) == ARRAY_TYPE && variably_modified_type_p (TREE_TYPE (type), NULL_TREE)) inform (input_location, "because the array element type %qT has " "variable size", TREE_TYPE (type)); type = error_mark_node; } else { type = lambda_capture_field_type (initializer, explicit_init_p); if (by_reference_p) { type = build_reference_type (type); if (!dependent_type_p (type) && !real_lvalue_p (initializer)) error ("cannot capture %qE by reference", initializer); } else { /* Capture by copy requires a complete type. */ type = complete_type (type); if (!dependent_type_p (type) && !COMPLETE_TYPE_P (type)) { error ("capture by copy of incomplete type %qT", type); cxx_incomplete_type_inform (type); return error_mark_node; } } } /* Add __ to the beginning of the field name so that user code won't find the field with name lookup. We can't just leave the name unset because template instantiation uses the name to find instantiated fields. */ buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3); buf[1] = buf[0] = '_'; memcpy (buf + 2, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id) + 1); name = get_identifier (buf); /* If TREE_TYPE isn't set, we're still in the introducer, so check for duplicates. */ if (!LAMBDA_EXPR_CLOSURE (lambda)) { if (IDENTIFIER_MARKED (name)) { pedwarn (input_location, 0, "already captured %qD in lambda expression", id); return NULL_TREE; } IDENTIFIER_MARKED (name) = true; } if (variadic) type = make_pack_expansion (type); /* Make member variable. */ member = build_decl (input_location, FIELD_DECL, name, type); DECL_VLA_CAPTURE_P (member) = vla; if (!explicit_init_p) /* Normal captures are invisible to name lookup but uses are replaced with references to the capture field; we implement this by only really making them invisible in unevaluated context; see qualify_lookup. For now, let's make explicitly initialized captures always visible. */ DECL_NORMAL_CAPTURE_P (member) = true; if (id == this_identifier) LAMBDA_EXPR_THIS_CAPTURE (lambda) = member; /* Add it to the appropriate closure class if we've started it. */ if (current_class_type && current_class_type == LAMBDA_EXPR_CLOSURE (lambda)) finish_member_declaration (member); tree listmem = member; if (variadic) { listmem = make_pack_expansion (member); initializer = orig_init; } LAMBDA_EXPR_CAPTURE_LIST (lambda) = tree_cons (listmem, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda)); if (LAMBDA_EXPR_CLOSURE (lambda)) return build_capture_proxy (member); /* For explicit captures we haven't started the function yet, so we wait and build the proxy from cp_parser_lambda_body. */ return NULL_TREE; }