2016-03-29 Nathan Sidwell <nathan@acm.org>
PR c++/70393
* varasm.c (output_constructor_regular_field): Flush bitfield
earlier. Assert we don't want to move backwards.
gcc/
PR c++/70393
* constexpr.c (cxx_eval_store_expression): Keep CONSTRUCTOR
elements in field order.
PR c++/70393
* g++.dg/cpp0x/constexpr-virtual6.C: New.
===================================================================
@@ -4929,6 +4929,14 @@ output_constructor_regular_field (oc_loc
unsigned int align2;
+ /* Output any buffered-up bit-fields preceding this element. */
+ if (local->byte_buffer_in_use)
+ {
+ assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
+ local->total_bytes++;
+ local->byte_buffer_in_use = false;
+ }
+
if (local->index != NULL_TREE)
{
/* Perform the index calculation in modulo arithmetic but
@@ -4945,22 +4953,19 @@ output_constructor_regular_field (oc_loc
else
fieldpos = 0;
- /* Output any buffered-up bit-fields preceding this element. */
- if (local->byte_buffer_in_use)
- {
- assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
- local->total_bytes++;
- local->byte_buffer_in_use = false;
- }
-
/* Advance to offset of this element.
Note no alignment needed in an array, since that is guaranteed
if each element has the proper size. */
- if ((local->field != NULL_TREE || local->index != NULL_TREE)
- && fieldpos > local->total_bytes)
+ if (local->field != NULL_TREE || local->index != NULL_TREE)
{
- assemble_zeros (fieldpos - local->total_bytes);
- local->total_bytes = fieldpos;
+ if (fieldpos > local->total_bytes)
+ {
+ assemble_zeros (fieldpos - local->total_bytes);
+ local->total_bytes = fieldpos;
+ }
+ else
+ /* Must not go backwards. */
+ gcc_assert (fieldpos == local->total_bytes);
}
/* Find the alignment of this element. */
===================================================================
@@ -2959,16 +2959,39 @@ cxx_eval_store_expression (const constex
else
{
gcc_assert (TREE_CODE (index) == FIELD_DECL);
- for (unsigned HOST_WIDE_INT idx = 0;
+
+ /* We must keep the CONSTRUCTOR's ELTS in FIELD order.
+ Usually we meet initializers in that order, but it is
+ possible for base types to be placed not in program
+ order. */
+ tree fields = TYPE_FIELDS (DECL_CONTEXT (index));
+ unsigned HOST_WIDE_INT idx;
+
+ for (idx = 0;
vec_safe_iterate (CONSTRUCTOR_ELTS (*valp), idx, &cep);
idx++)
- if (index == cep->index)
- break;
- if (!cep)
{
- constructor_elt ce = { index, NULL_TREE };
- cep = vec_safe_push (CONSTRUCTOR_ELTS (*valp), ce);
+ if (index == cep->index)
+ goto found;
+
+ /* The field we're initializing must be on the field
+ list. Look to see if it is present before the
+ field the current ELT initializes. */
+ for (; fields != cep->index; fields = DECL_CHAIN (fields))
+ if (index == fields)
+ goto insert;
}
+
+ /* We fell off the end of the CONSTRUCTOR, so insert a new
+ entry at the end. */
+ insert:
+ {
+ constructor_elt ce = { index, NULL_TREE };
+
+ vec_safe_insert (CONSTRUCTOR_ELTS (*valp), idx, ce);
+ cep = CONSTRUCTOR_ELT (*valp, idx);
+ }
+ found:;
}
valp = &cep->value;
}
===================================================================
@@ -0,0 +1,49 @@
+// PR c++/70393
+// { dg-do run { target c++11 } }
+
+/* 'ab' has a static initializer, but we flubbed the initializer,
+ because of B being the primary base. */
+
+struct A
+{
+ int a = 1;
+};
+
+struct B
+{
+ B *element = (B*)2;
+
+ virtual int vfunc() = 0;
+
+ int call_element()
+ {
+ return element->vfunc();
+ }
+
+ void set_element()
+ {
+ element = this;
+ }
+};
+
+struct AB : public A, public B
+{
+ int vfunc()
+ {
+ return 0;
+ }
+};
+
+static AB ab;
+
+int main()
+{
+ if (ab.a != 1)
+ return 1;
+ if (ab.element != (void*)2)
+ return 2;
+
+ ab.set_element();
+ return ab.call_element();
+}
+