Patchwork PATCH RFA: Support Plan 9 extensions in gcc

login
register
mail settings
Submitter Ian Taylor
Date Sept. 30, 2010, 3:50 a.m.
Message ID <mcrtyl7q47z.fsf@google.com>
Download mbox | patch
Permalink /patch/66109/
State New
Headers show

Comments

Ian Taylor - Sept. 30, 2010, 3:50 a.m.
"Joseph S. Myers" <joseph@codesourcery.com> writes:

> On Sun, 26 Sep 2010, Ian Lance Taylor wrote:
>
>> Joseph Myers asked specifically about standardization; I very much doubt
>> the Plan 9 folks care one way or another about whether this
>> functionality is added to the standard.  However, it seems to me
>> unlikely that any contradictory functionality would be added.
>
> It is also the case that we now know what form of anonymous structures and 
> unions is in C1X and I implemented support for that in GCC.

Thanks for the review.  You are correct that I didn't fully grasp the
fact that anonymous structures and unions are now implemented.

> However, one case of ambiguity that this patch does not detect appears to 
> conflict with the standard semantics.
>
> typedef struct { int a; } s1;
> struct s2 { s1; int s1; };
> int f(struct s2 *p) { return p->s1; }
>
> In C1X, p->s1 is an unambiguous reference to the int field.  With 
> -fplan9-extensions, there is ambiguity; this is not detected as such, but 
> instead you get an error:
>
> t1.c:3:23: error: incompatible types when returning type 's1' but 'int' was expected
>
> Logically this option should perhaps cause such a case to be detected with 
> an error for duplicate fields (and so be documented as causing some code 
> to be rejected that is otherwise accepted).

I have implemented this, and added a test case.

> The duplicate field errors for anonymous structures and unions post-date 
> your previous patch.  I don't actually see how the other cases of 
> ambiguity that your patch tries to detect can arise without an error being 
> given earlier for duplicate field names - they all involve multiple fields 
> with the same anonymous structure or union type, which would mean all the 
> fields within that type are duplicated.

I agree.  I have removed the ambiguity detection, and the code now
relies on the duplicate field test.

Here is the updated patch.  Bootstrapped and tested on
x86_64-unknown-linux-gnu.  OK for mainline?

Ian


gcc/ChangeLog:

2010-09-29  Ian Lance Taylor  <iant@google.com>

	* 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/ChangeLog:

2010-09-29  Ian Lance Taylor  <iant@google.com>

	* c.opt (-fplan9-extensions): New option.

gcc/testsuite/ChangeLog:

2010-09-29  Ian Lance Taylor  <iant@google.com>

	* 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.
Joseph S. Myers - Oct. 3, 2010, 6:41 p.m.
On Wed, 29 Sep 2010, Ian Lance Taylor wrote:

> Here is the updated patch.  Bootstrapped and tested on
> x86_64-unknown-linux-gnu.  OK for mainline?

OK.

Patch

Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 164724)
+++ doc/extend.texi	(working copy)
@@ -13019,6 +13019,34 @@  also be a definition with a tag such as 
 @samp{struct foo;}, or a reference to a @code{typedef} name for a
 previously defined structure or union type with a tag.
 
