This fixes PR49079 - the mem-ref merge broke the trailing array access detection of get_ref_base_and_extent because of the embedding of a view-conversion.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk and branch. Richard. 2011-05-20 Richard Guenther <rguent...@suse.de> PR tree-optimization/49079 * tree-dfa.c (get_ref_base_and_extent): Handle view-converting MEM_REFs correctly for the trailing array access detection. Special case constants the same way as decls for overall size constraining. * gcc.dg/torture/pr49079.c: New testcase. Index: gcc/tree-dfa.c =================================================================== *** gcc/tree-dfa.c (revision 173939) --- gcc/tree-dfa.c (working copy) *************** get_ref_base_and_extent (tree exp, HOST_ *** 709,714 **** --- 709,715 ---- tree size_tree = NULL_TREE; HOST_WIDE_INT bit_offset = 0; bool seen_variable_array_ref = false; + tree base_type; /* First get the final access size from just the outermost expression. */ if (TREE_CODE (exp) == COMPONENT_REF) *************** get_ref_base_and_extent (tree exp, HOST_ *** 739,744 **** --- 740,747 ---- and find the ultimate containing object. */ while (1) { + base_type = TREE_TYPE (exp); + switch (TREE_CODE (exp)) { case BIT_FIELD_REF: *************** get_ref_base_and_extent (tree exp, HOST_ *** 926,934 **** the array. The simplest way to conservatively deal with this is to punt in the case that offset + maxsize reaches the base type boundary. This needs to include possible trailing padding ! that is there for alignment purposes. ! That is of course only true if the base object is not a decl. */ if (DECL_P (exp)) { --- 929,944 ---- the array. The simplest way to conservatively deal with this is to punt in the case that offset + maxsize reaches the base type boundary. This needs to include possible trailing padding ! that is there for alignment purposes. */ ! ! if (seen_variable_array_ref ! && maxsize != -1 ! && (!host_integerp (TYPE_SIZE (base_type), 1) ! || (bit_offset + maxsize ! == (signed) TREE_INT_CST_LOW (TYPE_SIZE (base_type))))) ! maxsize = -1; ! /* In case of a decl or constant base object we can do better. */ if (DECL_P (exp)) { *************** get_ref_base_and_extent (tree exp, HOST_ *** 938,949 **** && host_integerp (DECL_SIZE (exp), 1)) maxsize = TREE_INT_CST_LOW (DECL_SIZE (exp)) - bit_offset; } ! else if (seen_variable_array_ref ! && maxsize != -1 ! && (!host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1) ! || (bit_offset + maxsize ! == (signed) TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp)))))) ! maxsize = -1; /* ??? Due to negative offsets in ARRAY_REF we can end up with negative bit_offset here. We might want to store a zero offset --- 948,961 ---- && host_integerp (DECL_SIZE (exp), 1)) maxsize = TREE_INT_CST_LOW (DECL_SIZE (exp)) - bit_offset; } ! else if (CONSTANT_CLASS_P (exp)) ! { ! /* If maxsize is unknown adjust it according to the size of the ! base type constant. */ ! if (maxsize == -1 ! && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)) ! maxsize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))) - bit_offset; ! } /* ??? Due to negative offsets in ARRAY_REF we can end up with negative bit_offset here. We might want to store a zero offset Index: gcc/testsuite/gcc.dg/torture/pr49079.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr49079.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr49079.c (revision 0) *************** *** 0 **** --- 1,31 ---- + /* { dg-do run } */ + + extern void abort (void); + + struct Ustr + { + unsigned char data[1]; + }; + + static unsigned int + ustr_xi__embed_val_get(const unsigned char *data) + { + return (unsigned int)data[0]; + } + + int __attribute__((noinline)) zero(void) { return 0; } + + static unsigned int + ustr_len(const struct Ustr *s1) + { + return ustr_xi__embed_val_get(s1->data + 1 + zero()); + } + + int + main() + { + if (ustr_len (((struct Ustr *) "\x01" "\x0002" "s2")) != 2) + abort (); + + return 0; + }