Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 278145)
+++ gcc/c/c-decl.c	(working copy)
@@ -4491,6 +4491,18 @@ c_simulate_builtin_function_decl (tree decl)
   C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type);
   return pushdecl (decl);
 }
+
+/* Warn about attributes in a context where they are unused
+   (attribute-declarations, except for the "fallthrough" case, and
+   attributes on statements).  */
+
+void
+c_warn_unused_attributes (tree attrs)
+{
+  for (tree t = attrs; t != NULL_TREE; t = TREE_CHAIN (t))
+    warning (OPT_Wattributes, "%qE attribute ignored",
+	     get_attribute_name (t));
+}
 
 /* Called when a declaration is seen that contains no names to declare.
    If its type is a reference to a structure, union or enum inherited
@@ -4545,6 +4557,7 @@ shadow_tag_warned (const struct c_declspecs *decls
 	    }
 	  else if (declspecs->typespec_kind != ctsk_tagdef
                    && declspecs->typespec_kind != ctsk_tagfirstref
+		   && declspecs->typespec_kind != ctsk_tagfirstref_attrs
 		   && declspecs->storage_class != csc_none)
 	    {
 	      if (warned != 1)
@@ -4556,6 +4569,7 @@ shadow_tag_warned (const struct c_declspecs *decls
 	    }
 	  else if (declspecs->typespec_kind != ctsk_tagdef
                    && declspecs->typespec_kind != ctsk_tagfirstref
+                   && declspecs->typespec_kind != ctsk_tagfirstref_attrs
 		   && (declspecs->const_p
 		       || declspecs->volatile_p
 		       || declspecs->atomic_p
@@ -4571,6 +4585,7 @@ shadow_tag_warned (const struct c_declspecs *decls
 	    }
 	  else if (declspecs->typespec_kind != ctsk_tagdef
                    && declspecs->typespec_kind != ctsk_tagfirstref
+                   && declspecs->typespec_kind != ctsk_tagfirstref_attrs
 		   && declspecs->alignas_p)
 	    {
 	      if (warned != 1)
@@ -4668,9 +4683,34 @@ shadow_tag_warned (const struct c_declspecs *decls
       warned = 2;
     }
 
+  if (found_tag
+      && warned == 2
+      && (declspecs->typespec_kind == ctsk_tagref_attrs
+	  || declspecs->typespec_kind == ctsk_tagfirstref_attrs))
+    {
+      /* Standard attributes after the "struct" or "union" keyword are
+	 only permitted when the contents of the type are defined, or
+	 in the form "struct-or-union attribute-specifier-sequence
+	 identifier;".  If the ';' was not present, attributes were
+	 diagnosed in the parser.  Here, ensure that any other useless
+	 elements of the declaration result in a pedwarn, not just a
+	 warning.  Forward declarations of enum types are not part of
+	 standard C, but handle them the same.  */
+      pedwarn (input_location, 0,
+	       "invalid use of attributes in empty declaration");
+      warned = 1;
+    }
+
   if (warned != 1)
     {
-      if (!found_tag)
+      if (declspecs->declspecs_seen_p
+	  && !declspecs->non_std_attrs_seen_p)
+	/* An attribute declaration (but not a fallthrough attribute
+	   declaration, which was handled separately); warn if there
+	   are any attributes being ignored (but not if the attributes
+	   were empty).  */
+	c_warn_unused_attributes (declspecs->attrs);
+      else if (!found_tag)
 	pedwarn (input_location, 0, "empty declaration");
     }
 }
@@ -5605,7 +5645,8 @@ check_compound_literal_type (location_t loc, struc
 {
   if (warn_cxx_compat
       && (type_name->specs->typespec_kind == ctsk_tagdef
-          || type_name->specs->typespec_kind == ctsk_tagfirstref))
+          || type_name->specs->typespec_kind == ctsk_tagfirstref
+	  || type_name->specs->typespec_kind == ctsk_tagfirstref_attrs))
     warning_at (loc, OPT_Wc___compat,
 		"defining a type in a compound literal is invalid in C++");
 }
@@ -6210,18 +6251,32 @@ grokdeclarator (const struct c_declarator *declara
 	    const struct c_declarator *inner_decl;
 	    int attr_flags = 0;
 	    declarator = declarator->declarator;
+	    /* Standard attribute syntax precisely defines what entity
+	       an attribute in each position appertains to, so only
+	       apply laxity about positioning to GNU attribute syntax.
+	       Standard attributes applied to a function or array
+	       declarator apply exactly to that type; standard
+	       attributes applied to the identifier apply to the
+	       declaration rather than to the type.  */
 	    inner_decl = declarator;
 	    while (inner_decl->kind == cdk_attrs)
 	      inner_decl = inner_decl->declarator;
-	    if (inner_decl->kind == cdk_id)
-	      attr_flags |= (int) ATTR_FLAG_DECL_NEXT;
-	    else if (inner_decl->kind == cdk_function)
-	      attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT;
-	    else if (inner_decl->kind == cdk_array)
-	      attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT;
-	    returned_attrs = decl_attributes (&type,
-					      chainon (returned_attrs, attrs),
-					      attr_flags);
+	    if (!cxx11_attribute_p (attrs))
+	      {
+		if (inner_decl->kind == cdk_id)
+		  attr_flags |= (int) ATTR_FLAG_DECL_NEXT;
+		else if (inner_decl->kind == cdk_function)
+		  attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT;
+		else if (inner_decl->kind == cdk_array)
+		  attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT;
+	      }
+	    if (cxx11_attribute_p (attrs) && inner_decl->kind == cdk_id)
+	      returned_attrs = chainon (returned_attrs, attrs);
+	    else
+	      returned_attrs = decl_attributes (&type,
+						chainon (returned_attrs,
+							 attrs),
+						attr_flags);
 	    break;
 	  }
 	case cdk_array:
@@ -7686,11 +7741,14 @@ get_parm_info (bool ellipsis, tree expr)
 
 /* Get the struct, enum or union (CODE says which) with tag NAME.
    Define the tag as a forward-reference with location LOC if it is
-   not defined.  Return a c_typespec structure for the type
-   specifier.  */
+   not defined.  HAVE_STD_ATTRS says whether any standard attributes
+   were present after the struct, union or enum keyword; ATTRS are the
+   standard attributes present there.  Return a c_typespec structure
+   for the type specifier.  */
 
 struct c_typespec
-parser_xref_tag (location_t loc, enum tree_code code, tree name)
+parser_xref_tag (location_t loc, enum tree_code code, tree name,
+		 bool have_std_attrs, tree attrs)
 {
   struct c_typespec ret;
   tree ref;
@@ -7714,9 +7772,12 @@ struct c_typespec
      this would not work properly if we return the reference found.
      (For example, with "struct foo" in an outer scope, "union foo;"
      must shadow that tag with a new one of union type.)  */
-  ret.kind = (ref ? ctsk_tagref : ctsk_tagfirstref);
+  ret.kind = (ref
+	      ? (have_std_attrs ? ctsk_tagref_attrs : ctsk_tagref)
+	      : (have_std_attrs ? ctsk_tagfirstref_attrs : ctsk_tagfirstref));
   if (ref && TREE_CODE (ref) == code)
     {
+      decl_attributes (&ref, attrs, (int) ATTR_FLAG_TYPE_IN_PLACE);
       if (C_TYPE_DEFINED_IN_STRUCT (ref)
 	  && loc != UNKNOWN_LOCATION
 	  && warn_cxx_compat)
@@ -7770,6 +7831,7 @@ struct c_typespec
     }
 
   pushtag (loc, name, ref);
+  decl_attributes (&ref, attrs, (int) ATTR_FLAG_TYPE_IN_PLACE);
 
   ret.spec = ref;
   return ret;
@@ -7782,7 +7844,7 @@ struct c_typespec
 tree
 xref_tag (enum tree_code code, tree name)
 {
-  return parser_xref_tag (input_location, code, name).spec;
+  return parser_xref_tag (input_location, code, name, false, NULL_TREE).spec;
 }
 
 /* Make sure that the tag NAME is defined *in the current scope*
@@ -10214,6 +10276,7 @@ declspecs_add_addrspace (location_t location,
 {
   specs->non_sc_seen_p = true;
   specs->declspecs_seen_p = true;
+  specs->non_std_attrs_seen_p = true;
 
   if (!ADDR_SPACE_GENERIC_P (specs->address_space)
       && specs->address_space != as)
@@ -10239,6 +10302,7 @@ declspecs_add_qual (location_t loc,
   bool dupe = false;
   specs->non_sc_seen_p = true;
   specs->declspecs_seen_p = true;
+  specs->non_std_attrs_seen_p = true;
   gcc_assert (TREE_CODE (qual) == IDENTIFIER_NODE
 	      && C_IS_RESERVED_WORD (qual));
   i = C_RID_CODE (qual);
@@ -10297,6 +10361,7 @@ declspecs_add_type (location_t loc, struct c_decls
   tree type = spec.spec;
   specs->non_sc_seen_p = true;
   specs->declspecs_seen_p = true;
+  specs->non_std_attrs_seen_p = true;
   specs->typespec_kind = spec.kind;
   if (TREE_DEPRECATED (type))
     specs->deprecated_p = true;
@@ -11162,6 +11227,7 @@ declspecs_add_scspec (location_t loc,
   enum c_storage_class n = csc_none;
   bool dupe = false;
   specs->declspecs_seen_p = true;
+  specs->non_std_attrs_seen_p = true;
   gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE
 	      && C_IS_RESERVED_WORD (scspec));
   i = C_RID_CODE (scspec);
@@ -11278,6 +11344,9 @@ declspecs_add_attrs (location_t loc, struct c_decl
   specs->attrs = chainon (attrs, specs->attrs);
   specs->locations[cdw_attributes] = loc;
   specs->declspecs_seen_p = true;
+  /* In the case of standard attributes at the start of the
+     declaration, the caller will reset this.  */
+  specs->non_std_attrs_seen_p = true;
   return specs;
 }
 
