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]

New version of sequence point warnings


This is another overhaul of the sequence point warning code.  It became
necessary since Jim Meyering found that the current code will gobble up
all virtual memory in some circumstances involving heavy use of SAVE_EXPRs.

This patch also adds a bunch of new tests to the corresponding testcase.
One of these fails because after constant folding, the code is no longer
undefined.  It would be nice to be able to run this code on unfolded trees.

The changes in fold-const.c fix the following type of testcase:
  a = (a++ && 3);
which currently gets transformed into
  a = (a++ != 0);
which is undefined.

This patch almost bootstraps; there's a segmentation fault when the stage1
compiler tries to compile f/data.c.  This appears to be a bug in the
preprocessor and unrelated to this patch.  After removing Fortran from
LANGUAGES, it's successful (i686-linux).

I'd like to enable this warning by default (after compiling a few large
packages to verify there aren't any spurious warnings).  We still seem
to get quite a few bogus bug reports for undefined code, and I think
enabling this warning by default would reduce the number.  Comments?


Bernd

	* Makefile.in (c-common.o): Depend on $(OBSTACK_H).
	* c-common.c (c-obstack.c): Include "obstack.h".
	(struct reverse_tree): Delete.
	(reverse_list, reverse_max_depth): Delete.
	(build_reverse_tree, common_ancestor, modify_ok): Delete functions.
	(struct tlist, struct tlist_cache): New.
	(tlist_obstack, tlist_firstobj, warned_ids, save_expr_cache): New.
	(add_tlist, merge_tlist, verify_tree, warning_candidate_p,
	warn_for_collisions, warn_for_collisions_1, new_tlist): New
	static functions.
	(verify_sequence_points): Rewritten.
	* fold-const.c (fold): Don't lose possibly important sequence
	points when removing one arm of TRUTH_ORIF_EXPRs or TRUTH_ANDIF_EXPRs.

	* gcc.dg/sequence-point-1.c: Add some new tests.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/Makefile.in,v
retrieving revision 1.540
diff -u -p -r1.540 Makefile.in
--- Makefile.in	2000/11/10 17:23:08	1.540
+++ Makefile.in	2000/11/11 14:52:46
@@ -1210,7 +1210,7 @@ s-under: $(GCC_PASSES)
 
 # A file used by all variants of C.
 
-c-common.o : c-common.c $(CONFIG_H) system.h $(TREE_H) \
+c-common.o : c-common.c $(CONFIG_H) system.h $(TREE_H) $(OBSTACK_H) \
 	$(C_COMMON_H) flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \
 	$(EXPR_H) diagnostic.h
 
Index: c-common.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.c,v
retrieving revision 1.186
diff -u -p -r1.186 c-common.c
--- c-common.c	2000/11/10 04:29:43	1.186
+++ c-common.c	2000/11/11 14:52:48
@@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA.  */
 #include "tm_p.h"
 #include "intl.h"
 #include "diagnostic.h"
+#include "obstack.h"
 
 #if USE_CPPLIB
 #include "cpplib.h"
@@ -3416,193 +3417,388 @@ convert_and_check (type, expr)
   return t;
 }
 
