[PATCH] varasm: Fix output_constructor where a RANGE_EXPR index needs to skip some elts [PR94303]

Richard Biener rguenther@suse.de
Wed Mar 25 08:13:49 GMT 2020


On Wed, 25 Mar 2020, Jakub Jelinek wrote:

> Hi!
> 
> The following testcase is miscompiled, because output_constructor doesn't
> output the initializer correctly.  The FE creates {[1...2] = 9} in this
> case, and we emit .long 9; long 9; .zero 8 instead of the expected
> .zero 8; .long 9; .long 9.  If the CONSTRUCTOR is {[1] = 9, [2] = 9},
> output_constructor_regular_field has code to notice that the current
> location (local->total_bytes) is smaller than the location we want to write
> to (1*sizeof(elt)) and will call assemble_zeros to skip those.  But
> RANGE_EXPRs are handled by a different function which didn't do this,
> so for RANGE_EXPRs we emitted them properly only if local->total_bytes
> was always equal to the location where the RANGE_EXPR needs to start.

Ouch.

> Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for
> trunk?

OK.

Thanks,
Richard.

> 2020-03-25  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR middle-end/94303
> 	* varasm.c (output_constructor_array_range): If local->index
> 	RANGE_EXPR doesn't start at the current location in the constructor,
> 	skip needed number of bytes using assemble_zeros or assert we don't
> 	go backwards.
> 
> 	PR middle-end/94303
> 	* g++.dg/torture/pr94303.C: New test.
> 
> --- gcc/varasm.c.jj	2020-01-22 10:19:24.000000000 +0100
> +++ gcc/varasm.c	2020-03-24 18:03:08.532690584 +0100
> @@ -5152,6 +5152,26 @@ struct oc_local_state {
>  static void
>  output_constructor_array_range (oc_local_state *local)
>  {
> +  /* Perform the index calculation in modulo arithmetic but
> +     sign-extend the result because Ada has negative DECL_FIELD_OFFSETs
> +     but we are using an unsigned sizetype.  */
> +  unsigned prec = TYPE_PRECISION (sizetype);
> +  offset_int idx = wi::sext (wi::to_offset (TREE_OPERAND (local->index, 0))
> +			     - wi::to_offset (local->min_index), prec);
> +  tree valtype = TREE_TYPE (local->val);
> +  HOST_WIDE_INT fieldpos
> +    = (idx * wi::to_offset (TYPE_SIZE_UNIT (valtype))).to_short_addr ();
> +
> +  /* Advance to offset of this element.  */
> +  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);
> +
>    unsigned HOST_WIDE_INT fieldsize
>      = int_size_in_bytes (TREE_TYPE (local->type));
>  
> --- gcc/testsuite/g++.dg/torture/pr94303.C.jj	2020-03-24 18:14:21.114688840 +0100
> +++ gcc/testsuite/g++.dg/torture/pr94303.C	2020-03-24 18:13:56.434055853 +0100
> @@ -0,0 +1,17 @@
> +// PR middle-end/94303
> +// { dg-do run }
> +
> +struct A {
> +  int d = 9;
> +  A () = default;
> +  A (int x) : d(x) {}
> +  void foo () { if (d < 1) __builtin_abort (); }
> +};
> +
> +A a[3] = { 1 };
> +
> +int
> +main ()
> +{
> +  a[2].foo ();
> +}
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)


More information about the Gcc-patches mailing list