static bool cp_var_mod_type_p (tree type) { /* If TYPE is a pointer-to-member, it is variably modified if either the class or the member are variably modified. */ if (TYPE_PTR_TO_MEMBER_P (type)) return (variably_modified_type_p (TYPE_PTRMEM_CLASS_TYPE (type)) || variably_modified_type_p (TYPE_PTRMEM_POINTED_TO_TYPE (type))); /* All other types are not variably modified. */ return false; }
static bool is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw) { tree expr = is_throw ? t : NULL_TREE; tree type = TREE_TYPE (t); /* C++11 [except.handle] The exception-declaration shall not denote an incomplete type, an abstract class type, or an rvalue reference type. */ /* 15.1/4 [...] The type of the throw-expression shall not be an incomplete type, or a pointer or a reference to an incomplete type, other than void*, const void*, volatile void*, or const volatile void*. Except for these restriction and the restrictions on type matching mentioned in 15.3, the operand of throw is treated exactly as a function argument in a call (5.2.2) or the operand of a return statement. */ if (!complete_ptr_ref_or_void_ptr_p (type, expr)) return false; /* 10.4/3 An abstract class shall not be used as a parameter type, as a function return type or as type of an explicit conversion. */ else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type)) return false; else if (!is_throw && TREE_CODE (type) == REFERENCE_TYPE && TYPE_REF_IS_RVALUE (type)) { error ("cannot declare catch parameter to be of rvalue " "reference type %qT", type); return false; } else if (variably_modified_type_p (type, NULL_TREE)) { if (is_throw) error ("cannot throw expression of type %qT because it involves " "types of variable size", type); else error ("cannot catch type %qT because it involves types of " "variable size", type); return false; } return true; }
bool is_normal_capture_proxy (tree decl) { if (!is_capture_proxy (decl)) /* It's not a capture proxy. */ return false; if (variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) /* VLA capture. */ return true; /* It is a capture proxy, is it a normal capture? */ tree val = DECL_VALUE_EXPR (decl); if (val == error_mark_node) return true; gcc_assert (TREE_CODE (val) == COMPONENT_REF); val = TREE_OPERAND (val, 1); return DECL_NORMAL_CAPTURE_P (val); }
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; }