@@ -11306,7 +11375,7 @@ declspecs_add_alignas (location_t loc,
    specifiers with any other type specifier to determine the resulting
    type.  This is where ISO C checks on complex types are made, since
    "_Complex long" is a prefix of the valid ISO C type "_Complex long
-   double".  */
+   double".  Also apply postfix standard attributes to modify the type.  */
 
 struct c_declspecs *
 finish_declspecs (struct c_declspecs *specs)
@@ -11376,6 +11445,8 @@ finish_declspecs (struct c_declspecs *specs)
 		  && !specs->signed_p && !specs->unsigned_p
 		  && !specs->complex_p);
       /* Type to be filled in later.  */
+      if (specs->postfix_attrs)
+	error ("%<__auto_type%> followed by %<[[]]%> attributes");
       break;
     case cts_void:
       gcc_assert (!specs->long_p && !specs->short_p
@@ -11581,6 +11652,11 @@ finish_declspecs (struct c_declspecs *specs)
     default:
       gcc_unreachable ();
     }
+  if (specs->type != NULL)
+    {
+      decl_attributes (&specs->type, specs->postfix_attrs, 0);
+      specs->postfix_attrs = NULL_TREE;
+    }
 
   return specs;
 }
Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 278145)
+++ gcc/c/c-parser.c	(working copy)
@@ -633,8 +633,8 @@ c_parser_next_token_is_qualifier (c_parser *parser
   return c_token_is_qualifier (token);
 }
 
-/* Return true if TOKEN can start declaration specifiers, false
-   otherwise.  */
+/* Return true if TOKEN can start declaration specifiers (not
+   including standard attributes), false otherwise.  */
 static bool
 c_token_starts_declspecs (c_token *token)
 {
@@ -713,8 +713,9 @@ c_token_starts_declspecs (c_token *token)
 }
 
 
-/* Return true if TOKEN can start declaration specifiers or a static
-   assertion, false otherwise.  */
+/* Return true if TOKEN can start declaration specifiers (not
+   including standard attributes) or a static assertion, false
+   otherwise.  */
 static bool
 c_token_starts_declaration (c_token *token)
 {
@@ -726,7 +727,8 @@ c_token_starts_declaration (c_token *token)
 }
 
 /* Return true if the next token from PARSER can start declaration
-   specifiers, false otherwise.  */
+   specifiers (not including standard attributes), false
+   otherwise.  */
 bool
 c_parser_next_token_starts_declspecs (c_parser *parser)
 {
@@ -748,7 +750,8 @@ c_parser_next_token_starts_declspecs (c_parser *pa
 }
 
 /* Return true if the next tokens from PARSER can start declaration
-   specifiers or a static assertion, false otherwise.  */
+   specifiers (not including standard attributes) or a static
+   assertion, false otherwise.  */
 bool
 c_parser_next_tokens_start_declaration (c_parser *parser)
 {
@@ -787,8 +790,12 @@ c_parser_consume_token (c_parser *parser)
   parser->last_token_location = parser->tokens[0].location;
   if (parser->tokens != &parser->tokens_buf[0])
     parser->tokens++;
-  else if (parser->tokens_avail == 2)
-    parser->tokens[0] = parser->tokens[1];
+  else if (parser->tokens_avail >= 2)
+    {
+      parser->tokens[0] = parser->tokens[1];
+      if (parser->tokens_avail >= 3)
+	parser->tokens[1] = parser->tokens[2];
+    }
   parser->tokens_avail--;
 }
 
@@ -803,8 +810,12 @@ c_parser_consume_pragma (c_parser *parser)
   gcc_assert (parser->tokens[0].type == CPP_PRAGMA);
   if (parser->tokens != &parser->tokens_buf[0])
     parser->tokens++;
-  else if (parser->tokens_avail == 2)
-    parser->tokens[0] = parser->tokens[1];
+  else if (parser->tokens_avail >= 2)
+    {
+      parser->tokens[0] = parser->tokens[1];
+      if (parser->tokens_avail >= 3)
+	parser->tokens[1] = parser->tokens[2];
+    }
   parser->tokens_avail--;
   parser->in_pragma = true;
 }
@@ -1384,10 +1395,15 @@ struct oacc_routine_data {
   location_t loc;
 };
 
+static bool c_parser_nth_token_starts_std_attributes (c_parser *,
+						      unsigned int);
+static tree c_parser_std_attribute_specifier_sequence (c_parser *);
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
 					   bool, bool, tree *, vec<c_token>,
+					   bool have_attrs = false,
+					   tree attrs = NULL,
 					   struct oacc_routine_data * = NULL,
 					   bool * = NULL);
 static void c_parser_static_assert_declaration_no_semi (c_parser *);
@@ -1402,10 +1418,11 @@ static struct c_declarator *c_parser_direct_declar
 static struct c_declarator *c_parser_direct_declarator_inner (c_parser *,
 							      bool,
 							      struct c_declarator *);
-static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree);
+static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree,
+						     bool);
 static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree,
-							  tree);
-static struct c_parm *c_parser_parameter_declaration (c_parser *, tree);
+							  tree, bool);
+static struct c_parm *c_parser_parameter_declaration (c_parser *, tree, bool);
 static tree c_parser_simple_asm_expr (c_parser *);
 static tree c_parser_gnu_attributes (c_parser *);
 static struct c_expr c_parser_initializer (c_parser *);
@@ -1706,11 +1723,15 @@ add_debug_begin_stmt (location_t loc)
    declarations are OK (subject to all other constraints); otherwise
    (old-style parameter declarations) they are diagnosed.  If
    START_ATTR_OK is true, the declaration specifiers may start with
-   attributes; otherwise they may not.
+   attributes (GNU or standard); otherwise they may not.
    OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed
    declaration when parsing an Objective-C foreach statement.
    FALLTHRU_ATTR_P is used to signal whether this function parsed
-   "__attribute__((fallthrough));".
+   "__attribute__((fallthrough));".  ATTRS are any standard attributes
+   parsed in the caller (in contexts where such attributes had to be
+   parsed to determine whether what follows is a declaration or a
+   statement); HAVE_ATTRS says whether there were any such attributes
+   (even empty).
 
    declaration:
      declaration-specifiers init-declarator-list[opt] ;
