From: Nathan Sidwell Date: Thu, 31 Mar 2016 15:30:33 +0000 (+0000) Subject: re PR c++/70393 (Miscompilation: missing constructor call for static object) X-Git-Tag: basepoints/gcc-7~202 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=88504f3435845976b92ee7e9d358f8e687502772;p=thirdparty%2Fgcc.git re PR c++/70393 (Miscompilation: missing constructor call for static object) PR c++/70393 * varasm.c (output_constructor_regular_field): Flush bitfield earlier. Assert we don't want to move backwards. cp/ * constexpr.c (cxx_eval_store_expression): Keep CONSTRUCTOR elements in field order. testsuite/ * g++.dg/cpp0x/constexpr-virtual6.C: New. From-SVN: r234636 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5a9b32158223..c58b659b190b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2016-03-31 Nathan Sidwell + + PR c++/70393 + * varasm.c (output_constructor_regular_field): Flush bitfield + earlier. Assert we don't want to move backwards. + 2016-03-31 Kirill Yukhin PR target/70453 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8aad906fc127..4a6dc5125330 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2016-03-31 Nathan Sidwell + + PR c++/70393 + * constexpr.c (cxx_eval_store_expression): Keep CONSTRUCTOR + elements in field order. + 2016-03-31 Marek Polacek PR c/70297 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 8ea71113d999..ea605dc641b4 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -2959,16 +2959,39 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, 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) + idx++, fields = DECL_CHAIN (fields)) { - 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; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4cab39478b7a..f977fc82992d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-03-31 Nathan Sidwell + + PR c++/70393 + * g++.dg/cpp0x/constexpr-virtual6.C: New. + 2016-03-31 Kirill Yukhin PR target/70453 diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual6.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual6.C new file mode 100644 index 000000000000..f5abf2cf9b94 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-virtual6.C @@ -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(); +} + diff --git a/gcc/varasm.c b/gcc/varasm.c index 3a3573e53951..b0f2af03de49 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -4929,6 +4929,14 @@ output_constructor_regular_field (oc_local_state *local) 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_local_state *local) 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. */