diff mbox

C++ PATCH for c++/64356 and libstdc++/58777 (constexpr pointer arithmetic)

Message ID 54B58800.2080601@redhat.com
State New
Headers show

Commit Message

Jason Merrill Jan. 13, 2015, 9:02 p.m. UTC
In this testcase we are iterating through an array which is a local 
variable in a constexpr function.  So its address is not constant, but 
we can still do arithmetic on it to get to the address of an element and 
then pull out the value of the element; we shouldn't reject the 
evaluation as non-constant unless the non-constant address is part of 
the value of the complete expression.

This patch also fixes libstdc++/58777, another issue with giving up on 
an intermediate non-constant address even though the final value is 
constant.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit 10760eb60bfd8f5de38ff1194718851a3d0f9073
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jan 13 07:45:03 2015 -0500

    	PR c++/64356
    	PR libstdc++/58777
    	* constexpr.c (cxx_eval_binary_expression): Don't VERIFY_CONSTANT
    	pointer expressions.
    	(cxx_eval_increment_expression): Likewise.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 650250b..1432506 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1616,10 +1616,15 @@  cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
   tree lhs, rhs;
   lhs = cxx_eval_constant_expression (ctx, orig_lhs, /*lval*/false,
 				      non_constant_p, overflow_p);
-  VERIFY_CONSTANT (lhs);
+  /* Don't VERIFY_CONSTANT if this might be dealing with a pointer to
+     a local array in a constexpr function.  */
+  bool ptr = POINTER_TYPE_P (TREE_TYPE (lhs));
+  if (!ptr)
+    VERIFY_CONSTANT (lhs);
   rhs = cxx_eval_constant_expression (ctx, orig_rhs, /*lval*/false,
 				      non_constant_p, overflow_p);
-  VERIFY_CONSTANT (rhs);
+  if (!ptr)
+    VERIFY_CONSTANT (lhs);
 
   location_t loc = EXPR_LOCATION (t);
   enum tree_code code = TREE_CODE (t);
@@ -1634,7 +1639,8 @@  cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
     }
   else if (cxx_eval_check_shift_p (loc, ctx, code, type, lhs, rhs))
     *non_constant_p = true;
-  VERIFY_CONSTANT (r);
+  if (!ptr)
+    VERIFY_CONSTANT (lhs);
   return r;
 }
 
@@ -2704,7 +2710,11 @@  cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
   tree val = rvalue (op);
   val = cxx_eval_constant_expression (ctx, val, false,
 				      non_constant_p, overflow_p);
-  VERIFY_CONSTANT (val);
+  /* Don't VERIFY_CONSTANT if this might be dealing with a pointer to
+     a local array in a constexpr function.  */
+  bool ptr = POINTER_TYPE_P (TREE_TYPE (val));
+  if (!ptr)
+    VERIFY_CONSTANT (val);
 
   /* The modified value.  */
   bool inc = (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR);
@@ -2719,7 +2729,8 @@  cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
     }
   else
     mod = fold_build2 (inc ? PLUS_EXPR : MINUS_EXPR, type, val, offset);
-  VERIFY_CONSTANT (mod);
+  if (!ptr)
+    VERIFY_CONSTANT (mod);
 
   /* Storing the modified value.  */
   tree store = build2 (MODIFY_EXPR, type, op, mod);
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-local2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-local2.C
new file mode 100644
index 0000000..fd6143b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-local2.C
@@ -0,0 +1,22 @@ 
+// PR c++/64356
+// { dg-do compile { target c++14 } }
+
+typedef unsigned long size_t;
+
+template<size_t N>
+constexpr size_t f(const char (&x)[N]) {
+  size_t s = 0;
+  for(size_t c : x)
+    s += c;
+  return s;
+}
+
+template<size_t N>
+constexpr size_t g(const char (&x)[N]) {
+  char y[N] = {0};
+  for(size_t i = 0; i < N; ++i)
+    y[i] = x[i];
+  return f(y);
+}
+
+constexpr auto x = g(__DATE__);
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr63996.C b/gcc/testsuite/g++.dg/cpp1y/pr63996.C
index d0bf9b5..8f66cdc 100644
--- a/gcc/testsuite/g++.dg/cpp1y/pr63996.C
+++ b/gcc/testsuite/g++.dg/cpp1y/pr63996.C
@@ -6,5 +6,5 @@  foo (int i)
   int a[i] = { }; // { dg-error "forbids variable length" }
 }
 
-constexpr int j = foo (1); // { dg-error "is not a constant expression" }
+constexpr int j = foo (1); // { dg-error "flows off the end" }
 
diff --git a/libstdc++-v3/testsuite/experimental/optional/constexpr/make_optional.cc b/libstdc++-v3/testsuite/experimental/optional/constexpr/make_optional.cc
index f3b4388..d57cf5c 100644
--- a/libstdc++-v3/testsuite/experimental/optional/constexpr/make_optional.cc
+++ b/libstdc++-v3/testsuite/experimental/optional/constexpr/make_optional.cc
@@ -1,7 +1,4 @@ 
 // { dg-options "-std=gnu++14" }
-// XFAIL pending resolution of PR libstdc++/58777
-// { dg-do compile { xfail *-*-* } }
-// { dg-excess-errors "" }
 
 // Copyright (C) 2013-2015 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/experimental/optional/constexpr/observers/2.cc b/libstdc++-v3/testsuite/experimental/optional/constexpr/observers/2.cc
index 20c307d..803927b 100644
--- a/libstdc++-v3/testsuite/experimental/optional/constexpr/observers/2.cc
+++ b/libstdc++-v3/testsuite/experimental/optional/constexpr/observers/2.cc
@@ -1,7 +1,4 @@ 
 // { dg-options "-std=gnu++14" }
-// XFAIL pending resolution of PR libstdc++/58777
-// { dg-do compile { xfail *-*-* } }
-// { dg-excess-errors "" }
 
 // Copyright (C) 2013-2015 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/experimental/optional/constexpr/observers/3.cc b/libstdc++-v3/testsuite/experimental/optional/constexpr/observers/3.cc
index 59b1bdd..be170f5 100644
--- a/libstdc++-v3/testsuite/experimental/optional/constexpr/observers/3.cc
+++ b/libstdc++-v3/testsuite/experimental/optional/constexpr/observers/3.cc
@@ -1,7 +1,4 @@ 
 // { dg-options "-std=gnu++14" }
-// XFAIL pending resolution of PR libstdc++/58777
-// { dg-do compile { xfail *-*-* } }
-// { dg-excess-errors "" }
 
 // Copyright (C) 2013-2015 Free Software Foundation, Inc.
 //