-/* Describe a reversed version of a normal tree, so that we can get to the
-   parent of each node.  */
-struct reverse_tree
-{
-  /* All reverse_tree structures for a given tree are chained through this
-     field.  */
-  struct reverse_tree *next;
-  /* The parent of this node.  */
-  struct reverse_tree *parent;
-  /* The actual tree node.  */
-  tree x;
-  /* The operand number this node corresponds to in the parent.  */
-  int operandno;
-  /* Describe whether this expression is written to or read.  */
-  char read, write;
+/* A node in a list that describes references to variables (EXPR), which are
+   either read accesses if WRITER is zero, or write accesses, in which case
+   WRITER is the parent of EXPR.  */
+struct tlist
+{
+  struct tlist *next;
+  tree expr, writer;
+};
+
+/* Used to implement a cache the results of a call to verify_tree.  We only
+   use this for SAVE_EXPRs.  */
+struct tlist_cache
+{
+  struct tlist_cache *next;
+  struct tlist *cache_before_sp;
+  struct tlist *cache_after_sp;
+  tree expr;
 };
 
-/* A list of all reverse_tree structures for a given expression, built by
-   build_reverse_tree.  */
-static struct reverse_tree *reverse_list;
-/* The maximum depth of a tree, computed by build_reverse_tree.  */
-static int reverse_max_depth;
-
-static void build_reverse_tree PARAMS ((tree, struct reverse_tree *, int, int,
-					int, int));
-static struct reverse_tree *common_ancestor PARAMS ((struct reverse_tree *,
-						     struct reverse_tree *,
-						     struct reverse_tree **,
-						     struct reverse_tree **));
-static int modify_ok PARAMS ((struct reverse_tree *, struct reverse_tree *));
+/* Obstack to use when allocating tlist structures, and corresponding
+   firstobj.  */
+static struct obstack tlist_obstack;
+static char *tlist_firstobj = 0;
+
+/* Keep track of the identifiers we've warned about, so we can avoid duplicate
+   warnings.  */
+static struct tlist *warned_ids;
+/* SAVE_EXPRs need special treatment.  We process them only once and then
+   cache the results.  */
+static struct tlist_cache *save_expr_cache;
+
+static void add_tlist PARAMS ((struct tlist **, struct tlist *, tree, int));
+static void merge_tlist PARAMS ((struct tlist **, struct tlist *, int));
+static void verify_tree PARAMS ((tree, struct tlist **, struct tlist **, tree));
+static int warning_candidate_p PARAMS ((tree));
+static void warn_for_collisions PARAMS ((struct tlist *));
+static void warn_for_collisions_1 PARAMS ((tree, tree, struct tlist *, int));
+static struct tlist *new_tlist PARAMS ((struct tlist *, tree, tree));
 static void verify_sequence_points PARAMS ((tree));
+
+/* Create a new struct tlist and fill in its fields.  */
+static struct tlist *
+new_tlist (next, t, writer)
+     struct tlist *next;
+     tree t;
+     tree writer;
+{
+  struct tlist *l;
+  l = (struct tlist *) obstack_alloc (&tlist_obstack, sizeof *l);
+  l->next = next;
+  l->expr = t;
+  l->writer = writer;
+  return l;
+}
+
+/* Add duplicates of the nodes found in ADD to the list *TO.  If EXCLUDE_WRITER
+   is nonnull, we ignore any node we find which has a writer equal to it.  */
+
+static void
+add_tlist (to, add, exclude_writer, copy)
+     struct tlist **to;
+     struct tlist *add;
+     tree exclude_writer;
+     int copy;
+{
+  while (add)
+    {
+      struct tlist *next = add->next;
+      if (! copy)
+	add->next = *to;
+      if (! exclude_writer || add->writer != exclude_writer)
+	*to = copy ? new_tlist (*to, add->expr, add->writer) : add;
+      add = next;
+    }
+}
+
+/* Merge the nodes of ADD into TO.  This merging process is done so that for
+   each variable that already exists in TO, no new node is added; however if
+   there is a write access recorded in ADD, and an occurrence on TO is only
+   a read access, then the occurrence in TO will be modified to record the
+   write.  */
+
+static void
+merge_tlist (to, add, copy)
+     struct tlist **to;
+     struct tlist *add;
+     int copy;
+{
+  struct tlist **end = to;
+
+  while (*end)
+    end = &(*end)->next;
+
+  while (add)
+    {
+      int found = 0;
+      struct tlist *tmp2;
+      struct tlist *next = add->next;
+
+      for (tmp2 = *to; tmp2; tmp2 = tmp2->next)
+	if (tmp2->expr == add->expr)
+	  {
+	    found = 1;
+	    if (! tmp2->writer)
+	      tmp2->writer = add->writer;
+	  }
+      if (! found)
+	{
+	  *end = copy ? add : new_tlist (NULL, add->expr, add->writer);
+	  end = &(*end)->next;
+	  *end = 0;
+	}
+      add = next;
+    }
+}
+
+/* WRITTEN is a variable, WRITER is its parent.  Warn if any of the variable
+   references in list LIST conflict with it, excluding reads if ONLY writers
+   is nonzero.  */
+
+static void
+warn_for_collisions_1 (written, writer, list, only_writes)
+     tree written, writer;
+     struct tlist *list;
+     int only_writes;
+{
+  struct tlist *tmp;
+
+  /* Avoid duplicate warnings.  */
+  for (tmp = warned_ids; tmp; tmp = tmp->next)
+    if (tmp->expr == written)
+      return;
+
+  while (list)
+    {
+      if (list->expr == written
+	  && list->writer != writer
+	  && (! only_writes || list->writer))
+	{
+	  warned_ids = new_tlist (warned_ids, written, NULL_TREE);
+	  warning ("operation on `%s' may be undefined",
+		   IDENTIFIER_POINTER (DECL_NAME (list->expr)));
+	}
+      list = list->next;
+    }
+}
 
-/* Recursively process an expression, X, building a reverse tree while
-   descending and recording OPERANDNO, READ, and WRITE in the created
-   structures.  DEPTH is used to compute reverse_max_depth.
-   FIXME: if walk_tree gets moved out of the C++ front end, this should
-   probably use walk_tree.  */
+/* Given a list LIST of references to variables, find whether any of these
+   can cause conflicts due to missing sequence points.  */
 
 static void
-build_reverse_tree (x, parent, operandno, read, write, depth)
+warn_for_collisions (list)
+     struct tlist *list;
+{
+  struct tlist *tmp;
+  
+  for (tmp = list; tmp; tmp = tmp->next)
+    {
+      if (tmp->writer)
+	warn_for_collisions_1 (tmp->expr, tmp->writer, list, 0);
+    }
+}
+
+/* Return nonzero if X is a tree that can be verified by the sequence poitn
+   warnings.  */
+static int
+warning_candidate_p (x)
      tree x;
-     struct reverse_tree *parent;
-     int operandno, read, write, depth;
 {
-  struct reverse_tree *node;
+  return TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == PARM_DECL;
+}
 
-  if (x == 0 || x == error_mark_node)
-    return;
+/* Walk the tree X, and record accesses to variables.  If X is written by the
+   parent tree, WRITER is the parent.
+   We store accesses in one of the two lists: PBEFORE_SP, and PNO_SP.  If this
+   expression or its only operand forces a sequence point, then everything up
+   to the sequence point is stored in PBEFORE_SP.  Everything else gets stored
+   in PNO_SP.
+   Once we return, we will have emitted warnings if any subexpression before
+   such a sequence point could be undefined.  On a higher level, however, the
+   sequence point may not be relevant, and we'll merge the two lists.
+
+   Example: (b++, a) + b;
+   The call that processes the COMPOUND_EXPR will store the increment of B
+   in PBEFORE_SP, and the use of A in PNO_SP.  The higher-level call that
+   processes the PLUS_EXPR will need to merge the two lists so that
+   eventually, all accesses end up on the same list (and we'll warn about the
+   unordered subexpressions b++ and b.
+
+   A note on merging.  If we modify the former example so that our expression
+   becomes
+     (b++, b) + a
+   care must be taken not simply to add all three expressions into the final
+   PNO_SP list.  The function merge_tlist takes care of that by merging the
+   before-SP list of the COMPOUND_EXPR into its after-SP list in a special
+   way, so that no more than one access to B is recorded.  */
 
-  node = (struct reverse_tree *) xmalloc (sizeof (struct reverse_tree));
+static void
+verify_tree (x, pbefore_sp, pno_sp, writer)
+     tree x;
+     struct tlist **pbefore_sp, **pno_sp;
+     tree writer;
+{
+  struct tlist *tmp_before, *tmp_nosp, *tmp_list2, *tmp_list3;
+  enum tree_code code;
+  char class;
 
-  node->parent = parent;
-  node->x = x;
-  node->read = read;
-  node->write = write;
-  node->operandno = operandno;
-  node->next = reverse_list;
-  reverse_list = node;
-  if (depth > reverse_max_depth)
-    reverse_max_depth = depth;
+ restart:
+  code = TREE_CODE (x);
+  class = TREE_CODE_CLASS (code);
 
-  switch (TREE_CODE (x))
+  if (warning_candidate_p (x))
     {
+      *pno_sp = new_tlist (*pno_sp, x, writer);
+      return;
+    }
+
+  switch (code)
+    {
+    case COMPOUND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+      tmp_before = tmp_nosp = tmp_list3 = 0;
+      verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE);
+      warn_for_collisions (tmp_nosp);
+      merge_tlist (pbefore_sp, tmp_before, 0);
+      merge_tlist (pbefore_sp, tmp_nosp, 0);
+      verify_tree (TREE_OPERAND (x, 1), &tmp_list3, pno_sp, NULL_TREE);
+      merge_tlist (pbefore_sp, tmp_list3, 0);
+      return;
+
+    case COND_EXPR:
+      tmp_before = tmp_list2 = 0;
+      verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_list2, NULL_TREE);
+      warn_for_collisions (tmp_list2);
+      merge_tlist (pbefore_sp, tmp_before, 0);
+      merge_tlist (pbefore_sp, tmp_list2, 1);
+
+      tmp_list3 = tmp_nosp = 0;
+      verify_tree (TREE_OPERAND (x, 1), &tmp_list3, &tmp_nosp, NULL_TREE);
+      warn_for_collisions (tmp_nosp);
+      merge_tlist (pbefore_sp, tmp_list3, 0);
+
+      tmp_list3 = tmp_list2 = 0;
+      verify_tree (TREE_OPERAND (x, 2), &tmp_list3, &tmp_list2, NULL_TREE);
+      warn_for_collisions (tmp_list2);
+      merge_tlist (pbefore_sp, tmp_list3, 0);
+      /* Rather than add both tmp_nosp and tmp_list2, we have to merge the
+	 two first, to avoid warning for (a ? b++ : b++).  */
+      merge_tlist (&tmp_nosp, tmp_list2, 0);
+      add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
+      return;
+
     case PREDECREMENT_EXPR:
     case PREINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
     case POSTINCREMENT_EXPR:
-      build_reverse_tree (TREE_OPERAND (x, 0), node, 0, 1, 1, depth + 1);
-      break;
+      verify_tree (TREE_OPERAND (x, 0), pno_sp, pno_sp, x);
+      return;
 
+    case MODIFY_EXPR:
+      tmp_before = tmp_nosp = tmp_list3 = 0;
+      verify_tree (TREE_OPERAND (x, 1), &tmp_before, &tmp_nosp, NULL_TREE);
+      verify_tree (TREE_OPERAND (x, 0), &tmp_list3, &tmp_list3, x);
+      /* Expressions inside the LHS are not ordered wrt. the sequence points
+	 in the RHS.  Example:
+	   *a = (a++, 2)
+	 Despite the fact that the modification of "a" is in the before_sp
+	 list (tmp_before), it conflicts with the use of "a" in the LHS.
+	 We can handle this by adding the contents of tmp_list3
+	 to those of tmp_before, and redoing the collision warnings for that
+	 list.  */
+      add_tlist (&tmp_before, tmp_list3, x, 1);
+      warn_for_collisions (tmp_before);
+      /* Exclude the LHS itself here; we first have to merge it into the
+	 tmp_nosp list.  This is done to avoid warning for "a = a"; if we
+	 didn't exclude the LHS, we'd get it twice, once as a read and once
+	 as a write.  */
+      add_tlist (pno_sp, tmp_list3, x, 0);
+      warn_for_collisions_1 (TREE_OPERAND (x, 0), x, tmp_nosp, 1);
+
+      merge_tlist (pbefore_sp, tmp_before, 0);
+      if (warning_candidate_p (TREE_OPERAND (x, 0)))
+	merge_tlist (&tmp_nosp, new_tlist (NULL, TREE_OPERAND (x, 0), x), 0);
+      add_tlist (pno_sp, tmp_nosp, NULL_TREE, 1);
+      return;
+
     case CALL_EXPR:
-      build_reverse_tree (TREE_OPERAND (x, 0), node, 0, 1, 0, depth + 1);
-      x = TREE_OPERAND (x, 1);
-      while (x)
-	{
-	  build_reverse_tree (TREE_VALUE (x), node, 1, 1, 0, depth + 1);
-	  x = TREE_CHAIN (x);
-	}
-      break;
+      /* We need to warn about conflicts among arguments and conflicts between
+	 args and the function address.  Side effects of the function address,
+	 however, are not ordered by the sequence point of the call.  */
+      tmp_before = tmp_nosp = tmp_list2 = tmp_list3 = 0;
+      verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE);
+      if (TREE_OPERAND (x, 1))
+	verify_tree (TREE_OPERAND (x, 1), &tmp_list2, &tmp_list3, NULL_TREE);
+      merge_tlist (&tmp_list3, tmp_list2, 0);
+      add_tlist (&tmp_before, tmp_list3, NULL_TREE, 0);
+      add_tlist (&tmp_before, tmp_nosp, NULL_TREE, 0);
+      warn_for_collisions (tmp_before);
+      add_tlist (pbefore_sp, tmp_before, NULL_TREE, 0);
+      return;
 
     case TREE_LIST:
       /* Scan all the list, e.g. indices of multi dimensional array.  */
       while (x)
 	{
-	  build_reverse_tree (TREE_VALUE (x), node, 0, 1, 0, depth + 1);
+	  tmp_before = tmp_nosp = 0;
+	  verify_tree (TREE_VALUE (x), &tmp_before, &tmp_nosp, NULL_TREE);
+	  merge_tlist (&tmp_nosp, tmp_before, 0);
+	  add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
 	  x = TREE_CHAIN (x);
 	}
