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
This commit is contained in:
Neil Booth 2001-11-04 17:54:57 +00:00 committed by Neil Booth
parent f282747406
commit e9b2c82318
4 changed files with 83 additions and 50 deletions

View File

@ -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> Sun Nov 4 11:53:31 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* config/sparc/sparc.c (sparc_emit_set_const32, GEN_HIGHINT64): * config/sparc/sparc.c (sparc_emit_set_const32, GEN_HIGHINT64):

View File

@ -55,7 +55,7 @@ static int comp_target_types PARAMS ((tree, tree));
static int function_types_compatible_p PARAMS ((tree, tree)); static int function_types_compatible_p PARAMS ((tree, tree));
static int type_lists_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 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 convert_arguments PARAMS ((tree, tree, tree, tree));
static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree)); static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree));
static tree pointer_diff PARAMS ((tree, tree)); static tree pointer_diff PARAMS ((tree, tree));
@ -990,17 +990,20 @@ default_conversion (exp)
return exp; return exp;
} }
/* Look up component name in the structure type definition. /* Look up COMPONENT in a structure or union DECL.
If this component name is found indirectly within an anonymous union, If the component name is not found, returns NULL_TREE. Otherwise,
store in *INDIRECT the component which directly contains the return value is a TREE_LIST, with each TREE_VALUE a FIELD_DECL
that anonymous union. Otherwise, set *INDIRECT to 0. */ 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 static tree
lookup_field (type, component, indirect) lookup_field (decl, component)
tree type, component; tree decl, component;
tree *indirect;
{ {
tree type = TREE_TYPE (decl);
tree field; tree field;
/* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers /* 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. */ /* Step through all anon unions in linear fashion. */
while (DECL_NAME (field_array[bot]) == NULL_TREE) while (DECL_NAME (field_array[bot]) == NULL_TREE)
{ {
tree anon = 0, junk;
field = field_array[bot++]; field = field_array[bot++];
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
anon = lookup_field (TREE_TYPE (field), component, &junk);
if (anon != NULL_TREE)
{ {
*indirect = field; tree anon = lookup_field (field, component);
return anon;
} if (anon)
return tree_cons (NULL_TREE, field, anon);
}
} }
/* Entire record is only anon unions. */ /* Entire record is only anon unions. */
@ -1059,35 +1059,31 @@ lookup_field (type, component, indirect)
if (DECL_NAME (field_array[bot]) == component) if (DECL_NAME (field_array[bot]) == component)
field = field_array[bot]; field = field_array[bot];
else if (DECL_NAME (field) != component) else if (DECL_NAME (field) != component)
field = 0; return NULL_TREE;
} }
else else
{ {
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 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 = lookup_field (field, component);
tree anon = 0;
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE if (anon)
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) return tree_cons (NULL_TREE, field, anon);
anon = lookup_field (TREE_TYPE (field), component, &junk);
if (anon != NULL_TREE)
{
*indirect = field;
return anon;
}
} }
if (DECL_NAME (field) == component) if (DECL_NAME (field) == component)
break; break;
} }
if (field == NULL_TREE)
return NULL_TREE;
} }
*indirect = NULL_TREE; return tree_cons (NULL_TREE, field, NULL_TREE);
return field;
} }
/* Make an expression to refer to the COMPONENT field of /* 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) if (code == RECORD_TYPE || code == UNION_TYPE)
{ {
tree indirect = 0;
if (!COMPLETE_TYPE_P (type)) if (!COMPLETE_TYPE_P (type))
{ {
incomplete_type_error (NULL_TREE, type); incomplete_type_error (NULL_TREE, type);
return error_mark_node; return error_mark_node;
} }
field = lookup_field (type, component, &indirect); field = lookup_field (datum, component);
if (!field) if (!field)
{ {
@ -1143,29 +1137,27 @@ build_component_ref (datum, component)
IDENTIFIER_POINTER (component)); IDENTIFIER_POINTER (component));
return error_mark_node; return error_mark_node;
} }
if (TREE_TYPE (field) == error_mark_node)
return error_mark_node;
/* If FIELD was found buried within an anonymous union, /* Chain the COMPONENT_REFs if necessary down to the FIELD.
make one COMPONENT_REF to get that anonymous union, This might be better solved in future the way the C++ front
then fall thru to make a second COMPONENT_REF to get FIELD. */ end does it - by giving the anonymous entities each a
if (indirect != 0) 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); tree subdatum = TREE_VALUE (field);
if (TREE_READONLY (datum) || TREE_READONLY (indirect))
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; 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; TREE_THIS_VOLATILE (ref) = 1;
datum = ref; 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; return ref;
} }
else if (code != ERROR_MARK) else if (code != ERROR_MARK)

View File

@ -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> 2001-11-03 Geoffrey Keating <geoffk@redhat.com>
* g++.old-deja/g++.bugs/900227_01.C: short and pointer are the * g++.old-deja/g++.bugs/900227_01.C: short and pointer are the

View File

@ -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;
}