From: Marek Polacek Date: Tue, 29 Oct 2019 20:34:43 +0000 (+0000) Subject: PR c++/91548 - fix detecting modifying const objects for ARRAY_REF. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0f1848002a137f3cac5026c5a3af6e16ceabe552;p=gcc.git PR c++/91548 - fix detecting modifying const objects for ARRAY_REF. 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c244438bca1..09d1c18e808 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2019-10-29 Marek Polacek + + 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 * cp-objcp-common.h (cxx_simulate_enum_decl): Declare. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 11a1eaa0e82..6b4e854e35c 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index aba99221a42..cffd5921772 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-10-29 Marek Polacek + + 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 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 index 00000000000..db1b2bb7ea6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const15.C @@ -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(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 index 00000000000..5a5b92bc8cc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const16.C @@ -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(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 index 00000000000..a3856b8e7ec --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-tracking-const1.C @@ -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 +constexpr T& impl(T const (&array)[N], size_t index) { + return const_cast(array[index]); +} + +template +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 arr = {}; + arr[2] = true; + return arr; + }(); + return table[i]; +}