diff options
author | Richard Guenther <rguenther@suse.de> | 2009-09-25 12:12:51 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2009-09-25 12:12:51 +0000 |
commit | 79441eca0eb2fc14297a09ac73fde9a629a72941 (patch) | |
tree | 43b83ef28811075b335e9d3175c045885975e100 | |
parent | 6ef41fd08f9e000c1842a2309969fb8bb0f347c9 (diff) | |
download | gcc-79441eca0eb2fc14297a09ac73fde9a629a72941.tar.gz |
re PR middle-end/41463 (Another get_ref_base_and_extent problem)
2009-09-25 Richard Guenther <rguenther@suse.de>
PR middle-end/41463
* tree-dfa.c (get_ref_base_and_extent): Fix issue with trailing
arrays again.
* gcc.c-torture/execute/pr41463.c: New testcase.
From-SVN: r152167
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/pr41463.c | 56 | ||||
-rw-r--r-- | gcc/tree-dfa.c | 72 |
4 files changed, 99 insertions, 40 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6d4c47b3b6a..331faa147e2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2009-09-25 Richard Guenther <rguenther@suse.de> + + PR middle-end/41463 + * tree-dfa.c (get_ref_base_and_extent): Fix issue with trailing + arrays again. + 2009-09-25 Ben Elliston <bje@au.ibm.com> * doc/invoke.texi (RS/6000 and PowerPC Options): Add missing comma diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9fcd65db5aa..3ad55f87bdd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2009-09-25 Richard Guenther <rguenther@suse.de> + + PR middle-end/41463 + * gcc.c-torture/execute/pr41463.c: New testcase. + 2009-09-25 Olivier Hainque <hainque@adacore.com> * gnat.dg/sse_nolib.adb: New testcase. diff --git a/gcc/testsuite/gcc.c-torture/execute/pr41463.c b/gcc/testsuite/gcc.c-torture/execute/pr41463.c new file mode 100644 index 00000000000..c410fe0218b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr41463.c @@ -0,0 +1,56 @@ +#include <stdlib.h> + +union tree_node; + +struct tree_common +{ + int a; + long b; + long c; + void *p; + int d; +}; + +struct other_tree +{ + struct tree_common common; + int arr[14]; +}; + +struct tree_vec +{ + struct tree_common common; + int length; + union tree_node *a[1]; +}; + +union tree_node +{ + struct other_tree othr; + struct tree_vec vec; +}; + +union tree_node global; + +union tree_node * __attribute__((noinline)) +foo (union tree_node *p, int i) +{ + union tree_node **q; + p->vec.a[i] = (union tree_node *) 0; + q = &p->vec.a[1]; + *q = &global; + return p->vec.a[i]; +} + +extern void abort (void); +extern void *malloc (__SIZE_TYPE__); + +int +main() +{ + union tree_node *p = malloc (sizeof (union tree_node)); + if (foo (p, 1) != &global) + abort (); + return 0; +} + diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index 3fd8477cf7e..847a6818b1b 100644 --- a/gcc/tree-dfa.c +++ b/gcc/tree-dfa.c @@ -799,8 +799,35 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset, { HOST_WIDE_INT hthis_offset = TREE_INT_CST_LOW (this_offset); hthis_offset *= BITS_PER_UNIT; + hthis_offset + += TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)); bit_offset += hthis_offset; - bit_offset += TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)); + + /* If we had seen a variable array ref already and we just + referenced the last field of a struct or a union member + then we have to adjust maxsize by the padding at the end + of our field. */ + if (seen_variable_array_ref + && maxsize != -1) + { + tree stype = TREE_TYPE (TREE_OPERAND (exp, 0)); + tree next = TREE_CHAIN (field); + while (next && TREE_CODE (next) != FIELD_DECL) + next = TREE_CHAIN (next); + if (!next + || TREE_CODE (stype) != RECORD_TYPE) + { + tree fsize = DECL_SIZE_UNIT (field); + tree ssize = TYPE_SIZE_UNIT (stype); + if (host_integerp (fsize, 0) + && host_integerp (ssize, 0)) + maxsize += ((TREE_INT_CST_LOW (ssize) + - TREE_INT_CST_LOW (fsize)) + * BITS_PER_UNIT - hthis_offset); + else + maxsize = -1; + } + } } else { @@ -845,40 +872,6 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset, else { tree asize = TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0))); - /* Get at the array size but include trailing padding if - the array is the last element of a struct or union. */ - if (maxsize != -1 - && TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF) - { - tree cref = TREE_OPERAND (exp, 0); - tree field = TREE_OPERAND (cref, 1); - tree stype = TREE_TYPE (TREE_OPERAND (cref, 0)); - tree next = TREE_CHAIN (field); - while (next && TREE_CODE (next) != FIELD_DECL) - next = TREE_CHAIN (next); - if (!next - || TREE_CODE (stype) != RECORD_TYPE) - { - /* The size including padding is the size of - the whole structure minus the offset of the - array in it. */ - tree field_offset = component_ref_field_offset (cref); - if (field_offset - && host_integerp (field_offset, 0) - && host_integerp (TYPE_SIZE_UNIT (stype), 0)) - { - unsigned HOST_WIDE_INT as; - as = (((TREE_INT_CST_LOW (TYPE_SIZE_UNIT (stype)) - - TREE_INT_CST_LOW (field_offset)) - * BITS_PER_UNIT) - - TREE_INT_CST_LOW - (DECL_FIELD_BIT_OFFSET (field))); - asize = build_int_cstu (sizetype, as); - } - else - asize = NULL_TREE; - } - } /* We need to adjust maxsize to the whole array bitsize. But we can subtract any constant offset seen so far, because that would get us outside of the array otherwise. */ @@ -902,7 +895,6 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset, break; case VIEW_CONVERT_EXPR: - /* ??? We probably should give up here and bail out. */ break; default: @@ -925,10 +917,10 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset, that is there for alignment purposes. */ 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 + && (!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 |