summaryrefslogtreecommitdiff
path: root/gcc/c-typeck.c
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2010-10-04 03:50:39 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2010-10-04 03:50:39 +0000
commit478a1c5b906a165853b77a8dd1c0548b66ace018 (patch)
treec18cd90272c7a2cb06261eb2a6d5a845ebb150f2 /gcc/c-typeck.c
parent3b5269a95e9e50001c2e4fabbb1712c9e984a09d (diff)
downloadgcc-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.c140
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