diff options
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r-- | gcc/cp/parser.c | 76 |
1 files changed, 47 insertions, 29 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index deb36fe..63a6b88 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -9412,7 +9412,7 @@ cp_parser_explicit_instantiation (cp_parser* parser) if (declarator != cp_error_declarator) { decl = grokdeclarator (declarator, &decl_specifiers, - NORMAL, 0, NULL); + NORMAL, 0, &decl_specifiers.attributes); /* Turn access control back on for names used during template instantiation. */ pop_deferring_access_checks (); @@ -9561,22 +9561,11 @@ cp_parser_type_specifier (cp_parser* parser, switch (keyword) { case RID_ENUM: - /* 'enum' [identifier] '{' introduces an enum-specifier; - 'enum' <anything else> introduces an elaborated-type-specifier. */ - if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_BRACE - || (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME - && cp_lexer_peek_nth_token (parser->lexer, 3)->type - == CPP_OPEN_BRACE)) + /* Look for the enum-specifier. */ + type_spec = cp_parser_enum_specifier (parser); + /* If that worked, we're done. */ + if (type_spec) { - if (parser->num_template_parameter_lists) - { - error ("template declaration of %qs", "enum"); - cp_parser_skip_to_end_of_block_or_statement (parser); - type_spec = error_mark_node; - } - else - type_spec = cp_parser_enum_specifier (parser); - if (declares_class_or_enum) *declares_class_or_enum = 2; if (decl_specs) @@ -10078,6 +10067,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, /*type_p=*/true, is_declaration); /* For everything but enumeration types, consider a template-id. */ + /* For an enumeration type, consider only a plain identifier. */ if (tag_type != enum_type) { bool template_p = false; @@ -10109,7 +10099,6 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, type = TREE_TYPE (decl); } - /* For an enumeration type, consider only a plain identifier. */ if (!type) { identifier = cp_parser_identifier (parser); @@ -10237,11 +10226,6 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, else ts = ts_global; - /* Warn about attributes. They are ignored. */ - if (attributes) - warning (OPT_Wattributes, - "type attributes are honored only at type definition"); - template_p = (parser->num_template_parameter_lists && (cp_parser_next_token_starts_class_definition_p (parser) @@ -10254,6 +10238,21 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, type = xref_tag (tag_type, identifier, ts, template_p); } } + + /* Allow attributes on forward declarations of classes. */ + if (attributes) + { + if (tag_type != enum_type && CLASSTYPE_TEMPLATE_INSTANTIATION (type) + && ! processing_explicit_instantiation) + warning (OPT_Wattributes, + "attributes ignored on template instantiation"); + else if (is_declaration && cp_parser_declares_only_class_p (parser)) + cplus_decl_attributes (&type, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); + else + warning (OPT_Wattributes, + "attributes ignored on elaborated-type-specifier that is not a forward declaration"); + } + if (tag_type != enum_type) cp_parser_check_class_key (tag_type, type); @@ -10270,15 +10269,22 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, enum identifier [opt] { enumerator-list [opt] } GNU Extensions: - enum identifier [opt] { enumerator-list [opt] } attributes + enum attributes[opt] identifier [opt] { enumerator-list [opt] } + attributes[opt] - Returns an ENUM_TYPE representing the enumeration. */ + Returns an ENUM_TYPE representing the enumeration, or NULL_TREE + if the token stream isn't an enum-specifier after all. */ static tree cp_parser_enum_specifier (cp_parser* parser) { tree identifier; tree type; + tree attributes; + + /* Parse tentatively so that we can back up if we don't find a + enum-specifier. */ + cp_parser_parse_tentatively (parser); /* Caller guarantees that the current token is 'enum', an identifier possibly follows, and the token after that is an opening brace. @@ -10286,11 +10292,20 @@ cp_parser_enum_specifier (cp_parser* parser) the enumeration being defined. */ cp_lexer_consume_token (parser->lexer); + attributes = cp_parser_attributes_opt (parser); + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) identifier = cp_parser_identifier (parser); else identifier = make_anon_name (); + /* Look for the `{' but don't consume it yet. */ + if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + cp_parser_simulate_error (parser); + + if (!cp_parser_parse_definitely (parser)) + return NULL_TREE; + /* Issue an error message if type-definitions are forbidden here. */ cp_parser_check_type_definition (parser); @@ -10302,6 +10317,12 @@ cp_parser_enum_specifier (cp_parser* parser) /* Consume the opening brace. */ cp_lexer_consume_token (parser->lexer); + if (type == error_mark_node) + { + cp_parser_skip_to_end_of_block_or_statement (parser); + return error_mark_node; + } + /* If the next token is not '}', then there are some enumerators. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE)) cp_parser_enumerator_list (parser, type); @@ -12917,7 +12938,7 @@ cp_parser_class_specifier (cp_parser* parser) scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type)); old_scope = push_inner_scope (scope); } - type = begin_class_definition (type); + type = begin_class_definition (type, attributes); if (type == error_mark_node) /* If the type is erroneous, skip the entire body of the class. */ @@ -12934,10 +12955,7 @@ cp_parser_class_specifier (cp_parser* parser) has_trailing_semicolon = (token->type == CPP_SEMICOLON); /* Look for trailing attributes to apply to this class. */ if (cp_parser_allow_gnu_extensions_p (parser)) - { - tree sub_attr = cp_parser_attributes_opt (parser); - attributes = chainon (attributes, sub_attr); - } + attributes = cp_parser_attributes_opt (parser); if (type != error_mark_node) type = finish_struct (type, attributes); if (nested_name_specifier_p) |