@@ -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