r257860 introduced an unsafe assumption under some conditions that the base object referenced by a memcpy strcpy necessarily has a pointer or array type. The attached patch removes this assumption.
In addition, as discussed in the bug and in IRC, the patch also removes a test for the result of get_inner_reference() being non-null (a vestige of handling the result of a call to get_addr_base_and_unit_offset() made previously here), and a test for the bit offset computed by get_inner_reference() not being convertible to HOST_WIDE_INT. As far as we can tell poly64_int is always convertible to HOST_WIDE_INT (i.e., poly64_int::is_constant() always returns true). The conversion from poly64_int to HOST_WIDE_INT is necessary even though the result is stored in an offset_int because there is apparently no way to convert from the former to the latter directly, even though it's wider. Martin
PR tree-optimization/84526 - ICE in generic_overlap at gcc/gimple-ssa-warn-restrict.c:927 since r257860 gcc/ChangeLog: PR tree-optimization/84526 * gimple-ssa-warn-restrict.c (builtin_memref::set_base_and_offset): Remove dead code. (builtin_access::generic_overlap): Be prepared to handle non-array base objects. gcc/testsuite/ChangeLog: PR tree-optimization/84526 * gcc.dg/Wrestrict-10.c: New test. Index: gcc/gimple-ssa-warn-restrict.c =================================================================== --- gcc/gimple-ssa-warn-restrict.c (revision 257933) +++ gcc/gimple-ssa-warn-restrict.c (working copy) @@ -409,15 +409,15 @@ builtin_memref::set_base_and_offset (tree expr) base = get_inner_reference (expr, &bitsize, &bitpos, &var_off, &mode, &sign, &reverse, &vol); + /* get_inner_reference is not expected to return null. */ + gcc_assert (base != NULL); + poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT); - HOST_WIDE_INT const_off; - if (!base || !bytepos.is_constant (&const_off)) - { - base = get_base_address (TREE_OPERAND (expr, 0)); - return; - } - + /* There is no conversion from poly_int64 to offset_int even + though the latter is wider, so go through HOST_WIDE_INT. + The offset is expected to always be constant. */ + HOST_WIDE_INT const_off = bytepos.to_constant (); offrange[0] += const_off; offrange[1] += const_off; @@ -923,7 +923,11 @@ builtin_access::generic_overlap () /* There's no way to distinguish an access to the same member of a structure from one to two distinct members of the same structure. Give up to avoid excessive false positives. */ - tree basetype = TREE_TYPE (TREE_TYPE (dstref->base)); + tree basetype = TREE_TYPE (dstref->base); + if (POINTER_TYPE_P (basetype) + || TREE_CODE (basetype) == ARRAY_TYPE) + basetype = TREE_TYPE (basetype); + if (RECORD_OR_UNION_TYPE_P (basetype)) return false; } Index: gcc/testsuite/gcc.dg/Wrestrict-10.c =================================================================== --- gcc/testsuite/gcc.dg/Wrestrict-10.c (nonexistent) +++ gcc/testsuite/gcc.dg/Wrestrict-10.c (working copy) @@ -0,0 +1,121 @@ +/* PR tree-optimization/84526 - ICE in generic_overlap + { dg-do compile } + { dg-options "-O2 -Wrestrict" } */ + +typedef __SIZE_TYPE__ size_t; + +extern void* memcpy (void* restrict, const void* restrict, size_t); +extern char* strcat (char* restrict, const char* restrict); +extern char* strcpy (char* restrict, const char* restrict); +extern char* strncat (char* restrict, const char* restrict, size_t); +extern char* strncpy (char* restrict, const char* restrict, size_t); + +struct +{ + char a[1]; +} b; + +int i; +size_t n; + +void __attribute__ ((noclone, noinline)) +test_arr_memcpy_1 (void) +{ + memcpy (&b.a[i], b.a, n); +} + +void __attribute__ ((noclone, noinline)) +test_arr_memcpy_2 (void) +{ + memcpy (b.a, &b.a[i], n); +} + +void __attribute__ ((noclone, noinline)) +test_arr_strcat_1 (void) +{ + strcat (&b.a[i], b.a); /* { dg-warning "\\\[-Wrestrict" } */ +} + +void __attribute__ ((noclone, noinline)) +test_arr_strcat_2 (void) +{ + /* This probably deserves a warning. */ + strcpy (b.a, &b.a[i]); +} + +void __attribute__ ((noclone, noinline)) +test_arr_strncat_1 (void) +{ + strncat (&b.a[i], b.a, n); /* { dg-warning "\\\[-Wrestrict" } */ +} + +void __attribute__ ((noclone, noinline)) +test_arr_strncat_2 (void) +{ + strncat (b.a, &b.a[i], n); /* { dg-warning "\\\[-Wrestrict" } */ +} + +void __attribute__ ((noclone, noinline)) +test_arr_strcpy_1 (void) +{ + strcpy (&b.a[i], b.a); +} + +void __attribute__ ((noclone, noinline)) +test_arr_strcpy_2 (void) +{ + strcpy (b.a, &b.a[i]); +} + + +struct S { + int a; + char b[10]; +} d; + +void __attribute__ ((noclone, noinline)) +test_obj_memcpy_1 (void) +{ + memcpy (d.b, (char *) &d, n); +} + +void __attribute__ ((noclone, noinline)) +test_obj_memcpy_2 (void) +{ + memcpy ((char *) &d, d.b, n); +} + +void __attribute__ ((noclone, noinline)) +test_obj_strcpy_1 (void) +{ + strcpy (d.b, (char *) &d); +} + +void __attribute__ ((noclone, noinline)) +test_obj_strcpy_2 (void) +{ + strcpy ((char *) &d, d.b); +} + +void __attribute__ ((noclone, noinline)) +test_obj_strncat_1 (void) +{ + strncat (d.b, (char *) &d, n); /* { dg-warning "\\\[-Wrestrict" } */ +} + +void __attribute__ ((noclone, noinline)) +test_obj_strncat_2 (void) +{ + strncat ((char *) &d, d.b, n); /* { dg-warning "\\\[-Wrestrict" } */ +} + +void __attribute__ ((noclone, noinline)) +test_obj_strncpy_1 (void) +{ + strncpy (d.b, (char *) &d, n); +} + +void test_obj_strncpy_2 (void) +{ + strncpy ((char *) &d, d.b, n); +}