+@opindex fplan9-extensions
+The option @option{-fplan9-extensions} enables
+@option{-fms-extensions} as well as two other extensions.  First, a
+pointer to a structure is automatically converted to a pointer to an
+anonymous field for assignments and function calls.  For example:
+
+@smallexample
+struct s1 @{ int a; @};
+struct s2 @{ struct s1; @};
+extern void f1 (struct s1 *);
+void f2 (struct s2 *p) @{ f1 (p); @}
+@end smallexample
+
+In the call to @code{f1} inside @code{f2}, the pointer @code{p} is
+converted into a pointer to the anonymous field.
+
+Second, when the type of an anonymous field is a @code{typedef} for a
+@code{struct} or @code{union}, code may refer to the field using the
+name of the @code{typedef}.
+
+@smallexample
+typedef struct @{ int a; @} s1;
+struct s2 @{ s1; @};
+s1 f1 (struct s2 *p) @{ return p->s1; @}
+@end smallexample
+
+These usages are only permitted when they are not ambiguous.
+
 @node Thread-Local
 @section Thread-Local Storage
 @cindex Thread-Local Storage
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 164724)
+++ doc/invoke.texi	(working copy)
@@ -172,7 +172,7 @@  in the following sections.
 @gccoptlist{-ansi  -std=@var{standard}  -fgnu89-inline @gol
 -aux-info @var{filename} @gol
 -fno-asm  -fno-builtin  -fno-builtin-@var{function} @gol
--fhosted  -ffreestanding -fopenmp -fms-extensions @gol
+-fhosted  -ffreestanding -fopenmp -fms-extensions -fplan9-extensions @gol
 -trigraphs  -no-integrated-cpp  -traditional  -traditional-cpp @gol
 -fallow-single-precision  -fcond-mismatch -flax-vector-conversions @gol
 -fsigned-bitfields  -fsigned-char @gol
@@ -1689,6 +1689,16 @@  Some cases of unnamed fields in structur
 accepted with this option.  @xref{Unnamed Fields,,Unnamed struct/union
 fields within structs/unions}, for details.
 
+@item -fplan9-extensions
+Accept some non-standard constructs used in Plan 9 code.
+
+This enables @option{-fms-extensions}, permits passing pointers to
+structures with anonymous fields to functions which expect pointers to
+elements of the type of the field, and permits referring to anonymous
+fields declared using a typedef.  @xref{Unnamed Fields,,Unnamed
+struct/union fields within structs/unions}, for details.  This is only
+supported for C, not C++.
+
 @item -trigraphs
 @opindex trigraphs
 Support ISO C trigraphs.  The @option{-ansi} option (and @option{-std}
Index: c-family/c.opt
===================================================================
--- c-family/c.opt	(revision 164724)
+++ c-family/c.opt	(working copy)
@@ -893,6 +893,10 @@  fpermissive
 C++ ObjC++
 Downgrade conformance errors to warnings
 
+fplan9-extensions
+C ObjC Var(flag_plan9_extensions)
+Enable Plan 9 language extensions
+
 fpreprocessed
 C ObjC C++ ObjC++
 Treat the input file as already preprocessed
Index: c-decl.c
===================================================================
--- c-decl.c	(revision 164724)
+++ c-decl.c	(working copy)
@@ -6609,15 +6609,15 @@  grokfield (location_t loc,
 	 is the anonymous union extension.  Similarly for struct.
 
 	 If this is something of the form "struct foo;", then
-	   If MS extensions are enabled, this is handled as an
-	     anonymous struct.
+	   If MS or Plan 9 extensions are enabled, this is handled as
+	     an anonymous struct.
 	   Otherwise this is a forward declaration of a structure tag.
 
 	 If this is something of the form "foo;" and foo is a TYPE_DECL, then
 	   If foo names a structure or union without a tag, then this
 	     is an anonymous struct (this is permitted by C1X).
-	   If MS extensions are enabled and foo names a structure, then
-	     again this is an anonymous struct.
+	   If MS or Plan 9 extensions are enabled and foo names a
+	     structure, then again this is an anonymous struct.
 	   Otherwise this is an error.
 
 	 Oh what a horrid tangled web we weave.  I wonder if MS consciously
@@ -6631,7 +6631,7 @@  grokfield (location_t loc,
 
       if (type_ok)
 	{
-	  if (flag_ms_extensions)
+	  if (flag_ms_extensions || flag_plan9_extensions)
 	    ok = true;
 	  else if (TYPE_NAME (TYPE_MAIN_VARIANT (type)) == NULL)
 	    ok = true;
@@ -6683,6 +6683,50 @@  grokfield (location_t loc,
   return value;
 }
 
+/* Subroutine of detect_field_duplicates: return whether X and Y,
+   which are both fields in the same struct, have duplicate field
+   names.  */
+
+static bool
+is_duplicate_field (tree x, tree y)
+{
+  if (DECL_NAME (x) != NULL_TREE && DECL_NAME (x) == DECL_NAME (y))
+    return true;
+
+  /* When using -fplan9-extensions, an anonymous field whose name is a
+     typedef can duplicate a field name.  */
+  if (flag_plan9_extensions
+      && (DECL_NAME (x) == NULL_TREE || DECL_NAME (y) == NULL_TREE))
+    {
+      tree xt, xn, yt, yn;
+
+      xt = TREE_TYPE (x);
+      if (DECL_NAME (x) != NULL_TREE)
+	xn = DECL_NAME (x);
+      else if ((TREE_CODE (xt) == RECORD_TYPE || TREE_CODE (xt) == UNION_TYPE)
+	       && TYPE_NAME (xt) != NULL_TREE
+	       && TREE_CODE (TYPE_NAME (xt)) == TYPE_DECL)
+	xn = DECL_NAME (TYPE_NAME (xt));
+      else
+	xn = NULL_TREE;
+
+      yt = TREE_TYPE (y);
+      if (DECL_NAME (y) != NULL_TREE)
+	yn = DECL_NAME (y);
+      else if ((TREE_CODE (yt) == RECORD_TYPE || TREE_CODE (yt) == UNION_TYPE)
+	       && TYPE_NAME (yt) != NULL_TREE
+	       && TREE_CODE (TYPE_NAME (yt)) == TYPE_DECL)
+	yn = DECL_NAME (TYPE_NAME (yt));
+      else
+	yn = NULL_TREE;
+
+      if (xn != NULL_TREE && xn == yn)
+	return true;
+    }
+
+  return false;
+}
+
 /* Subroutine of detect_field_duplicates: add the fields of FIELDLIST
    to HTAB, giving errors for any duplicates.  */
 
@@ -6705,7 +6749,22 @@  detect_field_duplicates_hash (tree field
       }
     else if (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE
 	     || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE)
-      detect_field_duplicates_hash (TYPE_FIELDS (TREE_TYPE (x)), htab);
+      {
+	detect_field_duplicates_hash (TYPE_FIELDS (TREE_TYPE (x)), htab);
+
+	/* When using -fplan9-extensions, an anonymous field whose
+	   name is a typedef can duplicate a field name.  */
+	if (flag_plan9_extensions
+	    && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE
+	    && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL)
+	  {
+	    tree xn = DECL_NAME (TYPE_NAME (TREE_TYPE (x)));
+	    slot = htab_find_slot (htab, xn, INSERT);
+	    if (*slot)
+	      error ("duplicate member %q+D", TYPE_NAME (TREE_TYPE (x)));
+	    *slot = xn;
+	  }
+      }
 }
 
 /* Generate an error for any duplicate field names in FIELDLIST.  Munge
@@ -6750,10 +6809,18 @@  detect_field_duplicates (tree fieldlist)
   if (timeout > 0)
     {
       for (x = DECL_CHAIN (fieldlist); x; x = DECL_CHAIN (x))
-	if (DECL_NAME (x))
+	/* When using -fplan9-extensions, we can have duplicates
+	   between typedef names and fields.  */
+	if (DECL_NAME (x)
+	    || (flag_plan9_extensions
+		&& DECL_NAME (x) == NULL_TREE
+		&& (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE
+		    || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE)
+		&& TYPE_NAME (TREE_TYPE (x)) != NULL_TREE
+		&& TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL))
 	  {
 	    for (y = fieldlist; y != x; y = TREE_CHAIN (y))
-	      if (DECL_NAME (y) == DECL_NAME (x))
+	      if (is_duplicate_field (y, x))
 		{
 		  error ("duplicate member %q+D", x);
 		  DECL_NAME (x) = NULL_TREE;
Index: c-typeck.c
===================================================================
--- c-typeck.c	(revision 164724)
+++ c-typeck.c	(working copy)
@@ -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, 
   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 locat
       /* 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
Index: testsuite/gcc.dg/anon-struct-11.c
===================================================================
--- testsuite/gcc.dg/anon-struct-11.c	(revision 0)
+++ testsuite/gcc.dg/anon-struct-11.c	(revision 0)
@@ -0,0 +1,111 @@ 
+/* { dg-do compile } */
+
+/* No special options--in particular, turn off the default
+   -pedantic-errors option.  */
+/* { dg-options "" } */
+
+/* When not using -fplan9-extensions, we don't support automatic
+   conversion of pointer types, and we don't support referring to a
+   typedef name directly.  */
+
+extern void exit (int);
+extern void abort (void);
+
+struct A { char a; };
+
+struct B {
+  char b;
+  struct A;		/* { dg-warning "does not declare anything" } */
+  char c;
+};
+
+void
+f1 (struct A *p)	/* { dg-message "expected" } */
+{
+  p->a = 1;
+}
+
+void
+test1 (void)
+{
+  struct B b;
+  struct A *p;
+
+  b.b = 2;
+  b.c = 3;
+  f1 (&b);		/* { dg-warning "incompatible pointer type" } */
+  if (b.a != 1)		/* { dg-error "no member" } */
+    abort ();
+  if (b.b != 2 || b.c != 3)
+    abort ();
+  p = &b;		/* { dg-warning "incompatible pointer type" } */
+  if (p->a != 1)
+    abort ();
+}
+
+typedef struct { char d; } D;
+
+struct E {
+  char b;
+  struct F { char f; };	/* { dg-warning "does not declare anything" } */
+  char c;
+  union {
+    D;
+  };
+  char e;
+};
+
+void
+f2 (struct F *p)	/* { dg-message "expected" } */
+{
+  p->f = 6;
+}
+
+void
+f3 (D *p)		/* { dg-message "expected" } */
+{
+  p->d = 4;
+}
+
+void
+f4 (D d)
+{
+}
+
+void
+test2 (void)
+{
+  struct E e;
+  struct F *pf;
+  D *pd;
+  D d;
+
+  e.b = 2;
+  e.c = 3;
+  e.e = 5;
+  f2 (&e);		/* { dg-warning "incompatible pointer type" } */
+  f3 (&e);		/* { dg-warning "incompatible pointer type" } */
+  if (e.d != 4)
+    abort ();
+  if (e.f != 6)		/* { dg-error "no member" } */
+    abort ();
+  if (e.b != 2 || e.c != 3 || e.e != 5)
+    abort ();
+  pf = &e;		/* { dg-warning "incompatible pointer type" } */
+  if (pf->f != 6)
+    abort ();
+  pd = &e;		/* { dg-warning "incompatible pointer type" } */
+  if (pd->d != 4)
+    abort ();
+  d = e.D;		/* { dg-error "no member" } */
+  f3 (&e.D);		/* { dg-error "no member" } */
+  f4 (e.D);		/* { dg-error "no member" } */
+}
+
+int
+main ()
+{
+  test1 ();
+  test2 ();
+  exit (0);
+}
Index: testsuite/gcc.dg/anon-struct-12.c
===================================================================
--- testsuite/gcc.dg/anon-struct-12.c	(revision 0)
+++ testsuite/gcc.dg/anon-struct-12.c	(revision 0)
@@ -0,0 +1,108 @@ 
+/* { dg-do run } */
+/* { dg-options "-fplan9-extensions" } */
+
+/* When using -fplan9-extensions, we support automatic conversion of
+   pointer types, and we support referring to a typedef name
+   directly.  */
+
+extern void exit (int);
+extern void abort (void);
+
+struct A { char a; };
+
+struct B {
+  char b;
+  struct A;
+  char c;
+};
+
+void
+f1 (struct A *p)
+{
+  p->a = 1;
+}
+
+void
+test1 (void)
+{
+  struct B b;
+  struct A *p;
+
+  b.b = 2;
+  b.c = 3;
+  f1 (&b);
+  if (b.a != 1)
+    abort ();
+  if (b.b != 2 || b.c != 3)
+    abort ();
+  p = &b;
+  if (p->a != 1)
+    abort ();
+}
+
+typedef struct { char d; } D;
+
+struct E {
+  char b;
+  struct F { char f; };
+  char c;
+  union {
+    D;
+  };
+  char e;
+};
+
+void
+f2 (struct F *p)
+{
+  p->f = 6;
+}
+
+void
+f3 (D *p)
+{
+  p->d = 4;
+}
+
+void
+f4 (D d)
+{
+}
+
+void
+test2 (void)
+{
+  struct E e;
+  struct F *pf;
+  D *pd;
+  D d;
+
+  e.b = 2;
+  e.c = 3;
+  e.e = 5;
+  f2 (&e);
+  f3 (&e);
+  if (e.d != 4)
+    abort ();
+  if (e.f != 6)
+    abort ();
+  if (e.b != 2 || e.c != 3 || e.e != 5)
+    abort ();
+  pf = &e;
+  if (pf->f != 6)
+    abort ();
+  pd = &e;
+  if (pd->d != 4)
+    abort ();
+  d = e.D;
+  f3 (&e.D);
+  f4 (e.D);
+}
+
+int
+main ()
+{
+  test1 ();
+  test2 ();
+  exit (0);
+}
Index: testsuite/gcc.dg/anon-struct-13.c
===================================================================
--- testsuite/gcc.dg/anon-struct-13.c	(revision 0)
+++ testsuite/gcc.dg/anon-struct-13.c	(revision 0)
@@ -0,0 +1,76 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fplan9-extensions" } */
+
+/* Test for ambiguity when using the Plan 9 extensions.  */
+
+struct A {
+  char a;		/* { dg-error "duplicate member" } */
+};
+
+struct B
+{
+  struct A;
+  struct A;
+};
+
+char
+f1 (struct B *p)
+{
+  return p->a;		/* { dg-error "no member" } */
+}
+
+void
+f2 (struct A *p)	/* { dg-message "expected" } */
+{
+}
+
+void
+f3 (struct B *p)
+{
+  f2 (p);		/* { dg-warning "incompatible pointer type" } */
+}
+
+struct C
+{
+  char c;		/* { dg-error "duplicate member" } */
+};
+
+struct D
+{
+  struct C;
+};
+
+struct E
+{
+  struct C;
+  struct D;
+};
+
+char
+f4 (struct E *p)
+{
+  return p->c;		/* { dg-error "no member" } */
+}
+
+void
+f6 (struct C *p)	/* { dg-message "expected" } */
+{
+}
+
+void
+f7 (struct E *p)
+{
+  f6 (p);		/* { dg-warning "incompatible pointer type" } */
+}
+
+struct A
+f8 (struct B *p)
+{
+  return p->A;		/* { dg-error "no member" } */
+}
+
+struct C
+f9 (struct E *p)
+{
+  return p->C;		/* { dg-error "no member" } */
+}
Index: testsuite/gcc.dg/anon-struct-14.c
===================================================================
--- testsuite/gcc.dg/anon-struct-14.c	(revision 0)
+++ testsuite/gcc.dg/anon-struct-14.c	(revision 0)
@@ -0,0 +1,9 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fplan9-extensions" } */
+
+/* When using Plan 9 extensions, a typedef can conflict with an
+   anonymous field.  */
+
+typedef struct { int a; } s1;
+struct s2 { s1; int s1; };		/* { dg-error "duplicate" } */
+int f(struct s2 *p) { return p->s1; }	/* { dg-error "incompatible" } */