Here potential_constant_expression_1 rejects the testcase because the body of
the for loop calls a non-constexpr function.  But the range is empty so the
function would never get called.
The trick with evaluating the for-condition doesn't work here, because we're
dealing with a converted range-based for and can't evaluate

  __for_begin != __for_end

because the constexpr cache doesn't have the values of these two VAR_DECLs.

So either we can use this ugly hack (more specialized), or just not check the
body of the loop (more general), similarly to what we do (don't do) with
switch.

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

2018-10-11  Marek Polacek  <pola...@redhat.com>

        PR c++/87594 - constexpr rejects-valid with range-based for.
        * constexpr.c (potential_constant_expression_1) <case FOR_STMT>: Return
        true for a converted ange-based for-statement.

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

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 4fa8c965a9d..685ca743859 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -5827,6 +5827,17 @@ potential_constant_expression_1 (tree t, bool want_rval, 
bool strict, bool now,
            tmp = cxx_eval_outermost_constant_expr (tmp, true);
          if (integer_zerop (tmp))
            return true;
+         /* See if this is
+            __for_begin != __for_end
+            cp_convert_range_for created for us.  If so, this is a converted
+            range-based for-statement, and we're not able to evaluate this
+            condition, so we might end up skipping the body entirely.  */
+         else if (TREE_CODE (tmp) == NE_EXPR
+                  && VAR_P (TREE_OPERAND (tmp, 0))
+                  && DECL_NAME (TREE_OPERAND (tmp, 0)) == for_begin_identifier
+                  && VAR_P (TREE_OPERAND (tmp, 1))
+                  && DECL_NAME (TREE_OPERAND (tmp, 1)) == for_end_identifier)
+           return true;
        }
       if (!RECUR (FOR_EXPR (t), any))
        return false;
diff --git gcc/testsuite/g++.dg/cpp1y/constexpr-loop8.C 
gcc/testsuite/g++.dg/cpp1y/constexpr-loop8.C
index e69de29bb2d..bf132f2484e 100644
--- gcc/testsuite/g++.dg/cpp1y/constexpr-loop8.C
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-loop8.C
@@ -0,0 +1,44 @@
+// PR c++/87594
+// { dg-do compile { target c++14 } }
+
+constexpr bool always_false() { return false; }
+int f() { return 1; }
+
+constexpr int
+fn1()
+{
+  struct empty_range {
+    constexpr int* begin() { return 0; }
+    constexpr int* end() { return 0; }
+  } e;
+  for (auto x : e)
+    f();
+  return 0;
+}
+
+constexpr int
+fn2 ()
+{
+  int a[] = { 1, 2, 3 };
+  for (auto x : a)
+    f(); // { dg-error "call to non-.constexpr. function" }
+  return 0;
+}
+
+constexpr int
+fn3 ()
+{
+  __extension__ int a[] = { };
+  for (auto x : a)
+    f();
+  return 0;
+}
+
+
+void
+bar ()
+{
+  constexpr int i1 = fn1 ();
+  constexpr int i2 = fn2 (); // { dg-message "in .constexpr. expansion of " }
+  constexpr int i3 = fn3 ();
+}

Reply via email to