@@ -1784,6 +1805,7 @@ c_parser_declaration_or_fndef (c_parser *parser, b
 			       bool nested, bool start_attr_ok,
 			       tree *objc_foreach_object_declaration,
 			       vec<c_token> omp_declare_simd_clauses,
+			       bool have_attrs, tree attrs,
 			       struct oacc_routine_data *oacc_routine_data,
 			       bool *fallthru_attr_p)
 {
@@ -1803,6 +1825,13 @@ c_parser_declaration_or_fndef (c_parser *parser, b
     }
   specs = build_null_declspecs ();
 
+  /* Handle any standard attributes parsed in the caller.  */
+  if (have_attrs)
+    {
+      declspecs_add_attrs (here, specs, attrs);
+      specs->non_std_attrs_seen_p = false;
+    }
+
   /* Try to detect an unknown type name when we have "A B" or "A *B".  */
   if (c_parser_peek_token (parser)->type == CPP_NAME
       && c_parser_peek_token (parser)->id_kind == C_ID_ID
@@ -1867,8 +1896,14 @@ c_parser_declaration_or_fndef (c_parser *parser, b
       fndef_ok = !nested;
     }
 
+  /* When there are standard attributes at the start of the
+     declaration (to apply to the entity being declared), an
+     init-declarator-list or function definition must be present.  */
+  if (c_parser_nth_token_starts_std_attributes (parser, 1))
+    have_attrs = true;
+
   c_parser_declspecs (parser, specs, true, true, start_attr_ok,
-		      true, true, cla_nonabstract_decl);
+		      true, true, start_attr_ok, true, cla_nonabstract_decl);
   if (parser->error)
     {
       c_parser_skip_to_end_of_block_or_statement (parser);
@@ -1896,7 +1931,8 @@ c_parser_declaration_or_fndef (c_parser *parser, b
 						  void_type_node, 0);
 	  add_stmt (fn);
 	}
-      else if (empty_ok)
+      else if (empty_ok && !(have_attrs
+			     && specs->non_std_attrs_seen_p))
 	shadow_tag (specs);
       else
 	{
@@ -2556,7 +2592,14 @@ c_parser_static_assert_declaration_no_semi (c_pars
    Storage class specifiers are accepted iff SCSPEC_OK; type
    specifiers are accepted iff TYPESPEC_OK; alignment specifiers are
    accepted iff ALIGNSPEC_OK; gnu-attributes are accepted at the start
-   iff START_ATTR_OK; __auto_type is accepted iff AUTO_TYPE_OK.
+   iff START_ATTR_OK; __auto_type is accepted iff AUTO_TYPE_OK.  In
+   addition to the syntax shown, standard attributes are accepted at
+   the start iff START_STD_ATTR_OK and at the end iff END_STD_ATTR_OK;
+   unlike gnu-attributes, they are not accepted in the middle of the
+   list.  (This combines various different syntax productions in the C
+   standard, and in some cases gnu-attributes and standard attributes
+   at the start may already have been parsed before this function is
+   called.)
 
    declaration-specifiers:
      storage-class-specifier declaration-specifiers[opt]
@@ -2664,6 +2707,7 @@ void
 c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 		    bool scspec_ok, bool typespec_ok, bool start_attr_ok,
 		    bool alignspec_ok, bool auto_type_ok,
+		    bool start_std_attr_ok, bool end_std_attr_ok,
 		    enum c_lookahead_kind la)
 {
   bool attrs_ok = start_attr_ok;
@@ -2672,6 +2716,16 @@ c_parser_declspecs (c_parser *parser, struct c_dec
   if (!typespec_ok)
     gcc_assert (la == cla_prefer_id);
 
+  if (start_std_attr_ok
+      && c_parser_nth_token_starts_std_attributes (parser, 1))
+    {
+      gcc_assert (!specs->non_std_attrs_seen_p);
+      location_t loc = c_parser_peek_token (parser)->location;
+      tree attrs = c_parser_std_attribute_specifier_sequence (parser);
+      declspecs_add_attrs (loc, specs, attrs);
+      specs->non_std_attrs_seen_p = false;
+    }
+
   while (c_parser_next_token_is (parser, CPP_NAME)
 	 || c_parser_next_token_is (parser, CPP_KEYWORD)
 	 || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
@@ -2944,7 +2998,10 @@ c_parser_declspecs (c_parser *parser, struct c_dec
 	  goto out;
 	}
     }
- out: ;
+ out:
+  if (end_std_attr_ok
+      && c_parser_nth_token_starts_std_attributes (parser, 1))
+    specs->postfix_attrs = c_parser_std_attribute_specifier_sequence (parser);
 }
 
 /* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2, C11 6.7.2.2).
@@ -2967,14 +3024,16 @@ c_parser_declspecs (c_parser *parser, struct c_dec
      enumerator-list , enumerator
 
    enumerator:
-     enumeration-constant
-     enumeration-constant = constant-expression
+     enumeration-constant attribute-specifier-sequence[opt]
+     enumeration-constant attribute-specifier-sequence[opt]
+       = constant-expression
 
    GNU Extensions:
 
    enumerator:
-     enumeration-constant gnu-attributes[opt]
-     enumeration-constant gnu-attributes[opt] = constant-expression
+     enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt]
+     enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt]
+       = constant-expression
 
 */
 
@@ -2982,6 +3041,8 @@ static struct c_typespec
 c_parser_enum_specifier (c_parser *parser)
 {
   struct c_typespec ret;
+  bool have_std_attrs;
+  tree std_attrs = NULL_TREE;
   tree attrs;
   tree ident = NULL_TREE;
   location_t enum_loc;
@@ -2988,6 +3049,9 @@ c_parser_enum_specifier (c_parser *parser)
   location_t ident_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM));
   c_parser_consume_token (parser);
+  have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1);
+  if (have_std_attrs)
+    std_attrs = c_parser_std_attribute_specifier_sequence (parser);
   attrs = c_parser_gnu_attributes (parser);
   enum_loc = c_parser_peek_token (parser)->location;
   /* Set the location in case we create a decl now.  */
@@ -3044,7 +3108,11 @@ c_parser_enum_specifier (c_parser *parser)
 	  decl_loc = value_loc = token->location;
 	  c_parser_consume_token (parser);
 	  /* Parse any specified attributes.  */
-	  tree enum_attrs = c_parser_gnu_attributes (parser);
+	  tree std_attrs = NULL_TREE;
+	  if (c_parser_nth_token_starts_std_attributes (parser, 1))
+	    std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+	  tree enum_attrs = chainon (std_attrs,
+				     c_parser_gnu_attributes (parser));
 	  if (c_parser_next_token_is (parser, CPP_EQ))
 	    {
 	      c_parser_consume_token (parser);
@@ -3084,7 +3152,8 @@ c_parser_enum_specifier (c_parser *parser)
 	}
       postfix_attrs = c_parser_gnu_attributes (parser);
       ret.spec = finish_enum (type, nreverse (values),
-			      chainon (attrs, postfix_attrs));
+			      chainon (std_attrs,
+				       chainon (attrs, postfix_attrs)));
       ret.kind = ctsk_tagdef;
       ret.expr = NULL_TREE;
       ret.expr_const_operands = true;
@@ -3100,7 +3169,14 @@ c_parser_enum_specifier (c_parser *parser)
       ret.expr_const_operands = true;
       return ret;
     }
-  ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident);
+  /* Attributes may only appear when the members are defined or in
+     certain forward declarations (treat enum forward declarations in
+     GNU C analogously to struct and union forward declarations in
+     standard C).  */
+  if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+    c_parser_error (parser, "expected %<;%>");
+  ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs,
+			 std_attrs);
   /* In ISO C, enumerated types can be referred to only if already
      defined.  */
   if (pedantic && !COMPLETE_TYPE_P (ret.spec))
@@ -3115,9 +3191,10 @@ c_parser_enum_specifier (c_parser *parser)
 /* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1, C11 6.7.2.1).
 
    struct-or-union-specifier:
-     struct-or-union gnu-attributes[opt] identifier[opt]
-       { struct-contents } gnu-attributes[opt]
-     struct-or-union gnu-attributes[opt] identifier
+     struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt]
+       identifier[opt] { struct-contents } gnu-attributes[opt]
+     struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt]
+       identifier
 
    struct-contents:
      struct-declaration-list
@@ -3155,6 +3232,8 @@ static struct c_typespec
 c_parser_struct_or_union_specifier (c_parser *parser)
 {
   struct c_typespec ret;
+  bool have_std_attrs;
+  tree std_attrs = NULL_TREE;
   tree attrs;
   tree ident = NULL_TREE;
   location_t struct_loc;
@@ -3173,6 +3252,9 @@ c_parser_struct_or_union_specifier (c_parser *pars
     }
   struct_loc = c_parser_peek_token (parser)->location;
   c_parser_consume_token (parser);
+  have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1);
+  if (have_std_attrs)
+    std_attrs = c_parser_std_attribute_specifier_sequence (parser);
   attrs = c_parser_gnu_attributes (parser);
 
   /* Set the location in case we create a decl now.  */
@@ -3291,7 +3373,9 @@ c_parser_struct_or_union_specifier (c_parser *pars
 	}
       postfix_attrs = c_parser_gnu_attributes (parser);
       ret.spec = finish_struct (struct_loc, type, nreverse (contents),
-				chainon (attrs, postfix_attrs), struct_info);
+				chainon (std_attrs,
+					 chainon (attrs, postfix_attrs)),
+				struct_info);
       ret.kind = ctsk_tagdef;
       ret.expr = NULL_TREE;
       ret.expr_const_operands = true;