-      break;
+      return;
 
-    case MODIFY_EXPR:
-      build_reverse_tree (TREE_OPERAND (x, 0), node, 0, 0, 1, depth + 1);
-      build_reverse_tree (TREE_OPERAND (x, 1), node, 1, 1, 0, depth + 1);
-      break;
+    case SAVE_EXPR:
+      {
+	struct tlist_cache *t;
+	for (t = save_expr_cache; t; t = t->next)
+	  if (t->expr == x)
+	    break;
 
-    default:
-      switch (TREE_CODE_CLASS (TREE_CODE (x)))
-	{
-	case 'r':
-	case '<':
-	case '2':
-	case 'b':
-	case '1':
-	case 'e':
-	case 's':
-	case 'x':
+	if (! t)
 	  {
-	    int lp;
-	    int max = first_rtl_op (TREE_CODE (x));
-	    for (lp = 0; lp < max; lp++)
-	      build_reverse_tree (TREE_OPERAND (x, lp), node, lp, 1, 0,
-				  depth + 1);
-	    break;
+	    t = (struct tlist_cache *) obstack_alloc (&tlist_obstack,
+						      sizeof *t);
+	    t->next = save_expr_cache;
+	    t->expr = x;
+	    save_expr_cache = t;
+
+	    tmp_before = tmp_nosp = 0;
+	    verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE);
+	    warn_for_collisions (tmp_nosp);
+
+	    tmp_list3 = 0;
+	    while (tmp_nosp)
+	      {
+		struct tlist *t = tmp_nosp;
+		tmp_nosp = t->next;
+		merge_tlist (&tmp_list3, t, 0);
+	      }
+	    t->cache_before_sp = tmp_before;
+	    t->cache_after_sp = tmp_list3;
 	  }
-	default:
-	  break;
-	}
+	merge_tlist (pbefore_sp, t->cache_before_sp, 1);
+	add_tlist (pno_sp, t->cache_after_sp, NULL_TREE, 1);
+	return;
+      }
+    default:
       break;
     }
