diff options
author | Neil Booth <neil@cat.daikokuya.demon.co.uk> | 2001-11-04 17:54:57 +0000 |
---|---|---|
committer | Neil Booth <neil@gcc.gnu.org> | 2001-11-04 17:54:57 +0000 |
commit | e9b2c82318e18123d95a35e91b9c27806c0867d2 (patch) | |
tree | a8c85dc018f0945da2df4a02254876ffb9af0704 | |
parent | f28274740631a5af3c5e4f1828f83b93fc1ce14d (diff) | |
download | gcc-e9b2c82318e18123d95a35e91b9c27806c0867d2.tar.gz |
re PR c/2820 (unnamed union inside unnamed struct changes rest of the struct)
PR c/2820
* c-typeck.c (lookup_field): Rework to return a chain down to
the looked-up field.
(build_component_ref): Use the new lookup_field to handle
nested anonymous entities correctly.
* testsuite/gcc.c-torture/execute/anon-1.c: New test.
From-SVN: r46774
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/c-typeck.c | 94 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/anon-1.c | 29 |
4 files changed, 84 insertions, 51 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fb19c7df2c7..f5809897ce0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2001-11-04 Neil Booth <neil@cat.daikokuya.demon.co.uk> + + PR c/2820 + * c-typeck.c (lookup_field): Rework to return a chain down to + the looked-up field. + (build_component_ref): Use the new lookup_field to handle + nested anonymous entities correctly. + Sun Nov 4 11:53:31 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu> * config/sparc/sparc.c (sparc_emit_set_const32, GEN_HIGHINT64): diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 37810f610bb..34c7ba8495f 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -55,7 +55,7 @@ static int comp_target_types PARAMS ((tree, tree)); static int function_types_compatible_p PARAMS ((tree, tree)); static int type_lists_compatible_p PARAMS ((tree, tree)); static tree decl_constant_value_for_broken_optimization PARAMS ((tree)); -static tree lookup_field PARAMS ((tree, tree, tree *)); +static tree lookup_field PARAMS ((tree, tree)); static tree convert_arguments PARAMS ((tree, tree, tree, tree)); static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree)); static tree pointer_diff PARAMS ((tree, tree)); @@ -990,17 +990,20 @@ default_conversion (exp) return exp; } -/* Look up component name in the structure type definition. - - If this component name is found indirectly within an anonymous union, - store in *INDIRECT the component which directly contains - that anonymous union. Otherwise, set *INDIRECT to 0. */ +/* Look up COMPONENT in a structure or union DECL. + + If the component name is not found, returns NULL_TREE. Otherwise, + the return value is a TREE_LIST, with each TREE_VALUE a FIELD_DECL + stepping down the chain to the component, which is in the last + TREE_VALUE of the list. Normally the list is of length one, but if + the component is embedded within (nested) anonymous structures or + unions, the list steps down the chain to the component. */ static tree -lookup_field (type, component, indirect) - tree type, component; - tree *indirect; +lookup_field (decl, component) + tree decl, component; { + tree type = TREE_TYPE (decl); tree field; /* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers @@ -1026,18 +1029,15 @@ lookup_field (type, component, indirect) /* Step through all anon unions in linear fashion. */ while (DECL_NAME (field_array[bot]) == NULL_TREE) { - tree anon = 0, junk; - field = field_array[bot++]; if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) - anon = lookup_field (TREE_TYPE (field), component, &junk); - - if (anon != NULL_TREE) { - *indirect = field; - return anon; - } + tree anon = lookup_field (field, component); + + if (anon) + return tree_cons (NULL_TREE, field, anon); + } } /* Entire record is only anon unions. */ @@ -1059,35 +1059,31 @@ lookup_field (type, component, indirect) if (DECL_NAME (field_array[bot]) == component) field = field_array[bot]; else if (DECL_NAME (field) != component) - field = 0; + return NULL_TREE; } else { for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) { - if (DECL_NAME (field) == NULL_TREE) + if (DECL_NAME (field) == NULL_TREE + && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)) { - tree junk; - tree anon = 0; - - if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE - || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) - anon = lookup_field (TREE_TYPE (field), component, &junk); + tree anon = lookup_field (field, component); - if (anon != NULL_TREE) - { - *indirect = field; - return anon; - } + if (anon) + return tree_cons (NULL_TREE, field, anon); } if (DECL_NAME (field) == component) break; } + + if (field == NULL_TREE) + return NULL_TREE; } - *indirect = NULL_TREE; - return field; + return tree_cons (NULL_TREE, field, NULL_TREE); } /* Make an expression to refer to the COMPONENT field of @@ -1126,15 +1122,13 @@ build_component_ref (datum, component) if (code == RECORD_TYPE || code == UNION_TYPE) { - tree indirect = 0; - if (!COMPLETE_TYPE_P (type)) { incomplete_type_error (NULL_TREE, type); return error_mark_node; } - field = lookup_field (type, component, &indirect); + field = lookup_field (datum, component); if (!field) { @@ -1143,29 +1137,27 @@ build_component_ref (datum, component) IDENTIFIER_POINTER (component)); return error_mark_node; } - if (TREE_TYPE (field) == error_mark_node) - return error_mark_node; - /* If FIELD was found buried within an anonymous union, - make one COMPONENT_REF to get that anonymous union, - then fall thru to make a second COMPONENT_REF to get FIELD. */ - if (indirect != 0) + /* Chain the COMPONENT_REFs if necessary down to the FIELD. + This might be better solved in future the way the C++ front + end does it - by giving the anonymous entities each a + separate name and type, and then have build_component_ref + recursively call itself. We can't do that here. */ + for (; field; field = TREE_CHAIN (field)) { - ref = build (COMPONENT_REF, TREE_TYPE (indirect), datum, indirect); - if (TREE_READONLY (datum) || TREE_READONLY (indirect)) + tree subdatum = TREE_VALUE (field); + + if (TREE_TYPE (subdatum) == error_mark_node) + return error_mark_node; + + ref = build (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum); + if (TREE_READONLY (datum) || TREE_READONLY (subdatum)) TREE_READONLY (ref) = 1; - if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (indirect)) + if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (subdatum)) TREE_THIS_VOLATILE (ref) = 1; datum = ref; } - ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field); - - if (TREE_READONLY (datum) || TREE_READONLY (field)) - TREE_READONLY (ref) = 1; - if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field)) - TREE_THIS_VOLATILE (ref) = 1; - return ref; } else if (code != ERROR_MARK) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 572fb2ac330..985326e596d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2001-11-04 Neil Booth <neil@cat.daikokuya.demon.co.uk> + + * gcc.c-torture/execute/anon-1.c: New test. + 2001-11-03 Geoffrey Keating <geoffk@redhat.com> * g++.old-deja/g++.bugs/900227_01.C: short and pointer are the diff --git a/gcc/testsuite/gcc.c-torture/execute/anon-1.c b/gcc/testsuite/gcc.c-torture/execute/anon-1.c new file mode 100644 index 00000000000..98a9ed71d46 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/anon-1.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2001 Free Software Foundation, Inc. */ + +/* Source: Neil Booth, 4 Nov 2001, derived from PR 2820 - field lookup in + nested anonymous entities was broken. */ + +struct +{ + int x; + struct + { + int a; + union + { + int b; + }; + }; +} foo; + +int +main(int argc, char *argv[]) +{ + foo.b = 6; + foo.a = 5; + + if (foo.b != 6) + abort (); + + return 0; +} |