Hi!

The problem here is that for loops that have constant 0/false condition
the C++ FE wants to correctly emit if (0) { body; incr-expr; }
but doesn't just build3 (COND_EXPR, ...), but fold_build3, and COND_EXPR
folding with constant condition optimizes away the unused branch completely
if it doesn't contain any labels.  In this case it doesn't contain any
labels, but contains CASE_LABEL_EXPR that we should also take into account
(but can ignore it when during the walk we are inside a SWITCH_BODY).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/7.3?

2017-12-23  Jakub Jelinek  <ja...@redhat.com>

        PR c++/83553
        * fold-const.c (struct contains_label_data): New type.
        (contains_label_1): Return non-NULL even for CASE_LABEL_EXPR, unless
        inside of a SWITCH_BODY seen during the walk.
        (contains_label_p): Use walk_tree instead of
        walk_tree_without_duplicates, prepare data for contains_label_1 and
        provide own pset.

        * c-c++-common/torture/pr83553.c: New test.

--- gcc/fold-const.c.jj 2017-12-21 09:43:17.000000000 +0100
+++ gcc/fold-const.c    2017-12-23 00:22:54.447669504 +0100
@@ -11218,22 +11218,48 @@ fold_binary_loc (location_t loc, enum tr
     } /* switch (code) */
 }
 
+/* Used by contains_label_[p1].  */
+
+struct contains_label_data
+{
+  hash_set<tree> *pset;
+  bool inside_switch_p;
+};
+
 /* Callback for walk_tree, looking for LABEL_EXPR.  Return *TP if it is
-   a LABEL_EXPR; otherwise return NULL_TREE.  Do not check the subtrees
-   of GOTO_EXPR.  */
+   a LABEL_EXPR or CASE_LABEL_EXPR not inside of another SWITCH_EXPR; otherwise
+   return NULL_TREE.  Do not check the subtrees of GOTO_EXPR.  */
 
 static tree
-contains_label_1 (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+contains_label_1 (tree *tp, int *walk_subtrees, void *data)
 {
+  contains_label_data *d = (contains_label_data *) data;
   switch (TREE_CODE (*tp))
     {
     case LABEL_EXPR:
       return *tp;
 
+    case CASE_LABEL_EXPR:
+      if (!d->inside_switch_p)
+       return *tp;
+      return NULL_TREE;
+
+    case SWITCH_EXPR:
+      if (!d->inside_switch_p)
+       {
+         if (walk_tree (&SWITCH_COND (*tp), contains_label_1, data, d->pset))
+           return *tp;
+         d->inside_switch_p = true;
+         if (walk_tree (&SWITCH_BODY (*tp), contains_label_1, data, d->pset))
+           return *tp;
+         d->inside_switch_p = false;
+         *walk_subtrees = 0;
+       }
+      return NULL_TREE;
+
     case GOTO_EXPR:
       *walk_subtrees = 0;
-
-      /* fall through */
+      return NULL_TREE;
 
     default:
       return NULL_TREE;
@@ -11246,8 +11272,9 @@ contains_label_1 (tree *tp, int *walk_su
 static bool
 contains_label_p (tree st)
 {
-  return
-   (walk_tree_without_duplicates (&st, contains_label_1 , NULL) != NULL_TREE);
+  hash_set<tree> pset;
+  contains_label_data data = { &pset, false };
+  return walk_tree (&st, contains_label_1, &data, &pset) != NULL_TREE;
 }
 
 /* Fold a ternary expression of code CODE and type TYPE with operands
--- gcc/testsuite/c-c++-common/torture/pr83553.c.jj     2017-12-23 
00:30:20.548180122 +0100
+++ gcc/testsuite/c-c++-common/torture/pr83553.c        2017-12-23 
00:29:11.000000000 +0100
@@ -0,0 +1,29 @@
+/* PR c++/83553 */
+/* { dg-do run } */
+
+int a[3];
+
+int
+foo (int n)
+{
+  switch (n)
+    {
+    case 0:
+      for (n = 7, a[0]++; 0; a[2] = a[1] + 1)
+       {
+    case 2:
+         a[1] = a[0] + 1;
+       }
+    }
+  return n;
+}
+
+int
+main ()
+{
+  if (foo (0) != 7 || a[0] != 1 || a[1] || a[2])
+    __builtin_abort ();
+  if (foo (2) != 2 || a[0] != 1 || a[1] != 2 || a[2] != 3)
+    __builtin_abort ();
+  return 0;
+}

        Jakub

Reply via email to