diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1ac0d6a1ca77746fdd5e761917a71844565d67a8..5c380f3a102400c80b4bc112b4efff92b9e8c9c7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+2007-09-12  Richard Sandiford  <richard@codesourcery.com>
+
+	* c-tree.h (grokfield): Add a "tree *" argument.
+	* c-decl.c (grokdeclarator): Take a pointer to the decl's attributes.
+	Chain nested decl attributes to it.  Don't call decl_attributes here.
+	(groktypename): Pass grokdeclarator a pointer to the attribute list.
+	(start_decl, grokparm, push_parm_decl, start_function): Likewise.
+	(grokfield): Take a pointer to the decl's attributes and pass
+	it to grokdeclarator.
+	* c-parser.c (c_parser_struct_declaration): Update the calls to
+	grokfield.  Call decl_attributes for anonymous struct and union
+	fields.
+
 2007-09-12  Jan Hubicka  <jh@suse.cz>
 
 	* c-objc-common.h (LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION): Kill.
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 83fc7b9e1611cc8b59d6d426c5c908819ac3252f..719c2897397050fccee7a5c1d2abd118edadaf82 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -407,7 +407,7 @@ static tree lookup_name_in_scope (tree, struct c_scope *);
 static tree c_make_fname_decl (tree, int);
 static tree grokdeclarator (const struct c_declarator *,
 			    struct c_declspecs *,
-			    enum decl_context, bool, tree *,
+			    enum decl_context, bool, tree *, tree *,
 			    enum deprecated_states);
 static tree grokparms (struct c_arg_info *, bool);
 static void layout_array_type (tree);
@@ -3141,7 +3141,7 @@ groktypename (struct c_type_name *type_name)
   type_name->specs->attrs = NULL_TREE;
 
   type = grokdeclarator (type_name->declarator, type_name->specs, TYPENAME,
-			 false, NULL, DEPRECATED_NORMAL);
+			 false, NULL, &attrs, DEPRECATED_NORMAL);
 
   /* Apply attributes.  */
   decl_attributes (&type, attrs, 0);
@@ -3178,7 +3178,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
     deprecated_state = DEPRECATED_SUPPRESS;
 
   decl = grokdeclarator (declarator, declspecs,
-			 NORMAL, initialized, NULL,
+			 NORMAL, initialized, NULL, &attributes,
 			 deprecated_state);
   if (!decl)
     return 0;
@@ -3667,10 +3667,11 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
 tree
 grokparm (const struct c_parm *parm)
 {
+  tree attrs = parm->attrs;
   tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false,
-			      NULL, DEPRECATED_NORMAL);
+			      NULL, &attrs, DEPRECATED_NORMAL);
 
-  decl_attributes (&decl, parm->attrs, 0);
+  decl_attributes (&decl, attrs, 0);
 
   return decl;
 }
@@ -3681,11 +3682,12 @@ grokparm (const struct c_parm *parm)
 void
 push_parm_decl (const struct c_parm *parm)
 {
+  tree attrs = parm->attrs;
   tree decl;
 
   decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL,
-			 DEPRECATED_NORMAL);
-  decl_attributes (&decl, parm->attrs, 0);
+			 &attrs, DEPRECATED_NORMAL);
+  decl_attributes (&decl, attrs, 0);
 
   decl = pushdecl (decl);
 
@@ -3957,6 +3959,9 @@ warn_variable_length_array (const char *name, tree size)
    INITIALIZED is true if the decl has an initializer.
    WIDTH is non-NULL for bit-fields, and is a pointer to an INTEGER_CST node
    representing the width of the bit-field.
+   DECL_ATTRS points to the list of attributes that should be added to this
+     decl.  Any nested attributes that belong on the decl itself will be
+     added to this list.
    DEPRECATED_STATE is a deprecated_states value indicating whether
    deprecation warnings should be suppressed.
 
@@ -3971,7 +3976,7 @@ static tree
 grokdeclarator (const struct c_declarator *declarator,
 		struct c_declspecs *declspecs,
 		enum decl_context decl_context, bool initialized, tree *width,
-		enum deprecated_states deprecated_state)
+		tree *decl_attrs, enum deprecated_states deprecated_state)
 {
   tree type = declspecs->type;
   bool threadp = declspecs->thread_p;
@@ -4615,6 +4620,7 @@ grokdeclarator (const struct c_declarator *declarator,
 	  gcc_unreachable ();
 	}
     }
+  *decl_attrs = chainon (returned_attrs, *decl_attrs);
 
   /* Now TYPE has the actual type, apart from any qualifiers in
      TYPE_QUALS.  */