@@ -3307,7 +3391,13 @@ c_parser_struct_or_union_specifier (c_parser *pars
       ret.expr_const_operands = true;
       return ret;
     }
-  ret = parser_xref_tag (ident_loc, code, ident);
+  /* Attributes may only appear when the members are defined or in
+     certain forward declarations.  */
+  if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+    c_parser_error (parser, "expected %<;%>");
+  /* ??? Existing practice is that GNU attributes are ignored after
+     the struct or union keyword when not defining the members.  */
+  ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs);
   return ret;
 }
 
@@ -3315,7 +3405,8 @@ c_parser_struct_or_union_specifier (c_parser *pars
    *without* the trailing semicolon.
 
    struct-declaration:
-     specifier-qualifier-list struct-declarator-list
+     attribute-specifier-sequence[opt] specifier-qualifier-list
+       attribute-specifier-sequence[opt] struct-declarator-list
      static_assert-declaration-no-semi
 
    specifier-qualifier-list:
@@ -3375,7 +3466,7 @@ c_parser_struct_declaration (c_parser *parser)
      of N1731.
      <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1731.pdf>  */
   c_parser_declspecs (parser, specs, false, true, true,
-		      true, false, cla_nonabstract_decl);
+		      true, false, true, true, cla_nonabstract_decl);
   if (parser->error)
     return NULL_TREE;
   if (!specs->declspecs_seen_p)
@@ -3693,7 +3784,7 @@ c_parser_declarator (c_parser *parser, bool type_s
       struct c_declarator *inner;
       c_parser_consume_token (parser);
       c_parser_declspecs (parser, quals_attrs, false, false, true,
-			  false, false, cla_prefer_id);
+			  false, false, true, false, cla_prefer_id);
       inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
       if (inner == NULL)
 	return NULL;
@@ -3718,14 +3809,15 @@ c_parser_direct_declarator (c_parser *parser, bool
      parenthesized declarator.  In an abstract declarator or parameter
      declarator, they could start a parenthesized declarator or a
      parameter list.  To tell which, the open parenthesis and any
-     following gnu-attributes must be read.  If a declaration specifier
-     follows, then it is a parameter list; if the specifier is a
-     typedef name, there might be an ambiguity about redeclaring it,
-     which is resolved in the direction of treating it as a typedef
-     name.  If a close parenthesis follows, it is also an empty
-     parameter list, as the syntax does not permit empty abstract
-     declarators.  Otherwise, it is a parenthesized declarator (in
-     which case the analysis may be repeated inside it, recursively).
+     following gnu-attributes must be read.  If a declaration
+     specifier or standard attributes follow, then it is a parameter
+     list; if the specifier is a typedef name, there might be an
+     ambiguity about redeclaring it, which is resolved in the
+     direction of treating it as a typedef name.  If a close
+     parenthesis follows, it is also an empty parameter list, as the
+     syntax does not permit empty abstract declarators.  Otherwise, it
+     is a parenthesized declarator (in which case the analysis may be
+     repeated inside it, recursively).
 
      ??? There is an ambiguity in a parameter declaration "int
      (__attribute__((foo)) x)", where x is not a typedef name: it
@@ -3758,11 +3850,18 @@ c_parser_direct_declarator (c_parser *parser, bool
       *seen_id = true;
       inner->id_loc = c_parser_peek_token (parser)->location;
       c_parser_consume_token (parser);
+      if (c_parser_nth_token_starts_std_attributes (parser, 1))
+	{
+	  tree std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+	  if (std_attrs)
+	    inner = build_attrs_declarator (std_attrs, inner);
+	}
       return c_parser_direct_declarator_inner (parser, *seen_id, inner);
     }
 
   if (kind != C_DTR_NORMAL
-      && c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+      && c_parser_next_token_is (parser, CPP_OPEN_SQUARE)
+      && !c_parser_nth_token_starts_std_attributes (parser, 1))
     {
       struct c_declarator *inner = build_id_declarator (NULL_TREE);
       inner->id_loc = c_parser_peek_token (parser)->location;
@@ -3777,14 +3876,18 @@ c_parser_direct_declarator (c_parser *parser, bool
       tree attrs;
       struct c_declarator *inner;
       c_parser_consume_token (parser);
+      bool have_gnu_attrs = c_parser_next_token_is_keyword (parser,
+							    RID_ATTRIBUTE);
       attrs = c_parser_gnu_attributes (parser);
       if (kind != C_DTR_NORMAL
 	  && (c_parser_next_token_starts_declspecs (parser)
+	      || (!have_gnu_attrs
+		  && c_parser_nth_token_starts_std_attributes (parser, 1))
 	      || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
 	{
 	  struct c_arg_info *args
 	    = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL,
-					 attrs);
+					 attrs, have_gnu_attrs);
 	  if (args == NULL)
 	    return NULL;
 	  else
@@ -3792,6 +3895,16 @@ c_parser_direct_declarator (c_parser *parser, bool
 	      inner
 		= build_function_declarator (args,
 					     build_id_declarator (NULL_TREE));
+	      if (!(args->types
+		    && args->types != error_mark_node
+		    && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE)
+		  && c_parser_nth_token_starts_std_attributes (parser, 1))
+		{
+		  tree std_attrs
+		    = c_parser_std_attribute_specifier_sequence (parser);
+		  if (std_attrs)
+		    inner = build_attrs_declarator (std_attrs, inner);
+		}
 	      return c_parser_direct_declarator_inner (parser, *seen_id,
 						       inner);
 	    }
@@ -3837,7 +3950,8 @@ c_parser_direct_declarator_inner (c_parser *parser
 				  struct c_declarator *inner)
 {
   /* Parse a sequence of array declarators and parameter lists.  */
-  if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+  if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)
+      && !c_parser_nth_token_starts_std_attributes (parser, 1))
     {
       location_t brace_loc = c_parser_peek_token (parser)->location;
       struct c_declarator *declarator;
@@ -3850,13 +3964,13 @@ c_parser_direct_declarator_inner (c_parser *parser
       dimen.original_type = NULL_TREE;
       c_parser_consume_token (parser);
       c_parser_declspecs (parser, quals_attrs, false, false, true,
-			  false, false, cla_prefer_id);
+			  false, false, false, false, cla_prefer_id);
       static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
       if (static_seen)
 	c_parser_consume_token (parser);
       if (static_seen && !quals_attrs->declspecs_seen_p)
 	c_parser_declspecs (parser, quals_attrs, false, false, true,
-			    false, false, cla_prefer_id);
+			    false, false, false, false, cla_prefer_id);
       if (!quals_attrs->declspecs_seen_p)
 	quals_attrs = NULL;
       /* If "static" is present, there must be an array dimension.
@@ -3909,6 +4023,13 @@ c_parser_direct_declarator_inner (c_parser *parser
       if (declarator == NULL)
 	return NULL;
       inner = set_array_declarator_inner (declarator, inner);
+      if (c_parser_nth_token_starts_std_attributes (parser, 1))
+	{
+	  tree std_attrs
+	    = c_parser_std_attribute_specifier_sequence (parser);
+	  if (std_attrs)
+	    inner = build_attrs_declarator (std_attrs, inner);
+	}
       return c_parser_direct_declarator_inner (parser, id_present, inner);
     }
   else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
@@ -3916,13 +4037,26 @@ c_parser_direct_declarator_inner (c_parser *parser
       tree attrs;
       struct c_arg_info *args;
       c_parser_consume_token (parser);
+      bool have_gnu_attrs = c_parser_next_token_is_keyword (parser,
+							    RID_ATTRIBUTE);
       attrs = c_parser_gnu_attributes (parser);
-      args = c_parser_parms_declarator (parser, id_present, attrs);
+      args = c_parser_parms_declarator (parser, id_present, attrs,
+					have_gnu_attrs);
       if (args == NULL)
 	return NULL;
       else
 	{
 	  inner = build_function_declarator (args, inner);
+	  if (!(args->types
+		&& args->types != error_mark_node
+		&& TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE)
+	      && c_parser_nth_token_starts_std_attributes (parser, 1))
+	    {
+	      tree std_attrs
+		= c_parser_std_attribute_specifier_sequence (parser);
+	      if (std_attrs)
+		inner = build_attrs_declarator (std_attrs, inner);
+	    }
 	  return c_parser_direct_declarator_inner (parser, id_present, inner);
 	}
     }
@@ -3930,12 +4064,16 @@ c_parser_direct_declarator_inner (c_parser *parser
 }
 
 /* Parse a parameter list or identifier list, including the closing
-   parenthesis but not the opening one.  ATTRS are the attributes at
-   the start of the list.  ID_LIST_OK is true if an identifier list is
-   acceptable; such a list must not have attributes at the start.  */
+   parenthesis but not the opening one.  ATTRS are the gnu-attributes
+   at the start of the list.  ID_LIST_OK is true if an identifier list
+   is acceptable; such a list must not have attributes at the start.
+   HAVE_GNU_ATTRS says whether any gnu-attributes (including empty
+   attributes) were present (in which case standard attributes cannot
+   occur).  */
 
 static struct c_arg_info *
-c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs)
+c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs,
+			   bool have_gnu_attrs)
 {
   push_scope ();
   declare_parm_level ();
@@ -3988,8 +4126,8 @@ static struct c_arg_info *
     }
   else
     {
-      struct c_arg_info *ret = c_parser_parms_list_declarator (parser, attrs,
-							       NULL);
+      struct c_arg_info *ret
+	= c_parser_parms_list_declarator (parser, attrs, NULL, have_gnu_attrs);
       pop_scope ();
       return ret;
     }
@@ -3996,13 +4134,16 @@ static struct c_arg_info *
 }
 
 /* Parse a parameter list (possibly empty), including the closing
-   parenthesis but not the opening one.  ATTRS are the attributes at
-   the start of the list.  EXPR is NULL or an expression that needs to
-   be evaluated for the side effects of array size expressions in the
-   parameters.  */
+   parenthesis but not the opening one.  ATTRS are the gnu-attributes
+   at the start of the list; if HAVE_GNU_ATTRS, there were some such
+   attributes (possibly empty, in which case ATTRS is NULL_TREE),
+   which means standard attributes cannot start the list.  EXPR is
+   NULL or an expression that needs to be evaluated for the side
+   effects of array size expressions in the parameters.  */
 
 static struct c_arg_info *