-}
 
-/* Given nodes P1 and P2 as well as enough scratch space pointed to by TMP1
-   and TMP2, find the common ancestor of P1 and P2.  */
-
-static struct reverse_tree *
-common_ancestor (p1, p2, tmp1, tmp2)
-     struct reverse_tree *p1, *p2;
-     struct reverse_tree **tmp1, **tmp2;
-{
-  struct reverse_tree *t1 = p1;
-  struct reverse_tree *t2 = p2;
-  int i, j;
-
-  /* First, check if we're actually looking at the same expression twice,
-     which can happen if it's wrapped in a SAVE_EXPR - in this case there's
-     no chance of conflict.  */
-  while (t1 && t2 && t1->x == t2->x)
+  if (class == '1')
     {
-      if (TREE_CODE (t1->x) == SAVE_EXPR)
-	return 0;
-      t1 = t1->parent;
-      t2 = t2->parent;
+      if (first_rtl_op (code) == 0)
+	return;
+      x = TREE_OPERAND (x, 0);
+      writer = 0;
+      goto restart;
     }
-
-  for (i = 0; p1; i++, p1 = p1->parent)
-    tmp1[i] = p1;
-  for (j = 0; p2; j++, p2 = p2->parent)
-    tmp2[j] = p2;
-  while (tmp1[i - 1] == tmp2[j - 1])
-    i--, j--;
-
-  return tmp1[i];
-}
-
-/* Subroutine of verify_sequence_points to check whether a node T corresponding
-   to a MODIFY_EXPR invokes undefined behaviour.  OTHER occurs somewhere in the
-   RHS, and an identical expression is the LHS of T.
-   For MODIFY_EXPRs, some special cases apply when testing for undefined
-   behaviour if one of the expressions we found is the LHS of the MODIFY_EXPR.
-   If the other expression is just a use, then there's no undefined behaviour.
-   Likewise, if the other expression is wrapped inside another expression that
-   will force a sequence point, then there's no undefined behaviour either.  */
-
-static int
-modify_ok (t, other)
-     struct reverse_tree *t, *other;
-{
-  struct reverse_tree *p;
 
-  if (! other->write)
-    return 1;
-
-  /* See if there's an intervening sequence point.  */
-  for (p = other; p->parent != t; p = p->parent)
-    {
-      if ((TREE_CODE (p->parent->x) == COMPOUND_EXPR
-	   || TREE_CODE (p->parent->x) == TRUTH_ANDIF_EXPR
-	   || TREE_CODE (p->parent->x) == TRUTH_ORIF_EXPR
-	   || TREE_CODE (p->parent->x) == COND_EXPR)
-	  && p->operandno == 0)
-	return 1;
-      if (TREE_CODE (p->parent->x) == SAVE_EXPR)
-	return 1;
-      if (TREE_CODE (p->parent->x) == CALL_EXPR
-	  && p->operandno != 0)
-	return 1;
+  switch (class)
+    {
+    case 'r':
+    case '<':
+    case '2':
+    case 'b':
+    case 'e':
+    case 's':
+    case 'x':
+      {
+	int lp;
+	int max = first_rtl_op (TREE_CODE (x));
+	for (lp = 0; lp < max; lp++)
+	  {
+	    tmp_before = tmp_nosp = 0;
+	    verify_tree (TREE_OPERAND (x, lp), &tmp_before, &tmp_nosp, NULL_TREE);
+	    merge_tlist (&tmp_nosp, tmp_before, 0);
+	    add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
+	  }
+	break;
+      }
     }
-  return 0;
 }
 
 /* Try to warn for undefined behaviour in EXPR due to missing sequence
@@ -3612,65 +3808,19 @@ static void
 verify_sequence_points (expr)
      tree expr;
 {
-  struct reverse_tree **tmp1, **tmp2;
-  struct reverse_tree *p;
+  struct tlist *before_sp = 0, *after_sp = 0;
 
-  reverse_list = 0;
-  reverse_max_depth = 0;
-  build_reverse_tree (expr, NULL, 0, 1, 0, 1);
-
-  tmp1 = (struct reverse_tree **) xmalloc (sizeof (struct reverse_tree *)
-					   * reverse_max_depth);
-  tmp2 = (struct reverse_tree **) xmalloc (sizeof (struct reverse_tree *)
-					   * reverse_max_depth);
-
-  /* Search for multiple occurrences of the same variable, where either both
-     occurrences are writes, or one is a read and a write.  If we can't prove
-     that these are ordered by a sequence point, warn that the expression is
-     undefined.  */
-  for (p = reverse_list; p; p = p->next)
+  warned_ids = 0;
+  save_expr_cache = 0;
+  if (tlist_firstobj == 0)
     {
-      struct reverse_tree *p2;
-      if (TREE_CODE (p->x) != VAR_DECL && TREE_CODE (p->x) != PARM_DECL)
-	continue;
-      for (p2 = p->next; p2; p2 = p2->next)
-	{
-	  if ((TREE_CODE (p2->x) == VAR_DECL || TREE_CODE (p2->x) == PARM_DECL)
-	      && DECL_NAME (p->x) == DECL_NAME (p2->x)
-	      && (p->write || p2->write))
-	    {
-	      struct reverse_tree *t = common_ancestor (p, p2, tmp1, tmp2);
-
-	      if (t == 0
-		  || TREE_CODE (t->x) == COMPOUND_EXPR
-		  || TREE_CODE (t->x) == TRUTH_ANDIF_EXPR
-		  || TREE_CODE (t->x) == TRUTH_ORIF_EXPR
-		  || TREE_CODE (t->x) == COND_EXPR)
-		continue;
-	      if (TREE_CODE (t->x) == MODIFY_EXPR
-		  && p->parent == t
-		  && modify_ok (t, p2))
-		continue;
-	      if (TREE_CODE (t->x) == MODIFY_EXPR
-		  && p2->parent == t
-		  && modify_ok (t, p))
-		continue;
-
-	      warning ("operation on `%s' may be undefined",
-		       IDENTIFIER_POINTER (DECL_NAME (p->x)));
-	      break;
-	    }
-	}
+      gcc_obstack_init (&tlist_obstack);
+      tlist_firstobj = obstack_alloc (&tlist_obstack, 0);
     }
 
-  while (reverse_list)
-    {
-      struct reverse_tree *p = reverse_list;
-      reverse_list = p->next;
-      free (p);
-    }
-  free (tmp1);
-  free (tmp2);
+  verify_tree (expr, &before_sp, &after_sp, 0);
+  warn_for_collisions (after_sp);
+  obstack_free (&tlist_obstack, tlist_firstobj);
 }
 
 void
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/fold-const.c,v
retrieving revision 1.139
diff -u -p -r1.139 fold-const.c
--- fold-const.c	2000/11/10 00:12:01	1.139
+++ fold-const.c	2000/11/11 14:52:50
@@ -5962,7 +5962,9 @@ fold (expr)
       /* If either arg is constant true, drop it.  */
       if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
 	return non_lvalue (convert (type, arg1));