@@ -4649,7 +4655,6 @@ grokdeclarator (const struct c_declarator *declarator,
       decl = build_decl (TYPE_DECL, declarator->u.id, type);
       if (declspecs->explicit_signed_p)
 	C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
-      decl_attributes (&decl, returned_attrs, 0);
       if (declspecs->inline_p)
 	pedwarn ("typedef %q+D declared %<inline%>", decl);
       return decl;
@@ -4669,7 +4674,6 @@ grokdeclarator (const struct c_declarator *declarator,
 	pedwarn ("ISO C forbids const or volatile function types");
       if (type_quals)
 	type = c_build_qualified_type (type, type_quals);
-      decl_attributes (&type, returned_attrs, 0);
       return type;
     }
 
@@ -4987,8 +4991,6 @@ grokdeclarator (const struct c_declarator *declarator,
      name of a variable.  Thus, if it's known before this, die horribly.  */
     gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl));
 
-    decl_attributes (&decl, returned_attrs, 0);
-
     return decl;
   }
 }
@@ -5390,6 +5392,7 @@ start_struct (enum tree_code code, tree name)
 /* Process the specs, declarator and width (NULL if omitted)
    of a structure component, returning a FIELD_DECL node.
    WIDTH is non-NULL for bit-fields only, and is an INTEGER_CST node.
+   DECL_ATTRS is as for grokdeclarator.
 
    This is done during the parsing of the struct declaration.
    The FIELD_DECL nodes are chained together and the lot of them
@@ -5397,7 +5400,7 @@ start_struct (enum tree_code code, tree name)
 
 tree
 grokfield (struct c_declarator *declarator, struct c_declspecs *declspecs,
-	   tree width)
+	   tree width, tree *decl_attrs)
 {
   tree value;
 
@@ -5450,7 +5453,8 @@ grokfield (struct c_declarator *declarator, struct c_declspecs *declspecs,
     }
 
   value = grokdeclarator (declarator, declspecs, FIELD, false,
-			  width ? &width : NULL, DEPRECATED_NORMAL);
+			  width ? &width : NULL, decl_attrs,
+			  DEPRECATED_NORMAL);
 
   finish_decl (value, NULL_TREE, NULL_TREE);
   DECL_INITIAL (value) = width;
@@ -6091,7 +6095,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
   c_break_label = c_cont_label = size_zero_node;
 
   decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL,
-			  DEPRECATED_NORMAL);
+			  &attributes, DEPRECATED_NORMAL);
 
   /* If the declarator is not suitable for a function definition,
      cause a syntax error.  */
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index 4cd9479badab6bef9cd4d17d9138978aad6a9426..4bbc39d32d8ea3f3df11afeaabf2966c3a704739 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -2030,7 +2030,10 @@ c_parser_struct_declaration (c_parser *parser)
 	  /* Support for unnamed structs or unions as members of
 	     structs or unions (which is [a] useful and [b] supports
 	     MS P-SDK).  */
-	  ret = grokfield (build_id_declarator (NULL_TREE), specs, NULL_TREE);
+	  tree attrs = NULL;
+	  ret = grokfield (build_id_declarator (NULL_TREE), specs,
+			   NULL_TREE, &attrs);
+	  decl_attributes (&ret, attrs, 0);
 	}
       return ret;
     }
@@ -2070,7 +2073,7 @@ c_parser_struct_declaration (c_parser *parser)
 	    }
 	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
 	    postfix_attrs = c_parser_attributes (parser);
-	  d = grokfield (declarator, specs, width);
+	  d = grokfield (declarator, specs, width, &all_prefix_attrs);
 	  decl_attributes (&d, chainon (postfix_attrs,
 					all_prefix_attrs), 0);
 	  TREE_CHAIN (d) = decls;
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index 57b19f69857622dcde07121eaf40203c06e10c96..9fd696b925dbd7d69185894c46b6a87aa1566bfe 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -476,7 +476,8 @@ extern tree finish_enum (tree, tree, tree);
 extern void finish_function (void);
 extern tree finish_struct (tree, tree, tree);
 extern struct c_arg_info *get_parm_info (bool);
-extern tree grokfield (struct c_declarator *, struct c_declspecs *, tree);
+extern tree grokfield (struct c_declarator *, struct c_declspecs *,
+		       tree, tree *);
 extern tree groktypename (struct c_type_name *);
 extern tree grokparm (const struct c_parm *);
 extern tree implicitly_declare (tree);