diff options
author | Jason Merrill <jason@redhat.com> | 2022-04-12 17:46:59 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2022-05-06 16:29:49 -0400 |
commit | 967cdbe66296535fa496b88406a1125c8acaf6e2 (patch) | |
tree | 8433a2067d4817f40c43363ae4ea2240784b5f0a /gcc | |
parent | 469c76f0d94d03e29467a9d1e77cd3613f46ac2f (diff) | |
download | gcc-967cdbe66296535fa496b88406a1125c8acaf6e2.zip gcc-967cdbe66296535fa496b88406a1125c8acaf6e2.tar.gz gcc-967cdbe66296535fa496b88406a1125c8acaf6e2.tar.bz2 |
c++: empty base constexpr adjustment [PR105245]
While looking at PR105245 in stage 4, I wanted to reorganize the code a bit,
but it seemed prudent to defer that to stage 1.
PR c++/105245
PR c++/100111
gcc/cp/ChangeLog:
* constexpr.cc (cxx_eval_store_expression): Reorganize empty base
handling.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/constexpr.cc | 67 |
1 files changed, 34 insertions, 33 deletions
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 9b1e718..6c204ab 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -5718,6 +5718,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, releasing_vec ctors, indexes; auto_vec<int> index_pos_hints; bool activated_union_member_p = false; + bool empty_base = false; while (!refs->is_empty ()) { if (*valp == NULL_TREE) @@ -5759,7 +5760,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, no_zero_init = CONSTRUCTOR_NO_CLEARING (*valp); enum tree_code code = TREE_CODE (type); - type = refs->pop(); + tree reftype = refs->pop(); tree index = refs->pop(); if (code == RECORD_TYPE && is_empty_field (index)) @@ -5768,7 +5769,12 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, fields, which confuses the middle-end. The code below will notice that we don't have a CONSTRUCTOR for our inner target and just return init. */ - break; + { + empty_base = true; + break; + } + + type = reftype; if (code == UNION_TYPE && CONSTRUCTOR_NELTS (*valp) && CONSTRUCTOR_ELT (*valp, 0)->index != index) @@ -5902,45 +5908,42 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, } } + if (*non_constant_p) + return t; + /* Don't share a CONSTRUCTOR that might be changed later. */ init = unshare_constructor (init); - if (*valp && TREE_CODE (*valp) == CONSTRUCTOR - && TREE_CODE (init) == CONSTRUCTOR) + gcc_checking_assert (!*valp || (same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (*valp), type))); + if (empty_base || !(same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (init), type))) + { + /* For initialization of an empty base, the original target will be + *(base*)this, evaluation of which resolves to the object + argument, which has the derived type rather than the base type. In + this situation, just evaluate the initializer and return, since + there's no actual data to store, and we didn't build a CONSTRUCTOR. */ + empty_base = true; + gcc_assert (is_empty_class (TREE_TYPE (init))); + if (!*valp) + { + /* But do make sure we have something in *valp. */ + *valp = build_constructor (type, nullptr); + CONSTRUCTOR_NO_CLEARING (*valp) = no_zero_init; + } + } + else if (*valp && TREE_CODE (*valp) == CONSTRUCTOR + && TREE_CODE (init) == CONSTRUCTOR) { /* An outer ctx->ctor might be pointing to *valp, so replace its contents. */ - if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init), - TREE_TYPE (*valp))) - { - /* For initialization of an empty base, the original target will be - *(base*)this, evaluation of which resolves to the object - argument, which has the derived type rather than the base type. In - this situation, just evaluate the initializer and return, since - there's no actual data to store. */ - gcc_assert (is_empty_class (TREE_TYPE (init))); - return lval ? target : init; - } CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init); TREE_CONSTANT (*valp) = TREE_CONSTANT (init); TREE_SIDE_EFFECTS (*valp) = TREE_SIDE_EFFECTS (init); CONSTRUCTOR_NO_CLEARING (*valp) = CONSTRUCTOR_NO_CLEARING (init); } - else if (TREE_CODE (init) == CONSTRUCTOR - && !same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init), - type)) - { - /* See above on initialization of empty bases. */ - gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval); - if (!*valp) - { - /* But do make sure we have something in *valp. */ - *valp = build_constructor (type, nullptr); - CONSTRUCTOR_NO_CLEARING (*valp) = no_zero_init; - } - return init; - } else *valp = init; @@ -5958,7 +5961,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, constructor of a delegating constructor). Leave it up to the caller that set 'this' to set TREE_READONLY appropriately. */ gcc_checking_assert (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (target), type)); + (TREE_TYPE (target), type) || empty_base); else TREE_READONLY (*valp) = true; } @@ -5980,9 +5983,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, CONSTRUCTOR_NO_CLEARING (elt) = false; } - if (*non_constant_p) - return t; - else if (lval) + if (lval) return target; else return init; |