-c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr)
+c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr,
+				bool have_gnu_attrs)
 {
   bool bad_parm = false;
 
@@ -4009,7 +4150,7 @@ static struct c_arg_info *
   /* ??? Following the old parser, forward parameter declarations may
      use abstract declarators, and if no real parameter declarations
      follow the forward declarations then this is not diagnosed.  Also
-     note as above that attributes are ignored as the only contents of
+     note as above that gnu-attributes are ignored as the only contents of
      the parentheses, or as the only contents after forward
      declarations.  */
   if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
@@ -4053,8 +4194,10 @@ static struct c_arg_info *
   while (true)
     {
       /* Parse a parameter.  */
-      struct c_parm *parm = c_parser_parameter_declaration (parser, attrs);
+      struct c_parm *parm = c_parser_parameter_declaration (parser, attrs,
+							    have_gnu_attrs);
       attrs = NULL_TREE;
+      have_gnu_attrs = false;
       if (parm == NULL)
 	bad_parm = true;
       else
@@ -4064,8 +4207,11 @@ static struct c_arg_info *
 	  tree new_attrs;
 	  c_parser_consume_token (parser);
 	  mark_forward_parm_decls ();
+	  bool new_have_gnu_attrs
+	    = c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE);
 	  new_attrs = c_parser_gnu_attributes (parser);
-	  return c_parser_parms_list_declarator (parser, new_attrs, expr);
+	  return c_parser_parms_list_declarator (parser, new_attrs, expr,
+						 new_have_gnu_attrs);
 	}
       if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
 	{
@@ -4103,11 +4249,14 @@ static struct c_arg_info *
     }
 }
 
-/* Parse a parameter declaration.  ATTRS are the attributes at the
-   start of the declaration if it is the first parameter.  */
+/* Parse a parameter declaration.  ATTRS are the gnu-attributes at the
+   start of the declaration if it is the first parameter;
+   HAVE_GNU_ATTRS is true if there were any gnu-attributes there (even
+   empty) there.  */
 
 static struct c_parm *
-c_parser_parameter_declaration (c_parser *parser, tree attrs)
+c_parser_parameter_declaration (c_parser *parser, tree attrs,
+				bool have_gnu_attrs)
 {
   struct c_declspecs *specs;
   struct c_declarator *declarator;
@@ -4119,7 +4268,8 @@ static struct c_parm *
   while (c_parser_next_token_is (parser, CPP_PRAGMA))
     c_parser_pragma (parser, pragma_param, NULL);
 
-  if (!c_parser_next_token_starts_declspecs (parser))
+  if (!c_parser_next_token_starts_declspecs (parser)
+      && !c_parser_nth_token_starts_std_attributes (parser, 1))
     {
       c_token *token = c_parser_peek_token (parser);
       if (parser->error)
@@ -4161,7 +4311,7 @@ static struct c_parm *
       attrs = NULL_TREE;
     }
   c_parser_declspecs (parser, specs, true, true, true, true, false,
-		      cla_nonabstract_decl);
+		      !have_gnu_attrs, true, cla_nonabstract_decl);
   finish_declspecs (specs);
   pending_xref_error ();
   prefix_attrs = specs->attrs;
@@ -4733,6 +4883,33 @@ c_parser_std_attribute_specifier (c_parser *parser
   return nreverse (attributes);
 }
 
