diff options
author | Nick Clifton <nickc@redhat.com> | 2014-01-16 12:17:48 +0000 |
---|---|---|
committer | Nick Clifton <nickc@gcc.gnu.org> | 2014-01-16 12:17:48 +0000 |
commit | 54c7a7f3b07b2198ecd84cdab579ec41057389f9 (patch) | |
tree | f86b15eb863f6a929fad7d545aa4f7c28340eaa0 | |
parent | 5147d10aa4b2b608a02fb885a5510c983e148f06 (diff) | |
download | gcc-54c7a7f3b07b2198ecd84cdab579ec41057389f9.zip gcc-54c7a7f3b07b2198ecd84cdab579ec41057389f9.tar.gz gcc-54c7a7f3b07b2198ecd84cdab579ec41057389f9.tar.bz2 |
re PR middle-end/28865 (Structures with a flexible arrray member have wrong .size)
PR middle-end/28865
* varasm.c (output_constant): Return the number of bytes actually
emitted.
(output_constructor_array_range): Update the field size with the
number of bytes emitted by output_constant.
(output_constructor_regular_field): Likewise. Also do not
complain if the total number of bytes emitted is now greater
than the expected fieldpos.
* output.h (output_constant): Update prototype and descriptive
comment.
* gcc.c-torture/compile/pr28865.c: New.
* gcc.c-torture/execute/pr28865.c: New.
From-SVN: r206661
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/output.h | 8 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/pr28865.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/pr28865.c | 21 | ||||
-rw-r--r-- | gcc/varasm.c | 31 |
6 files changed, 77 insertions, 18 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0580d16..be73e9e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2014-01-16 Nick Clifton <nickc@redhat.com> + + PR middle-end/28865 + * varasm.c (output_constant): Return the number of bytes actually + emitted. + (output_constructor_array_range): Update the field size with the + number of bytes emitted by output_constant. + (output_constructor_regular_field): Likewise. Also do not + complain if the total number of bytes emitted is now greater + than the expected fieldpos. + * output.h (output_constant): Update prototype and descriptive + comment. + 2014-01-16 Marek Polacek <polacek@redhat.com> PR middle-end/59827 diff --git a/gcc/output.h b/gcc/output.h index 15a2b97..fead3d3 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -294,11 +294,13 @@ extern void output_quoted_string (FILE *, const char *); This includes the pseudo-op such as ".int" or ".byte", and a newline. Assumes output_addressed_constants has been done on EXP already. - Generate exactly SIZE bytes of assembler data, padding at the end - with zeros if necessary. SIZE must always be specified. + Generate at least SIZE bytes of assembler data, padding at the end + with zeros if necessary. SIZE must always be specified. The returned + value is the actual number of bytes of assembler data generated, which + may be bigger than SIZE if the object contains a variable length field. ALIGN is the alignment in bits that may be assumed for the data. */ -extern void output_constant (tree, unsigned HOST_WIDE_INT, unsigned int); +extern unsigned HOST_WIDE_INT output_constant (tree, unsigned HOST_WIDE_INT, unsigned int); /* When outputting delayed branch sequences, this rtx holds the sequence being output. It is null when no delayed branch diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7db83e6..868593b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2014-01-16 Nick Clifton <nickc@redhat.com> + + PR middle-end/28865 + * gcc.c-torture/compile/pr28865.c: New. + * gcc.c-torture/execute/pr28865.c: New. + 2014-01-16 Marek Polacek <polacek@redhat.com> PR middle-end/59827 diff --git a/gcc/testsuite/gcc.c-torture/compile/pr28865.c b/gcc/testsuite/gcc.c-torture/compile/pr28865.c new file mode 100644 index 0000000..aa6ae07 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr28865.c @@ -0,0 +1,16 @@ +struct var_len +{ + int field1; + const char field2[]; +}; + +/* Note - strictly speaking this array declaration is illegal + since each element has a variable length. GCC allows it + (for the moment) because it is used in existing code, such + as glibc. */ +static const struct var_len var_array[] = +{ + { 1, "Long exposure noise reduction" }, + { 2, "Shutter/AE lock buttons" }, + { 3, "Mirror lockup" } +}; diff --git a/gcc/testsuite/gcc.c-torture/execute/pr28865.c b/gcc/testsuite/gcc.c-torture/execute/pr28865.c new file mode 100644 index 0000000..627e6b8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr28865.c @@ -0,0 +1,21 @@ +struct A { int a; char b[]; }; +union B { struct A a; char b[sizeof (struct A) + 31]; }; +union B b = { { 1, "123456789012345678901234567890" } }; +union B c = { { 2, "123456789012345678901234567890" } }; + +__attribute__((noinline, noclone)) void +foo (int *x[2]) +{ + x[0] = &b.a.a; + x[1] = &c.a.a; +} + +int +main () +{ + int *x[2]; + foo (x); + if (*x[0] != 1 || *x[1] != 2) + __builtin_abort (); + return 0; +} diff --git a/gcc/varasm.c b/gcc/varasm.c index 24b36b6..6a41644 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -4584,8 +4584,10 @@ static unsigned HOST_WIDE_INT This includes the pseudo-op such as ".int" or ".byte", and a newline. Assumes output_addressed_constants has been done on EXP already. - Generate exactly SIZE bytes of assembler data, padding at the end - with zeros if necessary. SIZE must always be specified. + Generate at least SIZE bytes of assembler data, padding at the end + with zeros if necessary. SIZE must always be specified. The returned + value is the actual number of bytes of assembler data generated, which + may be bigger than SIZE if the object contains a variable length field. SIZE is important for structure constructors, since trailing members may have been omitted from the constructor. @@ -4600,14 +4602,14 @@ static unsigned HOST_WIDE_INT ALIGN is the alignment of the data in bits. */ -void +unsigned HOST_WIDE_INT output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) { enum tree_code code; unsigned HOST_WIDE_INT thissize; if (size == 0 || flag_syntax_only) - return; + return size; /* See if we're trying to initialize a pointer in a non-default mode to the address of some declaration somewhere. If the target says @@ -4672,7 +4674,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) && vec_safe_is_empty (CONSTRUCTOR_ELTS (exp))) { assemble_zeros (size); - return; + return size; } if (TREE_CODE (exp) == FDESC_EXPR) @@ -4684,7 +4686,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) #else gcc_unreachable (); #endif - return; + return size; } /* Now output the underlying data. If we've handling the padding, return. @@ -4723,8 +4725,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) switch (TREE_CODE (exp)) { case CONSTRUCTOR: - output_constructor (exp, size, align, NULL); - return; + return output_constructor (exp, size, align, NULL); case STRING_CST: thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp), size); @@ -4752,11 +4753,10 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) case RECORD_TYPE: case UNION_TYPE: gcc_assert (TREE_CODE (exp) == CONSTRUCTOR); - output_constructor (exp, size, align, NULL); - return; + return output_constructor (exp, size, align, NULL); case ERROR_MARK: - return; + return 0; default: gcc_unreachable (); @@ -4764,6 +4764,8 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) if (size > thissize) assemble_zeros (size - thissize); + + return size; } @@ -4860,7 +4862,7 @@ output_constructor_array_range (oc_local_state *local) if (local->val == NULL_TREE) assemble_zeros (fieldsize); else - output_constant (local->val, fieldsize, align2); + fieldsize = output_constant (local->val, fieldsize, align2); /* Count its size. */ local->total_bytes += fieldsize; @@ -4909,9 +4911,8 @@ output_constructor_regular_field (oc_local_state *local) 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) + && fieldpos > local->total_bytes) { - gcc_assert (fieldpos >= local->total_bytes); assemble_zeros (fieldpos - local->total_bytes); local->total_bytes = fieldpos; } @@ -4948,7 +4949,7 @@ output_constructor_regular_field (oc_local_state *local) if (local->val == NULL_TREE) assemble_zeros (fieldsize); else - output_constant (local->val, fieldsize, align2); + fieldsize = output_constant (local->val, fieldsize, align2); /* Count its size. */ local->total_bytes += fieldsize; |