This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [graphite] tree-check patch


Hi Nic,

I have some minor cleanups for the tree-check patch.  I will commit
the following patch in a second.  I have also had some time to read
more carefully your paper on http://mygcc.free.fr/condate-ppdp06.pdf
and I have some remarks and suggestions.

The parsing of condate language is not very robust, as for example if
you insert a single empty line before the beginning of the rules in
the checks file, no rule of that file are executed.  So this part has
to be reworked.

I have also tried some of the examples of the paper: with the
following checking rule,

from  "lock (%X, %Y)"
to    "return"
avoid "unlock (%X, %Y)" 

and the following C file:

/* Compile with ./gcc/cc1 -ftree-checks="~/foo.chk" ~/foo.c */

int i = 3;
int step[10];

void critical_section (void)
{
  /* Value of step[i+1] changes before getting to the unlock.  */
  step[i+1] = 20;
  /* Condate considers only syntactic constructs, no side effects,
     aliasing, etc.  */
}

void lock (int i, int wait) {}
void unlock (int i, int wait) {}

void foo (void)
{
  lock(step[i+1], 0);
  critical_section ();
  unlock(step[i+1], 0);
  return;
}

If we consider only the syntactic information, there exist bugs for
which the checker would not trigger the warning, as in the above
example.  That is not that annoying as having correct programs where
it is impossible to silent the checker, as in the following:

void foo (void)
{
  step[i+1] = 20;
  lock(step[i+1], 0);
  critical_section ();
  unlock(20, 0);
  return;
}

For correcting these false positives, I think that the only solution
is to go the classic way, implement your checker on top of a static
semantic analysis instead of on top of a syntactic analysis.

Sebastian

	* tree-match.c: Reformat following the GNU style.
	* tree-match.h: Reformat following the GNU style.
	* tree-pattern.h: Removed empty file.
	* Makefile.in: Remove references to tree-pattern.h.
	* tree-check.c: Reformat following the GNU style.
	(execute_tree_check): Move gate condition code to...
	(gate_tree_check): ...here.  New function.
	(pass_check): Use the gate function.

Index: tree-match.c
===================================================================
*** tree-match.c	(revision 115189)
--- tree-match.c	(working copy)
*************** Software Foundation, 51 Franklin Street,
*** 40,46 ****
  #include "tree-dump.h"
  #include "tree-pass.h"
  #include "toplev.h"
- #include "tree-pattern.h"
  #include "tree-match.h"
  
  /* The tree matching user interface is described in tree-pattern.h  */
--- 40,45 ----
*************** hole global_holes[GLOBAL_MAX]; /* global
*** 49,113 ****
  hole local_holes[LOCAL_MAX]; /* local holes */
  
  /* Check whether a variable is a temporary introduced by the compiler */
  static bool 
  is_tmp_var (tree var) 
  {
    const char *name;
    if (TREE_CODE (var) != VAR_DECL)
      return false;
    /* artificial decls like return values have no name, so don't get hung */
    if (!DECL_NAME (var)) 
      return true;
    name = IDENTIFIER_POINTER (DECL_NAME (var));
    return !strncmp (name, "D.", 2) || strchr (name, '.');
  }
  
  /* If t is a cast expression, return the value without the cast */
  static tree 
  substitute_cast_expr (tree t) 
  {
    if (TREE_CODE (t) == CONVERT_EXPR || TREE_CODE (t) == NOP_EXPR)
      return TREE_OPERAND (t, 0);
    return NULL;
  }
  
! /* If t is a temporary and you can find its def from current node upwards 
!    in the same block, (including the current node or not),
!    return its value; otherwise return NULL. */
  static tree 
  substitute_tmp_var (tree var, cfg_node ctx_node, bool including_crt) 
  {
    tree val;
    if (!is_tmp_var (var))
      return NULL;
!   if (!ctx_node) /* we are at the beginning of the block, 
! 		   or the context is unknown */
      return NULL;
    if ((val = NULL, tree_scanf (cfg_node_stmt (ctx_node), "%t = %t", 
  			       NULL, &var, &val))
        || (val = NULL, 
  	  tree_scanf (cfg_node_stmt (ctx_node), "%t = (%_)%t", 
! 		     NULL, &var, &val))) {
!     if (including_crt) {
!       PP_TRACE (TRACE_MATCH_STEPS, {
! 	  fprintf (stderr, "substitute_tmp_var(");
! 	  print_generic_expr (stderr, var, 0);
! 	  fprintf (stderr, ")=");
! 	  lazy_print_generic_expr (stderr, val, 0);
! 	  fprintf (stderr, "\n");
! 	});
!       return val;
!     } else /* we are on a def, but exclude it => don't go up */
!       return NULL; 
!   } else /* we are not on a def => go up and try again */
!     return substitute_tmp_var (var, ctx_node->prev, 
! 			       true); /* true on recursive call */
  }
  
! static bool tree_equal_mod_tmps (tree t1, tree t2, cfg_node ctx_node1, 
! 				 cfg_node ctx_node2);
  
