This adds a verification that we do not refer to BLOCKs not in the functions BLOCK tree from locations.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied. Richard. 2013-01-14 Richard Biener <rguent...@suse.de> * tree-cfg.c (verify_expr_location, verify_expr_location_1, verify_location, collect_subblocks): New functions. (verify_gimple_in_cfg): Verify that locations only reference BLOCKs in the functions BLOCK tree. Index: gcc/tree-cfg.c =================================================================== *** gcc/tree-cfg.c.orig 2013-01-14 14:09:49.000000000 +0100 --- gcc/tree-cfg.c 2013-01-14 14:11:29.401025151 +0100 *************** verify_eh_throw_stmt_node (void **slot, *** 4519,4524 **** --- 4519,4581 ---- return 1; } + /* Verify if the location LOCs block is in BLOCKS. */ + + static bool + verify_location (pointer_set_t *blocks, location_t loc) + { + tree block = LOCATION_BLOCK (loc); + if (block != NULL_TREE + && !pointer_set_contains (blocks, block)) + { + error ("location references block not in block tree"); + return true; + } + return false; + } + + /* Called via walk_tree. Verify locations of expressions. */ + + static tree + verify_expr_location_1 (tree *tp, int *walk_subtrees, void *data) + { + struct pointer_set_t *blocks = (struct pointer_set_t *) data; + + if (!EXPR_P (*tp)) + { + *walk_subtrees = false; + return NULL; + } + + location_t loc = EXPR_LOCATION (*tp); + if (verify_location (blocks, loc)) + return *tp; + + return NULL; + } + + /* Called via walk_gimple_op. Verify locations of expressions. */ + + static tree + verify_expr_location (tree *tp, int *walk_subtrees, void *data) + { + struct walk_stmt_info *wi = (struct walk_stmt_info *) data; + return verify_expr_location_1 (tp, walk_subtrees, wi->info); + } + + /* Insert all subblocks of BLOCK into BLOCKS and recurse. */ + + static void + collect_subblocks (pointer_set_t *blocks, tree block) + { + tree t; + for (t = BLOCK_SUBBLOCKS (block); t; t = BLOCK_CHAIN (t)) + { + pointer_set_insert (blocks, t); + collect_subblocks (blocks, t); + } + } + /* Verify the GIMPLE statements in the CFG of FN. */ DEBUG_FUNCTION void *************** verify_gimple_in_cfg (struct function *f *** 4526,4537 **** { basic_block bb; bool err = false; ! struct pointer_set_t *visited, *visited_stmts; timevar_push (TV_TREE_STMT_VERIFY); visited = pointer_set_create (); visited_stmts = pointer_set_create (); FOR_EACH_BB_FN (bb, fn) { gimple_stmt_iterator gsi; --- 4583,4602 ---- { basic_block bb; bool err = false; ! struct pointer_set_t *visited, *visited_stmts, *blocks; timevar_push (TV_TREE_STMT_VERIFY); visited = pointer_set_create (); visited_stmts = pointer_set_create (); + /* Collect all BLOCKs referenced by the BLOCK tree of FN. */ + blocks = pointer_set_create (); + if (DECL_INITIAL (fn->decl)) + { + pointer_set_insert (blocks, DECL_INITIAL (fn->decl)); + collect_subblocks (blocks, DECL_INITIAL (fn->decl)); + } + FOR_EACH_BB_FN (bb, fn) { gimple_stmt_iterator gsi; *************** verify_gimple_in_cfg (struct function *f *** 4552,4557 **** --- 4617,4629 ---- err2 |= verify_gimple_phi (phi); + /* Only PHI arguments have locations. */ + if (gimple_location (phi) != UNKNOWN_LOCATION) + { + error ("PHI node with location"); + err2 = true; + } + for (i = 0; i < gimple_phi_num_args (phi); i++) { tree arg = gimple_phi_arg_def (phi, i); *************** verify_gimple_in_cfg (struct function *f *** 4563,4568 **** --- 4635,4654 ---- debug_generic_expr (addr); err2 |= true; } + location_t loc = gimple_phi_arg_location (phi, i); + if (virtual_operand_p (gimple_phi_result (phi)) + && loc != UNKNOWN_LOCATION) + { + error ("virtual PHI with argument locations"); + err2 = true; + } + addr = walk_tree (&arg, verify_expr_location_1, blocks, NULL); + if (addr) + { + debug_generic_expr (addr); + err2 = true; + } + err2 |= verify_location (blocks, loc); } if (err2) *************** verify_gimple_in_cfg (struct function *f *** 4587,4592 **** --- 4673,4679 ---- } err2 |= verify_gimple_stmt (stmt); + err2 |= verify_location (blocks, gimple_location (stmt)); memset (&wi, 0, sizeof (wi)); wi.info = (void *) visited; *************** verify_gimple_in_cfg (struct function *f *** 4598,4603 **** --- 4685,4699 ---- err2 |= true; } + memset (&wi, 0, sizeof (wi)); + wi.info = (void *) blocks; + addr = walk_gimple_op (stmt, verify_expr_location, &wi); + if (addr) + { + debug_generic_expr (addr); + err2 |= true; + } + /* ??? Instead of not checking these stmts at all the walker should know its context via wi. */ if (!is_gimple_debug (stmt) *************** verify_gimple_in_cfg (struct function *f *** 4652,4657 **** --- 4748,4754 ---- pointer_set_destroy (visited); pointer_set_destroy (visited_stmts); + pointer_set_destroy (blocks); verify_histograms (); timevar_pop (TV_TREE_STMT_VERIFY); }