diff options
author | Marek Polacek <polacek@redhat.com> | 2020-03-06 17:30:11 -0500 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2020-03-11 16:25:09 -0400 |
commit | 7eb5be6ab91ec03f93038ac2bcf3028cf2e7c82b (patch) | |
tree | b15b0adac3bc6bc93e0afe5acff854aa599b68fa /gcc/cp/constexpr.c | |
parent | 4512b7d85184c7131e98d29255e53cd2d913ddc2 (diff) | |
download | gcc-7eb5be6ab91ec03f93038ac2bcf3028cf2e7c82b.zip gcc-7eb5be6ab91ec03f93038ac2bcf3028cf2e7c82b.tar.gz gcc-7eb5be6ab91ec03f93038ac2bcf3028cf2e7c82b.tar.bz2 |
c++: Fix wrong modifying const object error for COMPONENT_REF [PR94074]
I got a report that building Chromium fails with the "modifying a const
object" error. After some poking I realized it's a bug in GCC, not in
their codebase.
Much like with ARRAY_REFs, which can be const even though the array
itself isn't, COMPONENT_REFs can be const although neither the object
nor the field were declared const. So let's dial down the checking.
Here the COMPONENT_REF was const because of the "const_cast<const U &>(m)"
thing -- cxx_eval_component_reference then builds a COMPONENT_REF with
TREE_TYPE (t).
While looking into this I noticed that we don't detect modifying a const
object in certain cases like in
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94074#c2>. That's because
we never evaluate an X::X() CALL_EXPR -- there's none. Fixed as per
Jason's suggestion by setting TREE_READONLY on a CONSTRUCTOR after
initialization in cxx_eval_store_expression.
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.
* 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.
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r-- | gcc/cp/constexpr.c | 42 |
1 files changed, 41 insertions, 1 deletions
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; |