- /* Worker function for tree_equal_mod_tmps() */
  static bool 
  tree_equal (tree t1, tree t2, cfg_node ctx_node1, cfg_node ctx_node2) 
  {
--- 48,126 ----
  hole local_holes[LOCAL_MAX]; /* local holes */
  
  /* Check whether a variable is a temporary introduced by the compiler */
+ 
  static bool 
  is_tmp_var (tree var) 
  {
    const char *name;
    if (TREE_CODE (var) != VAR_DECL)
      return false;
+ 
    /* artificial decls like return values have no name, so don't get hung */
    if (!DECL_NAME (var)) 
      return true;
+ 
    name = IDENTIFIER_POINTER (DECL_NAME (var));
    return !strncmp (name, "D.", 2) || strchr (name, '.');
  }
  
  /* If t is a cast expression, return the value without the cast */
+ 
  static tree 
  substitute_cast_expr (tree t) 
  {
    if (TREE_CODE (t) == CONVERT_EXPR || TREE_CODE (t) == NOP_EXPR)
      return TREE_OPERAND (t, 0);
+ 
    return NULL;
  }
  
! /* If t is a temporary and you can find its def from current node
!    upwards in the same block, (including the current node or not),
!    return its value; otherwise return NULL.  INCLUDING_CRT is set to
!    true on recursive calls.  */
! 
  static tree 
  substitute_tmp_var (tree var, cfg_node ctx_node, bool including_crt) 
  {
    tree val;
    if (!is_tmp_var (var))
      return NULL;
! 
!   /* We are at the beginning of the block, or the context is unknown.  */
!   if (!ctx_node) 
      return NULL;
+ 
    if ((val = NULL, tree_scanf (cfg_node_stmt (ctx_node), "%t = %t", 
  			       NULL, &var, &val))
        || (val = NULL, 
  	  tree_scanf (cfg_node_stmt (ctx_node), "%t = (%_)%t", 
! 		     NULL, &var, &val)))
!     {
!       if (including_crt)
! 	{
! 	  PP_TRACE (TRACE_MATCH_STEPS, {
! 	    fprintf (stderr, "substitute_tmp_var(");
! 	    print_generic_expr (stderr, var, 0);
! 	    fprintf (stderr, ")=");
! 	    lazy_print_generic_expr (stderr, val, 0);
! 	    fprintf (stderr, "\n");
! 	  });
! 	  return val;
! 	}
!       else 
! 	/* We are on a def, but exclude it => don't go up.  */
! 	return NULL; 
!     }
!   else
!     /* We are not on a def => go up and try again.  */
!     return substitute_tmp_var (var, ctx_node->prev, true);
  }
  
! static bool tree_equal_mod_tmps (tree, tree, cfg_node, cfg_node);
! 
! /* Worker function for tree_equal_mod_tmps.  */
  
  static bool 
  tree_equal (tree t1, tree t2, cfg_node ctx_node1, cfg_node ctx_node2) 
  {
*************** tree_equal (tree t1, tree t2, cfg_node c
*** 117,126 ****
--- 130,142 ----
    
    if ((!t1 || !t2))
      return (t1 == t2);
+ 
    if (t1 == t2)
      return true;
+ 
    va1 = lazy_dump_generic_node (t1, 0, false);
    va2 = lazy_dump_generic_node (t2, 0, false);
+ 
    PP_TRACE (TRACE_MATCH_STEPS, {
      fprintf (stderr, "tree cmp:\n");
      lazy_print_generic_expr (stderr, t1, 0);
*************** tree_equal (tree t1, tree t2, cfg_node c
*** 128,162 ****
      lazy_print_generic_expr (stderr, t2, 0);
      fprintf (stderr, "---\n");
    });
    len1 = VARRAY_ACTIVE_SIZE (va1);
    len2 = VARRAY_ACTIVE_SIZE (va2);
!   if (len1 != len2) {
!     pp_free_list (va1);
!     pp_free_list (va2);
!     return 0;
!   }
!   for (i = 0; i < len1; i++) {
!     chunk1 = VARRAY_GENERIC_PTR_NOGC (va1, i);
!     chunk2 = VARRAY_GENERIC_PTR_NOGC (va2, i);
!     if ((chunk1->t || chunk2->t)
! 	&& (!(chunk1->t && chunk2->t) 
! 	    || !tree_equal_mod_tmps (chunk1->t, chunk2->t, 
! 				     ctx_node1, ctx_node2))) {
        pp_free_list (va1);
        pp_free_list (va2);
        return 0;
!     } else if ((chunk1->s || chunk2->s)
  	       && (!(chunk1->s && chunk2->s) 
! 		   || strcmp (chunk1->s, chunk2->s))) {
!       pp_free_list (va1);
!       pp_free_list (va2);
!       return 0;
!     } else if (chunk1->c != chunk2->c) { /* one-character chunk */
!       pp_free_list (va1);
!       pp_free_list (va2);
!       return 0;
      }
!   }
    pp_free_list (va1);
    pp_free_list (va2);
    return 1;
--- 144,193 ----
      lazy_print_generic_expr (stderr, t2, 0);
      fprintf (stderr, "---\n");
    });
+ 
    len1 = VARRAY_ACTIVE_SIZE (va1);
    len2 = VARRAY_ACTIVE_SIZE (va2);
! 
!   if (len1 != len2)
!     {
        pp_free_list (va1);
        pp_free_list (va2);
        return 0;
!     }
! 
!   for (i = 0; i < len1; i++)
!     {
!       chunk1 = VARRAY_GENERIC_PTR_NOGC (va1, i);
!       chunk2 = VARRAY_GENERIC_PTR_NOGC (va2, i);
! 
!       if ((chunk1->t || chunk2->t)
! 	  && (!(chunk1->t && chunk2->t) 
! 	      || !tree_equal_mod_tmps (chunk1->t, chunk2->t, 
! 				       ctx_node1, ctx_node2)))
! 	{
! 	  pp_free_list (va1);
! 	  pp_free_list (va2);
! 	  return 0;
! 	}
! 
!       else if ((chunk1->s || chunk2->s)
  	       && (!(chunk1->s && chunk2->s) 
! 		   || strcmp (chunk1->s, chunk2->s)))
! 	{
! 	  pp_free_list (va1);
! 	  pp_free_list (va2);
! 	  return 0;
! 	}
! 
!       else if (chunk1->c != chunk2->c)
! 	{
! 	  /* one-character chunk */
! 	  pp_free_list (va1);
! 	  pp_free_list (va2);
! 	  return 0;
! 	}
      }
! 
    pp_free_list (va1);
    pp_free_list (va2);
    return 1;
*************** tree_equal (tree t1, tree t2, cfg_node c
*** 164,224 ****
  
  /* Check if two trees are equal, modulo casts and substitutions of
     tmp vars with their values. */
  static bool 
  tree_equal_mod_tmps (tree t1, tree t2, cfg_node ctx_node1, cfg_node ctx_node2) 
  {
    tree val;
    if ((!t1 || !t2))
      return (t1 == t2);
!   return (tree_equal (t1, t2, ctx_node1, ctx_node2) ||
! 	  ((val = substitute_tmp_var (t1, ctx_node1, false)) != NULL &&
! 	   tree_equal_mod_tmps (val, t2, ctx_node1, ctx_node2)) ||
! 	  ((val = substitute_tmp_var (t2, ctx_node2, false)) != NULL &&
! 	   tree_equal_mod_tmps (t1, val, ctx_node1, ctx_node2)) ||
! 	  ((val = substitute_cast_expr (t1)) != NULL &&
! 	   tree_equal_mod_tmps (val, t2, ctx_node1, ctx_node2)) ||
! 	  ((val = substitute_cast_expr (t2)) != NULL &&
! 	   tree_equal_mod_tmps (t1, val, ctx_node1, ctx_node2))
! 	  );
  }
  	  
! static char tree_1st_char (tree t);
  
  /* Get the first character of (the printed form of) a tree chunk */
  static char 
  chunk_1st_char (tree_chunk *chunk) 
  {
    if (chunk->t)
      return tree_1st_char (chunk->t);
    else if (chunk->s)
      return *chunk->s;
    else 
      return chunk->c;
  }
  
  /* Search the first chunk of a lazy list not consisting of whitespace */
  static tree_chunk *
  chunks_lookahead (varray_type va, unsigned int i) 
  {
    tree_chunk *chunk;
    do {
      chunk = VARRAY_GENERIC_PTR_NOGC (va, i);
      i++;
    } while (chunk->c && chunk->c == ' ' && i <= VARRAY_ACTIVE_SIZE (va));
    return chunk;
  }
  
  /* Get the first character of (the printed form of) a tree */
  static char 
  tree_1st_char (tree t) 
  {
    varray_type va;
    tree_chunk *chunk;
  
!   /* don't hung on unnamed vars, etc. */
!   if (TREE_CODE (t) == VAR_DECL ||
!       TREE_CODE_CLASS (TREE_CODE (t)) == 'x')
!     return '\0'; /* cannot dump these nodes */
    va = lazy_dump_generic_node (t, 0, false);
    chunk = chunks_lookahead (va, 0);
    pp_free_list (va);
--- 195,264 ----
  
  /* Check if two trees are equal, modulo casts and substitutions of
     tmp vars with their values. */
+ 
  static bool 
  tree_equal_mod_tmps (tree t1, tree t2, cfg_node ctx_node1, cfg_node ctx_node2) 
  {
    tree val;
+ 
    if ((!t1 || !t2))
      return (t1 == t2);
! 
!   return (tree_equal (t1, t2, ctx_node1, ctx_node2)
! 	  || ((val = substitute_tmp_var (t1, ctx_node1, false)) != NULL
! 	      && tree_equal_mod_tmps (val, t2, ctx_node1, ctx_node2))
! 	  || ((val = substitute_tmp_var (t2, ctx_node2, false)) != NULL
! 	      && tree_equal_mod_tmps (t1, val, ctx_node1, ctx_node2))
! 	  || ((val = substitute_cast_expr (t1)) != NULL
! 	      && tree_equal_mod_tmps (val, t2, ctx_node1, ctx_node2))
! 	  || ((val = substitute_cast_expr (t2)) != NULL
! 	      && tree_equal_mod_tmps (t1, val, ctx_node1, ctx_node2)));
  }
  	  
! static char tree_1st_char (tree);
  
  /* Get the first character of (the printed form of) a tree chunk */
+ 
  static char 
  chunk_1st_char (tree_chunk *chunk) 
  {
    if (chunk->t)
      return tree_1st_char (chunk->t);
+ 
    else if (chunk->s)
      return *chunk->s;
+ 
    else 
      return chunk->c;
  }
  
  /* Search the first chunk of a lazy list not consisting of whitespace */
+ 
  static tree_chunk *
  chunks_lookahead (varray_type va, unsigned int i) 
  {
    tree_chunk *chunk;
+ 
    do {
      chunk = VARRAY_GENERIC_PTR_NOGC (va, i);
      i++;
    } while (chunk->c && chunk->c == ' ' && i <= VARRAY_ACTIVE_SIZE (va));
+ 
    return chunk;
  }
  
  /* Get the first character of (the printed form of) a tree */
+ 
  static char 
  tree_1st_char (tree t) 
  {
    varray_type va;
    tree_chunk *chunk;
  
!   /* Don't hung on unnamed vars, etc.  Cannot dump these nodes.  */
!   if (TREE_CODE (t) == VAR_DECL || TREE_CODE_CLASS (TREE_CODE (t)) == 'x')
!     return '\0';
! 
    va = lazy_dump_generic_node (t, 0, false);
    chunk = chunks_lookahead (va, 0);
    pp_free_list (va);
*************** tree_1st_char (tree t) 
*** 226,255 ****
  }
  
  /* Get the first non-space character in a pattern */
  static char 
  pattern_lookahead (patt_info *patt, int n) 
  {
    const char *s = patt->format_spec + n;
    int skip = 0;
!   do 
!     {
!       if (s[0] == '\\' && s[1] == ')')
! 	skip = 2;
!       else if (s[0] == ' ')
! 	skip = 1;
!       else 
! 	skip = 0;
!       s += skip;
!     } 
!   while (skip);
    return s[0];
  }
  
! static bool match_tree_pattinfo (tree t, patt_info *patt, const char *delim, 
! 				 cfg_node ctx_node);
  
! /* Worker function for match_tree_pattinfo(). Matches a lazy list with
     a pattern. */
  static bool 
  match_chunks_pattinfo (varray_type va, patt_info *patt, const char *delim, 
  		       cfg_node ctx_node) 
--- 266,299 ----
  }
  
  /* Get the first non-space character in a pattern */
+ 
  static char 
  pattern_lookahead (patt_info *patt, int n) 
  {
    const char *s = patt->format_spec + n;
    int skip = 0;
! 
!   do {
!     if (s[0] == '\\' && s[1] == ')')
!       skip = 2;
! 
!     else if (s[0] == ' ')
!       skip = 1;
! 
!     else 
!       skip = 0;
! 
!     s += skip;
!   } while (skip);
! 
    return s[0];
  }
  
! static bool match_tree_pattinfo (tree, patt_info *, const char *, cfg_node);
  
! /* Worker function for match_tree_pattinfo.  Matches a lazy list with
     a pattern. */
+ 
  static bool 
  match_chunks_pattinfo (varray_type va, patt_info *patt, const char *delim, 
  		       cfg_node ctx_node) 
*************** match_chunks_pattinfo (varray_type va, p
*** 260,331 ****
    for (i = 0; i < VARRAY_ACTIVE_SIZE (va); i++) 
      {
        chunk = VARRAY_GENERIC_PTR_NOGC (va, i);
!       if (chunk->t) {
! 	/* Compute delimiter for t */
! 	char next_char = (i + 1 == VARRAY_ACTIVE_SIZE (va)?
! 			  *delim : 
! 			  chunk_1st_char (chunks_lookahead (va, i + 1)));
! 	PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "tree delimited by %c", 
! 					      next_char));
! 	PP_TRACE (TRACE_MATCH_STEPS, {
  	    fprintf (stderr, "{match_tree_pattinfo(");
  	    print_generic_expr (stderr, chunk->t, 0); 
  	    fprintf (stderr, ", \"%s\") ", patt->format_spec);
  	  });
! 	if (!match_tree_pattinfo (chunk->t, patt, &next_char, ctx_node)) {
! 	  PP_TRACE (TRACE_MATCH_STEPS, 
! 		    fprintf (stderr, "=> fail tree chunk} "));
! 	  return 0;
! 	}
! 	PP_TRACE (TRACE_MATCH_STEPS, 
! 		  fprintf (stderr, "=> succeed tree chunk} "));
!       } else if (chunk->s) { 
! 	if (*patt->format_spec == '%') {
! 	  PP_TRACE (TRACE_MATCH_STEPS, 
! 		    fprintf (stderr, "fail str chunk '%s' vs hole", chunk->s));
! 	  return 0;
! 	} else {
! 	  if (memcmp (patt->format_spec, chunk->s, strlen (chunk->s))) {
! 	    char *x = strndup (patt->format_spec, strlen (chunk->s));
! 	    PP_TRACE (TRACE_MATCH_STEPS, 
! 		      fprintf (stderr, "fail str chunk '%s' vs patt '%s'", 
! 			       chunk->s, x));
! 	    free (x);
  	    return 0;
  	  }
! 	patt->format_spec += strlen (chunk->s);
  	PP_TRACE (TRACE_MATCH_STEPS, 
! 		  fprintf (stderr, "succeed str chunk '%s' vs patt", 
! 			   chunk->s));
  	}
!       } else { /* one-character chunk */
! 	if (chunk->c ==  ' ') { /* whitespace */
! 	  while (*patt->format_spec == ' ') 
! 	    patt->format_spec++;
! 	  PP_TRACE (TRACE_MATCH_STEPS, 
! 		    fprintf (stderr, 
! 			     "succeed space chunk vs patt whitespace"));
! 	} else { /* not whitespace */
! 	  if (*patt->format_spec == '%') {
! 	    PP_TRACE (TRACE_MATCH_STEPS, 
! 		      fprintf (stderr, "fail char chunk '%c' vs hole", 
! 			       chunk->c));
! 	    return 0;
! 	  } else {
! 	    if (*patt->format_spec != chunk->c) {
  	      PP_TRACE (TRACE_MATCH_STEPS, 
! 			fprintf (stderr, "fail char chunk '%c' vs patt '%c'",
! 				 chunk->c, *patt->format_spec));
  	      return 0;
  	    }
! 	    PP_TRACE (TRACE_MATCH_STEPS, 
! 		      fprintf (stderr, "succeed char chunk '%c' vs patt", 
! 			       chunk->c));
! 	    patt->format_spec++;
! 	  }
  	}
!       }
!     } /* for */
    return 1;
  }
  
--- 304,404 ----
    for (i = 0; i < VARRAY_ACTIVE_SIZE (va); i++) 
      {
        chunk = VARRAY_GENERIC_PTR_NOGC (va, i);
! 
!       if (chunk->t)
! 	{
! 	  /* Compute delimiter for t.  */
! 	  char next_char = (i + 1 == VARRAY_ACTIVE_SIZE (va) ?
! 			    *delim : 
! 			    chunk_1st_char (chunks_lookahead (va, i + 1)));
! 
! 	  PP_TRACE (TRACE_MATCH_STEPS, 
! 		    fprintf (stderr, "tree delimited by %c", next_char));
! 	  PP_TRACE (TRACE_MATCH_STEPS, {
  	    fprintf (stderr, "{match_tree_pattinfo(");
  	    print_generic_expr (stderr, chunk->t, 0); 
  	    fprintf (stderr, ", \"%s\") ", patt->format_spec);
  	  });
! 
! 	if (!match_tree_pattinfo (chunk->t, patt, &next_char, ctx_node))
! 	  {
! 	    PP_TRACE (TRACE_MATCH_STEPS,
! 		      fprintf (stderr, "=> fail tree chunk} "));
  	    return 0;
  	  }
! 
  	PP_TRACE (TRACE_MATCH_STEPS, 
! 		  fprintf (stderr, "=> succeed tree chunk} "));
  	}
!       else if (chunk->s)
! 	{ 
! 	  if (*patt->format_spec == '%')
! 	    {
  	      PP_TRACE (TRACE_MATCH_STEPS, 
! 			fprintf (stderr, "fail str chunk '%s' vs hole",
! 				 chunk->s));
  	      return 0;
  	    }
! 	  else
! 	    {
! 	      if (memcmp (patt->format_spec, chunk->s, strlen (chunk->s)))
! 		{
! 		  char *x = strndup (patt->format_spec, strlen (chunk->s));
! 		  PP_TRACE (TRACE_MATCH_STEPS, 
! 			    fprintf (stderr, "fail str chunk '%s' vs patt '%s'",
! 				     chunk->s, x));
! 		  free (x);
! 		  return 0;
! 		}
! 
! 	      patt->format_spec += strlen (chunk->s);
! 	      PP_TRACE (TRACE_MATCH_STEPS, 
! 			fprintf (stderr, "succeed str chunk '%s' vs patt", 
! 				 chunk->s));
! 	    }
  	}
!       else
! 	{
! 	  /* one-character chunk */
! 	  if (chunk->c ==  ' ')
! 	    {
! 	      /* whitespace */
! 	      while (*patt->format_spec == ' ') 
! 		patt->format_spec++;
! 
! 	      PP_TRACE (TRACE_MATCH_STEPS, 
! 			fprintf (stderr, 
! 				 "succeed space chunk vs patt whitespace"));
! 	    }
! 	  else
! 	    {
! 	      /* not whitespace */
! 	      if (*patt->format_spec == '%')
! 		{
! 		  PP_TRACE (TRACE_MATCH_STEPS, 
! 			    fprintf (stderr, "fail char chunk '%c' vs hole", 
! 				     chunk->c));
! 		  return 0;
! 		}
! 	      else
! 		{
! 		  if (*patt->format_spec != chunk->c)
! 		    {
! 		      PP_TRACE (TRACE_MATCH_STEPS, 
! 				fprintf (stderr,
! 					 "fail char chunk '%c' vs patt '%c'",
! 					 chunk->c, *patt->format_spec));
! 		      return 0;
! 		    }
! 
! 		  PP_TRACE (TRACE_MATCH_STEPS, 
! 			    fprintf (stderr, "succeed char chunk '%c' vs patt", 
! 				     chunk->c));
! 		  patt->format_spec++;
! 		}
! 	    }
! 	}
!     }
    return 1;
  }
  