-      if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1))
+      if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1)
+	  /* Preserve sequence points.  */
+	  && (code != TRUTH_ANDIF_EXPR || ! TREE_SIDE_EFFECTS (arg0)))
 	return non_lvalue (convert (type, arg0));
       /* If second arg is constant zero, result is zero, but first arg
 	 must be evaluated.  */
@@ -6048,7 +6050,9 @@ fold (expr)
       /* If either arg is constant zero, drop it.  */
       if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0))
 	return non_lvalue (convert (type, arg1));
-      if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1))
+      if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1)
+	  /* Preserve sequence points.  */
+	  && (code != TRUTH_ORIF_EXPR || ! TREE_SIDE_EFFECTS (arg0)))
 	return non_lvalue (convert (type, arg0));
       /* If second arg is constant true, result is true, but we must
 	 evaluate first arg.  */
Index: testsuite/gcc.dg/sequence-pt-1.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/gcc.dg/sequence-pt-1.c,v
retrieving revision 1.4
diff -u -p -r1.4 sequence-pt-1.c
--- testsuite/gcc.dg/sequence-pt-1.c	2000/11/10 00:01:29	1.4
+++ testsuite/gcc.dg/sequence-pt-1.c	2000/11/11 14:52:54
@@ -19,7 +19,7 @@ typedef __SIZE_TYPE__ size_t;
 
 void
 foo (int a, int b, int n, int p, int *ptr, struct s *sptr,
-     int *ap, int *bp, int **cp, char *ans)
+     int *ap, int *bp, int **cp, char *ans, int (*fnp[8])(int))
 {
   int len;
     
@@ -44,6 +44,9 @@ foo (int a, int b, int n, int p, int *pt
   a = (bp[a++] = b) + 1; /* { dg-warning "undefined" "sequence point warning" } */
   a = b++ * b++; /* { dg-warning "undefined" "sequence point warning" } */
   a = fnb (b++, b++); /* { dg-warning "undefined" "sequence point warning" } */
+  a = (*fnp[b++]) (b++); /* { dg-warning "undefined" "sequence point warning" } */
+  a = (*fnp[b]) (b++); /* { dg-warning "undefined" "sequence point warning" } */
+  a = (*fnp[b++]) (b); /* { dg-warning "undefined" "sequence point warning" } */
   *ap = fnc (ap++); /* { dg-warning "undefined" "sequence point warning" } */
   (a += b) + (a += n); /* { dg-warning "undefined" "sequence point warning" } */
   a =  (b, b++) + (b++, b); /* { dg-warning "undefined" "sequence point warning" } */
@@ -51,10 +54,25 @@ foo (int a, int b, int n, int p, int *pt
   ap[a+=1] += a; /* { dg-warning "undefined" "sequence point warning" } */
   ap[a++] += a++; /* { dg-warning "undefined" "sequence point warning" } */
   ap[a+=1] += a++; /* { dg-warning "undefined" "sequence point warning" } */
+  a = a++, b = a; /* { dg-warning "undefined" "sequence point warning" } */
+  b = a, a = a++; /* { dg-warning "undefined" "sequence point warning" } */
+  a = (b++ ? n : a) + b; /* { dg-warning "undefined" "sequence point warning" } */
+  b ? a = a++ : a; /* { dg-warning "undefined" "sequence point warning" } */
+  b ? a : a = a++; /* { dg-warning "undefined" "sequence point warning" } */
+  b && (a = a++); /* { dg-warning "undefined" "sequence point warning" } */
+  (a = a++) && b; /* { dg-warning "undefined" "sequence point warning" } */
+  b, (a = a++); /* { dg-warning "undefined" "sequence point warning" } */
+  (a = a++), b; /* { dg-warning "undefined" "sequence point warning" } */
+  a ^= b ^= a ^= b; /* { dg-warning "undefined" "sequence point warning" } */
 
+  a = a; /* { dg-bogus "undefined" "bogus sequence point warning" } */
   a = (a++ && 4); /* { dg-bogus "undefined" "bogus sequence point warning" } */
+  a = ! (a++ && 4); /* { dg-bogus "undefined" "bogus sequence point warning" } */
+  a = - (a++ && 4); /* { dg-bogus "undefined" "bogus sequence point warning" } */
+  a = (double) (a++ && 4); /* { dg-bogus "undefined" "bogus sequence point warning" } */
   len = sprintf (ans, "%d", len++); /* { dg-bogus "undefined" "bogus sequence point warning" } */
-  a = fn (a++); /* { dg-bogus "undefined" "sequence point warning" } */
+  a = fn (a++); /* { dg-bogus "undefined" "bogus sequence point warning" } */
+  b++, (b + b); /* { dg-bogus "undefined" "bogus sequence point warning" } */
   (a = b++), (a = b++); /* { dg-bogus "undefined" "bogus sequence point warning" } */
   a = (b++, b++); /* { dg-bogus "undefined" "bogus sequence point warning" } */
   a = b++ && b++; /* { dg-bogus "undefined" "bogus sequence point warning" } */
@@ -63,4 +81,30 @@ foo (int a, int b, int n, int p, int *pt
   a = (b++ ? a : b++); /* { dg-bogus "undefined" "bogus sequence point warning" } */
   ap[a++] += bp[b]; /* { dg-bogus "undefined" "bogus sequence point warning" } */
   ap[a += 1] += 1; /* { dg-bogus "undefined" "bogus sequence point warning" } */
+  *ptr < 128 ? *ptr++ : *(ptr += 2); /* { dg-bogus "undefined" "bogus sequence point warning" } */
+
+  /* The following will be represented internally with a tree consisting of
+     many duplicated SAVE_EXPRs.  This caused the previous version of the
+     sequence point warning code to fail by running out of virtual memory.  */
+  a = ((b & 1 ? 21 : 0)
+       | (b & 2 ? 22 : 0)
+       | (b & 3 ? 23 : 0)
+       | (b & 4 ? 24 : 0)
+       | (b & 5 ? 25 : 0)
+       | (b & 6 ? 26 : 0)
+       | (b & 7 ? 27 : 0)
+       | (b & 8 ? 28 : 0)
+       | (b & 9 ? 29 : 0)
+       | (b & 10 ? 30 : 0)
+       | (b & 11 ? 31 : 0)
+       | (b & 12 ? 32 : 0)
+       | (b & 13 ? 1 : 0)
+       | (b & 14 ? 2 : 0)
+       | (b & 15 ? 3 : 0)
+       | (b & 16 ? 4 : 0)
+       | (b & 17 ? 5 : 0)
+       | (b & 18 ? 6 : 0)
+       | (b & 19 ? 7 : 0)
+       | (b & 20 ? 8 : 0)
+       | (b & 21 ? 9 : 0));
 }


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