+/* Return whether standard attributes start with the Nth token.  */
+
+static bool
+c_parser_nth_token_starts_std_attributes (c_parser *parser, unsigned int n)
+{
+  if (!(c_parser_peek_nth_token (parser, n)->type == CPP_OPEN_SQUARE
+	&& c_parser_peek_nth_token (parser, n + 1)->type == CPP_OPEN_SQUARE))
+    return false;
+  /* In C, '[[' must start attributes.  In Objective-C, identifying
+     whether those tokens start attributes requires unbounded
+     lookahead, which is not yet implemented.  */
+  return !c_dialect_objc ();
+}
+
+static tree
+c_parser_std_attribute_specifier_sequence (c_parser *parser)
+{
+  tree attributes = NULL_TREE;
+  do
+    {
+      tree attrs = c_parser_std_attribute_specifier (parser, false);
+      attributes = chainon (attributes, attrs);
+    }
+  while (c_parser_nth_token_starts_std_attributes (parser, 1));
+  return attributes;
+}
+
 /* Parse a type name (C90 6.5.5, C99 6.7.6, C11 6.7.7).  ALIGNAS_OK
    says whether alignment specifiers are OK (only in cases that might
    be the type name of a compound literal).
@@ -4749,7 +4926,7 @@ c_parser_type_name (c_parser *parser, bool alignas
   struct c_type_name *ret;
   bool dummy = false;
   c_parser_declspecs (parser, specs, false, true, true, alignas_ok, false,
-		      cla_prefer_type);
+		      false, true, cla_prefer_type);
   if (!specs->declspecs_seen_p)
     {
       c_parser_error (parser, "expected specifier-qualifier-list");
@@ -5281,11 +5458,18 @@ c_parser_compound_statement_nostart (c_parser *par
     {
       location_t loc = c_parser_peek_token (parser)->location;
       loc = expansion_point_location_if_in_system_header (loc);
+      /* Standard attributes may start a statement or a declaration.  */
+      bool have_std_attrs
+	= c_parser_nth_token_starts_std_attributes (parser, 1);
+      tree std_attrs = NULL_TREE;
+      if (have_std_attrs)
+	std_attrs = c_parser_std_attribute_specifier_sequence (parser);
       if (c_parser_next_token_is_keyword (parser, RID_CASE)
 	  || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	  || (c_parser_next_token_is (parser, CPP_NAME)
 	      && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
 	{
+	  c_warn_unused_attributes (std_attrs);
 	  if (c_parser_next_token_is_keyword (parser, RID_CASE))
 	    label_loc = c_parser_peek_2nd_token (parser)->location;
 	  else
@@ -5296,14 +5480,17 @@ c_parser_compound_statement_nostart (c_parser *par
 	  c_parser_label (parser);
 	}
       else if (!last_label
-	       && c_parser_next_tokens_start_declaration (parser))
+	       && (c_parser_next_tokens_start_declaration (parser)
+		   || (have_std_attrs
+		       && c_parser_next_token_is (parser, CPP_SEMICOLON))))
 	{
 	  last_label = false;
 	  mark_valid_location_for_stdc_pragma (false);
 	  bool fallthru_attr_p = false;
-	  c_parser_declaration_or_fndef (parser, true, true, true, true,
-					 true, NULL, vNULL, NULL,
-					 &fallthru_attr_p);
+	  c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
+					 true, true, true, NULL,
+					 vNULL, have_std_attrs, std_attrs,
+					 NULL, &fallthru_attr_p);
 	  if (last_stmt && !fallthru_attr_p)
 	    pedwarn_c90 (loc, OPT_Wdeclaration_after_statement,
 			 "ISO C90 forbids mixed declarations and code");
@@ -5315,12 +5502,17 @@ c_parser_compound_statement_nostart (c_parser *par
 	  /* __extension__ can start a declaration, but is also an
 	     unary operator that can start an expression.  Consume all
 	     but the last of a possible series of __extension__ to
-	     determine which.  */
+	     determine which.  If standard attributes have already
+	     been seen, it must start a statement, not a declaration,
+	     but standard attributes starting a declaration may appear
+	     after __extension__.  */
 	  while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
 		 && (c_parser_peek_2nd_token (parser)->keyword
 		     == RID_EXTENSION))
 	    c_parser_consume_token (parser);
-	  if (c_token_starts_declaration (c_parser_peek_2nd_token (parser)))
+	  if (!have_std_attrs
+	      && (c_token_starts_declaration (c_parser_peek_2nd_token (parser))
+		  || c_parser_nth_token_starts_std_attributes (parser, 2)))
 	    {
 	      int ext;
 	      ext = disable_extension_diagnostics ();
@@ -5342,6 +5534,8 @@ c_parser_compound_statement_nostart (c_parser *par
 	}
       else if (c_parser_next_token_is (parser, CPP_PRAGMA))
 	{
+	  if (have_std_attrs)
+	    c_parser_error (parser, "expected declaration or statement");
 	  /* External pragmas, and some omp pragmas, are not associated
 	     with regular c code, and so are not to be considered statements
 	     syntactically.  This ensures that the user doesn't put them
@@ -5376,6 +5570,7 @@ c_parser_compound_statement_nostart (c_parser *par
       else
 	{
 	statement:
+	  c_warn_unused_attributes (std_attrs);
 	  last_label = false;
 	  last_stmt = true;
 	  mark_valid_location_for_stdc_pragma (false);
@@ -5391,11 +5586,22 @@ c_parser_compound_statement_nostart (c_parser *par
   mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
 }
 
-/* Parse all consecutive labels. */
+/* Parse all consecutive labels, possibly preceded by standard
+   attributes.  In this context, a statement is required, not a
+   declaration, so attributes must be followed by a statement that is
+   not just a semicolon.  */
 
 static void
 c_parser_all_labels (c_parser *parser)
 {
+  if (c_parser_nth_token_starts_std_attributes (parser, 1))
+    {
+      tree std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	c_parser_error (parser, "expected statement");
+      else
+	c_warn_unused_attributes (std_attrs);
+    }
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
@@ -5417,7 +5623,11 @@ c_parser_all_labels (c_parser *parser)
 
    The use of gnu-attributes on labels is a GNU extension.  The syntax in
    GNU C accepts any expressions without commas, non-constant
-   expressions being rejected later.  */
+   expressions being rejected later.  Any standard
+   attribute-specifier-sequence before the first label has been parsed
+   in the caller, to distinguish statements from declarations.  Any
+   attribute-specifier-sequence after the label is parsed in this
+   function.  */
 
 static void
 c_parser_label (c_parser *parser)
@@ -5480,8 +5690,18 @@ c_parser_label (c_parser *parser)
       else
 	FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p;
 
+      /* Standard attributes are only allowed here if they start a
+	 statement, not a declaration (including the case of an
+	 attribute-declaration with only attributes).  */
+      bool have_std_attrs
+	= c_parser_nth_token_starts_std_attributes (parser, 1);
+      tree std_attrs = NULL_TREE;
+      if (have_std_attrs)
+	std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+
       /* Allow '__attribute__((fallthrough));'.  */
-      if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+      if (!have_std_attrs
+	  && c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
 	{
 	  location_t loc = c_parser_peek_token (parser)->location;
 	  tree attrs = c_parser_gnu_attributes (parser);
@@ -5502,7 +5722,9 @@ c_parser_label (c_parser *parser)
 	    warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
 			" can be applied to a null statement");
 	}
-      if (c_parser_next_tokens_start_declaration (parser))
+      if (c_parser_next_tokens_start_declaration (parser)
+	  || (have_std_attrs
+	      && c_parser_next_token_is (parser, CPP_SEMICOLON)))
 	{
 	  error_at (c_parser_peek_token (parser)->location,
 		    "a label can only be part of a statement and "
@@ -5511,8 +5733,11 @@ c_parser_label (c_parser *parser)
 					 /*static_assert_ok*/ true,
 					 /*empty_ok*/ true, /*nested*/ true,
 					 /*start_attr_ok*/ true, NULL,
-					 vNULL);
+					 vNULL, have_std_attrs, std_attrs);
 	}
+      else if (std_attrs)
+	/* Nonempty attributes on the following statement are ignored.  */
+	c_warn_unused_attributes (std_attrs);
     }
 }
 
@@ -5520,17 +5745,18 @@ c_parser_label (c_parser *parser)
 
    statement:
      labeled-statement
-     compound-statement
+     attribute-specifier-sequence[opt] compound-statement
      expression-statement
-     selection-statement
-     iteration-statement
-     jump-statement
+     attribute-specifier-sequence[opt] selection-statement
+     attribute-specifier-sequence[opt] iteration-statement
+     attribute-specifier-sequence[opt] jump-statement
 
    labeled-statement:
-     label statement
+     attribute-specifier-sequence[opt] label statement
 
    expression-statement:
      expression[opt] ;
+     attribute-specifier-sequence expression ;
 
    selection-statement:
      if-statement
@@ -5550,7 +5776,7 @@ c_parser_label (c_parser *parser)
    GNU extensions:
 
    statement:
-     asm-statement
+     attribute-specifier-sequence[opt] asm-statement
 
    jump-statement:
      goto * expression ;
@@ -5561,9 +5787,9 @@ c_parser_label (c_parser *parser)
    Objective-C:
 
    statement:
-     objc-throw-statement
-     objc-try-catch-statement
-     objc-synchronized-statement
+     attribute-specifier-sequence[opt] objc-throw-statement
+     attribute-specifier-sequence[opt] objc-try-catch-statement
+     attribute-specifier-sequence[opt] objc-synchronized-statement
 
    objc-throw-statement:
      @throw expression ;
@@ -5572,7 +5798,7 @@ c_parser_label (c_parser *parser)
    OpenACC:
 
    statement:
-     openacc-construct
+     attribute-specifier-sequence[opt] openacc-construct
 
    openacc-construct:
      parallel-construct
@@ -5595,7 +5821,7 @@ c_parser_label (c_parser *parser)
    OpenMP:
 
    statement:
-     openmp-construct
+     attribute-specifier-sequence[opt] openmp-construct
 
    openmp-construct:
      parallel-construct
@@ -5654,8 +5880,8 @@ c_parser_label (c_parser *parser)
    Transactional Memory:
 
    statement:
-     transaction-statement
-     transaction-cancel-statement
+     attribute-specifier-sequence[opt] transaction-statement
+     attribute-specifier-sequence[opt] transaction-cancel-statement
 
    IF_P is used to track whether there's a (possibly labeled) if statement
    which is not enclosed in braces and has an else clause.  This is used to
@@ -5671,7 +5897,8 @@ c_parser_statement (c_parser *parser, bool *if_p,
 }
 
 /* Parse a statement, other than a labeled statement.  CHAIN is a vector
-   of if-else-if conditions.
+   of if-else-if conditions.  All labels and standard attributes have
+   been parsed in the caller.
 
    IF_P is used to track whether there's a (possibly labeled) if statement
    which is not enclosed in braces and has an else clause.  This is used to
@@ -6394,7 +6621,8 @@ c_parser_for_statement (c_parser *parser, bool ivd
 	  c_parser_consume_token (parser);
 	  c_finish_expr_stmt (loc, NULL_TREE);
 	}
-      else if (c_parser_next_tokens_start_declaration (parser))
+      else if (c_parser_next_tokens_start_declaration (parser)
+	       || c_parser_nth_token_starts_std_attributes (parser, 1))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, 
 					 &object_expression, vNULL);
@@ -6421,7 +6649,8 @@ c_parser_for_statement (c_parser *parser, bool ivd
 		 && (c_parser_peek_2nd_token (parser)->keyword
 		     == RID_EXTENSION))
 	    c_parser_consume_token (parser);
-	  if (c_token_starts_declaration (c_parser_peek_2nd_token (parser)))
+	  if (c_token_starts_declaration (c_parser_peek_2nd_token (parser))
+	      || c_parser_nth_token_starts_std_attributes (parser, 2))
 	    {
 	      int ext;
 	      ext = disable_extension_diagnostics ();
@@ -10983,7 +11212,7 @@ c_parser_objc_method_decl (c_parser *parser, bool
 						(parser, attributes) ;
 	      break;
 	    }
-	  parm = c_parser_parameter_declaration (parser, NULL_TREE);
+	  parm = c_parser_parameter_declaration (parser, NULL_TREE, false);
 	  if (parm == NULL)
 	    break;
 	  parms = chainon (parms,
@@ -11148,7 +11377,7 @@ c_parser_objc_try_catch_finally_statement (c_parse
 	{
 	  /* We have "@catch (NSException *exception)" or something
 	     like that.  Parse the parameter declaration.  */
-	  parm = c_parser_parameter_declaration (parser, NULL_TREE);
+	  parm = c_parser_parameter_declaration (parser, NULL_TREE, false);
 	  if (parm == NULL)
 	    parameter_declaration = error_mark_node;
 	  else
@@ -16490,12 +16719,12 @@ c_parser_oacc_routine (c_parser *parser, enum prag
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, vNULL, &data);
+					 NULL, vNULL, false, NULL, &data);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, vNULL, &data);
+				       NULL, vNULL, false, NULL, &data);
     }
 }
 