*************** match_chunks_pattinfo (varray_type va, p
*** 334,341 ****
     va_args, so consume the args as you go.  Otherwise (args is null),
     you have a pattern with named holes.  The ctx_node (if non-null)
     indicates the cfg_node where the tree is supposed to occur, in case
!    some tmp vars are to be searched for from this point backwards.
! */
  static bool
  match_tree_pattinfo (tree t, patt_info *patt, const char *delim, 
  		     cfg_node ctx_node)
--- 407,414 ----
     va_args, so consume the args as you go.  Otherwise (args is null),
     you have a pattern with named holes.  The ctx_node (if non-null)
     indicates the cfg_node where the tree is supposed to occur, in case
!    some tmp vars are to be searched for from this point backwards.  */
! 
  static bool
  match_tree_pattinfo (tree t, patt_info *patt, const char *delim, 
  		     cfg_node ctx_node)
*************** match_tree_pattinfo (tree t, patt_info *
*** 349,428 ****
  
    if (patt->format_spec[0] == '%'
        && TREE_CODE (t) != TREE_LIST /* don't match entire lists */
!       && *delim == pattern_lookahead (patt, 2)) { /* lookahead(1) ok */
!     if (patt->format_spec[1] != '_') {/* not "any" hole */
!       if (patt->args_ptr) /* anonymous holes */
! 	pt = va_arg (*patt->args_ptr, tree *);
!       else { /* named holes */ 
! 	ph = get_hole_named (patt->format_spec[1]); 
! 	if (!ph) 
! 	  fatal_error ("Invalid pattern variable: %%%c\n", 
! 		       patt->format_spec[1]);
! 	pt = &ph->tree;
!       }
!       if (!*pt) { /* var hole */
! 	/* refuse to catch a tmpvar def */
! 	if (is_tmp_var (t) && ctx_node &&
! 	    (tree_scanf (cfg_node_stmt (ctx_node), "%t = %_", NULL, &t) ||
! 	     tree_scanf (cfg_node_stmt (ctx_node), "%t = (%_)%_", NULL, &t))) {
! 	  PP_TRACE (TRACE_MATCH_STEPS, 
! 		    fprintf (stderr, 
! 			     "refusing to assign tmpvar def to global hole"));
! 	  return 0;
  	}
! 	PP_TRACE (TRACE_MATCH_STEPS, 
! 		  fprintf (stderr, "assign tree chunk to hole"));
! 	*pt = t;
! 	if (ph) ph->ctx = ctx_node;
!       } else { /* instantiated hole */
! 	if (!tree_equal_mod_tmps (*pt, t, ph? ph->ctx : NULL, ctx_node)) {
! 	  PP_TRACE (TRACE_MATCH_STEPS, 
! 		    fprintf (stderr, "fail eq tree chunk vs hole"));
! 	  return 0;
  	}
! 	PP_TRACE (TRACE_MATCH_STEPS, 
! 		  fprintf (stderr, "succeed eq tree chunk vs hole"));
!       }
!     } /* else (%_) just go on */
!     patt->format_spec += 2; /* consume %h */
!     return 1;
!   } else { /* can't swallow a whole tree, must recurse on it */
!     PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "check chunks vs patt"));
!     /* check an eventual pattern-only '(' to be skipped */
!     if (patt->format_spec[0] == '\\' && patt->format_spec[1] == '(') {
!       PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "[skip lpar]"));
!       patt->format_spec+=2; parskip = 1;
!     }
! 
!     /* On a tmpvar or a cast, there is no point to recurse directly (they
!        cannot be in the pattern), so substitute it before */
!     while ((val = substitute_tmp_var (t, ctx_node, false)) != NULL
! 	   || (val = substitute_cast_expr (t)) != NULL) {
!       PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "succeed subst tmp"));
!       t = val;
!     }
! 
!     maybe_init_pretty_print (stdout);
!     va = lazy_dump_generic_node (t, 0, false);
!     res = match_chunks_pattinfo (va, patt, delim, ctx_node);
!     pp_free_list (va);
!     PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "%s chunks vs patt",
! 					  (res? "succeed": "fail")));
!     /* if needed, look for corresponding pattern-only ')' */
!     if (res && parskip) {
!       if (patt->format_spec[0] == '\\' && patt->format_spec[1] == ')') {
! 	PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "[skip rpar]"));
! 	patt->format_spec+=2;
!       } else {
! 	PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "[no rpar!]"));
! 	res = 0;
!       }
      }
