C++ PATCH to fix infinite constexpr evaluation (PR c++/86767)

Message ID 20180806153555.GD1051@redhat.com
State New
Headers show
Series
  • C++ PATCH to fix infinite constexpr evaluation (PR c++/86767)
Related show

Commit Message

Marek Polacek Aug. 6, 2018, 3:35 p.m.
This PR points out infinite looping in constexpr evaluation for e.g.

  for (...)
    {
      continue;
      while (1);
    }

where we tried to evaluate the while despite the continue.  The problem
started with r240591 and its cxx_eval_statement_list changes.  This
patch fixes it by handling continue in such a way that we skip stmts that
are not meant to be evaluated.

Bootstrapped/regtested on x86_64-linux, ok for trunk/8.3?

2018-08-06  Marek Polacek  <polacek@redhat.com>

	PR c++/86767
	* constexpr.c (cxx_eval_statement_list): Handle continue.

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


	Marek

Comments

Nathan Sidwell Aug. 6, 2018, 3:42 p.m. | #1
On 08/06/2018 11:35 AM, Marek Polacek wrote:
> This PR points out infinite looping in constexpr evaluation for e.g.

> Bootstrapped/regtested on x86_64-linux, ok for trunk/8.3?
> 
> 2018-08-06  Marek Polacek  <polacek@redhat.com>
> 
> 	PR c++/86767
> 	* constexpr.c (cxx_eval_statement_list): Handle continue.

ok.  I like the use of 'continue' in the processing of 'continue' :)

nathan

Patch

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 365296d6e3b..79039ff2b79 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -3950,6 +3950,16 @@  cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
   for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
     {
       tree stmt = tsi_stmt (i);
+      /* We've found a continue, so skip everything until we reach
+	 the label its jumping to.  */
+      if (continues (jump_target))
+	{
+	  if (label_matches (ctx, jump_target, stmt))
+	    /* Found it.  */
+	    *jump_target = NULL_TREE;
+	  else
+	    continue;
+	}
       if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
 	continue;
       r = cxx_eval_constant_expression (ctx, stmt, false,
diff --git gcc/testsuite/g++.dg/cpp1y/constexpr-86767.C gcc/testsuite/g++.dg/cpp1y/constexpr-86767.C
index e69de29bb2d..2ad71d507d1 100644
--- gcc/testsuite/g++.dg/cpp1y/constexpr-86767.C
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-86767.C
@@ -0,0 +1,119 @@ 
+// PR c++/86767
+// { dg-do compile { target c++14 } }
+
+constexpr int
+fn0 () noexcept
+{
+  int r = 0;
+  for (int i = 0; i < 10; ++i)
+    {
+      continue;
+      r++;
+      for (int j = 0; j < 10; ++j )
+	{
+	}
+    }
+  return r;
+}
+static_assert (fn0 () == 0, "");
+
+constexpr int
+fn1 () noexcept
+{
+  int r = 0;
+  for (int i = 0; i < 10; ++i)
+    for (int j = 0; j < 10; ++j)
+      {
+	continue;
+	r++;
+      }
+  return r;
+}
+static_assert (fn1 () == 0, "");
+
+constexpr int
+fn2 () noexcept
+{
+  int r = 0;
+  for (int i = 0; i < 10; ++i)
+    {
+      continue;
+      r++;
+    }
+  return r;
+}
+static_assert (fn2 () == 0, "");
+
+constexpr int
+fn3 () noexcept
+{
+  int r = 0;
+  for (int i = 0; i < 10; ++i)
+    {
+      continue;
+      r++;
+      while (1)
+	{
+	}
+    }
+  return r;
+}
+static_assert (fn3 () == 0, "");
+
+constexpr int
+fn4 () noexcept
+{
+  for (int i = 0; i < 10; ++i)
+    {
+      switch (i)
+	{
+	case 5:
+	  return i;
+	default:
+	  continue;
+	}
+      while (1)
+	{
+	}
+    }
+  return 0;
+}
+static_assert (fn4 () == 5, "");
+
+constexpr int
+fn5 () noexcept
+{
+  for (int i = 0; i < 10; ++i)
+    {
+      switch (i)
+	{
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	  continue;
+	default:
+	  return i;
+	}
+      while (1)
+	{
+	}
+    }
+  return 0;
+}
+static_assert (fn5 () == 5, "");
+
+constexpr int
+fn6 () noexcept
+{
+  int r = 0;
+  for (int i = 0; i < 10; ++i)
+    {
+      continue;
+      for (int j = 0; j < 10; ++j )
+	r++;
+    }
+  return r;
+}
+static_assert (fn6 () == 0, "");