PR c++/91548 - fix detecting modifying const objects for ARRAY_REF.
authorMarek Polacek <polacek@redhat.com>
Tue, 29 Oct 2019 20:34:43 +0000 (20:34 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Tue, 29 Oct 2019 20:34:43 +0000 (20:34 +0000)
This fixes a bogus "modifying a const object" error for an array that actually
isn't declared const.  The problem was how I handled ARRAY_REFs here; we
shouldn't look at the ARRAY_REF itself, but at the array its accessing.

* constexpr.c (cxx_eval_store_expression): Don't call
modifying_const_object_p for ARRAY_REF.

* g++.dg/cpp1y/constexpr-tracking-const15.C: New test.
* g++.dg/cpp1y/constexpr-tracking-const16.C: New test.
* g++.dg/cpp1z/constexpr-tracking-const1.C: New test.

From-SVN: r277591

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/constexpr-tracking-const1.C [new file with mode: 0644]

index c244438bca14493d9dc96a788cc56643790d48b8..09d1c18e8083ed9777e04094badf953ade146829 100644 (file)
@@ -1,3 +1,9 @@
+2019-10-29  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/91548 - fix detecting modifying const objects for ARRAY_REF.
+       * constexpr.c (cxx_eval_store_expression): Don't call
+       modifying_const_object_p for ARRAY_REF.
+
 2019-10-29  Richard Sandiford  <richard.sandiford@arm.com>
 
        * cp-objcp-common.h (cxx_simulate_enum_decl): Declare.
index 11a1eaa0e82a3acdd2df33e0152b9c7a393fb1d8..6b4e854e35c31a94d4104edc62fa589799db3acb 100644 (file)
@@ -3910,10 +3910,6 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
            tree elt = TREE_OPERAND (probe, 1);
            if (TREE_CODE (elt) == FIELD_DECL && DECL_MUTABLE_P (elt))
              mutable_p = true;
-           if (evaluated
-               && modifying_const_object_p (TREE_CODE (t), probe, mutable_p)
-               && const_object_being_modified == NULL_TREE)
-             const_object_being_modified = probe;
            if (TREE_CODE (probe) == ARRAY_REF)
              {
                elt = eval_and_check_array_index (ctx, probe, false,
@@ -3921,6 +3917,15 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
                if (*non_constant_p)
                  return t;
              }
+           /* We don't check modifying_const_object_p for ARRAY_REFs.  Given
+              "int a[10]", an ARRAY_REF "a[2]" can be "const int", even though
+              the array isn't const.  Instead, check "a" in the next iteration;
+              that will detect modifying "const int a[10]".  */
+           else if (evaluated
+                    && modifying_const_object_p (TREE_CODE (t), probe,
+                                                 mutable_p)
+                    && const_object_being_modified == NULL_TREE)
+             const_object_being_modified = probe;
            vec_safe_push (refs, elt);
            vec_safe_push (refs, TREE_TYPE (probe));
            probe = ob;
index aba99221a42ee325f101249ba09cbfdf3a120a42..cffd59217720bf96a26bcf5276bade8d558f2c0f 100644 (file)
@@ -1,3 +1,10 @@
+2019-10-29  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/91548 - fix detecting modifying const objects for ARRAY_REF.
+       * g++.dg/cpp1y/constexpr-tracking-const15.C: New test.
+       * g++.dg/cpp1y/constexpr-tracking-const16.C: New test.
+       * g++.dg/cpp1z/constexpr-tracking-const1.C: New test.
+
 2019-10-29  Martin Sebor  <msebor@redhat.com>
 
        PR testsuite/92144
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const15.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const15.C
new file mode 100644 (file)
index 0000000..db1b2bb
--- /dev/null
@@ -0,0 +1,21 @@
+// PR c++/91548 - fix detecting modifying const objects for ARRAY_REF.
+// { dg-do compile { target c++14 } }
+
+constexpr int& impl(const int (&array)[10], int index) {
+  return const_cast<int&>(array[index]);
+}
+
+struct A {
+  constexpr int& operator[](int i) { return impl(elems, i); }
+  int elems[10];
+};
+
+constexpr bool
+f()
+{
+  A arr = {};
+  arr[2] = true;
+  return false;
+}
+
+constexpr bool b = f();
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const16.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const16.C
new file mode 100644 (file)
index 0000000..5a5b92b
--- /dev/null
@@ -0,0 +1,22 @@
+// PR c++/91548 - fix detecting modifying const objects for ARRAY_REF.
+// { dg-do compile { target c++14 } }
+
+constexpr int& impl(const int (&array)[10], int index) {
+  return const_cast<int&>(array[index]);
+}
+
+struct A {
+  constexpr int& operator[](int i) { return impl(elems, i); }
+  const int elems[10];
+};
+
+constexpr bool
+f()
+{
+  A arr = {};
+  arr[2] = 1; // { dg-error "modifying a const object" }
+  return false;
+}
+
+constexpr bool b = f(); // { dg-message "in .constexpr. expansion of " }
+// { dg-message "originally declared" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-tracking-const1.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-tracking-const1.C
new file mode 100644 (file)
index 0000000..a3856b8
--- /dev/null
@@ -0,0 +1,25 @@
+// PR c++/91548 - fix detecting modifying const objects for ARRAY_REF.
+// { dg-do compile { target c++17 } }
+
+using size_t = decltype(sizeof(0));
+
+template <typename T, size_t N>
+constexpr T& impl(T const (&array)[N], size_t index) {
+    return const_cast<T&>(array[index]);
+}
+
+template <typename T, size_t N>
+struct my_array {
+    constexpr T& operator[](size_t i) { return impl(elems, i); }
+    constexpr T const& operator[](size_t i) const { return elems[i]; }
+    T elems[N];
+};
+
+bool f(int i) {
+    static constexpr auto table = []() {
+        my_array<bool, 256> arr = {};
+        arr[2] = true;
+        return arr;
+    }();
+    return table[i];
+}