summaryrefslogtreecommitdiff
path: root/gcc48-pr28865.patch
diff options
context:
space:
mode:
Diffstat (limited to 'gcc48-pr28865.patch')
-rw-r--r--gcc48-pr28865.patch190
1 files changed, 190 insertions, 0 deletions
diff --git a/gcc48-pr28865.patch b/gcc48-pr28865.patch
new file mode 100644
index 0000000..8e07e94
--- /dev/null
+++ b/gcc48-pr28865.patch
@@ -0,0 +1,190 @@
+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" }
++};