diff options
author | Ian Lance Taylor <iant@google.com> | 2010-10-04 03:50:39 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2010-10-04 03:50:39 +0000 |
commit | 478a1c5b906a165853b77a8dd1c0548b66ace018 (patch) | |
tree | c18cd90272c7a2cb06261eb2a6d5a845ebb150f2 /gcc/c-typeck.c | |
parent | 3b5269a95e9e50001c2e4fabbb1712c9e984a09d (diff) | |
download | gcc-478a1c5b906a165853b77a8dd1c0548b66ace018.tar.gz |
c-typeck.c (lookup_field): If -fplan9-extensions, permit referring to a field using a typedef name.
gcc/:
* c-typeck.c (lookup_field): If -fplan9-extensions, permit
referring to a field using a typedef name.
(find_anonymous_field_with_type): New static function.
(convert_to_anonymous_field): New static function.
(convert_for_assignment): If -fplan9-extensions, permit converting
pointer to struct to pointer to anonymous field.
* c-decl.c (grokfield): If -fplan9-extensions, permit anonymous
fields.
(is_duplicate_field): New static function.
(detect_field_duplicates_hash): If -fplan9-extensions, check for
typedef names duplicating field names.
(detect_field_duplicates): Likewise.
* doc/invoke.texi (Option Summary): Mention -fplan9-extensions.
(C Dialect Options): Document -fplan9-extensions.
* doc/extend.texi (Unnamed Fields): Document -fplan9-extensions.
gcc/c-family/:
* c.opt (-fplan9-extensions): New option.
gcc/testsuite/:
* gcc.dg/anon-struct-11.c: New test.
* gcc.dg/anon-struct-12.c: New test.
* gcc.dg/anon-struct-13.c: New test.
* gcc.dg/anon-struct-14.c: New test.
From-SVN: r164926
Diffstat (limited to 'gcc/c-typeck.c')
-rw-r--r-- | gcc/c-typeck.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index e20c234006b..14bc281615e 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -2044,6 +2044,17 @@ lookup_field (tree type, tree component) if (anon) return tree_cons (NULL_TREE, field, anon); + + /* The Plan 9 compiler permits referring + directly to an anonymous struct/union field + using a typedef name. */ + if (flag_plan9_extensions + && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE + && (TREE_CODE (TYPE_NAME (TREE_TYPE (field))) + == TYPE_DECL) + && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) + == component)) + break; } } @@ -2080,6 +2091,16 @@ lookup_field (tree type, tree component) if (anon) return tree_cons (NULL_TREE, field, anon); + + /* The Plan 9 compiler permits referring directly to an + anonymous struct/union field using a typedef + name. */ + if (flag_plan9_extensions + && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE + && TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL + && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) + == component)) + break; } if (DECL_NAME (field) == component) @@ -4952,6 +4973,106 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype, return result; } +/* Return whether STRUCT_TYPE has an anonymous field with type TYPE. + This is used to implement -fplan9-extensions. */ + +static bool +find_anonymous_field_with_type (tree struct_type, tree type) +{ + tree field; + bool found; + + gcc_assert (TREE_CODE (struct_type) == RECORD_TYPE + || TREE_CODE (struct_type) == UNION_TYPE); + found = false; + for (field = TYPE_FIELDS (struct_type); + field != NULL_TREE; + field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) == NULL + && comptypes (type, TYPE_MAIN_VARIANT (TREE_TYPE (field)))) + { + if (found) + return false; + found = true; + } + else if (DECL_NAME (field) == NULL + && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + && find_anonymous_field_with_type (TREE_TYPE (field), type)) + { + if (found) + return false; + found = true; + } + } + return found; +} + +/* RHS is an expression whose type is pointer to struct. If there is + an anonymous field in RHS with type TYPE, then return a pointer to + that field in RHS. This is used with -fplan9-extensions. This + returns NULL if no conversion could be found. */ + +static tree +convert_to_anonymous_field (location_t location, tree type, tree rhs) +{ + tree rhs_struct_type, lhs_main_type; + tree field, found_field; + bool found_sub_field; + tree ret; + + gcc_assert (POINTER_TYPE_P (TREE_TYPE (rhs))); + rhs_struct_type = TREE_TYPE (TREE_TYPE (rhs)); + gcc_assert (TREE_CODE (rhs_struct_type) == RECORD_TYPE + || TREE_CODE (rhs_struct_type) == UNION_TYPE); + + gcc_assert (POINTER_TYPE_P (type)); + lhs_main_type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + + found_field = NULL_TREE; + found_sub_field = false; + for (field = TYPE_FIELDS (rhs_struct_type); + field != NULL_TREE; + field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) != NULL_TREE + || (TREE_CODE (TREE_TYPE (field)) != RECORD_TYPE + && TREE_CODE (TREE_TYPE (field)) != UNION_TYPE)) + continue; + if (comptypes (lhs_main_type, TYPE_MAIN_VARIANT (TREE_TYPE (field)))) + { + if (found_field != NULL_TREE) + return NULL_TREE; + found_field = field; + } + else if (find_anonymous_field_with_type (TREE_TYPE (field), + lhs_main_type)) + { + if (found_field != NULL_TREE) + return NULL_TREE; + found_field = field; + found_sub_field = true; + } + } + + if (found_field == NULL_TREE) + return NULL_TREE; + + ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (found_field), + build_fold_indirect_ref (rhs), found_field, + NULL_TREE); + ret = build_fold_addr_expr_loc (location, ret); + + if (found_sub_field) + { + ret = convert_to_anonymous_field (location, type, ret); + gcc_assert (ret != NULL_TREE); + } + + return ret; +} + /* Convert value RHS to type TYPE as preparation for an assignment to an lvalue of type TYPE. If ORIGTYPE is not NULL_TREE, it is the original type of RHS; this differs from TREE_TYPE (RHS) for enum @@ -5323,6 +5444,25 @@ convert_for_assignment (location_t location, tree type, tree rhs, /* Opaque pointers are treated like void pointers. */ is_opaque_pointer = vector_targets_convertible_p (ttl, ttr); + /* The Plan 9 compiler permits a pointer to a struct to be + automatically converted into a pointer to an anonymous field + within the struct. */ + if (flag_plan9_extensions + && (TREE_CODE (mvl) == RECORD_TYPE || TREE_CODE(mvl) == UNION_TYPE) + && (TREE_CODE (mvr) == RECORD_TYPE || TREE_CODE(mvr) == UNION_TYPE) + && mvl != mvr) + { + tree new_rhs = convert_to_anonymous_field (location, type, rhs); + if (new_rhs != NULL_TREE) + { + rhs = new_rhs; + rhstype = TREE_TYPE (rhs); + coder = TREE_CODE (rhstype); + ttr = TREE_TYPE (rhstype); + mvr = TYPE_MAIN_VARIANT (ttr); + } + } + /* C++ does not allow the implicit conversion void* -> T*. However, for the purpose of reducing the number of false positives, we tolerate the special case of |