PR c++/88983 - ICE with switch in constexpr function.
authorMarek Polacek <polacek@redhat.com>
Fri, 1 Feb 2019 00:30:46 +0000 (00:30 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Fri, 1 Feb 2019 00:30:46 +0000 (00:30 +0000)
* constexpr.c (cxx_eval_switch_expr): Use SWITCH_COND and SWITCH_BODY.
(cxx_eval_constant_expression) <case COND_EXPR>: Don't look for the
label in the else branch if we found it in the then branch.

* g++.dg/cpp1y/constexpr-88983.C: New test.

From-SVN: r268438

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/constexpr-88983.C [new file with mode: 0644]

index a48b14c2091f4ec05017de864b0dcccfd7fa08b5..2a2aba3ad44bd5d049d097a950fbe7e2170035d6 100644 (file)
@@ -6,6 +6,11 @@
        * decl.c (reshape_init_r): Don't reshape a digested initializer.
        Return the initializer for COMPOUND_LITERAL_P.
 
+       PR c++/88983 - ICE with switch in constexpr function.
+       * constexpr.c (cxx_eval_switch_expr): Use SWITCH_COND and SWITCH_BODY.
+       (cxx_eval_constant_expression) <case COND_EXPR>: Don't look for the
+       label in the else branch if we found it in the then branch.
+
 2019-01-30  Jason Merrill  <jason@redhat.com>
 
        PR c++/88752 - ICE with lambda and constexpr if.
index 19eb44fc0c059800461cf483e979aa9a3062cf2b..923763faa0a03d57deb64de9ce63d2cb2314a207 100644 (file)
@@ -4140,13 +4140,13 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
                      bool *non_constant_p, bool *overflow_p,
                      tree *jump_target)
 {
-  tree cond = TREE_OPERAND (t, 0);
+  tree cond = SWITCH_COND (t);
   cond = cxx_eval_constant_expression (ctx, cond, false,
                                       non_constant_p, overflow_p);
   VERIFY_CONSTANT (cond);
   *jump_target = cond;
 
-  tree body = TREE_OPERAND (t, 1);
+  tree body = SWITCH_BODY (t);
   constexpr_ctx new_ctx = *ctx;
   constexpr_switch_state css = css_default_not_seen;
   new_ctx.css_state = &css;
@@ -4681,6 +4681,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case COND_EXPR:
       if (jump_target && *jump_target)
        {
+         tree orig_jump = *jump_target;
          /* When jumping to a label, the label might be either in the
             then or else blocks, so process then block first in skipping
             mode first, and if we are still in the skipping mode at its end,
@@ -4688,7 +4689,19 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
          r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
                                            lval, non_constant_p, overflow_p,
                                            jump_target);
-         if (*jump_target)
+         /* It's possible that we found the label in the then block.  But
+            it could have been followed by another jumping statement, e.g.
+            say we're looking for case 1:
+             if (cond)
+               {
+                 // skipped statements
+                 case 1:; // clears up *jump_target
+                 return 1; // and sets it to a RETURN_EXPR
+               }
+             else { ... }
+            in which case we need not go looking to the else block.
+            (goto is not allowed in a constexpr function.)  */
+         if (*jump_target == orig_jump)
            r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
                                              lval, non_constant_p, overflow_p,
                                              jump_target);
index ec3b597339f46a11b7b5339cd98c2d451d7e0fb9..989f4c5acec9b526cc13a15f1952d3b757a1051d 100644 (file)
@@ -1,3 +1,8 @@
+2019-01-31  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/88983 - ICE with switch in constexpr function.
+       * g++.dg/cpp1y/constexpr-88983.C: New test.
+
 2019-01-31  Thomas Koenig  <tkoenig@gcc.gnu.org>
 
        PR fortran/88669
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-88983.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-88983.C
new file mode 100644 (file)
index 0000000..9d70601
--- /dev/null
@@ -0,0 +1,71 @@
+// PR c++/88983
+// { dg-do compile { target c++14 } }
+
+constexpr int
+fn1 (int ay)
+{
+  switch (ay)
+    {
+      if (1)
+        {
+          case 1:
+            return 1;
+        }
+      else
+        {
+          default:;
+        }
+    }
+
+  return 0;
+}
+
+constexpr int
+fn2 (int ay)
+{
+  switch (ay)
+    {
+      if (1)
+        {
+          case 1:
+           break;
+        }
+      else
+        {
+          default:;
+        }
+    }
+
+  return 0;
+}
+
+constexpr int
+fn3 (int ay)
+{
+  int i = 0;
+  while (i++ < 100)
+    {
+      if (i == 1)
+       return 1;
+      switch (ay)
+       {
+         if (1)
+           {
+             case 1:
+               continue;
+           }
+         else
+           {
+             default:;
+             return -1;
+           }
+       }
+      return -1;
+    }
+
+  return -1;
+}
+
+static_assert (fn1 (1) == 1, "");
+static_assert (fn2 (1) == 0, "");
+static_assert (fn3 (1) == 1, "");