ab223e416b
Resolves: #1916228
191 lines
6.4 KiB
Diff
191 lines
6.4 KiB
Diff
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.
|
||
|
||
* gcc.c-torture/compile/pr28865.c: New.
|
||
* gcc.c-torture/execute/pr28865.c: New.
|
||
|
||
--- gcc/varasm.c (revision 206660)
|
||
+++ gcc/varasm.c (revision 206661)
|
||
@@ -4474,8 +4474,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.
|
||
@@ -4490,14 +4492,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
|
||
@@ -4562,7 +4564,7 @@ output_constant (tree exp, unsigned HOST
|
||
&& vec_safe_is_empty (CONSTRUCTOR_ELTS (exp)))
|
||
{
|
||
assemble_zeros (size);
|
||
- return;
|
||
+ return size;
|
||
}
|
||
|
||
if (TREE_CODE (exp) == FDESC_EXPR)
|
||
@@ -4574,7 +4576,7 @@ output_constant (tree exp, unsigned HOST
|
||
#else
|
||
gcc_unreachable ();
|
||
#endif
|
||
- return;
|
||
+ return size;
|
||
}
|
||
|
||
/* Now output the underlying data. If we've handling the padding, return.
|
||
@@ -4612,8 +4614,7 @@ output_constant (tree exp, unsigned HOST
|
||
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);
|
||
@@ -4648,11 +4649,10 @@ output_constant (tree exp, unsigned HOST
|
||
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 ();
|
||
@@ -4660,6 +4660,8 @@ output_constant (tree exp, unsigned HOST
|
||
|
||
if (size > thissize)
|
||
assemble_zeros (size - thissize);
|
||
+
|
||
+ return size;
|
||
}
|
||
|
||
|
||
@@ -4759,7 +4761,7 @@ output_constructor_array_range (oc_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;
|
||
@@ -4808,9 +4810,8 @@ output_constructor_regular_field (oc_loc
|
||
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;
|
||
}
|
||
@@ -4847,7 +4848,7 @@ output_constructor_regular_field (oc_loc
|
||
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;
|
||
--- gcc/output.h (revision 206660)
|
||
+++ gcc/output.h (revision 206661)
|
||
@@ -294,11 +294,13 @@ extern void output_quoted_string (FILE *
|
||
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
|
||
--- gcc/testsuite/gcc.c-torture/execute/pr28865.c (revision 0)
|
||
+++ gcc/testsuite/gcc.c-torture/execute/pr28865.c (revision 206661)
|
||
@@ -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;
|
||
+}
|
||
--- gcc/testsuite/gcc.c-torture/compile/pr28865.c (revision 0)
|
||
+++ gcc/testsuite/gcc.c-torture/compile/pr28865.c (revision 206661)
|
||
@@ -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" }
|
||
+};
|