Index: gcc/c/c-parser.h
===================================================================
--- gcc/c/c-parser.h	(revision 278145)
+++ gcc/c/c-parser.h	(working copy)
@@ -190,7 +190,8 @@ extern struct c_declarator *
 c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
 		     bool *seen_id);
 extern void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
-				bool, bool, bool, enum c_lookahead_kind);
+				bool, bool, bool, bool, bool,
+				enum c_lookahead_kind);
 extern struct c_type_name *c_parser_type_name (c_parser *, bool = false);
 
 #endif
Index: gcc/c/c-tree.h
===================================================================
--- gcc/c/c-tree.h	(revision 278145)
+++ gcc/c/c-tree.h	(working copy)
@@ -186,9 +186,13 @@ enum c_typespec_kind {
      kind of tag, in which case this is only valid if shadowing that
      tag in an inner scope.  */
   ctsk_tagref,
+  /* Likewise, with standard attributes present in the reference.  */
+  ctsk_tagref_attrs,
   /* A reference to a tag, not previously declared in a visible
      scope.  */
   ctsk_tagfirstref,
+  /* Likewise, with standard attributes present in the reference.  */
+  ctsk_tagfirstref_attrs,
   /* A definition of a tag such as "struct foo { int a; }".  */
   ctsk_tagdef,
   /* A typedef name.  */
@@ -311,10 +315,15 @@ struct c_declspecs {
   tree expr;
   /* The attributes from a typedef decl.  */
   tree decl_attr;
-  /* When parsing, the attributes.  Outside the parser, this will be
-     NULL; attributes (possibly from multiple lists) will be passed
-     separately.  */
+  /* When parsing, the GNU attributes and prefix standard attributes.
+     Outside the parser, this will be NULL; attributes (possibly from
+     multiple lists) will be passed separately.  */
   tree attrs;
+  /* When parsing, postfix standard attributes (which appertain to the
+     type specified by the preceding declaration specifiers, unlike
+     prefix standard attributes which appertain to the declaration or
+     declarations as a whole).  */
+  tree postfix_attrs;
   /* The pass to start compiling a __GIMPLE or __RTL function with.  */
   char *gimple_or_rtl_pass;
   /* ENTRY BB count.  */
@@ -335,7 +344,7 @@ struct c_declspecs {
   ENUM_BITFIELD (c_typespec_keyword) typespec_word : 8;
   /* The kind of type specifier if one has been seen, ctsk_none
      otherwise.  */
-  ENUM_BITFIELD (c_typespec_kind) typespec_kind : 3;
+  ENUM_BITFIELD (c_typespec_kind) typespec_kind : 4;
   ENUM_BITFIELD (c_declspec_il) declspec_il : 3;
   /* Whether any expressions in typeof specifiers may appear in
      constant expressions.  */
@@ -342,6 +351,10 @@ struct c_declspecs {
   BOOL_BITFIELD expr_const_operands : 1;
   /* Whether any declaration specifiers have been seen at all.  */
   BOOL_BITFIELD declspecs_seen_p : 1;
+  /* Whether any declaration specifiers other than standard attributes
+     have been seen at all.  If only standard attributes have been
+     seen, this is an attribute-declaration.  */
+  BOOL_BITFIELD non_std_attrs_seen_p : 1;
   /* Whether something other than a storage class specifier or
      attribute has been seen.  This is used to warn for the
      obsolescent usage of storage class specifiers other than at the
@@ -582,6 +595,7 @@ extern struct c_declarator *set_array_declarator_i
 extern tree c_builtin_function (tree);
 extern tree c_builtin_function_ext_scope (tree);
 extern tree c_simulate_builtin_function_decl (tree);
+extern void c_warn_unused_attributes (tree);
 extern void shadow_tag (const struct c_declspecs *);
 extern void shadow_tag_warned (const struct c_declspecs *, int);
 extern tree start_enum (location_t, struct c_enum_contents *, tree);
@@ -595,7 +609,8 @@ extern void store_parm_decls_from (struct c_arg_in
 extern void temp_store_parm_decls (tree, tree);
 extern void temp_pop_parm_decls (void);
 extern tree xref_tag (enum tree_code, tree);
-extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree);
+extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree,
+					  bool, tree);
 extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
 				    struct c_declarator *, location_t);
 extern struct c_declarator *build_attrs_declarator (tree,
Index: gcc/c/gimple-parser.c
===================================================================
--- gcc/c/gimple-parser.c	(revision 278145)
+++ gcc/c/gimple-parser.c	(working copy)
@@ -2014,7 +2014,7 @@ c_parser_gimple_declaration (gimple_parser &parser
   struct c_declarator *declarator;
   struct c_declspecs *specs = build_null_declspecs ();
   c_parser_declspecs (parser, specs, true, true, true,
-		      true, true, cla_nonabstract_decl);
+		      true, true, true, true, cla_nonabstract_decl);
   finish_declspecs (specs);
 
   /* Provide better error recovery.  Note that a type name here is usually
Index: gcc/testsuite/gcc.dg/c2x-attr-fallthrough-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-fallthrough-1.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/c2x-attr-fallthrough-1.c	(working copy)
@@ -0,0 +1,21 @@
+/* Test C2x attribute syntax.  Valid use of fallthrough attribute.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors -Wextra" } */
+
+int
+f (int a)
+{
+  int b = 2;
+  switch (a)
+    {
+    case 1:
+      b = 1; /* { dg-warning "may fall through" } */
+    case 2:
+      b = 2;
+      [[fallthrough]];
+    case 3:
+      b += 7;
+      break;
+    }
+  return b;
+}
Index: gcc/testsuite/gcc.dg/c2x-attr-syntax-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-syntax-1.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/c2x-attr-syntax-1.c	(working copy)
@@ -0,0 +1,55 @@
+/* Test C2x attribute syntax.  Basic tests of valid uses of empty
+   attributes.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[ [ ] ] [[]];
+
+[[]] int [[]] a [[]] = 123;
+
+int f([[]] int x [[]], [[]] long [[]], short [[]] *[[]] [3] [[]],
+      int [[]] (int)[[]], int (*)(int)[[]]) [[]] [[]];
+
+int g [[]] [2] [[]] [3] [[]];
+
+int *[[]] const *[[]] volatile *[[]] *const p;
+
+int *[[]][[]] q = 0;
+
+struct [[]] s;
+union [[]][[]] u;
+
+struct [[]] s2 { [[]] long [[]] *a[[]] [3] [[]] [4], b[[]]; };
+
+union [[]] u2 { [[]] long [[]] *a[[]] [3] [[]] [4]; };
+
+int z = sizeof (int [[]]);
+
+enum [[]] { E1 [[]][[]], E2[[]][[]] = 3 };
+enum [[]] e { E3 = 4, E4 [[]] };
+
+void
+func (void) [[]]
+{
+  [[]] int var;
+  [[]] { }
+  [[]] switch (a) { [[]] case 1: [[]] case 2: [[]] default: [[]] var = 3; }
+  [[]] x : [[]] y: [[]] var = 1;
+  [[]];
+  int [[]] var2;
+  [[]] if (a) [[]] (void) 0; else [[]] (void) 1;
+  [[]] while (0) [[]] var = 2;
+  [[]] do [[]] var = 3; while (0);
+  for ([[]] int zz = 1; zz < 10; zz++)
+    {
+      [[]] var2 = 8;
+      [[]] continue;
+      [[]] break;
+    }
+  if (a) [[]] goto x;
+  [[]] return;
+}
+
+void func2 () [[]];
+
+void func3 () [[]] { }
Index: gcc/testsuite/gcc.dg/c2x-attr-syntax-2.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-syntax-2.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/c2x-attr-syntax-2.c	(working copy)
@@ -0,0 +1,60 @@
+/* Test C2x attribute syntax.  Test ignored attributes diagnosed.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+/* A GNU attribute that is valid in some contexts, but should be
+   diagnosed in contexts where all attributes are ignored (attribute
+   declarations, except for fallthrough attributes, and
+   statements).  */
+#define CTX [[gnu::const]]
+
+/* An attribute that is unknown, so ignored with a warning.  */
+#define UNK [[gnu::no_such_attribute(![!(!)!]!,;;)]]
+
+CTX; /* { dg-warning "ignored" } */
+UNK; /* { dg-warning "ignored" } */
+
+UNK extern int a; /* { dg-warning "ignored" } */
+extern int UNK a; /* { dg-warning "ignored" } */
+extern int a UNK; /* { dg-warning "ignored" } */
+
+int f () UNK; /* { dg-warning "ignored" } */
+int f (void) UNK; /* { dg-warning "ignored" } */
+int g (UNK int a); /* { dg-warning "ignored" } */
+int g (int UNK a); /* { dg-warning "ignored" } */
+int g (int a UNK); /* { dg-warning "ignored" } */
+int g (UNK int); /* { dg-warning "ignored" } */
+int g (int UNK); /* { dg-warning "ignored" } */
+int g (int) UNK; /* { dg-warning "ignored" } */
+
+int *UNK p; /* { dg-warning "ignored" } */
+int b[3] UNK; /* { dg-warning "ignored" } */
+
+int h (int () UNK); /* { dg-warning "ignored" } */
+
+struct UNK s; /* { dg-warning "ignored" } */
+union UNK u; /* { dg-warning "ignored" } */
+
+struct UNK s2 { int a; }; /* { dg-warning "ignored" } */
+union UNK u2 { int a; }; /* { dg-warning "ignored" } */
+
+struct s3 { UNK int a; }; /* { dg-warning "ignored" } */
+struct s4 { int UNK a; }; /* { dg-warning "ignored" } */
+union u3 { UNK int a; }; /* { dg-warning "ignored" } */
+union u4 { int UNK a; }; /* { dg-warning "ignored" } */
+
+int z = sizeof (int UNK); /* { dg-warning "ignored" } */
+
+enum UNK { E1 }; /* { dg-warning "ignored" } */
+enum { E2 UNK }; /* { dg-warning "ignored" } */
+enum { E3 UNK = 4 }; /* { dg-warning "ignored" } */
+
+void
+func (void) UNK { /* { dg-warning "ignored" } */
+  UNK int var; /* { dg-warning "ignored" } */
+  CTX { } /* { dg-warning "ignored" } */
+  CTX; /* { dg-warning "ignored" } */
+  CTX var = 1; /* { dg-warning "ignored" } */
+  CTX x: var = 2; /* { dg-warning "ignored" } */
+  for (UNK int zz = 1; zz < 10; zz++) ; /* { dg-warning "ignored" } */
+}
Index: gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c	(working copy)
@@ -0,0 +1,56 @@
+/* Test C2x attribute syntax.  Invalid uses of attributes.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+/* Prefix attributes not allowed on declarations without declarators.  */
+
+[[]] struct s { int a; }; /* { dg-error "empty declaration" } */
+
+[[]] union u { int a; }; /* { dg-error "empty declaration" } */
+
+void
+f1 (void)
+{
+  [[]] struct t { int a; }; /* { dg-error "empty declaration" } */
+}
+
+/* Prefix attributes not allowed on _Static_assert.  */
+
+[[]] _Static_assert (1); /* { dg-error "expected" } */
+
+void
+f2 (void)
+{
+  [[]] _Static_assert (1); /* { dg-error "expected" } */
+}
+
+/* Declarations, including attribute declarations, cannot appear after
+   labels.  */
+
+void
+f3 (void)
+{
+ x: [[]];; /* { dg-error "can only be part of a statement" } */
+}
+
+/* Prefix attributes cannot appear on type names.  */
+
+int z = sizeof ([[]] int); /* { dg-error "expected" } */
+
+/* Attributes are not allowed after struct, union or enum, except when
+   the type contents are being defined or the declaration is just
+   "struct-or-union atribute-specifier-sequence identifier;".  */
+
+const struct [[]] s2; /* { dg-warning "useless type qualifier" } */
+/* { dg-error "invalid use of attributes in empty declaration" "invalid" { target *-*-* } .-1 } */
+
+const union [[]] u2; /* { dg-warning "useless type qualifier" } */
+/* { dg-error "invalid use of attributes in empty declaration" "invalid" { target *-*-* } .-1 } */
+
+struct [[]] s3 *sv; /* { dg-error "expected" } */
+
+union [[]] u3 *uv; /* { dg-error "expected" } */
+
+enum e { E1 };
+
+enum [[]] e *ev; /* { dg-error "expected" } */
Index: gcc/testsuite/gcc.dg/gnu2x-attr-syntax-1.c
===================================================================
--- gcc/testsuite/gcc.dg/gnu2x-attr-syntax-1.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/gnu2x-attr-syntax-1.c	(working copy)
@@ -0,0 +1,16 @@
+/* Test C2x attribute syntax.  Basic tests of valid uses of empty
+   attributes with GNU C features.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu2x" } */
+
+/* Attributes can be used in declarations after __extension__, and
+   before asm statements.  */
+
+__extension__ [[]] int a;
+
+void
+f (void)
+{
+  __extension__ [[]] int b;
+  [[]] asm ("");
+}
Index: gcc/testsuite/gcc.dg/gnu2x-attr-syntax-2.c
===================================================================
--- gcc/testsuite/gcc.dg/gnu2x-attr-syntax-2.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/gnu2x-attr-syntax-2.c	(working copy)
@@ -0,0 +1,16 @@
+/* Test C2x attribute syntax.  Invalid uses of attributes with GNU C
+   features.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu2x -w" } */
+
+/* Attributes cannot be used as prefix attributes on old-style
+   parameter declarations or on function declarators with identifier
+   lists (removed from C2x).  */
+
+void (*f(a, b) [[]])() int a, b; { } /* { dg-error "expected" } */
+
+void f(x, y) int x; [[]] int y; { } /* { dg-error "expected" } */
+
+/* Nonempty attributes cannot be used as postfix attributes with
+   __auto_type.  */
+__auto_type [[gnu::no_such_attr]] x = 1; /* { dg-error "'__auto_type' followed by" } */
Index: gcc/testsuite/gcc.dg/gnu2x-attrs-1.c
===================================================================
--- gcc/testsuite/gcc.dg/gnu2x-attrs-1.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/gnu2x-attrs-1.c	(working copy)
@@ -0,0 +1,72 @@
+/* Test C2x attribute syntax.  Test GNU attributes appertain to
+   appropriate constructs.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu2x" } */
+
+void f (void) {};
+
+[[gnu::alias("f")]] void g (void);
+
+void [[gnu::alias("f")]] h (void); /* { dg-warning "ignored" } */
+/* { dg-message "that appertains to a type-specifier" "appertains" { target *-*-* } .-1 } */
+
+struct [[gnu::packed]] s { int a; char b; };
+_Static_assert (sizeof (struct s) == (sizeof (int) + sizeof (char)));
+
+int
+f2 (void)
+{
+  [[gnu::deprecated]] int a = 1;
+  return a; /* { dg-warning "deprecated" } */
+}
+
+int
+f3 (void)
+{
+  int a [[gnu::deprecated]] = 1;
+  return a; /* { dg-warning "deprecated" } */
+}
+
+struct s2 { [[gnu::deprecated]] int a; int b [[gnu::deprecated]]; } x;
+
+int
+f4 (void)
+{
+  return x.a; /* { dg-warning "deprecated" } */
+}
+
+int
+f5 (void)
+{
+  return x.b; /* { dg-warning "deprecated" } */
+}
+
+enum e { E1 [[gnu::deprecated]] };
+
+enum e
+f6 (void)
+{
+  return E1; /* { dg-warning "deprecated" } */
+}
+
+int
+f7 ([[gnu::deprecated]] int y)
+{
+  return y; /* { dg-warning "deprecated" } */
+}
+
+union [[gnu::deprecated]] u { int x; };
+
+void
+f8 (void)
+{
+  union u var; /* { dg-warning "deprecated" } */
+}
+
+enum [[gnu::deprecated]] edep { E2 };
+
+void
+f9 (void)
+{
+  enum edep var; /* { dg-warning "deprecated" } */
+}