-     return res;
-   }
  }
  
  /* Check whether a hole name represents a global variable */
  inline bool 
  is_global_hole (char c) 
  {
--- 422,533 ----
  
    if (patt->format_spec[0] == '%'
        && TREE_CODE (t) != TREE_LIST /* don't match entire lists */
!       && *delim == pattern_lookahead (patt, 2))
!     {
!       /* lookahead(1) ok */
!       if (patt->format_spec[1] != '_')
! 	{
! 	  /* not "any" hole */
! 	  if (patt->args_ptr) /* anonymous holes */
! 	    pt = va_arg (*patt->args_ptr, tree *);
! 	  else
! 	    {
! 	      /* named holes */ 
! 	      ph = get_hole_named (patt->format_spec[1]); 
! 
! 	      if (!ph) 
! 		fatal_error ("Invalid pattern variable: %%%c\n", 
! 			     patt->format_spec[1]);
! 
! 	      pt = &ph->tree;
! 	    }
! 
! 	  if (!*pt)
! 	    { 
! 	      /* var hole */
! 	      /* refuse to catch a tmpvar def */
! 	      if (is_tmp_var (t) && ctx_node &&
! 		  (tree_scanf (cfg_node_stmt (ctx_node), "%t = %_", NULL, &t)
! 		   || tree_scanf (cfg_node_stmt (ctx_node), "%t = (%_)%_",
! 				  NULL, &t)))
! 		{
! 		  PP_TRACE (TRACE_MATCH_STEPS, 
! 			    fprintf (stderr, 
! 				     "refusing to assign tmpvar def to global hole"));
! 		  return 0;
! 		}
! 
! 	      PP_TRACE (TRACE_MATCH_STEPS, 
! 			fprintf (stderr, "assign tree chunk to hole"));
! 	      *pt = t;
! 	      if (ph)
! 		ph->ctx = ctx_node;
! 	    }
! 	  else
! 	    {
! 	      /* instantiated hole */
! 	      if (!tree_equal_mod_tmps (*pt, t, ph? ph->ctx : NULL, ctx_node))
! 		{
! 		  PP_TRACE (TRACE_MATCH_STEPS, 
! 			    fprintf (stderr, "fail eq tree chunk vs hole"));
! 		  return 0;
! 		}
! 	      PP_TRACE (TRACE_MATCH_STEPS, 
! 			fprintf (stderr, "succeed eq tree chunk vs hole"));
! 	    }
! 	} /* else (%_) just go on */
! 
!       patt->format_spec += 2; /* consume %h */
!       return 1;
!     }
!   else
!     {
!       /* can't swallow a whole tree, must recurse on it */
!       PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "check chunks vs patt"));
!       /* check an eventual pattern-only '(' to be skipped */
!       if (patt->format_spec[0] == '\\' && patt->format_spec[1] == '(')
! 	{
! 	  PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "[skip lpar]"));
! 	  patt->format_spec+=2; parskip = 1;
  	}
! 
!       /* On a tmpvar or a cast, there is no point to recurse directly (they
! 	 cannot be in the pattern), so substitute it before */
!       while ((val = substitute_tmp_var (t, ctx_node, false)) != NULL
! 	     || (val = substitute_cast_expr (t)) != NULL)
! 	{
! 	  PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "succeed subst tmp"));
! 	  t = val;
  	}
! 
!       maybe_init_pretty_print (stdout);
!       va = lazy_dump_generic_node (t, 0, false);
!       res = match_chunks_pattinfo (va, patt, delim, ctx_node);
!       pp_free_list (va);
!       PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "%s chunks vs patt",
! 					    (res? "succeed": "fail")));
! 
!       /* if needed, look for corresponding pattern-only ')' */
!       if (res && parskip)
! 	{
! 	  if (patt->format_spec[0] == '\\' && patt->format_spec[1] == ')') 
! 	    {
! 	      PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "[skip rpar]"));
! 	      patt->format_spec+=2;
! 	    }
! 	  else
! 	    {
! 	      PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "[no rpar!]"));
! 	      res = 0;
! 	    }
! 	}
! 
!       return res;
      }
  }
  
  /* Check whether a hole name represents a global variable */
+ 
  inline bool 
  is_global_hole (char c) 
  {
*************** is_global_hole (char c) 
*** 430,446 ****
--- 535,555 ----
  }
  
  /* Get the hole named by a (local or global) variable name */
+ 
  hole *
  get_hole_named (char c) 
  {
    if ('a' <= c && c <= 'z')
      return &local_holes[c - 'a'];
+ 
    if ('A' <= c && c <= 'Z')
      return &global_holes[c - 'A'];
+ 
    return NULL;
  }
  
  /* Unbind all global variables */
+ 
  void 
  reset_global_holes (void) 
  {
*************** reset_global_holes (void) 
*** 453,458 ****
--- 562,568 ----
  }
  
  /* Unbind all local variables */
+ 
  void 
  reset_local_holes (void) 
  {
*************** reset_local_holes (void) 
*** 465,470 ****
--- 575,581 ----
  }
  
  /* Save the values of all global variables in a buffer */
+ 
  hole *
  save_global_holes (void) 
  {
*************** save_global_holes (void) 
*** 474,479 ****
--- 585,591 ----
  }
  
  /* Restore the values of all global variables from a buffer */
+ 
  void 
  restore_global_holes (hole *saved) 
  {
*************** restore_global_holes (hole *saved) 
*** 482,537 ****
  }
  
  /* Compare two sets of global variables */
  bool 
  eq_global_holes (hole *holes1, hole *holes2) 
  {
    int i;
    for (i=0; i<GLOBAL_MAX; i++)
      if (!tree_equal_mod_tmps (holes1[i].tree, holes2[i].tree, 
  			      holes1[i].ctx, holes2[i].ctx))
        return 0;
    return 1;
  }
  
  /* Print the list of bounded local variables */
  void 
  print_local_holes (void) 
  {
    int i;
    for (i=0; i<LOCAL_MAX; i++) 
      {
!       if (local_holes[i].tree) {
! 	fprintf (stderr, "local_holes[%d] == ", i);
! 	print_generic_expr (stderr, local_holes[i].tree, 0); 
! 	fprintf (stderr, "\n");
!       }
      }
  }
  
  /* Print the list of bounded global variables */
  void 
  print_global_holes (void) 
  {
    int i, state = 0;
    fprintf (stderr, "{");
    for (i=0; i<GLOBAL_MAX; i++) 
      {
!       if (global_holes[i].tree) {
! 	if (state) 
! 	  fprintf (stderr, ", ");
! 	fprintf (stderr, "%c <- ", 'A' + i);
! 	print_generic_expr (stderr, global_holes[i].tree, 0);
! 	state = 1;
!       }
      }
    fprintf (stderr, "}");
  }
  
  /* Match a tree with a pattern with anonymous holes, and bind the
!    corresponding subtrees to the list of extra arguments. Returns true
!    if the tree completely matched the pattern, false otherwise. Even
!    on unsuccessful match, some holes might be filled in.
!  */
  bool
  tree_scanf (tree t, const char *fmt, cfg_node ctx_node, ...)
  {
--- 594,660 ----
  }
  
  /* Compare two sets of global variables */
