On Fri, Jan 26, 2018 at 02:11:19PM +0100, Richard Biener wrote: > >> POINTER_PLUS_EXPR offets are to be interpreted as signed (ptrdiff_t) > >> so using uhwi and then performing an unsigned division is wrong code. > >> See mem_ref_offset how to deal with this (ugh - poly-ints...). Basically > >> you have to force the thing to signed. Like just use > >> > >> HOST_WIDE_INT offset = TREE_INT_CST_LOW (op01); > > > > Does it really matter here though? Any negative offsets there are UB, we > > should punt on them rather than try to optimize them. > > As we known op01 is unsigned, if we check that it fits into shwi_p, it means > > it will be 0 to shwi max and then we can handle it in uhwi too. > > Ah, of course. Didn't look up enough context to see what this code > does in the end ;) > > > /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */ > > if (VECTOR_TYPE_P (op00type) > > && (same_type_ignoring_top_level_qualifiers_p > > - (type, TREE_TYPE (op00type)))) > > + (type, TREE_TYPE (op00type))) > > + && tree_fits_shwi_p (op01)) > > nevertheless this appearant "mismatch" deserves a comment (checking > shwi and using uhwi).
So like this? Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2018-01-26 Marek Polacek <pola...@redhat.com> Jakub Jelinek <ja...@redhat.com> PR c++/83659 * constexpr.c (cxx_fold_indirect_ref): Use unsigned HOST_WIDE_INT when computing offsets. Verify first that tree_fits_shwi_p (op01). Formatting fix. * g++.dg/torture/pr83659.C: New test. --- gcc/cp/constexpr.c.jj 2018-01-24 17:18:42.392392254 +0100 +++ gcc/cp/constexpr.c 2018-01-26 18:54:43.991828743 +0100 @@ -3070,7 +3070,8 @@ cxx_fold_indirect_ref (location_t loc, t { tree part_width = TYPE_SIZE (type); tree index = bitsize_int (0); - return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width, index); + return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width, + index); } /* Also handle conversion to an empty base class, which is represented with a NOP_EXPR. */ @@ -3109,12 +3110,22 @@ cxx_fold_indirect_ref (location_t loc, t /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */ if (VECTOR_TYPE_P (op00type) - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (op00type)))) + && same_type_ignoring_top_level_qualifiers_p + (type, TREE_TYPE (op00type)) + /* POINTER_PLUS_EXPR second operand is sizetype, unsigned, + but we want to treat offsets with MSB set as negative. + For the code below negative offsets are invalid and + TYPE_SIZE of the element is something unsigned, so + check whether op01 fits into HOST_WIDE_INT, which implies + it is from 0 to INTTYPE_MAXIMUM (HOST_WIDE_INT), and + then just use tree_to_uhwi because we want to treat the + value as unsigned. */ + && tree_fits_shwi_p (op01)) { - HOST_WIDE_INT offset = tree_to_shwi (op01); + unsigned HOST_WIDE_INT offset = tree_to_uhwi (op01); tree part_width = TYPE_SIZE (type); - unsigned HOST_WIDE_INT part_widthi = tree_to_shwi (part_width)/BITS_PER_UNIT; + unsigned HOST_WIDE_INT part_widthi + = tree_to_uhwi (part_width) / BITS_PER_UNIT; unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT; tree index = bitsize_int (indexi); --- gcc/testsuite/g++.dg/torture/pr83659.C.jj 2018-01-26 18:46:40.077572013 +0100 +++ gcc/testsuite/g++.dg/torture/pr83659.C 2018-01-26 18:56:36.822888606 +0100 @@ -0,0 +1,18 @@ +// PR c++/83659 +// { dg-do compile } + +typedef int V __attribute__ ((__vector_size__ (16))); +V a; +V b[2]; + +int +foo () +{ + return reinterpret_cast <int *> (&a)[-1] += 1; +} + +int +bar () +{ + return reinterpret_cast <int *> (&a[1])[-1]; +} Jakub