Skip to content

Commit d19b434

Browse files
committed
c++: more constexpr empty base [PR105795]
Following on from the previous patch, for trunk let's consistently set ctx->ctor to NULL_TREE for empty subobjects. PR c++/105795 gcc/cp/ChangeLog: * constexpr.cc (init_subob_ctx): Clear ctx->ctor for empty subob. (cxx_eval_store_expression): Likewise. (cxx_eval_bare_aggregate): Handle null ctx->ctor.
1 parent db4243b commit d19b434

File tree

1 file changed

+42
-23
lines changed

1 file changed

+42
-23
lines changed

gcc/cp/constexpr.cc

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4695,9 +4695,17 @@ init_subob_ctx (const constexpr_ctx *ctx, constexpr_ctx &new_ctx,
46954695
else
46964696
new_ctx.object = build_ctor_subob_ref (index, type, ctx->object);
46974697
}
4698-
tree elt = build_constructor (type, NULL);
4699-
CONSTRUCTOR_NO_CLEARING (elt) = true;
4700-
new_ctx.ctor = elt;
4698+
4699+
if (is_empty_class (type))
4700+
/* Leave ctor null for an empty subobject, they aren't represented in the
4701+
result of evaluation. */
4702+
new_ctx.ctor = NULL_TREE;
4703+
else
4704+
{
4705+
tree elt = build_constructor (type, NULL);
4706+
CONSTRUCTOR_NO_CLEARING (elt) = true;
4707+
new_ctx.ctor = elt;
4708+
}
47014709

47024710
if (TREE_CODE (value) == TARGET_EXPR)
47034711
/* Avoid creating another CONSTRUCTOR when we expand the TARGET_EXPR. */
@@ -4762,11 +4770,14 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
47624770
ctx = &new_ctx;
47634771
};
47644772
verify_ctor_sanity (ctx, type);
4765-
vec<constructor_elt, va_gc> **p = &CONSTRUCTOR_ELTS (ctx->ctor);
4766-
vec_alloc (*p, vec_safe_length (v));
4767-
4768-
if (CONSTRUCTOR_PLACEHOLDER_BOUNDARY (t))
4769-
CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ctx->ctor) = 1;
4773+
vec<constructor_elt, va_gc> **p = nullptr;
4774+
if (ctx->ctor)
4775+
{
4776+
p = &CONSTRUCTOR_ELTS (ctx->ctor);
4777+
vec_alloc (*p, vec_safe_length (v));
4778+
if (CONSTRUCTOR_PLACEHOLDER_BOUNDARY (t))
4779+
CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ctx->ctor) = 1;
4780+
}
47704781

47714782
unsigned i;
47724783
tree index, value;
@@ -4814,17 +4825,19 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
48144825
inner->value = elt;
48154826
changed = true;
48164827
}
4828+
else if (no_slot)
4829+
/* This is an initializer for an empty field; now that we've
4830+
checked that it's constant, we can ignore it. */
4831+
changed = true;
48174832
else if (index
48184833
&& (TREE_CODE (index) == NOP_EXPR
48194834
|| TREE_CODE (index) == POINTER_PLUS_EXPR))
48204835
{
4821-
/* This is an initializer for an empty base; now that we've
4822-
checked that it's constant, we can ignore it. */
4836+
/* Old representation of empty bases. FIXME remove. */
4837+
gcc_checking_assert (false);
48234838
gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index))));
48244839
changed = true;
48254840
}
4826-
else if (no_slot)
4827-
changed = true;
48284841
else
48294842
{
48304843
if (TREE_CODE (type) == UNION_TYPE
@@ -4849,6 +4862,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
48494862
if (*non_constant_p || !changed)
48504863
return t;
48514864
t = ctx->ctor;
4865+
if (!t)
4866+
t = build_constructor (type, NULL);
48524867
/* We're done building this CONSTRUCTOR, so now we can interpret an
48534868
element without an explicit initializer as value-initialized. */
48544869
CONSTRUCTOR_NO_CLEARING (t) = false;
@@ -5833,6 +5848,16 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
58335848
valp = &cep->value;
58345849
}
58355850

5851+
/* For initialization of an empty base, the original target will be
5852+
*(base*)this, evaluation of which resolves to the object
5853+
argument, which has the derived type rather than the base type. */
5854+
if (!empty_base && !(same_type_ignoring_top_level_qualifiers_p
5855+
(initialized_type (init), type)))
5856+
{
5857+
gcc_assert (is_empty_class (TREE_TYPE (target)));
5858+
empty_base = true;
5859+
}
5860+
58365861
/* Detect modifying a constant object in constexpr evaluation.
58375862
We have found a const object that is being modified. Figure out
58385863
if we need to issue an error. Consider
@@ -5901,7 +5926,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
59015926
*valp = build_constructor (type, NULL);
59025927
CONSTRUCTOR_NO_CLEARING (*valp) = no_zero_init;
59035928
}
5904-
new_ctx.ctor = *valp;
5929+
new_ctx.ctor = empty_base ? NULL_TREE : *valp;
59055930
new_ctx.object = target;
59065931
/* Avoid temporary materialization when initializing from a TARGET_EXPR.
59075932
We don't need to mess with AGGR_EXPR_SLOT/VEC_INIT_EXPR_SLOT because
@@ -5931,16 +5956,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
59315956

59325957
gcc_checking_assert (!*valp || (same_type_ignoring_top_level_qualifiers_p
59335958
(TREE_TYPE (*valp), type)));
5934-
if (empty_base || !(same_type_ignoring_top_level_qualifiers_p
5935-
(initialized_type (init), type)))
5936-
{
5937-
/* For initialization of an empty base, the original target will be
5938-
*(base*)this, evaluation of which resolves to the object
5939-
argument, which has the derived type rather than the base type. In
5940-
this situation, just evaluate the initializer and return, since
5941-
there's no actual data to store, and we didn't build a CONSTRUCTOR. */
5942-
gcc_assert (is_empty_class (TREE_TYPE (target)));
5943-
empty_base = true;
5959+
if (empty_base)
5960+
{
5961+
/* Just evaluate the initializer and return, since there's no actual data
5962+
to store, and we didn't build a CONSTRUCTOR. */
59445963
if (!*valp)
59455964
{
59465965
/* But do make sure we have something in *valp. */

0 commit comments

Comments
 (0)