diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 193e268f04e..539ad407f49 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8538,41 +8538,7 @@ grokfield (location_t loc,
 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 (RECORD_OR_UNION_TYPE_P (xt)
-	       && 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 (RECORD_OR_UNION_TYPE_P (yt)
-	       && 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;
+  return DECL_NAME (x) != NULL_TREE && DECL_NAME (x) == DECL_NAME (y);
 }
 
 /* Subroutine of detect_field_duplicates: add the fields of FIELDLIST
@@ -8599,19 +8565,6 @@ detect_field_duplicates_hash (tree fieldlist,
     else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)))
       {
 	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 (xn, INSERT);
-	    if (*slot)
-	      error ("duplicate member %q+D", TYPE_NAME (TREE_TYPE (x)));
-	    *slot = xn;
-	  }
       }
 }
 
@@ -8639,6 +8592,11 @@ detect_field_duplicates (tree fieldlist)
     if (objc_detect_field_duplicates (false))
       return;
 
+  /* When using -fplan9-extensions, do not perform duplicate field
+     checks until a field look up is performed.  */
+  if (flag_plan9_extensions)
+   return;
+
   /* First, see if there are more than "a few" fields.
      This is trivially true if there are zero or one fields.  */
   if (!fieldlist || !DECL_CHAIN (fieldlist))
@@ -8658,14 +8616,7 @@ detect_field_duplicates (tree fieldlist)
   if (timeout > 0)
     {
       for (x = DECL_CHAIN (fieldlist); x; x = DECL_CHAIN (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
-		&& RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))
-		&& TYPE_NAME (TREE_TYPE (x)) != NULL_TREE
-		&& TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL))
+	if (DECL_NAME (x))
 	  {
 	    for (y = fieldlist; y != x; y = TREE_CHAIN (y))
 	      if (is_duplicate_field (y, x))
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index f9190680a3c..97ffa329ba7 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -95,6 +95,7 @@ static int comp_target_types (location_t, tree, tree);
 static int function_types_compatible_p (const_tree, const_tree, bool *,
 					bool *);
 static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *);
+static tree lookup_field_plan9 (tree, tree);
 static tree lookup_field (tree, tree);
 static int convert_arguments (location_t, vec<location_t>, tree,
 			      vec<tree, va_gc> *, vec<tree, va_gc> *, tree,
@@ -2280,6 +2281,81 @@ default_conversion (tree exp)
   return exp;
 }
 
+/* Look up COMPONENT in a structure or union TYPE like a Plan 9 C compiler.
+
+   Look up is performed in 3 passes:
+   1.  Look for field names that match the look up name.
+   2.  Look for anonymous records who's typedef name matches the look up name.
+   3.  Look for fields in embedded anonymous records.
+
+   If the component name is not found, returns NULL_TREE. If the component
+   name references multiple fields, issue an error.  */
+
+static tree
+lookup_field_plan9 (tree type, tree component)
+{
+  tree field;
+  tree found = NULL_TREE;
+
+  /* Passes 1 & 2 are fused: conflicts are an error.  */
+  for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    {
+      /* Pass 1.  */
+      if (DECL_NAME (field) == component)
+	{
+	  if (found != NULL_TREE)
+	    {
+	      error ("duplicate member %q+D", found);
+	      return NULL_TREE;
+	    }
+	  found = field;
+	}
+
+      /* Pass 2.  */
+      if (DECL_NAME (field) == NULL_TREE
+	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	{
+	  if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
+	      && TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL
+	      && (DECL_NAME (TYPE_NAME (TREE_TYPE (field)))
+		  == component))
+	    {
+	      if (found != NULL_TREE)
+		{
+		  error ("duplicate member %q+D", found);
+		  return NULL_TREE;
+		}
+	      found = field;
+	    }
+	}
+    }
+
+  if (found != NULL_TREE)
+    return tree_cons (NULL_TREE, found, NULL_TREE);
+
+  /* Pass 3.  */
+  for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    {
+      if (DECL_NAME (field) == NULL_TREE
+	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	{
+	  tree anon = lookup_field_plan9 (TREE_TYPE (field), component);
+
+	  if (anon != NULL_TREE)
+	    {
+	      if (found != NULL_TREE)
+		{
+		  error ("duplicate member %q+D", TREE_VALUE (nreverse (anon)));
+		  return NULL_TREE;
+		}
+	      found = tree_cons (NULL_TREE, field, anon);
+	    }
+	}
+    }
+
+  return found;
+}
+
 /* Look up COMPONENT in a structure or union TYPE.
 
    If the component name is not found, returns NULL_TREE.  Otherwise,
@@ -2294,6 +2370,10 @@ lookup_field (tree type, tree component)
 {
   tree field;
 
+  /* The Plan 9 compiler has a different field resolution scheme.  */
+  if (flag_plan9_extensions)
+    return lookup_field_plan9 (type, component);
+
   /* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers
      to the field elements.  Use a binary search on this array to quickly
      find the element.  Otherwise, do a linear search.  TYPE_LANG_SPECIFIC
@@ -2329,17 +2409,6 @@ 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;
 		    }
 		}
 
@@ -2375,16 +2444,6 @@ 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)
diff --git a/gcc/testsuite/gcc.dg/anon-struct-13.c b/gcc/testsuite/gcc.dg/anon-struct-13.c
index 6a508141bac..c7b7d8cb101 100644
--- a/gcc/testsuite/gcc.dg/anon-struct-13.c
+++ b/gcc/testsuite/gcc.dg/anon-struct-13.c
@@ -5,6 +5,8 @@
 
 struct A {
   char a;		/* { dg-error "duplicate member" } */
+  char b;
+  char b;
 };
 
 struct B
@@ -46,6 +48,13 @@ struct E
   struct D;
 };
 
+struct F
+{
+  char a;
+  char a;
+  char a;
+};
+
 char
 f4 (struct E *p)
 {
