X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-cfg.c;h=b8afb57a9702289958bb1b0e0d88e43db8a8128b;hb=c3a945cde92094f4713cefdafe5c1bd3f07fbbcc;hp=ec69dd8907078db8183e640be45cf8c3cbc80f1e;hpb=ce084dfc1cd60d867d38dbed86a914d82fa908d1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index ec69dd89070..b8afb57a970 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -29,16 +29,15 @@ along with GCC; see the file COPYING3. If not see #include "output.h" #include "flags.h" #include "function.h" -#include "expr.h" #include "ggc.h" #include "langhooks.h" -#include "diagnostic.h" #include "tree-pretty-print.h" #include "gimple-pretty-print.h" #include "tree-flow.h" #include "timevar.h" #include "tree-dump.h" #include "tree-pass.h" +#include "diagnostic-core.h" #include "toplev.h" #include "except.h" #include "cfgloop.h" @@ -231,10 +230,6 @@ build_gimple_cfg (gimple_seq seq) dump_end (TDI_vcg, vcg_file); } } - -#ifdef ENABLE_CHECKING - verify_stmts (); -#endif } static unsigned int @@ -438,13 +433,13 @@ create_bb (void *h, void *e, basic_block after) gcc_assert (!e); /* Create and initialize a new basic block. Since alloc_block uses - ggc_alloc_cleared to allocate a basic block, we do not have to - clear the newly allocated basic block here. */ + GC allocation that clears memory to allocate a basic block, we do + not have to clear the newly allocated basic block here. */ bb = alloc_block (); bb->index = last_basic_block; bb->flags = BB_NEW; - bb->il.gimple = GGC_CNEW (struct gimple_bb_info); + bb->il.gimple = ggc_alloc_cleared_gimple_bb_info (); set_bb_seq (bb, h ? (gimple_seq) h : gimple_seq_alloc ()); /* Add the new block to the linked list of blocks. */ @@ -568,8 +563,12 @@ make_edges (void) create abnormal edges to them. */ make_eh_edges (last); + /* BUILTIN_RETURN is really a return statement. */ + if (gimple_call_builtin_p (last, BUILT_IN_RETURN)) + make_edge (bb, EXIT_BLOCK_PTR, 0), fallthru = false; /* Some calls are known not to return. */ - fallthru = !(gimple_call_flags (last) & ECF_NORETURN); + else + fallthru = !(gimple_call_flags (last) & ECF_NORETURN); break; case GIMPLE_ASSIGN: @@ -964,7 +963,7 @@ label_to_block_fn (struct function *ifun, tree dest) /* We would die hard when faced by an undefined label. Emit a label to the very first basic block. This will hopefully make even the dataflow and undefined variable warnings quite right. */ - if ((errorcount || sorrycount) && uid < 0) + if (seen_error () && uid < 0) { gimple_stmt_iterator gsi = gsi_start_bb (BASIC_BLOCK (NUM_FIXED_BLOCKS)); gimple stmt; @@ -1473,6 +1472,23 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b) && name_mappings_registered_p ()) return false; + /* When not optimizing, don't merge if we'd lose goto_locus. */ + if (!optimize + && single_succ_edge (a)->goto_locus != UNKNOWN_LOCATION) + { + location_t goto_locus = single_succ_edge (a)->goto_locus; + gimple_stmt_iterator prev, next; + prev = gsi_last_nondebug_bb (a); + next = gsi_after_labels (b); + if (!gsi_end_p (next) && is_gimple_debug (gsi_stmt (next))) + gsi_next_nondebug (&next); + if ((gsi_end_p (prev) + || gimple_location (gsi_stmt (prev)) != goto_locus) + && (gsi_end_p (next) + || gimple_location (gsi_stmt (next)) != goto_locus)) + return false; + } + return true; } @@ -2110,7 +2126,7 @@ dump_cfg_stats (FILE *file) /* Dump CFG statistics on stderr. Keep extern so that it's always linked in the final executable. */ -void +DEBUG_FUNCTION void debug_cfg_stats (void) { dump_cfg_stats (stderr); @@ -2248,6 +2264,10 @@ is_ctrl_altering_stmt (gimple t) /* A call also alters control flow if it does not return. */ if (flags & ECF_NORETURN) return true; + + /* BUILT_IN_RETURN call is same as return statement. */ + if (gimple_call_builtin_p (t, BUILT_IN_RETURN)) + return true; } break; @@ -2510,6 +2530,49 @@ gimple_split_edge (edge edge_in) return new_bb; } + +/* Verify properties of the address expression T with base object BASE. */ + +static tree +verify_address (tree t, tree base) +{ + bool old_constant; + bool old_side_effects; + bool new_constant; + bool new_side_effects; + + old_constant = TREE_CONSTANT (t); + old_side_effects = TREE_SIDE_EFFECTS (t); + + recompute_tree_invariant_for_addr_expr (t); + new_side_effects = TREE_SIDE_EFFECTS (t); + new_constant = TREE_CONSTANT (t); + + if (old_constant != new_constant) + { + error ("constant not recomputed when ADDR_EXPR changed"); + return t; + } + if (old_side_effects != new_side_effects) + { + error ("side effects not recomputed when ADDR_EXPR changed"); + return t; + } + + if (!(TREE_CODE (base) == VAR_DECL + || TREE_CODE (base) == PARM_DECL + || TREE_CODE (base) == RESULT_DECL)) + return NULL_TREE; + + if (DECL_GIMPLE_REG_P (base)) + { + error ("DECL_GIMPLE_REG_P set on a variable with address taken"); + return base; + } + + return NULL_TREE; +} + /* Callback for walk_tree, check that all elements with address taken are properly noticed as such. The DATA is an int* that is 1 if TP was seen inside a PHI node. */ @@ -2538,12 +2601,27 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) break; case INDIRECT_REF: + error ("INDIRECT_REF in gimple IL"); + return t; + + case MEM_REF: x = TREE_OPERAND (t, 0); - if (!is_gimple_reg (x) && !is_gimple_min_invariant (x)) + if (!POINTER_TYPE_P (TREE_TYPE (x)) + || !is_gimple_mem_ref_addr (x)) { - error ("Indirect reference's operand is not a register or a constant."); + error ("Invalid first operand of MEM_REF."); return x; } + if (TREE_CODE (TREE_OPERAND (t, 1)) != INTEGER_CST + || !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 1)))) + { + error ("Invalid offset operand of MEM_REF."); + return TREE_OPERAND (t, 1); + } + if (TREE_CODE (x) == ADDR_EXPR + && (x = verify_address (x, TREE_OPERAND (x, 0)))) + return x; + *walk_subtrees = 0; break; case ASSERT_EXPR: @@ -2561,31 +2639,10 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) case ADDR_EXPR: { - bool old_constant; - bool old_side_effects; - bool new_constant; - bool new_side_effects; + tree tem; gcc_assert (is_gimple_address (t)); - old_constant = TREE_CONSTANT (t); - old_side_effects = TREE_SIDE_EFFECTS (t); - - recompute_tree_invariant_for_addr_expr (t); - new_side_effects = TREE_SIDE_EFFECTS (t); - new_constant = TREE_CONSTANT (t); - - if (old_constant != new_constant) - { - error ("constant not recomputed when ADDR_EXPR changed"); - return t; - } - if (old_side_effects != new_side_effects) - { - error ("side effects not recomputed when ADDR_EXPR changed"); - return t; - } - /* Skip any references (they will be checked when we recurse down the tree) and ensure that any variable used as a prefix is marked addressable. */ @@ -2594,20 +2651,19 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) x = TREE_OPERAND (x, 0)) ; + if ((tem = verify_address (t, x))) + return tem; + if (!(TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == PARM_DECL || TREE_CODE (x) == RESULT_DECL)) return NULL; + if (!TREE_ADDRESSABLE (x)) { error ("address taken, but ADDRESSABLE bit not set"); return x; } - if (DECL_GIMPLE_REG_P (x)) - { - error ("DECL_GIMPLE_REG_P set on a variable with address taken"); - return x; - } break; } @@ -2792,8 +2848,8 @@ verify_types_in_gimple_min_lval (tree expr) if (is_gimple_id (expr)) return false; - if (!INDIRECT_REF_P (expr) - && TREE_CODE (expr) != TARGET_MEM_REF) + if (TREE_CODE (expr) != TARGET_MEM_REF + && TREE_CODE (expr) != MEM_REF) { error ("invalid expression for min lvalue"); return true; @@ -2810,14 +2866,7 @@ verify_types_in_gimple_min_lval (tree expr) debug_generic_stmt (op); return true; } - if (!useless_type_conversion_p (TREE_TYPE (expr), - TREE_TYPE (TREE_TYPE (op)))) - { - error ("type mismatch in indirect reference"); - debug_generic_stmt (TREE_TYPE (expr)); - debug_generic_stmt (TREE_TYPE (TREE_TYPE (op))); - return true; - } + /* Memory references now generally can involve a value conversion. */ return false; } @@ -2904,6 +2953,13 @@ verify_types_in_gimple_reference (tree expr, bool require_lvalue) debug_generic_stmt (expr); return true; } + else if (TREE_CODE (op) == SSA_NAME + && TYPE_SIZE (TREE_TYPE (expr)) != TYPE_SIZE (TREE_TYPE (op))) + { + error ("Conversion of register to a different size."); + debug_generic_stmt (expr); + return true; + } else if (!handled_component_p (op)) return false; } @@ -2911,6 +2967,40 @@ verify_types_in_gimple_reference (tree expr, bool require_lvalue) expr = op; } + if (TREE_CODE (expr) == MEM_REF) + { + if (!is_gimple_mem_ref_addr (TREE_OPERAND (expr, 0))) + { + error ("Invalid address operand in MEM_REF."); + debug_generic_stmt (expr); + return true; + } + if (TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST + || !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1)))) + { + error ("Invalid offset operand in MEM_REF."); + debug_generic_stmt (expr); + return true; + } + } + else if (TREE_CODE (expr) == TARGET_MEM_REF) + { + if (!TMR_BASE (expr) + || !is_gimple_mem_ref_addr (TMR_BASE (expr))) + { + error ("Invalid address operand in in TARGET_MEM_REF."); + return true; + } + if (!TMR_OFFSET (expr) + || TREE_CODE (TMR_OFFSET (expr)) != INTEGER_CST + || !POINTER_TYPE_P (TREE_TYPE (TMR_OFFSET (expr)))) + { + error ("Invalid offset operand in TARGET_MEM_REF."); + debug_generic_stmt (expr); + return true; + } + } + return ((require_lvalue || !is_gimple_min_invariant (expr)) && verify_types_in_gimple_min_lval (expr)); } @@ -3038,7 +3128,10 @@ verify_gimple_call (gimple stmt) for (i = 0; i < gimple_call_num_args (stmt); ++i) { tree arg = gimple_call_arg (stmt, i); - if (!is_gimple_operand (arg)) + if ((is_gimple_reg_type (TREE_TYPE (arg)) + && !is_gimple_val (arg)) + || (!is_gimple_reg_type (TREE_TYPE (arg)) + && !is_gimple_lvalue (arg))) { error ("invalid argument to gimple call"); debug_generic_expr (arg); @@ -3510,6 +3603,65 @@ do_pointer_plus_expr_check: return false; } +/* Verify a gimple assignment statement STMT with a ternary rhs. + Returns true if anything is wrong. */ + +static bool +verify_gimple_assign_ternary (gimple stmt) +{ + enum tree_code rhs_code = gimple_assign_rhs_code (stmt); + tree lhs = gimple_assign_lhs (stmt); + tree lhs_type = TREE_TYPE (lhs); + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs1_type = TREE_TYPE (rhs1); + tree rhs2 = gimple_assign_rhs2 (stmt); + tree rhs2_type = TREE_TYPE (rhs2); + tree rhs3 = gimple_assign_rhs3 (stmt); + tree rhs3_type = TREE_TYPE (rhs3); + + if (!is_gimple_reg (lhs) + && !(optimize == 0 + && TREE_CODE (lhs_type) == COMPLEX_TYPE)) + { + error ("non-register as LHS of ternary operation"); + return true; + } + + if (!is_gimple_val (rhs1) + || !is_gimple_val (rhs2) + || !is_gimple_val (rhs3)) + { + error ("invalid operands in ternary operation"); + return true; + } + + /* First handle operations that involve different types. */ + switch (rhs_code) + { + case WIDEN_MULT_PLUS_EXPR: + case WIDEN_MULT_MINUS_EXPR: + if ((!INTEGRAL_TYPE_P (rhs1_type) + && !FIXED_POINT_TYPE_P (rhs1_type)) + || !useless_type_conversion_p (rhs1_type, rhs2_type) + || !useless_type_conversion_p (lhs_type, rhs3_type) + || 2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type) + || TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)) + { + error ("type mismatch in widening multiply-accumulate expression"); + debug_generic_expr (lhs_type); + debug_generic_expr (rhs1_type); + debug_generic_expr (rhs2_type); + debug_generic_expr (rhs3_type); + return true; + } + break; + + default: + gcc_unreachable (); + } + return false; +} + /* Verify a gimple assignment statement STMT with a single rhs. Returns true if anything is wrong. */ @@ -3560,17 +3712,19 @@ verify_gimple_assign_single (gimple stmt) } /* tcc_reference */ + case INDIRECT_REF: + error ("INDIRECT_REF in gimple IL"); + return true; + case COMPONENT_REF: case BIT_FIELD_REF: - case INDIRECT_REF: - case ALIGN_INDIRECT_REF: - case MISALIGNED_INDIRECT_REF: case ARRAY_REF: case ARRAY_RANGE_REF: case VIEW_CONVERT_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: case TARGET_MEM_REF: + case MEM_REF: if (!is_gimple_reg (lhs) && is_gimple_reg_type (TREE_TYPE (lhs))) { @@ -3608,6 +3762,20 @@ verify_gimple_assign_single (gimple stmt) return res; case COND_EXPR: + if (!is_gimple_reg (lhs) + || (!is_gimple_reg (TREE_OPERAND (rhs1, 0)) + && !COMPARISON_CLASS_P (TREE_OPERAND (rhs1, 0))) + || (!is_gimple_reg (TREE_OPERAND (rhs1, 1)) + && !is_gimple_min_invariant (TREE_OPERAND (rhs1, 1))) + || (!is_gimple_reg (TREE_OPERAND (rhs1, 2)) + && !is_gimple_min_invariant (TREE_OPERAND (rhs1, 2)))) + { + error ("invalid COND_EXPR in gimple assignment"); + debug_generic_stmt (rhs1); + return true; + } + return res; + case CONSTRUCTOR: case OBJ_TYPE_REF: case ASSERT_EXPR: @@ -3642,6 +3810,9 @@ verify_gimple_assign (gimple stmt) case GIMPLE_BINARY_RHS: return verify_gimple_assign_binary (stmt); + case GIMPLE_TERNARY_RHS: + return verify_gimple_assign_ternary (stmt); + default: gcc_unreachable (); } @@ -3669,12 +3840,14 @@ verify_gimple_return (gimple stmt) return true; } - if (!useless_type_conversion_p (restype, TREE_TYPE (op)) - /* ??? With C++ we can have the situation that the result - decl is a reference type while the return type is an aggregate. */ - && !(TREE_CODE (op) == RESULT_DECL - && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE - && useless_type_conversion_p (restype, TREE_TYPE (TREE_TYPE (op))))) + if ((TREE_CODE (op) == RESULT_DECL + && DECL_BY_REFERENCE (op)) + || (TREE_CODE (op) == SSA_NAME + && TREE_CODE (SSA_NAME_VAR (op)) == RESULT_DECL + && DECL_BY_REFERENCE (SSA_NAME_VAR (op)))) + op = TREE_TYPE (op); + + if (!useless_type_conversion_p (restype, TREE_TYPE (op))) { error ("invalid conversion in return statement"); debug_generic_stmt (restype); @@ -3981,14 +4154,8 @@ verify_stmt (gimple_stmt_iterator *gsi) { if (!stmt_could_throw_p (stmt)) { - /* During IPA passes, ipa-pure-const sets nothrow flags on calls - and they are updated on statements only after fixup_cfg - is executed at beggining of expansion stage. */ - if (cgraph_state != CGRAPH_STATE_IPA_SSA) - { - error ("statement marked for throw, but doesn%'t"); - goto fail; - } + error ("statement marked for throw, but doesn%'t"); + goto fail; } else if (lp_nr > 0 && !last_in_block && stmt_can_throw_internal (stmt)) { @@ -4074,7 +4241,7 @@ verify_eh_throw_stmt_node (void **slot, void *data) /* Verify the GIMPLE statements in every basic block. */ -void +DEBUG_FUNCTION void verify_stmts (void) { basic_block bb; @@ -4422,6 +4589,10 @@ gimple_verify_flow_info (void) } break; + case GIMPLE_CALL: + if (!gimple_call_builtin_p (stmt, BUILT_IN_RETURN)) + break; + /* ... fallthru ... */ case GIMPLE_RETURN: if (!single_succ_p (bb) || (single_succ_edge (bb)->flags @@ -5441,7 +5612,7 @@ replace_by_duplicate_decl (tree *tp, struct pointer_map_t *vars_map, if (SSA_VAR_P (t)) { new_t = copy_var_decl (t, DECL_NAME (t), TREE_TYPE (t)); - f->local_decls = tree_cons (NULL_TREE, new_t, f->local_decls); + add_local_decl (f, new_t); } else { @@ -5695,21 +5866,6 @@ move_stmt_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, return NULL_TREE; } -/* Marks virtual operands of all statements in basic blocks BBS for - renaming. */ - -void -mark_virtual_ops_in_bb (basic_block bb) -{ - gimple_stmt_iterator gsi; - - for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - mark_virtual_ops_for_renaming (gsi_stmt (gsi)); - - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - mark_virtual_ops_for_renaming (gsi_stmt (gsi)); -} - /* Move basic block BB from function CFUN to function DEST_FN. The block is moved out of the original linked list and placed after block AFTER in the new list. Also, the block is removed from the @@ -5927,7 +6083,7 @@ replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map, { tree *tp, t; - for (tp = &BLOCK_VARS (block); *tp; tp = &TREE_CHAIN (*tp)) + for (tp = &BLOCK_VARS (block); *tp; tp = &DECL_CHAIN (*tp)) { t = *tp; if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != CONST_DECL) @@ -5940,7 +6096,7 @@ replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map, SET_DECL_VALUE_EXPR (t, DECL_VALUE_EXPR (*tp)); DECL_HAS_VALUE_EXPR_P (t) = 1; } - TREE_CHAIN (t) = TREE_CHAIN (*tp); + DECL_CHAIN (t) = DECL_CHAIN (*tp); *tp = t; } } @@ -6057,7 +6213,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, { eh_region region = NULL; - for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++) + FOR_EACH_VEC_ELT (basic_block, bbs, i, bb) region = find_outermost_region_in_block (saved_cfun, bb, region); init_eh_for_function (); @@ -6086,7 +6242,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, d.eh_map = eh_map; d.remap_decls_p = true; - for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++) + FOR_EACH_VEC_ELT (basic_block, bbs, i, bb) { /* No need to update edge counts on the last block. It has already been updated earlier when we detached the region from @@ -6151,7 +6307,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, } set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry); - for (i = 0; VEC_iterate (basic_block, dom_bbs, i, abb); i++) + FOR_EACH_VEC_ELT (basic_block, dom_bbs, i, abb) set_immediate_dominator (CDI_DOMINATORS, abb, bb); VEC_free (basic_block, heap, dom_bbs); @@ -6176,7 +6332,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, void dump_function_to_file (tree fn, FILE *file, int flags) { - tree arg, vars, var; + tree arg, var; struct function *dsf; bool ignore_topmost_bind = false, any_var = false; basic_block bb; @@ -6192,9 +6348,9 @@ dump_function_to_file (tree fn, FILE *file, int flags) print_generic_expr (file, arg, dump_flags); if (flags & TDF_VERBOSE) print_node (file, "", arg, 4); - if (TREE_CHAIN (arg)) + if (DECL_CHAIN (arg)) fprintf (file, ", "); - arg = TREE_CHAIN (arg); + arg = DECL_CHAIN (arg); } fprintf (file, ")\n"); @@ -6216,15 +6372,14 @@ dump_function_to_file (tree fn, FILE *file, int flags) /* When GIMPLE is lowered, the variables are no longer available in BIND_EXPRs, so display them separately. */ - if (cfun && cfun->decl == fn && cfun->local_decls) + if (cfun && cfun->decl == fn && !VEC_empty (tree, cfun->local_decls)) { + unsigned ix; ignore_topmost_bind = true; fprintf (file, "{\n"); - for (vars = cfun->local_decls; vars; vars = TREE_CHAIN (vars)) + FOR_EACH_LOCAL_DECL (cfun, ix, var) { - var = TREE_VALUE (vars); - print_generic_decl (file, var, flags); if (flags & TDF_VERBOSE) print_node (file, "", var, 4); @@ -6305,6 +6460,8 @@ dump_function_to_file (tree fn, FILE *file, int flags) fprintf (file, "}\n"); } + if (flags & TDF_ENUMERATE_LOCALS) + dump_enumerated_decls (file, flags); fprintf (file, "\n\n"); /* Restore CFUN. */ @@ -6314,7 +6471,7 @@ dump_function_to_file (tree fn, FILE *file, int flags) /* Dump FUNCTION_DECL FN to stderr using FLAGS (see TDF_* in tree.h) */ -void +DEBUG_FUNCTION void debug_function (tree fn, int flags) { dump_function_to_file (fn, stderr, flags); @@ -6455,7 +6612,7 @@ print_loops (FILE *file, int verbosity) /* Debugging loops structure at tree level, at some VERBOSITY level. */ -void +DEBUG_FUNCTION void debug_loops (int verbosity) { print_loops (stderr, verbosity); @@ -6463,7 +6620,7 @@ debug_loops (int verbosity) /* Print on stderr the code of LOOP, at some VERBOSITY level. */ -void +DEBUG_FUNCTION void debug_loop (struct loop *loop, int verbosity) { print_loop (stderr, loop, 0, verbosity); @@ -6472,7 +6629,7 @@ debug_loop (struct loop *loop, int verbosity) /* Print on stderr the code of loop number NUM, at some VERBOSITY level. */ -void +DEBUG_FUNCTION void debug_loop_num (unsigned num, int verbosity) { debug_loop (get_loop (num), verbosity); @@ -6486,7 +6643,7 @@ static bool gimple_block_ends_with_call_p (basic_block bb) { gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb); - return is_gimple_call (gsi_stmt (gsi)); + return !gsi_end_p (gsi) && is_gimple_call (gsi_stmt (gsi)); } @@ -6760,7 +6917,7 @@ remove_edge_and_dominated_blocks (edge e) else { bbs_to_remove = get_all_dominated_blocks (CDI_DOMINATORS, e->dest); - for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++) + FOR_EACH_VEC_ELT (basic_block, bbs_to_remove, i, bb) { FOR_EACH_EDGE (f, ei, bb->succs) { @@ -6768,7 +6925,7 @@ remove_edge_and_dominated_blocks (edge e) bitmap_set_bit (df, f->dest->index); } } - for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++) + FOR_EACH_VEC_ELT (basic_block, bbs_to_remove, i, bb) bitmap_clear_bit (df, bb->index); EXECUTE_IF_SET_IN_BITMAP (df, 0, i, bi) @@ -7036,7 +7193,9 @@ split_critical_edges (void) gsi = gsi_last_bb (e->src); if (!gsi_end_p (gsi) && stmt_ends_bb_p (gsi_stmt (gsi)) - && gimple_code (gsi_stmt (gsi)) != GIMPLE_RETURN) + && (gimple_code (gsi_stmt (gsi)) != GIMPLE_RETURN + && !gimple_call_builtin_p (gsi_stmt (gsi), + BUILT_IN_RETURN))) split_edge (e); } } @@ -7134,7 +7293,8 @@ execute_warn_function_return (void) FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) { last = last_stmt (e->src); - if (gimple_code (last) == GIMPLE_RETURN + if ((gimple_code (last) == GIMPLE_RETURN + || gimple_call_builtin_p (last, BUILT_IN_RETURN)) && (location = gimple_location (last)) != UNKNOWN_LOCATION) break; } @@ -7218,22 +7378,24 @@ struct gimple_opt_pass pass_warn_function_return = static unsigned int execute_warn_function_noreturn (void) { - if (warn_missing_noreturn - && !TREE_THIS_VOLATILE (cfun->decl) - && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0 - && !lang_hooks.missing_noreturn_ok_p (cfun->decl)) - warning_at (DECL_SOURCE_LOCATION (cfun->decl), OPT_Wmissing_noreturn, - "function might be possible candidate " - "for attribute %"); + if (!TREE_THIS_VOLATILE (current_function_decl) + && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0) + warn_function_noreturn (current_function_decl); return 0; } +static bool +gate_warn_function_noreturn (void) +{ + return warn_suggest_attribute_noreturn; +} + struct gimple_opt_pass pass_warn_function_noreturn = { { GIMPLE_PASS, "*warn_function_noreturn", /* name */ - NULL, /* gate */ + gate_warn_function_noreturn, /* gate */ execute_warn_function_noreturn, /* execute */ NULL, /* sub */ NULL, /* next */