aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog10
-rw-r--r--gcc/cp/constexpr.c42
-rw-r--r--gcc/testsuite/ChangeLog10
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const17.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const18.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const19.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const20.C28
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const21.C28
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const22.C17
9 files changed, 203 insertions, 1 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index ebccb51..da768cd 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,13 @@
+2020-03-11 Marek Polacek <polacek@redhat.com>
+ Jason Merrill <jason@redhat.com>
+
+ PR c++/94074 - wrong modifying const object error for COMPONENT_REF.
+ * constexpr.c (cref_has_const_field): New function.
+ (modifying_const_object_p): Consider a COMPONENT_REF
+ const only if any of its fields are const.
+ (cxx_eval_store_expression): Mark a CONSTRUCTOR of a const type
+ as readonly after its initialization has been done.
+
2020-03-10 Marek Polacek <polacek@redhat.com>
PR c++/94124 - wrong conversion error with non-viable overload.
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 76af0d7..192face 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -4384,6 +4384,22 @@ maybe_simplify_trivial_copy (tree &target, tree &init)
}
}
+/* Returns true if REF, which is a COMPONENT_REF, has any fields
+ of constant type. This does not check for 'mutable', so the
+ caller is expected to be mindful of that. */
+
+static bool
+cref_has_const_field (tree ref)
+{
+ while (TREE_CODE (ref) == COMPONENT_REF)
+ {
+ if (CP_TYPE_CONST_P (TREE_TYPE (TREE_OPERAND (ref, 1))))
+ return true;
+ ref = TREE_OPERAND (ref, 0);
+ }
+ return false;
+}
+
/* Return true if we are modifying something that is const during constant
expression evaluation. CODE is the code of the statement, OBJ is the
object in question, MUTABLE_P is true if one of the subobjects were
@@ -4401,7 +4417,23 @@ modifying_const_object_p (tree_code code, tree obj, bool mutable_p)
if (mutable_p)
return false;
- return (TREE_READONLY (obj) || CP_TYPE_CONST_P (TREE_TYPE (obj)));
+ if (TREE_READONLY (obj))
+ return true;
+
+ if (CP_TYPE_CONST_P (TREE_TYPE (obj)))
+ {
+ /* Although a COMPONENT_REF may have a const type, we should
+ only consider it modifying a const object when any of the
+ field components is const. This can happen when using
+ constructs such as const_cast<const T &>(m), making something
+ const even though it wasn't declared const. */
+ if (TREE_CODE (obj) == COMPONENT_REF)
+ return cref_has_const_field (obj);
+ else
+ return true;
+ }
+
+ return false;
}
/* Evaluate an INIT_EXPR or MODIFY_EXPR. */
@@ -4759,6 +4791,14 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
else
*valp = init;
+ /* After initialization, 'const' semantics apply to the value of the
+ object. Make a note of this fact by marking the CONSTRUCTOR
+ TREE_READONLY. */
+ if (TREE_CODE (t) == INIT_EXPR
+ && TREE_CODE (*valp) == CONSTRUCTOR
+ && TYPE_READONLY (type))
+ TREE_READONLY (*valp) = true;
+
/* Update TREE_CONSTANT and TREE_SIDE_EFFECTS on enclosing
CONSTRUCTORs, if any. */
tree elt;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ba4cd14..1ed0071 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2020-03-06 Marek Polacek <polacek@redhat.com>
+
+ PR c++/94074 - wrong modifying const object error for COMPONENT_REF.
+ * g++.dg/cpp1y/constexpr-tracking-const17.C: New test.
+ * g++.dg/cpp1y/constexpr-tracking-const18.C: New test.
+ * g++.dg/cpp1y/constexpr-tracking-const19.C: New test.
+ * g++.dg/cpp1y/constexpr-tracking-const20.C: New test.
+ * g++.dg/cpp1y/constexpr-tracking-const21.C: New test.
+ * g++.dg/cpp1y/constexpr-tracking-const22.C: New test.
+
2020-03-11 Jakub Jelinek <jakub@redhat.com>
PR target/94134
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const17.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const17.C
new file mode 100644
index 0000000..3f215d2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const17.C
@@ -0,0 +1,23 @@
+// PR c++/94074 - wrong modifying const object error for COMPONENT_REF.
+// { dg-do compile { target c++14 } }
+
+typedef decltype (sizeof (0)) size_t;
+
+template <typename E, size_t N>
+struct array
+{
+ constexpr const E &operator[](size_t n) const noexcept { return elems[n]; }
+ E elems[N];
+};
+
+template <typename T>
+struct S {
+ using U = array<T, 4>;
+ U m;
+ constexpr S(int) : m{}
+ {
+ const_cast<int &>(const_cast<const U &>(m)[0]) = 42;
+ }
+};
+
+constexpr S<int> p = { 10 };
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const18.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const18.C
new file mode 100644
index 0000000..11a6804
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const18.C
@@ -0,0 +1,23 @@
+// PR c++/94074 - wrong modifying const object error for COMPONENT_REF.
+// { dg-do compile { target c++14 } }
+
+typedef decltype (sizeof (0)) size_t;
+
+template <typename E, size_t N>
+struct array
+{
+ constexpr const E &operator[](size_t n) const noexcept { return elems[n]; }
+ E elems[N];
+};
+
+template <typename T>
+struct S {
+ using U = array<T, 4>;
+ const U m;
+ constexpr S(int) : m{}
+ {
+ const_cast<int &>(const_cast<const U &>(m)[0]) = 42; // { dg-error "modifying a const object" }
+ }
+};
+
+constexpr S<int> p = { 10 }; // { dg-message "originally declared" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const19.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const19.C
new file mode 100644
index 0000000..c31222f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const19.C
@@ -0,0 +1,23 @@
+// PR c++/94074 - wrong modifying const object error for COMPONENT_REF.
+// { dg-do compile { target c++14 } }
+
+typedef decltype (sizeof (0)) size_t;
+
+template <typename E, size_t N>
+struct array
+{
+ constexpr const E &operator[](size_t n) const noexcept { return elems[n]; }
+ const E elems[N];
+};
+
+template <typename T>
+struct S {
+ using U = array<T, 4>;
+ U m;
+ constexpr S(int) : m{}
+ {
+ const_cast<int &>(const_cast<const U &>(m)[0]) = 42; // { dg-error "modifying a const object" }
+ }
+};
+
+constexpr S<int> p = { 10 }; // { dg-message "originally declared" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const20.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const20.C
new file mode 100644
index 0000000..2d50349
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const20.C
@@ -0,0 +1,28 @@
+// PR c++/94074 - wrong modifying const object error for COMPONENT_REF.
+// { dg-do compile { target c++14 } }
+
+typedef decltype (sizeof (0)) size_t;
+
+template <typename E, size_t N>
+struct array
+{
+ constexpr const E &operator[](size_t n) const noexcept { return elems[n]; }
+ E elems[N];
+};
+
+template <typename E, size_t N>
+struct array2 {
+ array<E, N> a;
+};
+
+template <typename T>
+struct S {
+ using U = array2<T, 4>;
+ U m;
+ constexpr S(int) : m{}
+ {
+ const_cast<int &>(const_cast<const U &>(m).a[0]) = 42;
+ }
+};
+
+constexpr S<int> p = { 10 };
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const21.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const21.C
new file mode 100644
index 0000000..0b16193
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const21.C
@@ -0,0 +1,28 @@
+// PR c++/94074 - wrong modifying const object error for COMPONENT_REF.
+// { dg-do compile { target c++14 } }
+
+typedef decltype (sizeof (0)) size_t;
+
+template <typename E, size_t N>
+struct array
+{
+ constexpr const E &operator[](size_t n) const noexcept { return elems[n]; }
+ E elems[N];
+};
+
+template <typename E, size_t N>
+struct array2 {
+ array<E, N> a;
+};
+
+template <typename T>
+struct S {
+ using U = array2<T, 4>;
+ const U m;
+ constexpr S(int) : m{}
+ {
+ const_cast<int &>(m.a[0]) = 42; // { dg-error "modifying a const object" }
+ }
+};
+
+constexpr S<int> p = { 10 }; // { dg-message "originally declared" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const22.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const22.C
new file mode 100644
index 0000000..216cf16
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const22.C
@@ -0,0 +1,17 @@
+// PR c++/94074 - wrong modifying const object error for COMPONENT_REF.
+// { dg-do compile { target c++14 } }
+
+struct X {
+ int i;
+};
+
+template <typename T>
+struct S {
+ const X x;
+ constexpr S(int) : x{}
+ {
+ const_cast<X&>(x).i = 19; // { dg-error "modifying a const object" }
+ }
+};
+
+constexpr S<int> p = { 10 }; // { dg-message "originally declared" }