aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r--gcc/cp/parser.c76
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)