static void create_an_loop (tree init, tree cond, tree incr, tree body) { tree for_stmt; finish_expr_stmt (init); for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE); finish_for_init_stmt (for_stmt); finish_for_cond (cond, for_stmt, false); finish_for_expr (incr, for_stmt); finish_expr_stmt (body); finish_for_stmt (for_stmt); }
static tree cp_ubsan_dfs_initialize_vtbl_ptrs (tree binfo, void *data) { if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo))) return dfs_skip_bases; if (!BINFO_PRIMARY_P (binfo)) { tree base_ptr = TREE_VALUE ((tree) data); base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1, tf_warning_or_error); /* Compute the location of the vtpr. */ tree vtbl_ptr = build_vfield_ref (cp_build_fold_indirect_ref (base_ptr), TREE_TYPE (binfo)); gcc_assert (vtbl_ptr != error_mark_node); /* Assign NULL to the vptr. */ tree vtbl = build_zero_cst (TREE_TYPE (vtbl_ptr)); tree stmt = cp_build_modify_expr (input_location, vtbl_ptr, NOP_EXPR, vtbl, tf_warning_or_error); if (vptr_via_virtual_p (binfo)) /* If this vptr comes from a virtual base of the complete object, only clear it if we're in charge of virtual bases. */ stmt = build_if_in_charge (stmt); finish_expr_stmt (stmt); } return NULL_TREE; }
static tree cp_ubsan_dfs_initialize_vtbl_ptrs (tree binfo, void *data) { if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo))) return dfs_skip_bases; if (!BINFO_PRIMARY_P (binfo) || BINFO_VIRTUAL_P (binfo)) { tree base_ptr = TREE_VALUE ((tree) data); base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1, tf_warning_or_error); /* Compute the location of the vtpr. */ tree vtbl_ptr = build_vfield_ref (cp_build_indirect_ref (base_ptr, RO_NULL, tf_warning_or_error), TREE_TYPE (binfo)); gcc_assert (vtbl_ptr != error_mark_node); /* Assign NULL to the vptr. */ tree vtbl = build_zero_cst (TREE_TYPE (vtbl_ptr)); finish_expr_stmt (cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl, tf_warning_or_error)); } return NULL_TREE; }
void expand_end_catch_block (void) { if (! doing_eh (1)) return; /* The exception being handled is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor. */ if (in_function_try_handler && (DECL_CONSTRUCTOR_P (current_function_decl) || DECL_DESTRUCTOR_P (current_function_decl))) finish_expr_stmt (build_throw (NULL_TREE)); }
static tree replace_invariant_exprs (tree *node) { size_t ix = 0; tree node_list = NULL_TREE; tree t = NULL_TREE, new_var = NULL_TREE; struct inv_list data; data.list_values = NULL; data.replacement = NULL; data.additional_tcodes = NULL; cp_walk_tree (node, find_inv_trees, (void *) &data, NULL); if (vec_safe_length (data.list_values)) { node_list = push_stmt_list (); for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++) { /* Sometimes, when comma_expr has a function call in it, it will typecast it to void. Find_inv_trees finds those nodes and so if it void type, then don't bother creating a new var to hold the return value. */ if (VOID_TYPE_P (TREE_TYPE (t))) { finish_expr_stmt (t); new_var = void_node; } else new_var = get_temp_regvar (TREE_TYPE (t), t); vec_safe_push (data.replacement, new_var); } cp_walk_tree (node, replace_inv_trees, (void *) &data, NULL); node_list = pop_stmt_list (node_list); } return node_list; }
tree expand_start_catch_block (tree decl) { tree exp; tree type; if (! doing_eh (1)) return NULL_TREE; /* Make sure this declaration is reasonable. */ if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE)) decl = NULL_TREE; if (decl) type = prepare_eh_type (TREE_TYPE (decl)); else type = NULL_TREE; if (decl && decl_is_java_type (type, 1)) { /* Java only passes object via pointer and doesn't require adjusting. The java object is immediately before the generic exception header. */ exp = build_exc_ptr (); exp = build1 (NOP_EXPR, build_pointer_type (type), exp); exp = build2 (MINUS_EXPR, TREE_TYPE (exp), exp, TYPE_SIZE_UNIT (TREE_TYPE (exp))); exp = build_indirect_ref (exp, NULL); initialize_handler_parm (decl, exp); return type; } /* Call __cxa_end_catch at the end of processing the exception. */ push_eh_cleanup (type); /* If there's no decl at all, then all we need to do is make sure to tell the runtime that we've begun handling the exception. */ if (decl == NULL) finish_expr_stmt (do_begin_catch ()); /* If the C++ object needs constructing, we need to do that before calling __cxa_begin_catch, so that std::uncaught_exception gets the right value during the copy constructor. */ else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) { exp = do_get_exception_ptr (); initialize_handler_parm (decl, exp); finish_expr_stmt (do_begin_catch ()); } /* Otherwise the type uses a bitwise copy, and we don't have to worry about the value of std::uncaught_exception and therefore can do the copy with the return value of __cxa_end_catch instead. */ else { tree init = do_begin_catch (); exp = create_temporary_var (ptr_type_node); DECL_REGISTER (exp) = 1; cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING); finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init)); initialize_handler_parm (decl, exp); } return type; }
tree expand_start_catch_block (tree decl) { tree exp; tree type, init; if (! doing_eh ()) return NULL_TREE; if (decl) { if (!is_admissible_throw_operand_or_catch_parameter (decl, false)) decl = error_mark_node; type = prepare_eh_type (TREE_TYPE (decl)); mark_used (eh_type_info (type)); } else type = NULL_TREE; /* Call __cxa_end_catch at the end of processing the exception. */ push_eh_cleanup (type); init = do_begin_catch (); /* If there's no decl at all, then all we need to do is make sure to tell the runtime that we've begun handling the exception. */ if (decl == NULL || decl == error_mark_node || init == error_mark_node) finish_expr_stmt (init); /* If the C++ object needs constructing, we need to do that before calling __cxa_begin_catch, so that std::uncaught_exception gets the right value during the copy constructor. */ else if (flag_use_cxa_get_exception_ptr && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) { exp = do_get_exception_ptr (); initialize_handler_parm (decl, exp); finish_expr_stmt (init); } /* Otherwise the type uses a bitwise copy, and we don't have to worry about the value of std::uncaught_exception and therefore can do the copy with the return value of __cxa_end_catch instead. */ else { tree init_type = type; /* Pointers are passed by values, everything else by reference. */ if (!TYPE_PTR_P (type)) init_type = build_pointer_type (type); if (init_type != TREE_TYPE (init)) init = build1 (NOP_EXPR, init_type, init); exp = create_temporary_var (init_type); cp_finish_decl (exp, init, /*init_const_expr=*/false, NULL_TREE, LOOKUP_ONLYCONVERTING); DECL_REGISTER (exp) = 1; initialize_handler_parm (decl, exp); } return type; }
static tree expand_unary_array_notation_exprs (tree orig_stmt) { vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; size_t list_size = 0, rank = 0, ii = 0; tree body; tree builtin_loop, stmt = NULL_TREE, new_var = NULL_TREE; location_t location = EXPR_LOCATION (orig_stmt); tree an_init, loop_with_init = alloc_stmt_list (); vec<vec<an_parts> > an_info = vNULL; auto_vec<an_loop_parts> an_loop_info; if (!find_rank (location, orig_stmt, orig_stmt, true, &rank)) return error_mark_node; if (rank == 0) return orig_stmt; extract_array_notation_exprs (orig_stmt, false, &array_list); list_size = vec_safe_length (array_list); location = EXPR_LOCATION (orig_stmt); stmt = NULL_TREE; for (ii = 0; ii < list_size; ii++) if (TREE_CODE ((*array_list)[ii]) == CALL_EXPR || TREE_CODE ((*array_list)[ii]) == AGGR_INIT_EXPR) { tree list_node = (*array_list)[ii]; builtin_loop = expand_sec_reduce_builtin (list_node, &new_var); if (builtin_loop == error_mark_node) return error_mark_node; else if (builtin_loop) { vec<tree, va_gc> *sub_list = NULL, *new_var_list = NULL; stmt = alloc_stmt_list (); append_to_statement_list (builtin_loop, &stmt); vec_safe_push (sub_list, list_node); vec_safe_push (new_var_list, new_var); replace_array_notations (&orig_stmt, false, sub_list, new_var_list); } } if (stmt != NULL_TREE) append_to_statement_list (finish_expr_stmt (orig_stmt), &stmt); else stmt = orig_stmt; rank = 0; list_size = 0; array_list = NULL; extract_array_notation_exprs (stmt, true, &array_list); list_size = vec_safe_length (array_list); if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank)) return error_mark_node; if (rank == 0 || list_size == 0) return stmt; an_loop_info.safe_grow_cleared (rank); an_init = push_stmt_list (); /* Assign the array notation components to variable so that they can satisfy the exec-once rule. */ for (ii = 0; ii < list_size; ii++) { tree array_node = (*array_list)[ii]; make_triplet_val_inv (&ARRAY_NOTATION_START (array_node)); make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (array_node)); make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (array_node)); } cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); for (ii = 0; ii < rank; ii++) { tree typ = ptrdiff_type_node; an_loop_info[ii].var = create_temporary_var (typ); add_decl_expr (an_loop_info[ii].var); an_loop_info[ii].ind_init = build_x_modify_expr (location, an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), tf_warning_or_error); } array_operand = create_array_refs (location, an_info, an_loop_info, list_size, rank); replace_array_notations (&stmt, true, array_list, array_operand); create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error); an_init = pop_stmt_list (an_init); append_to_statement_list (an_init, &loop_with_init); body = stmt; for (ii = 0; ii < rank; ii++) { tree new_loop = push_stmt_list (); create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp, an_loop_info[ii].incr, body); body = pop_stmt_list (new_loop); } append_to_statement_list (body, &loop_with_init); release_vec_vec (an_info); return loop_with_init; }
static tree cp_expand_cond_array_notations (tree orig_stmt) { vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; size_t list_size = 0; size_t rank = 0, ii = 0; tree an_init, body, stmt = NULL_TREE; tree builtin_loop, new_var = NULL_TREE; tree loop_with_init = alloc_stmt_list (); location_t location = UNKNOWN_LOCATION; vec<vec<an_parts> > an_info = vNULL; auto_vec<an_loop_parts> an_loop_info; if (TREE_CODE (orig_stmt) == COND_EXPR) { size_t cond_rank = 0, yes_rank = 0, no_rank = 0; tree yes_expr = COND_EXPR_THEN (orig_stmt); tree no_expr = COND_EXPR_ELSE (orig_stmt); tree cond = COND_EXPR_COND (orig_stmt); if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank) || !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true, &yes_rank) || find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true, &no_rank)) return error_mark_node; /* If the condition has a zero rank, then handle array notations in body separately. */ if (cond_rank == 0) return orig_stmt; if (cond_rank != yes_rank && yes_rank != 0) { error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling" " expression of parent if-statement"); return error_mark_node; } else if (cond_rank != no_rank && no_rank != 0) { error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling " "expression of parent if-statement"); return error_mark_node; } } else if (TREE_CODE (orig_stmt) == IF_STMT) { size_t cond_rank = 0, yes_rank = 0, no_rank = 0; tree yes_expr = THEN_CLAUSE (orig_stmt); tree no_expr = ELSE_CLAUSE (orig_stmt); tree cond = IF_COND (orig_stmt); if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank) || (yes_expr && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true, &yes_rank)) || (no_expr && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true, &no_rank))) return error_mark_node; /* Same reasoning as for COND_EXPR. */ if (cond_rank == 0) return orig_stmt; else if (cond_rank != yes_rank && yes_rank != 0) { error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling" " expression of parent if-statement"); return error_mark_node; } else if (cond_rank != no_rank && no_rank != 0) { error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling " "expression of parent if-statement"); return error_mark_node; } } else if (truth_value_p (TREE_CODE (orig_stmt))) { size_t left_rank = 0, right_rank = 0; tree left_expr = TREE_OPERAND (orig_stmt, 0); tree right_expr = TREE_OPERAND (orig_stmt, 1); if (!find_rank (EXPR_LOCATION (left_expr), left_expr, left_expr, true, &left_rank) || !find_rank (EXPR_LOCATION (right_expr), right_expr, right_expr, true, &right_rank)) return error_mark_node; if (right_rank == 0 && left_rank == 0) return orig_stmt; } if (!find_rank (EXPR_LOCATION (orig_stmt), orig_stmt, orig_stmt, true, &rank)) return error_mark_node; if (rank == 0) return orig_stmt; extract_array_notation_exprs (orig_stmt, false, &array_list); stmt = alloc_stmt_list (); for (ii = 0; ii < vec_safe_length (array_list); ii++) { tree array_node = (*array_list)[ii]; if (TREE_CODE (array_node) == CALL_EXPR || TREE_CODE (array_node) == AGGR_INIT_EXPR) { builtin_loop = expand_sec_reduce_builtin (array_node, &new_var); if (builtin_loop == error_mark_node) finish_expr_stmt (error_mark_node); else if (new_var) { vec<tree, va_gc> *sub_list = NULL, *new_var_list = NULL; vec_safe_push (sub_list, array_node); vec_safe_push (new_var_list, new_var); replace_array_notations (&orig_stmt, false, sub_list, new_var_list); append_to_statement_list (builtin_loop, &stmt); } } } append_to_statement_list (orig_stmt, &stmt); rank = 0; array_list = NULL; if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank)) return error_mark_node; if (rank == 0) return stmt; extract_array_notation_exprs (stmt, true, &array_list); list_size = vec_safe_length (array_list); if (list_size == 0) return stmt; location = EXPR_LOCATION (orig_stmt); list_size = vec_safe_length (array_list); an_loop_info.safe_grow_cleared (rank); an_init = push_stmt_list (); /* Assign the array notation components to variable so that they can satisfy the exec-once rule. */ for (ii = 0; ii < list_size; ii++) { tree anode = (*array_list)[ii]; make_triplet_val_inv (&ARRAY_NOTATION_START (anode)); make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode)); make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode)); } cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); for (ii = 0; ii < rank; ii++) { tree typ = ptrdiff_type_node; an_loop_info[ii].var = create_temporary_var (typ); add_decl_expr (an_loop_info[ii].var); an_loop_info[ii].ind_init = build_x_modify_expr (location, an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), tf_warning_or_error); } array_operand = create_array_refs (location, an_info, an_loop_info, list_size, rank); replace_array_notations (&stmt, true, array_list, array_operand); create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error); an_init = pop_stmt_list (an_init); append_to_statement_list (an_init, &loop_with_init); body = stmt; for (ii = 0; ii < rank; ii++) { tree new_loop = push_stmt_list (); create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp, an_loop_info[ii].incr, body); body = pop_stmt_list (new_loop); } append_to_statement_list (body, &loop_with_init); release_vec_vec (an_info); return loop_with_init; }
static tree expand_an_in_modify_expr (location_t location, tree lhs, enum tree_code modifycode, tree rhs, tsubst_flags_t complain) { tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE; tree array_expr = NULL_TREE; tree body = NULL_TREE; auto_vec<tree> cond_expr; vec<tree, va_gc> *lhs_array_operand = NULL, *rhs_array_operand = NULL; size_t lhs_rank = 0, rhs_rank = 0, ii = 0; vec<tree, va_gc> *rhs_list = NULL, *lhs_list = NULL; size_t rhs_list_size = 0, lhs_list_size = 0; tree new_modify_expr, new_var = NULL_TREE, builtin_loop, scalar_mods; bool found_builtin_fn = false; tree an_init, loop_with_init = alloc_stmt_list (); vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL; auto_vec<an_loop_parts> lhs_an_loop_info, rhs_an_loop_info; tree lhs_len, rhs_len; if (!find_rank (location, rhs, rhs, false, &rhs_rank)) return error_mark_node; extract_array_notation_exprs (rhs, false, &rhs_list); rhs_list_size = vec_safe_length (rhs_list); an_init = push_stmt_list (); if (rhs_rank) { scalar_mods = replace_invariant_exprs (&rhs); if (scalar_mods) finish_expr_stmt (scalar_mods); } for (ii = 0; ii < rhs_list_size; ii++) { tree rhs_node = (*rhs_list)[ii]; if (TREE_CODE (rhs_node) == CALL_EXPR) { builtin_loop = expand_sec_reduce_builtin (rhs_node, &new_var); if (builtin_loop == error_mark_node) return error_mark_node; else if (builtin_loop) { finish_expr_stmt (builtin_loop); found_builtin_fn = true; if (new_var) { vec <tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL; vec_safe_push (rhs_sub_list, rhs_node); vec_safe_push (new_var_list, new_var); replace_array_notations (&rhs, false, rhs_sub_list, new_var_list); } } } } lhs_rank = 0; rhs_rank = 0; if (!find_rank (location, lhs, lhs, true, &lhs_rank) || !find_rank (location, rhs, rhs, true, &rhs_rank)) { pop_stmt_list (an_init); return error_mark_node; } /* If both are scalar, then the only reason why we will get this far is if there is some array notations inside it and was using a builtin array notation functions. If so, we have already broken those guys up and now a simple build_x_modify_expr would do. */ if (lhs_rank == 0 && rhs_rank == 0) { if (found_builtin_fn) { new_modify_expr = build_x_modify_expr (location, lhs, modifycode, rhs, complain); finish_expr_stmt (new_modify_expr); pop_stmt_list (an_init); return an_init; } else gcc_unreachable (); } /* If for some reason location is not set, then find if LHS or RHS has location info. If so, then use that so we atleast have an idea. */ if (location == UNKNOWN_LOCATION) { if (EXPR_LOCATION (lhs) != UNKNOWN_LOCATION) location = EXPR_LOCATION (lhs); else if (EXPR_LOCATION (rhs) != UNKNOWN_LOCATION) location = EXPR_LOCATION (rhs); } /* We need this when we have a scatter issue. */ extract_array_notation_exprs (lhs, true, &lhs_list); rhs_list = NULL; extract_array_notation_exprs (rhs, true, &rhs_list); rhs_list_size = vec_safe_length (rhs_list); lhs_list_size = vec_safe_length (lhs_list); if (lhs_rank == 0 && rhs_rank != 0) { error_at (location, "%qE cannot be scalar when %qE is not", lhs, rhs); return error_mark_node; } if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank) { error_at (location, "rank mismatch between %qE and %qE", lhs, rhs); return error_mark_node; } /* Assign the array notation components to variable so that they can satisfy the execute-once rule. */ for (ii = 0; ii < lhs_list_size; ii++) { tree anode = (*lhs_list)[ii]; make_triplet_val_inv (&ARRAY_NOTATION_START (anode)); make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode)); make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode)); } for (ii = 0; ii < rhs_list_size; ii++) if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF) { tree aa = (*rhs_list)[ii]; make_triplet_val_inv (&ARRAY_NOTATION_START (aa)); make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (aa)); make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (aa)); } lhs_an_loop_info.safe_grow_cleared (lhs_rank); if (rhs_rank) rhs_an_loop_info.safe_grow_cleared (rhs_rank); cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank)); cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank, &lhs_an_info); if (rhs_list) cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank, &rhs_an_info); if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info) || (rhs_list && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info))) { pop_stmt_list (an_init); goto error; } rhs_len = ((rhs_list_size > 0 && rhs_rank > 0) ? rhs_an_info[0][0].length : NULL_TREE); lhs_len = ((lhs_list_size > 0 && lhs_rank > 0) ? lhs_an_info[0][0].length : NULL_TREE); if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0 && TREE_CODE (lhs_len) == INTEGER_CST && rhs_len && TREE_CODE (rhs_len) == INTEGER_CST && !tree_int_cst_equal (rhs_len, lhs_len)) { error_at (location, "length mismatch between LHS and RHS"); pop_stmt_list (an_init); goto error; } for (ii = 0; ii < lhs_rank; ii++) { tree typ = ptrdiff_type_node; lhs_an_loop_info[ii].var = create_temporary_var (typ); add_decl_expr (lhs_an_loop_info[ii].var); lhs_an_loop_info[ii].ind_init = build_x_modify_expr (location, lhs_an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), complain); } if (rhs_list_size > 0) { rhs_array_operand = fix_sec_implicit_args (location, rhs_list, lhs_an_loop_info, lhs_rank, lhs); if (!rhs_array_operand) goto error; } replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); rhs_list_size = 0; rhs_list = NULL; extract_array_notation_exprs (rhs, true, &rhs_list); rhs_list_size = vec_safe_length (rhs_list); for (ii = 0; ii < rhs_rank; ii++) { tree typ = ptrdiff_type_node; rhs_an_loop_info[ii].var = create_temporary_var (typ); add_decl_expr (rhs_an_loop_info[ii].var); rhs_an_loop_info[ii].ind_init = build_x_modify_expr (location, rhs_an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), complain); } if (lhs_rank) { lhs_array_operand = create_array_refs (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank); replace_array_notations (&lhs, true, lhs_list, lhs_array_operand); } if (rhs_array_operand) vec_safe_truncate (rhs_array_operand, 0); if (rhs_rank) { rhs_array_operand = create_array_refs (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank); /* Replace all the array refs created by the above function because this variable is blown away by the fix_sec_implicit_args function below. */ replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); vec_safe_truncate (rhs_array_operand , 0); rhs_array_operand = fix_sec_implicit_args (location, rhs_list, rhs_an_loop_info, rhs_rank, rhs); if (!rhs_array_operand) goto error; replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); } array_expr_rhs = rhs; array_expr_lhs = lhs; array_expr = build_x_modify_expr (location, array_expr_lhs, modifycode, array_expr_rhs, complain); create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info, complain); if (rhs_rank) create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info, complain); for (ii = 0; ii < MAX (rhs_rank, lhs_rank); ii++) if (ii < lhs_rank && ii < rhs_rank) cond_expr[ii] = build_x_binary_op (location, TRUTH_ANDIF_EXPR, lhs_an_loop_info[ii].cmp, TREE_CODE (lhs_an_loop_info[ii].cmp), rhs_an_loop_info[ii].cmp, TREE_CODE (rhs_an_loop_info[ii].cmp), NULL, complain); else if (ii < lhs_rank && ii >= rhs_rank) cond_expr[ii] = lhs_an_loop_info[ii].cmp; else /* No need to compare ii < rhs_rank && ii >= lhs_rank because in a valid Array notation expression, rank of RHS cannot be greater than LHS. */ gcc_unreachable (); an_init = pop_stmt_list (an_init); append_to_statement_list (an_init, &loop_with_init); body = array_expr; for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++) { tree incr_list = alloc_stmt_list (); tree init_list = alloc_stmt_list (); tree new_loop = push_stmt_list (); if (lhs_rank) { append_to_statement_list (lhs_an_loop_info[ii].ind_init, &init_list); append_to_statement_list (lhs_an_loop_info[ii].incr, &incr_list); } if (rhs_rank) { append_to_statement_list (rhs_an_loop_info[ii].ind_init, &init_list); append_to_statement_list (rhs_an_loop_info[ii].incr, &incr_list); } create_an_loop (init_list, cond_expr[ii], incr_list, body); body = pop_stmt_list (new_loop); } append_to_statement_list (body, &loop_with_init); release_vec_vec (lhs_an_info); release_vec_vec (rhs_an_info); return loop_with_init; error: release_vec_vec (lhs_an_info); release_vec_vec (rhs_an_info); return error_mark_node; }
static void do_build_assign_ref (tree fndecl) { tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); tree compound_stmt; compound_stmt = begin_compound_stmt (0); parm = convert_from_reference (parm); if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type) && is_empty_class (current_class_type)) /* Don't copy the padding byte; it might not have been allocated if *this is a base subobject. */; else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)) { tree t = build2 (MODIFY_EXPR, void_type_node, current_class_ref, parm); finish_expr_stmt (t); } else { tree fields; int cvquals = cp_type_quals (TREE_TYPE (parm)); int i; tree binfo, base_binfo; /* Assign to each of the direct base classes. */ for (binfo = TYPE_BINFO (current_class_type), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) { tree converted_parm; /* We must convert PARM directly to the base class explicitly since the base class may be ambiguous. */ converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1); /* Call the base class assignment operator. */ finish_expr_stmt (build_special_member_call (current_class_ref, ansi_assopname (NOP_EXPR), build_tree_list (NULL_TREE, converted_parm), base_binfo, LOOKUP_NORMAL | LOOKUP_NONVIRTUAL)); } /* Assign to each of the non-static data members. */ for (fields = TYPE_FIELDS (current_class_type); fields; fields = TREE_CHAIN (fields)) { tree comp = current_class_ref; tree init = parm; tree field = fields; tree expr_type; int quals; if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field)) continue; expr_type = TREE_TYPE (field); if (CP_TYPE_CONST_P (expr_type)) { error ("non-static const member %q#D, can't use default " "assignment operator", field); continue; } else if (TREE_CODE (expr_type) == REFERENCE_TYPE) { error ("non-static reference member %q#D, can't use " "default assignment operator", field); continue; } if (DECL_NAME (field)) { if (VFIELD_NAME_P (DECL_NAME (field))) continue; } else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type) != NULL_TREE) /* Just use the field; anonymous types can't have nontrivial copy ctors or assignment ops. */; else continue; comp = build3 (COMPONENT_REF, expr_type, comp, field, NULL_TREE); /* Compute the type of init->field */ quals = cvquals; if (DECL_MUTABLE_P (field)) quals &= ~TYPE_QUAL_CONST; expr_type = cp_build_qualified_type (expr_type, quals); init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE); if (DECL_NAME (field)) init = build_modify_expr (comp, NOP_EXPR, init); else init = build2 (MODIFY_EXPR, TREE_TYPE (comp), comp, init); finish_expr_stmt (init); } } finish_return_stmt (current_class_ref); finish_compound_stmt (compound_stmt); }
static void do_build_copy_constructor (tree fndecl) { tree parm = FUNCTION_FIRST_USER_PARM (fndecl); parm = convert_from_reference (parm); if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type) && is_empty_class (current_class_type)) /* Don't copy the padding byte; it might not have been allocated if *this is a base subobject. */; else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)) { tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm); finish_expr_stmt (t); } else { tree fields = TYPE_FIELDS (current_class_type); tree member_init_list = NULL_TREE; int cvquals = cp_type_quals (TREE_TYPE (parm)); int i; tree binfo, base_binfo; VEC(tree,gc) *vbases; /* Initialize all the base-classes with the parameter converted to their type so that we get their copy constructor and not another constructor that takes current_class_type. We must deal with the binfo's directly as a direct base might be inaccessible due to ambiguity. */ for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0; VEC_iterate (tree, vbases, i, binfo); i++) { member_init_list = tree_cons (binfo, build_tree_list (NULL_TREE, build_base_path (PLUS_EXPR, parm, binfo, 1)), member_init_list); } for (binfo = TYPE_BINFO (current_class_type), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) { if (BINFO_VIRTUAL_P (base_binfo)) continue; member_init_list = tree_cons (base_binfo, build_tree_list (NULL_TREE, build_base_path (PLUS_EXPR, parm, base_binfo, 1)), member_init_list); } for (; fields; fields = TREE_CHAIN (fields)) { tree init = parm; tree field = fields; tree expr_type; if (TREE_CODE (field) != FIELD_DECL) continue; expr_type = TREE_TYPE (field); if (DECL_NAME (field)) { if (VFIELD_NAME_P (DECL_NAME (field))) continue; } else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type)) /* Just use the field; anonymous types can't have nontrivial copy ctors or assignment ops. */; else continue; /* Compute the type of "init->field". If the copy-constructor parameter is, for example, "const S&", and the type of the field is "T", then the type will usually be "const T". (There are no cv-qualified variants of reference types.) */ if (TREE_CODE (expr_type) != REFERENCE_TYPE) { int quals = cvquals; if (DECL_MUTABLE_P (field)) quals &= ~TYPE_QUAL_CONST; expr_type = cp_build_qualified_type (expr_type, quals); } init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE); init = build_tree_list (NULL_TREE, init); member_init_list = tree_cons (field, init, member_init_list); } finish_mem_initializers (member_init_list); } }
void use_thunk (tree thunk_fndecl, bool emit_p) { tree a, t, function, alias; tree virtual_offset; HOST_WIDE_INT fixed_offset, virtual_value; bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl); /* We should have called finish_thunk to give it a name. */ gcc_assert (DECL_NAME (thunk_fndecl)); /* We should never be using an alias, always refer to the aliased thunk. */ gcc_assert (!THUNK_ALIAS (thunk_fndecl)); if (TREE_ASM_WRITTEN (thunk_fndecl)) return; function = THUNK_TARGET (thunk_fndecl); if (DECL_RESULT (thunk_fndecl)) /* We already turned this thunk into an ordinary function. There's no need to process this thunk again. */ return; if (DECL_THUNK_P (function)) /* The target is itself a thunk, process it now. */ use_thunk (function, emit_p); /* Thunks are always addressable; they only appear in vtables. */ TREE_ADDRESSABLE (thunk_fndecl) = 1; /* Figure out what function is being thunked to. It's referenced in this translation unit. */ TREE_ADDRESSABLE (function) = 1; mark_used (function); if (!emit_p) return; if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)) alias = make_alias_for_thunk (function); else alias = function; fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl); virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl); if (virtual_offset) { if (!this_adjusting) virtual_offset = BINFO_VPTR_FIELD (virtual_offset); virtual_value = tree_low_cst (virtual_offset, /*pos=*/0); gcc_assert (virtual_value); } else virtual_value = 0; /* And, if we need to emit the thunk, it's used. */ mark_used (thunk_fndecl); /* This thunk is actually defined. */ DECL_EXTERNAL (thunk_fndecl) = 0; /* The linkage of the function may have changed. FIXME in linkage rewrite. */ TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function); DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function); DECL_VISIBILITY_SPECIFIED (thunk_fndecl) = DECL_VISIBILITY_SPECIFIED (function); if (DECL_ONE_ONLY (function)) make_decl_one_only (thunk_fndecl); if (flag_syntax_only) { TREE_ASM_WRITTEN (thunk_fndecl) = 1; return; } push_to_top_level (); if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function) && targetm.have_named_sections) { resolve_unique_section (function, 0, flag_function_sections); if (DECL_SECTION_NAME (function) != NULL && DECL_ONE_ONLY (function)) { resolve_unique_section (thunk_fndecl, 0, flag_function_sections); /* Output the thunk into the same section as function. */ DECL_SECTION_NAME (thunk_fndecl) = DECL_SECTION_NAME (function); } } /* The back-end expects DECL_INITIAL to contain a BLOCK, so we create one. */ DECL_INITIAL (thunk_fndecl) = make_node (BLOCK); /* Set up cloned argument trees for the thunk. */ t = NULL_TREE; for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a)) { tree x = copy_node (a); TREE_CHAIN (x) = t; DECL_CONTEXT (x) = thunk_fndecl; SET_DECL_RTL (x, NULL_RTX); DECL_HAS_VALUE_EXPR_P (x) = 0; t = x; } a = nreverse (t); DECL_ARGUMENTS (thunk_fndecl) = a; BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = a; if (this_adjusting && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset, virtual_value, alias)) { const char *fnname; current_function_decl = thunk_fndecl; DECL_RESULT (thunk_fndecl) = build_decl (RESULT_DECL, 0, integer_type_node); fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0); init_function_start (thunk_fndecl); current_function_is_thunk = 1; assemble_start_function (thunk_fndecl, fnname); targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl, fixed_offset, virtual_value, alias); assemble_end_function (thunk_fndecl, fnname); init_insn_lengths (); current_function_decl = 0; cfun = 0; TREE_ASM_WRITTEN (thunk_fndecl) = 1; } else { /* If this is a covariant thunk, or we don't have the necessary code for efficient thunks, generate a thunk function that just makes a call to the real function. Unfortunately, this doesn't work for varargs. */ if (varargs_function_p (function)) error ("generic thunk code fails for method %q#D which uses %<...%>", function); DECL_RESULT (thunk_fndecl) = NULL_TREE; start_preparsed_function (thunk_fndecl, NULL_TREE, SF_PRE_PARSED); /* We don't bother with a body block for thunks. */ /* There's no need to check accessibility inside the thunk body. */ push_deferring_access_checks (dk_no_check); t = a; if (this_adjusting) t = thunk_adjust (t, /*this_adjusting=*/1, fixed_offset, virtual_offset); /* Build up the call to the real function. */ t = tree_cons (NULL_TREE, t, NULL_TREE); for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a)) t = tree_cons (NULL_TREE, a, t); t = nreverse (t); t = build_call (alias, t); CALL_FROM_THUNK_P (t) = 1; if (VOID_TYPE_P (TREE_TYPE (t))) finish_expr_stmt (t); else { if (!this_adjusting) { tree cond = NULL_TREE; if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE) { /* If the return type is a pointer, we need to protect against NULL. We know there will be an adjustment, because that's why we're emitting a thunk. */ t = save_expr (t); cond = cp_convert (boolean_type_node, t); } t = thunk_adjust (t, /*this_adjusting=*/0, fixed_offset, virtual_offset); if (cond) t = build3 (COND_EXPR, TREE_TYPE (t), cond, t, cp_convert (TREE_TYPE (t), integer_zero_node)); } if (IS_AGGR_TYPE (TREE_TYPE (t))) t = build_cplus_new (TREE_TYPE (t), t); finish_return_stmt (t); } /* Since we want to emit the thunk, we explicitly mark its name as referenced. */ mark_decl_referenced (thunk_fndecl); /* But we don't want debugging information about it. */ DECL_IGNORED_P (thunk_fndecl) = 1; /* Re-enable access control. */ pop_deferring_access_checks (); thunk_fndecl = finish_function (0); tree_lowering_passes (thunk_fndecl); expand_body (thunk_fndecl); } pop_from_top_level (); }
tree expand_start_catch_block (tree decl) { tree exp; tree type, init; if (! doing_eh ()) return NULL_TREE; /* Make sure this declaration is reasonable. */ if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE)) decl = error_mark_node; if (decl) type = prepare_eh_type (TREE_TYPE (decl)); else type = NULL_TREE; if (decl && decl_is_java_type (type, 1)) { /* Java only passes object via pointer and doesn't require adjusting. The java object is immediately before the generic exception header. */ exp = build_exc_ptr (); exp = build1 (NOP_EXPR, build_pointer_type (type), exp); exp = fold_build_pointer_plus (exp, fold_build1_loc (input_location, NEGATE_EXPR, sizetype, TYPE_SIZE_UNIT (TREE_TYPE (exp)))); exp = cp_build_indirect_ref (exp, RO_NULL, tf_warning_or_error); initialize_handler_parm (decl, exp); return type; } /* Call __cxa_end_catch at the end of processing the exception. */ push_eh_cleanup (type); init = do_begin_catch (); /* If there's no decl at all, then all we need to do is make sure to tell the runtime that we've begun handling the exception. */ if (decl == NULL || decl == error_mark_node || init == error_mark_node) finish_expr_stmt (init); /* If the C++ object needs constructing, we need to do that before calling __cxa_begin_catch, so that std::uncaught_exception gets the right value during the copy constructor. */ else if (flag_use_cxa_get_exception_ptr && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) { exp = do_get_exception_ptr (); initialize_handler_parm (decl, exp); finish_expr_stmt (init); } /* Otherwise the type uses a bitwise copy, and we don't have to worry about the value of std::uncaught_exception and therefore can do the copy with the return value of __cxa_end_catch instead. */ else { tree init_type = type; /* Pointers are passed by values, everything else by reference. */ if (!TYPE_PTR_P (type)) init_type = build_pointer_type (type); if (init_type != TREE_TYPE (init)) init = build1 (NOP_EXPR, init_type, init); exp = create_temporary_var (init_type); DECL_REGISTER (exp) = 1; cp_finish_decl (exp, init, /*init_const_expr=*/false, NULL_TREE, LOOKUP_ONLYCONVERTING); initialize_handler_parm (decl, exp); } return type; }
tree expand_start_catch_block (tree decl) { tree exp = NULL_TREE; tree type; bool is_java; if (! doing_eh (1)) return NULL_TREE; /* Make sure this declaration is reasonable. */ if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE)) decl = NULL_TREE; if (decl) type = prepare_eh_type (TREE_TYPE (decl)); else type = NULL_TREE; is_java = false; if (decl) { tree init; if (decl_is_java_type (type, 1)) { /* Java only passes object via pointer and doesn't require adjusting. The java object is immediately before the generic exception header. */ init = build_exc_ptr (); init = build1 (NOP_EXPR, build_pointer_type (type), init); init = build (MINUS_EXPR, TREE_TYPE (init), init, TYPE_SIZE_UNIT (TREE_TYPE (init))); init = build_indirect_ref (init, NULL); is_java = true; } else { /* C++ requires that we call __cxa_begin_catch to get the pointer to the actual object. */ init = do_begin_catch (); } exp = create_temporary_var (ptr_type_node); DECL_REGISTER (exp) = 1; cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING); finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init)); } else finish_expr_stmt (do_begin_catch ()); /* C++ requires that we call __cxa_end_catch at the end of processing the exception. */ if (! is_java) push_eh_cleanup (type); if (decl) initialize_handler_parm (decl, exp); return type; }