+ 
  bool 
  eq_global_holes (hole *holes1, hole *holes2) 
  {
    int i;
+ 
    for (i=0; i<GLOBAL_MAX; i++)
      if (!tree_equal_mod_tmps (holes1[i].tree, holes2[i].tree, 
  			      holes1[i].ctx, holes2[i].ctx))
        return 0;
+ 
    return 1;
  }
  
  /* Print the list of bounded local variables */
+ 
  void 
  print_local_holes (void) 
  {
    int i;
+ 
    for (i=0; i<LOCAL_MAX; i++) 
      {
!       if (local_holes[i].tree)
! 	{
! 	  fprintf (stderr, "local_holes[%d] == ", i);
! 	  print_generic_expr (stderr, local_holes[i].tree, 0); 
! 	  fprintf (stderr, "\n");
! 	}
      }
  }
  
  /* Print the list of bounded global variables */
+ 
  void 
  print_global_holes (void) 
  {
    int i, state = 0;
+ 
    fprintf (stderr, "{");
+ 
    for (i=0; i<GLOBAL_MAX; i++) 
      {
!       if (global_holes[i].tree)
! 	{
! 	  if (state) 
! 	    fprintf (stderr, ", ");
! 	  fprintf (stderr, "%c <- ", 'A' + i);
! 	  print_generic_expr (stderr, global_holes[i].tree, 0);
! 	  state = 1;
! 	}
      }
+ 
    fprintf (stderr, "}");
  }
  
  /* Match a tree with a pattern with anonymous holes, and bind the
!    corresponding subtrees to the list of extra arguments.  Returns
!    true if the tree completely matched the pattern, false otherwise.
!    Even on unsuccessful match, some holes might be filled in.  */
! 
  bool
  tree_scanf (tree t, const char *fmt, cfg_node ctx_node, ...)
  {
*************** tree_scanf (tree t, const char *fmt, cfg
*** 550,555 ****
--- 673,679 ----
    res = match_tree_pattinfo (t, &patt, "", ctx_node);
    PP_TRACE (TRACE_MATCH_STEPS, fprintf (stderr, "} "));
    va_end (ap);
+ 
    /* nothing left in the pattern ? */
    if (res && (*patt.format_spec == '\0'))
      return true;
*************** tree_scanf (tree t, const char *fmt, cfg
*** 557,563 ****
      return false;
  }
  
! /* Match a tree against an atomic pattern with named holes. */
  bool
  tree_match (tree t, const char *fmt, cfg_node ctx_node)
  {
--- 681,688 ----
      return false;
  }
  
! /* Match a tree against an atomic pattern with named holes.  */
! 
  bool
  tree_match (tree t, const char *fmt, cfg_node ctx_node)
  {
*************** tree_match (tree t, const char *fmt, cfg
*** 572,592 ****
    PP_TRACE (TRACE_MATCH_STEPS, 
  	    fprintf (stderr, "=>match returned %d, and fmt='%s'\n", 
  		     res, patt.format_spec));
    /* nothing left in the pattern ? */
    if (res && (*patt.format_spec == '\0'))
      return true;
!   else {
!     restore_global_holes (old_global_holes); /* unbind global holes */
!     return false;
!   }
  }
  
  /* Match a tree against a disjunctive pattern with named holes. */
  bool 
  tree_match_disj (tree t, pattern patt, cfg_node ctx_node) 
  {
    if (!patt)
      return false;
!   return (tree_match (t, patt->format_spec, ctx_node) ||
! 	  (patt->next && tree_match_disj (t, patt->next, ctx_node)));
  }
--- 697,721 ----
    PP_TRACE (TRACE_MATCH_STEPS, 
  	    fprintf (stderr, "=>match returned %d, and fmt='%s'\n", 
  		     res, patt.format_spec));
+ 
    /* nothing left in the pattern ? */
    if (res && (*patt.format_spec == '\0'))
      return true;
!   else
!     {
!       restore_global_holes (old_global_holes); /* unbind global holes */
!       return false;
!     }
  }
  
  /* Match a tree against a disjunctive pattern with named holes. */
+ 
  bool 
  tree_match_disj (tree t, pattern patt, cfg_node ctx_node) 
  {
    if (!patt)
      return false;
! 
!   return (tree_match (t, patt->format_spec, ctx_node) 
! 	  || (patt->next && tree_match_disj (t, patt->next, ctx_node)));
  }
Index: tree-match.h
===================================================================
*** tree-match.h	(revision 115189)
--- tree-match.h	(working copy)
*************** Software Foundation, 51 Franklin Street,
*** 28,44 ****
  typedef struct tree_statement_list_node *cfg_node;
  
  /* Accessor for a CFG node */
! static inline tree cfg_node_stmt (cfg_node node) {
    return node->stmt;
  }
  
  /* Map a statement iterator to a CFG node */
! static inline cfg_node bsi_cfg_node (block_stmt_iterator bsi) {
    return bsi.tsi.ptr;
  }
  
  /* Get 1st CFG node in a basic block */
! static inline cfg_node bb_1st_cfg_node (basic_block bb) {
    return STATEMENT_LIST_HEAD (bb->stmt_list);
  }
  
--- 28,50 ----
  typedef struct tree_statement_list_node *cfg_node;
  
  /* Accessor for a CFG node */
! static inline tree
! cfg_node_stmt (cfg_node node)
! {
    return node->stmt;
  }
  
  /* Map a statement iterator to a CFG node */
! static inline cfg_node
! bsi_cfg_node (block_stmt_iterator bsi)
! {
    return bsi.tsi.ptr;
  }
  
  /* Get 1st CFG node in a basic block */
! static inline cfg_node
! bb_1st_cfg_node (basic_block bb)
! {
    return STATEMENT_LIST_HEAD (bb->stmt_list);
  }
  
*************** typedef struct patt_info_s {
*** 51,56 ****
--- 57,63 ----
    va_list *args_ptr; /* only used for anomymous holes */
    struct patt_info_s *next;
  } patt_info;
+ 
  typedef patt_info *pattern;
  
  /* Atomic pattern constructor */
*************** pat_print (pattern p) 
*** 88,99 ****
  {
    if (!p)
      return;
    if (!p->next) 
      fprintf (stderr, "\"%s\"", p->format_spec);
!   else {
!     fprintf (stderr, "\"%s\" or ", p->format_spec);
!     pat_print (p->next);
!   } 
  }
  
  /* A "hole" is a pattern variable (aka meta-variable). It contains a
--- 95,108 ----
  {
    if (!p)
      return;
+ 
    if (!p->next) 
      fprintf (stderr, "\"%s\"", p->format_spec);
!   else
!     {
!       fprintf (stderr, "\"%s\" or ", p->format_spec);
!       pat_print (p->next);
!     }
  }
  
  /* A "hole" is a pattern variable (aka meta-variable). It contains a
Index: Makefile.in
===================================================================
*** Makefile.in	(revision 115189)
--- Makefile.in	(working copy)
*************** STAGECOPYSTUFF = insn-flags.h insn-confi
*** 1034,1040 ****
   insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \
   insn-attr.h insn-attrtab.c insn-opinit.c insn-preds.c insn-constants.h \
   tm-preds.h tm-constrs.h \
!  tree-check.h tree-pattern.h min-insn-modes.c insn-modes.c insn-modes.h \
   genrtl.c genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-gen.h
  
  # Files to be moved away after each stage in building.
--- 1034,1040 ----
   insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \
   insn-attr.h insn-attrtab.c insn-opinit.c insn-preds.c insn-constants.h \
   tm-preds.h tm-constrs.h \
!  tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \
   genrtl.c genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-gen.h
  
  # Files to be moved away after each stage in building.
*************** tree-check.o : tree-check.c $(TREE_FLOW_
*** 1935,1947 ****
     $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
     $(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \
     $(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h $(HASHTAB_H) toplev.h \
!    tree-ssa-propagate.h tree-pattern.h tree-match.h
  tree-match.o : tree-match.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
     $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
     $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
     $(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \
     $(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h $(HASHTAB_H) toplev.h \
!    tree-ssa-propagate.h tree-pattern.h tree-match.h
  tree-cfgcleanup.o : tree-cfgcleanup.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
     $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
     $(DIAGNOSTIC_H) errors.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
--- 1935,1947 ----
     $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
     $(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \
     $(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h $(HASHTAB_H) toplev.h \
!    tree-ssa-propagate.h tree-match.h
  tree-match.o : tree-match.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
     $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
     $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
     $(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \
     $(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h $(HASHTAB_H) toplev.h \
!    tree-ssa-propagate.h tree-match.h
  tree-cfgcleanup.o : tree-cfgcleanup.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
     $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
     $(DIAGNOSTIC_H) errors.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
Index: tree-pattern.h
===================================================================
Index: tree-check.c
===================================================================
*** tree-check.c	(revision 115189)
--- tree-check.c	(working copy)
*************** Software Foundation, 51 Franklin Street,
*** 39,58 ****
  #include "tree-dump.h"
  #include "tree-pass.h"
  #include "toplev.h"
- #include "tree-pattern.h"
  #include "tree-match.h"
  
  /* Raise a warning upon detecting a satisfied condate.  The concept of
     condate (control & data property to be checked) is described in
!    tree-pattern.h */
  static void 
! tree_check_warning (const char *condname, tree stmt,
! 		    int check_option)
  {
    location_t saved_location = input_location;
  
    if (EXPR_HAS_LOCATION (stmt))
      input_location = EXPR_LOCATION (stmt);
    warning (check_option, "user-defined check failed:");
    fprintf (stderr, "%s:%d: check = %s,\n", 
  	   input_filename, input_line, condname);
--- 39,58 ----
  #include "tree-dump.h"
  #include "tree-pass.h"
  #include "toplev.h"
  #include "tree-match.h"
  
  /* Raise a warning upon detecting a satisfied condate.  The concept of
     condate (control & data property to be checked) is described in
!    tree-match.h.  */
! 
  static void 
! tree_check_warning (const char *condname, tree stmt, int check_option)
  {
    location_t saved_location = input_location;
  
    if (EXPR_HAS_LOCATION (stmt))
      input_location = EXPR_LOCATION (stmt);
+ 
    warning (check_option, "user-defined check failed:");
    fprintf (stderr, "%s:%d: check = %s,\n", 
  	   input_filename, input_line, condname);
*************** tree_check_warning (const char *condname
*** 66,119 ****
    input_location = saved_location;
  }
    
! /* Type of a callback for scan_cfg_stmts() */
  typedef void (*scan_cfg_stmts_fn)(cfg_node node, void *);
  
  /* Scan all statements in the CFG, and for every statement (matching
!    the patern, if non-null), execute the callback. */
  static void 
! scan_cfg_stmts (pattern patt, 
! 		scan_cfg_stmts_fn callback, void *data) 
  {
    basic_block bb;
  
!   if (!basic_block_info) {
!     fprintf (stderr, "no BBs available!\n");
!     return;
!   }
!   FOR_EACH_BB (bb) {
!     block_stmt_iterator bsi;
!     tree stmt;
!     for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) {
!       stmt = bsi_stmt (bsi);
!       PP_TRACE (TRACE_MATCH, {
! 	  lazy_print_generic_expr (stderr, stmt, 0);
! 	  fprintf (stderr, "= ");
! 	  print_generic_expr (stderr, stmt, 0); 
! 	  fprintf (stderr, "\n");
! 	});
!       if (!patt || tree_match_disj (stmt, patt, bsi_cfg_node (bsi)))
! 	(*callback) (bsi_cfg_node (bsi), data);
      }
-   }
  }
  
! /* Initialization function for the tree-check pass */
  static void 
  tree_check_init (void) 
  {
    reset_global_holes ();
  }
  
! /* scan_cfg_stmts() callback used in tree_check_instance() */
  static void 
  push_node (cfg_node node, void *data) 
  {
    varray_type va = (varray_type) data;
    tree stmt = cfg_node_stmt (node);
    VARRAY_PUSH_GENERIC_PTR_NOGC (va, node);
    if (stmt) 
      TREE_VISITED (stmt) = 1;
    PP_TRACE (TRACE_CHECK_STEPS, {
        fprintf (stderr, "found src stmt:");
        print_generic_expr (stderr, stmt, 0);
--- 66,131 ----
    input_location = saved_location;
  }
    
! /* Type of a callback for scan_cfg_stmts.  */
  typedef void (*scan_cfg_stmts_fn)(cfg_node node, void *);
  
  /* Scan all statements in the CFG, and for every statement (matching
!    the patern, if non-null), execute the callback.  */
! 
  static void 
! scan_cfg_stmts (pattern patt, scan_cfg_stmts_fn callback, void *data)
  {
    basic_block bb;
  
!   if (!basic_block_info)
!     {
!       fprintf (stderr, "no BBs available!\n");
!       return;
!     }
! 
!   FOR_EACH_BB (bb)
!     {
!       block_stmt_iterator bsi;
!       tree stmt;
! 
!       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
! 	{
! 	  stmt = bsi_stmt (bsi);
! 
! 	  PP_TRACE (TRACE_MATCH, {
! 	    lazy_print_generic_expr (stderr, stmt, 0);
! 	    fprintf (stderr, "= ");
! 	    print_generic_expr (stderr, stmt, 0); 
! 	    fprintf (stderr, "\n");
! 	  });
! 
! 	  if (!patt || tree_match_disj (stmt, patt, bsi_cfg_node (bsi)))
! 	    (*callback) (bsi_cfg_node (bsi), data);
! 	}
      }
  }
  
! /* Initialization function for the tree-check pass.  */
! 
  static void 
  tree_check_init (void) 
  {
    reset_global_holes ();
  }
  
! /* scan_cfg_stmts callback used in tree_check_instance.  */
! 
  static void 
  push_node (cfg_node node, void *data) 
  {
    varray_type va = (varray_type) data;
    tree stmt = cfg_node_stmt (node);
+ 
    VARRAY_PUSH_GENERIC_PTR_NOGC (va, node);
+ 
    if (stmt) 
      TREE_VISITED (stmt) = 1;
+ 
    PP_TRACE (TRACE_CHECK_STEPS, {
        fprintf (stderr, "found src stmt:");
        print_generic_expr (stderr, stmt, 0);
*************** push_node (cfg_node node, void *data) 
*** 121,154 ****
      });
  }
  
! /* Visit a CFG node. Used in tree_check_instance() */
  static bool 
  check_node (cfg_node node, condate cond) 
  {
    tree stmt = cfg_node_stmt (node);
    if (!stmt || TREE_VISITED (stmt))
      return 0;
    TREE_VISITED (stmt) = 1;
    PP_TRACE (TRACE_CHECK_STEPS, {
        fprintf (stderr, "checking stmt:");
        print_generic_expr (stderr, stmt, 0);
        fprintf (stderr, "\n");
    });
      
!   if (tree_match_disj (stmt, cond->to, node)) {
!     tree_check_warning (cond->name, stmt, OPT_ftree_checks_);
!     return 0;  /* follow_none */
!   }
  
    /* Inspect successors? */
!   if (cond->avoid && tree_match_disj (stmt, cond->avoid, node)) {
!     PP_TRACE (TRACE_CHECK, fprintf (stderr, "via node, backtracking\n"));
!     return 0; /* follow_none */;
!   } else
      return 1; /* follow_all */
  }
  
! /* Check a condate instance over the CFG of the current function */
  static void 
  tree_check_instance (condate cond)
  {
--- 133,174 ----
      });
  }
  
! /* Visit a CFG node.  Used in tree_check_instance.  */
! 
  static bool 
  check_node (cfg_node node, condate cond) 
  {
    tree stmt = cfg_node_stmt (node);
+ 
    if (!stmt || TREE_VISITED (stmt))
      return 0;
+ 
    TREE_VISITED (stmt) = 1;
+ 
    PP_TRACE (TRACE_CHECK_STEPS, {
        fprintf (stderr, "checking stmt:");
        print_generic_expr (stderr, stmt, 0);
        fprintf (stderr, "\n");
    });
      
!   if (tree_match_disj (stmt, cond->to, node))
!     {
!       tree_check_warning (cond->name, stmt, OPT_ftree_checks_);
!       return 0;  /* follow_none */
!     }
  
    /* Inspect successors? */
!   if (cond->avoid && tree_match_disj (stmt, cond->avoid, node))
!     {
!       PP_TRACE (TRACE_CHECK, fprintf (stderr, "via node, backtracking\n"));
!       return 0; /* follow_none */;
!     }
!   else
      return 1; /* follow_all */
  }
  
! /* Check a condate instance over the CFG of the current function.  */
! 
  static void 
  tree_check_instance (condate cond)
  {
*************** tree_check_instance (condate cond)
*** 161,174 ****
    /* Allocate stack for back-tracking up CFG.  */
    VARRAY_GENERIC_PTR_NOGC_INIT (stack, 100, "TreeCheckStmtStack");
  
!   /* Push from nodes on the stack */
    PP_TRACE (TRACE_CHECK, fprintf (stderr, "searching src pat %s\n", 
  				  cond->from->format_spec));
    scan_cfg_stmts (cond->from, push_node, stack);
    PP_TRACE (TRACE_CHECK, fprintf (stderr, "%d src stmts found\n", 
  				  (unsigned) VARRAY_ACTIVE_SIZE (stack)));
  
!   /* Perform depth-first search */
    while (VARRAY_ACTIVE_SIZE (stack)) 
      {
        cfg_node node;
--- 181,194 ----
    /* Allocate stack for back-tracking up CFG.  */
    VARRAY_GENERIC_PTR_NOGC_INIT (stack, 100, "TreeCheckStmtStack");
  
!   /* Push from nodes on the stack.  */
    PP_TRACE (TRACE_CHECK, fprintf (stderr, "searching src pat %s\n", 
  				  cond->from->format_spec));
    scan_cfg_stmts (cond->from, push_node, stack);
    PP_TRACE (TRACE_CHECK, fprintf (stderr, "%d src stmts found\n", 
  				  (unsigned) VARRAY_ACTIVE_SIZE (stack)));
  
!   /* Perform depth-first search.  */
    while (VARRAY_ACTIVE_SIZE (stack)) 
      {
        cfg_node node;
*************** tree_check_instance (condate cond)
*** 179,249 ****
        node = VARRAY_TOP_GENERIC_PTR_NOGC (stack); 
        VARRAY_POP (stack);
        stmt = cfg_node_stmt (node);
!       if (node->next == NULL) {
! 	edge e;
! 	edge_iterator ei;
! 	basic_block bb;
  	
! 	bb = bb_for_stmt (stmt);
! 	FOR_EACH_EDGE (e, ei, bb->succs) {
! 	  if (e->dest == EXIT_BLOCK_PTR) 
! 	    continue;
! 	  if (TREE_CODE (stmt) == COND_EXPR
! 	      && (e->flags & EDGE_TRUE_VALUE && cond->avoid_then
! 		  && tree_match_disj (COND_EXPR_COND (stmt), cond->avoid_then, 
! 				      node))) {
! 	    PP_TRACE (TRACE_CHECK, 
! 		      fprintf (stderr, "via-then edge, skipping\n"));
! 	    continue;
! 	  }
! 	  if (TREE_CODE (stmt) == COND_EXPR
! 	      && (e->flags & EDGE_FALSE_VALUE && cond->avoid_else
! 		  && tree_match_disj (COND_EXPR_COND (stmt), cond->avoid_else, 
! 				      node))) {
! 	    PP_TRACE (TRACE_CHECK, 
! 		      fprintf (stderr, "via-else edge, skipping\n"));
! 	    continue;
! 	  }
! 	  succ_node = bb_1st_cfg_node (e->dest);
  	  push_it = check_node (succ_node, cond);
  	  if (push_it)
  	    VARRAY_PUSH_GENERIC_PTR_NOGC (stack, succ_node);
  	}
-       } else {
- 	succ_node = node->next;
- 	push_it = check_node (succ_node, cond);
- 	if (push_it)
- 	  VARRAY_PUSH_GENERIC_PTR_NOGC (stack, succ_node);
-       }
      } /* while DFS */
    VARRAY_FREE (stack);
  }
  
  /* scan_cfg_stmts() callback used in tree_check() to collect condate
!    instances. An instance is new if the combination of global hole
!    values has not been seen yet. */
  static void 
  push_global_holes_if_new (cfg_node node ATTRIBUTE_UNUSED, void *data) 
  {
    varray_type va = (varray_type) data;
    unsigned int i;
!   /* check if these global holes were already seen: */
    for (i=0; i < VARRAY_ACTIVE_SIZE (va); i++)
!     if (eq_global_holes (global_holes, VARRAY_GENERIC_PTR_NOGC (va, i))) {
!       reset_global_holes ();
!       return; 
!     }
    VARRAY_PUSH_GENERIC_PTR_NOGC (va, save_global_holes ());
    reset_global_holes ();
  }
  
! /* Check a condate on a function  */
  static void 
  tree_check (condate cond)
  {
    varray_type holes_stack;
    
!   /* Allocate stack for collecting condate instances. */
    VARRAY_GENERIC_PTR_NOGC_INIT (holes_stack, 10, "TreeCheckHolesStack");
  
    PP_TRACE (TRACE_CHECK, 
--- 199,285 ----
        node = VARRAY_TOP_GENERIC_PTR_NOGC (stack); 
        VARRAY_POP (stack);
        stmt = cfg_node_stmt (node);
!       if (node->next == NULL)
! 	{
! 	  edge e;
! 	  edge_iterator ei;
! 	  basic_block bb;
  	
! 	  bb = bb_for_stmt (stmt);
! 	  FOR_EACH_EDGE (e, ei, bb->succs)
! 	    {
! 	      if (e->dest == EXIT_BLOCK_PTR) 
! 		continue;
! 
! 	      if (TREE_CODE (stmt) == COND_EXPR
! 		  && (e->flags & EDGE_TRUE_VALUE && cond->avoid_then
! 		      && tree_match_disj (COND_EXPR_COND (stmt), cond->avoid_then, 
! 					  node)))
! 		{
! 		  PP_TRACE (TRACE_CHECK, 
! 			    fprintf (stderr, "via-then edge, skipping\n"));
! 		  continue;
! 		}
! 
! 	      if (TREE_CODE (stmt) == COND_EXPR
! 		  && (e->flags & EDGE_FALSE_VALUE && cond->avoid_else
! 		      && tree_match_disj (COND_EXPR_COND (stmt), cond->avoid_else, 
! 					  node)))
! 		{
! 		  PP_TRACE (TRACE_CHECK, 
! 			    fprintf (stderr, "via-else edge, skipping\n"));
! 		  continue;
! 		}
! 
! 	      succ_node = bb_1st_cfg_node (e->dest);
! 	      push_it = check_node (succ_node, cond);
! 
! 	      if (push_it)
! 		VARRAY_PUSH_GENERIC_PTR_NOGC (stack, succ_node);
! 	    }
! 	}
!       else
! 	{
! 	  succ_node = node->next;
  	  push_it = check_node (succ_node, cond);
+ 
  	  if (push_it)
  	    VARRAY_PUSH_GENERIC_PTR_NOGC (stack, succ_node);
  	}
      } /* while DFS */
    VARRAY_FREE (stack);
  }
  
  /* scan_cfg_stmts() callback used in tree_check() to collect condate
!    instances.  An instance is new if the combination of global hole
!    values has not been seen yet.  */
! 
  static void 
  push_global_holes_if_new (cfg_node node ATTRIBUTE_UNUSED, void *data) 
  {
    varray_type va = (varray_type) data;
    unsigned int i;
! 
!   /* Check if these global holes were already seen.  */
    for (i=0; i < VARRAY_ACTIVE_SIZE (va); i++)
!     if (eq_global_holes (global_holes, VARRAY_GENERIC_PTR_NOGC (va, i)))
!       {
! 	reset_global_holes ();
! 	return; 
!       }
! 
    VARRAY_PUSH_GENERIC_PTR_NOGC (va, save_global_holes ());
    reset_global_holes ();
  }
  
! /* Check a condate on a function.  */
! 
  static void 
  tree_check (condate cond)
  {
    varray_type holes_stack;
    
!   /* Allocate stack for collecting condate instances.  */
    VARRAY_GENERIC_PTR_NOGC_INIT (holes_stack, 10, "TreeCheckHolesStack");
  
    PP_TRACE (TRACE_CHECK, 
*************** tree_check (condate cond)
*** 265,298 ****
    VARRAY_FREE (holes_stack);
  }
  
! /* Read from a file a string delimted by double quotes  */
  static char *
  read_delimited_string (FILE *infile) 
  {
    static char buf[256];
    int c, buf_sp;
    /* lookahead(1), to skip comment lines */
!   while ((c = getc (infile)) == '#') {
!     /* skip to \n */
!     while ((c = getc (infile)) != '\n' && c != EOF);
!   }
    ungetc (c, infile);
    /* skip to opening \" */
    while ((c = getc (infile)) != '"' && c != '\n' && c != EOF); 
    if (c == '\n' || c == EOF) 
      return NULL; /* no string found */
    /* fill in string contents */
    buf_sp = 0;
    while ((c = getc (infile)) != '"' && c != '\n' && c != EOF)
      buf[buf_sp++] = c;
    if (c == '\n' || c == EOF) 
      return NULL; /* unclosed string */
    /* end string */
    buf[buf_sp] = '\0';
    return buf;
  }
  
! /* Print a condate  */
  void 
  print_cond (condate cond) 
  {
--- 301,344 ----
    VARRAY_FREE (holes_stack);
  }
  
! /* Read from a file a string delimted by double quotes.  */
! 
  static char *
  read_delimited_string (FILE *infile) 
  {
    static char buf[256];
    int c, buf_sp;
+ 
    /* lookahead(1), to skip comment lines */
!   while ((c = getc (infile)) == '#')
!     {
!       /* skip to \n */
!       while ((c = getc (infile)) != '\n' && c != EOF);
!     }
! 
    ungetc (c, infile);
+ 
    /* skip to opening \" */
    while ((c = getc (infile)) != '"' && c != '\n' && c != EOF); 
+ 
    if (c == '\n' || c == EOF) 
      return NULL; /* no string found */
+ 
    /* fill in string contents */
    buf_sp = 0;
    while ((c = getc (infile)) != '"' && c != '\n' && c != EOF)
      buf[buf_sp++] = c;
+ 
    if (c == '\n' || c == EOF) 
      return NULL; /* unclosed string */
+ 
    /* end string */
    buf[buf_sp] = '\0';
    return buf;
  }
  
! /* Print a condate.  */
! 
  void 
  print_cond (condate cond) 
  {
*************** print_cond (condate cond) 
*** 309,324 ****
    fprintf (stderr, ")\n");
  }
  
! /* Check a list of condates on the current function */
  static void 
  execute_conds (condate conds[], int n) 
  {
    int i;
    condate cond;
  
!   for (i = 0; i < n; i++) {
!     cond = conds[i];
!     PP_TRACE (TRACE_CHECK, {
  	print_cond (cond);
        });
  
--- 355,372 ----
    fprintf (stderr, ")\n");
  }
  
! /* Check a list of condates on the current function.  */
! 
  static void 
  execute_conds (condate conds[], int n) 
  {
    int i;
    condate cond;
  
!   for (i = 0; i < n; i++)
!     {
!       cond = conds[i];
!       PP_TRACE (TRACE_CHECK, {
  	print_cond (cond);
        });
  
*************** execute_conds (condate conds[], int n) 
*** 330,349 ****
  static condate conds[CONDMAX];  /* list of condated to check */
  static int n_conds = 0;         /* number of condates to check */
  
! /* Flush the list of condates */
  static void 
  delete_conds (condate conds[], int n) 
  {
    int i;
    condate cond;
!   for (i = 0; i < n; i++) {
!     cond = conds[i];
!     rmcond (cond);
!   }
    n_conds = 0;
  }
  
! /* Parse the file containing condates definitions, and cache the result */
  static int 
  parse_tree_check_file_once (void) 
  {
--- 378,401 ----
  static condate conds[CONDMAX];  /* list of condated to check */
  static int n_conds = 0;         /* number of condates to check */
  
! /* Flush the list of condates.  */
! 
  static void 
  delete_conds (condate conds[], int n) 
  {
    int i;
    condate cond;
! 
!   for (i = 0; i < n; i++)
!     {
!       cond = conds[i];
!       rmcond (cond);
!     }
    n_conds = 0;
  }
  
! /* Parse the file containing condates definitions, and cache the result.  */
! 
  static int 
  parse_tree_check_file_once (void) 
  {
*************** parse_tree_check_file_once (void) 
*** 353,399 ****
    static char *name;
    FILE *checkfile;
    
!   if (current_check_file) { /* Not called for the first time */
!     if (!strcmp (current_check_file, tree_check_file)) 
!       /* file hasn't changed */
!       return 0;
!     else
!       delete_conds (conds, n_conds);
!   }
    current_check_file = tree_check_file;
    checkfile = fopen (tree_check_file, "r");
    if (!checkfile)
      return -1;
  
    while (1) 
      {
        from = to = avoid = avoid_then = avoid_else = NULL;
        while ((str = read_delimited_string (checkfile)) != NULL)
  	from = pat_or (mkpat (str), from);
!       if (!from) break;
        while ((str = read_delimited_string (checkfile)) != NULL)
  	to = pat_or (mkpat (str), to);
        while ((str = read_delimited_string (checkfile)) != NULL)
  	avoid = pat_or (mkpat (str), avoid);
        while ((str = read_delimited_string (checkfile)) != NULL)
  	avoid_then = pat_or (mkpat (str), avoid_then);
        while ((str = read_delimited_string (checkfile)) != NULL)
  	avoid_else = pat_or (mkpat (str), avoid_else);
        name = xmalloc (strlen (tree_check_file) + 6);
        strcpy (name, tree_check_file);
        sprintf (name + strlen (tree_check_file), "[%03d]", n_conds);
        conds[n_conds++] = mkcond (name, from, to, avoid, 
  			       avoid_then, avoid_else);
        free (name);
!       if (n_conds == CONDMAX) {
! 	fprintf (stderr, "Warning: ignoring checks beyond %d", CONDMAX);
! 	break;
!       }
      }
    return 0;
  }
  
! /* scan_cfg_stmts() callback used in execute_tree_check() */
  static void 
  print_matching_stmt (cfg_node node ATTRIBUTE_UNUSED, 
  		     void *data ATTRIBUTE_UNUSED) 
--- 405,466 ----
    static char *name;
    FILE *checkfile;
    
!   if (current_check_file)
!     {
!       /* Not called for the first time.  */
!       if (!strcmp (current_check_file, tree_check_file)) 
! 	/* file hasn't changed */
! 	return 0;
!       else
! 	delete_conds (conds, n_conds);
!     }
! 
    current_check_file = tree_check_file;
    checkfile = fopen (tree_check_file, "r");
+ 
    if (!checkfile)
      return -1;
  
    while (1) 
      {
        from = to = avoid = avoid_then = avoid_else = NULL;
+ 
        while ((str = read_delimited_string (checkfile)) != NULL)
  	from = pat_or (mkpat (str), from);
! 
!       if (!from)
! 	break;
! 
        while ((str = read_delimited_string (checkfile)) != NULL)
  	to = pat_or (mkpat (str), to);
+ 
        while ((str = read_delimited_string (checkfile)) != NULL)
  	avoid = pat_or (mkpat (str), avoid);
+ 
        while ((str = read_delimited_string (checkfile)) != NULL)
  	avoid_then = pat_or (mkpat (str), avoid_then);
+ 
        while ((str = read_delimited_string (checkfile)) != NULL)
  	avoid_else = pat_or (mkpat (str), avoid_else);
+ 
        name = xmalloc (strlen (tree_check_file) + 6);
        strcpy (name, tree_check_file);
        sprintf (name + strlen (tree_check_file), "[%03d]", n_conds);
        conds[n_conds++] = mkcond (name, from, to, avoid, 
  			       avoid_then, avoid_else);
        free (name);
!       if (n_conds == CONDMAX)
! 	{
! 	  fprintf (stderr, "Warning: ignoring checks beyond %d", CONDMAX);
! 	  break;
! 	}
      }
+ 
    return 0;
  }
  
! /* scan_cfg_stmts callback used in execute_tree_check.  */
! 
  static void 
  print_matching_stmt (cfg_node node ATTRIBUTE_UNUSED, 
  		     void *data ATTRIBUTE_UNUSED) 
*************** print_matching_stmt (cfg_node node ATTRI
*** 403,417 ****
    reset_global_holes ();
  }
  
! /* Main function of the tree-check pass. Triggered either by -ftree-check
!    or -ftree-checks. */
  static unsigned int
  execute_tree_check (void) 
  {
    const char *fn_name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
  
-   if (!tree_check_file && !tree_check_string) 
-     return 0;
    PP_TRACE (TRACE_CHECK, fprintf (stderr, "function %s() {\n", fn_name));
    PP_TRACE (TRACE_CHECK, 
  	   fprintf (stderr, 
--- 470,483 ----
    reset_global_holes ();
  }
  
! /* Main function of the tree-check pass.  Triggered either by
!    -ftree-check or -ftree-checks.  */
! 
  static unsigned int
  execute_tree_check (void) 
  {
    const char *fn_name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
  
    PP_TRACE (TRACE_CHECK, fprintf (stderr, "function %s() {\n", fn_name));
    PP_TRACE (TRACE_CHECK, 
  	   fprintf (stderr, 
*************** execute_tree_check (void) 
*** 419,445 ****
  		    tree_check_file, tree_check_string));
    PP_TRACE (TRACE_CHECK, fprintf (stderr, "counting stmts\n"));
    tree_check_init ();
!   if (tree_check_file) {
!     if (parse_tree_check_file_once () < 0) {
!       fprintf (stderr, "tree-check-file %s not found\n", tree_check_file);
!       return 0;
!     }
!     execute_conds (conds, n_conds);
!   } else { /* tree_check_string != NULL */
!     pattern patt;
!     reset_global_holes ();
!     patt = mkpat (tree_check_string);
!     scan_cfg_stmts (patt, print_matching_stmt, NULL);
!     rmpat (patt);
!   }
    PP_TRACE (TRACE_CHECK, fprintf (stderr, "}\n"));
    return 0;
  }
  
  struct tree_opt_pass pass_check =
  {
    "check",				/* name */
!   NULL,					/* gate */
    execute_tree_check,			/* execute */
    NULL,					/* sub */
    NULL,					/* next */
--- 485,524 ----
  		    tree_check_file, tree_check_string));
    PP_TRACE (TRACE_CHECK, fprintf (stderr, "counting stmts\n"));
    tree_check_init ();
! 
!   if (tree_check_file)
!     {
!       if (parse_tree_check_file_once () < 0)
! 	{
! 	  fprintf (stderr, "tree-check-file %s not found\n", tree_check_file);
! 	  return 0;
! 	}
!       execute_conds (conds, n_conds);
!     }
!   else
!     {
!       /* tree_check_string != NULL */
!       pattern patt;
!       reset_global_holes ();
!       patt = mkpat (tree_check_string);
!       scan_cfg_stmts (patt, print_matching_stmt, NULL);
!       rmpat (patt);
!     }
! 
    PP_TRACE (TRACE_CHECK, fprintf (stderr, "}\n"));
    return 0;
  }
  
+ static bool
+ gate_tree_check (void)
+ {
+   return (tree_check_file != 0 || tree_check_string != 0);
+ }
+ 
  struct tree_opt_pass pass_check =
  {
    "check",				/* name */
!   gate_tree_check,			/* gate */
    execute_tree_check,			/* execute */
    NULL,					/* sub */
    NULL,					/* next */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]