aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/parser.cc')
-rw-r--r--gcc/cp/parser.cc89
1 files changed, 69 insertions, 20 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index d96fdf8..21bec72c 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -3091,8 +3091,8 @@ static cp_token *cp_parser_require_keyword
(cp_parser *, enum rid, required_token);
static bool cp_parser_token_starts_function_definition_p
(cp_token *);
-static bool cp_parser_next_token_starts_class_definition_p
- (cp_parser *);
+static bool cp_parser_nth_token_starts_class_definition_p
+ (cp_parser *, size_t);
static bool cp_parser_next_token_ends_template_argument_p
(cp_parser *);
static bool cp_parser_nth_token_starts_template_argument_list_p
@@ -22031,7 +22031,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
bool template_p =
(template_parm_lists_apply
- && (cp_parser_next_token_starts_class_definition_p (parser)
+ && (cp_parser_nth_token_starts_class_definition_p (parser, 1)
|| cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)));
/* An unqualified name was used to reference this type, so
there were no qualifying templates. */
@@ -28068,6 +28068,64 @@ cp_parser_class_specifier (cp_parser* parser)
return type;
}
+/* Parse an (optional) class-property-specifier-seq.
+
+ class-property-specifier-seq:
+ class-property-specifier class-property-specifier-seq [opt]
+
+ class-property-specifier:
+ final
+
+ Returns a bitmask representing the class-property-specifiers. */
+
+static cp_virt_specifiers
+cp_parser_class_property_specifier_seq_opt (cp_parser *parser)
+{
+ cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED;
+
+ while (true)
+ {
+ cp_token *token;
+ cp_virt_specifiers virt_specifier;
+
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ /* See if it's a class-property-specifier. */
+ if (token->type != CPP_NAME)
+ break;
+ if (id_equal (token->u.value, "final"))
+ {
+ /* For C++98, quietly ignore final in e.g.
+ struct S final = 24; */
+ if (cxx_dialect == cxx98
+ && virt_specifiers == VIRT_SPEC_UNSPECIFIED
+ && !cp_parser_nth_token_starts_class_definition_p (parser, 2)
+ && !cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
+ break;
+ maybe_warn_cpp0x (CPP0X_OVERRIDE_CONTROLS);
+ virt_specifier = VIRT_SPEC_FINAL;
+ }
+ else if (id_equal (token->u.value, "__final"))
+ virt_specifier = VIRT_SPEC_FINAL;
+ else
+ break;
+
+ if (virt_specifiers & virt_specifier)
+ {
+ gcc_rich_location richloc (token->location);
+ richloc.add_fixit_remove ();
+ error_at (&richloc, "duplicate %qD specifier", token->u.value);
+ cp_lexer_purge_token (parser->lexer);
+ }
+ else
+ {
+ cp_lexer_consume_token (parser->lexer);
+ virt_specifiers |= virt_specifier;
+ }
+ }
+ return virt_specifiers;
+}
+
/* Parse a class-head.
class-head:
@@ -28258,18 +28316,16 @@ cp_parser_class_head (cp_parser* parser,
pop_deferring_access_checks ();
if (id)
- {
- cp_parser_check_for_invalid_template_id (parser, id,
- class_key,
- type_start_token->location);
- }
- virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
+ cp_parser_check_for_invalid_template_id (parser, id,
+ class_key,
+ type_start_token->location);
+ virt_specifiers = cp_parser_class_property_specifier_seq_opt (parser);
/* If it's not a `:' or a `{' then we can't really be looking at a
class-head, since a class-head only appears as part of a
class-specifier. We have to detect this situation before calling
xref_tag, since that has irreversible side-effects. */
- if (!cp_parser_next_token_starts_class_definition_p (parser))
+ if (!cp_parser_nth_token_starts_class_definition_p (parser, 1))
{
cp_parser_error (parser, "expected %<{%> or %<:%>");
type = error_mark_node;
@@ -28279,13 +28335,6 @@ cp_parser_class_head (cp_parser* parser,
/* At this point, we're going ahead with the class-specifier, even
if some other problem occurs. */
cp_parser_commit_to_tentative_parse (parser);
- if (virt_specifiers & VIRT_SPEC_OVERRIDE)
- {
- cp_parser_error (parser,
- "cannot specify %<override%> for a class");
- type = error_mark_node;
- goto out;
- }
/* Issue the error about the overly-qualified name now. */
if (qualified_p)
{
@@ -35654,15 +35703,15 @@ cp_parser_token_starts_function_definition_p (cp_token* token)
|| token->keyword == RID_RETURN);
}
-/* Returns TRUE iff the next token is the ":" or "{" beginning a class
+/* Returns TRUE iff the Nth token is the ":" or "{" beginning a class
definition. */
static bool
-cp_parser_next_token_starts_class_definition_p (cp_parser *parser)
+cp_parser_nth_token_starts_class_definition_p (cp_parser *parser, size_t n)
{
cp_token *token;
- token = cp_lexer_peek_token (parser->lexer);
+ token = cp_lexer_peek_nth_token (parser->lexer, n);
return (token->type == CPP_OPEN_BRACE
|| (token->type == CPP_COLON
&& !parser->colon_doesnt_start_class_def_p));