From 7bb0199604cf8ba978b2fbfb751f2081faa64f87 Mon Sep 17 00:00:00 2001
From: Richard Biener <rguenther@suse.de>
Date: Mon, 14 Jan 2013 14:59:20 +0000
Subject: [PATCH] tree-cfg.c (verify_expr_location, [...]): New functions.

2013-01-14  Richard Biener  <rguenther@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.

From-SVN: r195147
---
 gcc/ChangeLog  |  7 ++++
 gcc/tree-cfg.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 105 insertions(+), 1 deletion(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7b316199bdd4..93947b6e34f8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2013-01-14  Richard Biener  <rguenther@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.
+
 2013-01-14  Richard Biener  <rguenther@suse.de>
 
 	* tree-cfgcleanup.c (remove_forwarder_block): Unshare propagated
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index e0bf7ac6b3c1..83003fb8b44c 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -4499,6 +4499,63 @@ verify_eh_throw_stmt_node (void **slot, void *data)
   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
@@ -4506,12 +4563,20 @@ verify_gimple_in_cfg (struct function *fn)
 {
   basic_block bb;
   bool err = false;
-  struct pointer_set_t *visited, *visited_stmts;
+  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;
@@ -4532,6 +4597,13 @@ verify_gimple_in_cfg (struct function *fn)
 
 	  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);
@@ -4543,6 +4615,20 @@ verify_gimple_in_cfg (struct function *fn)
 		  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)
@@ -4567,6 +4653,7 @@ verify_gimple_in_cfg (struct function *fn)
 	    }
 
 	  err2 |= verify_gimple_stmt (stmt);
+	  err2 |= verify_location (blocks, gimple_location (stmt));
 
 	  memset (&wi, 0, sizeof (wi));
 	  wi.info = (void *) visited;
@@ -4578,6 +4665,15 @@ verify_gimple_in_cfg (struct function *fn)
 	      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)
@@ -4632,6 +4728,7 @@ verify_gimple_in_cfg (struct function *fn)
 
   pointer_set_destroy (visited);
   pointer_set_destroy (visited_stmts);
+  pointer_set_destroy (blocks);
   verify_histograms ();
   timevar_pop (TV_TREE_STMT_VERIFY);
 }
-- 
GitLab