a local class. */
bool in_function_body;
+ /* TRUE if we can auto-correct a colon to a scope operator. */
+ bool colon_corrects_to_scope_p;
+
/* If non-NULL, then we are parsing a construct where new type
definitions are not permitted. The string stored here will be
issued as an error message if a type is defined. */
(cp_parser *);
static tree cp_parser_iteration_statement
(cp_parser *);
-static void cp_parser_for_init_statement
- (cp_parser *);
-static tree cp_parser_c_for
- (cp_parser *);
-static tree cp_parser_range_for
+static bool cp_parser_for_init_statement
+ (cp_parser *, tree *decl);
+static tree cp_parser_for
(cp_parser *);
+static tree cp_parser_c_for
+ (cp_parser *, tree, tree);
+static tree cp_parser_range_for
+ (cp_parser *, tree, tree, tree);
static tree cp_parser_jump_statement
(cp_parser *);
static void cp_parser_declaration_statement
static void cp_parser_block_declaration
(cp_parser *, bool);
static void cp_parser_simple_declaration
- (cp_parser *, bool);
+ (cp_parser *, bool, tree *);
static void cp_parser_decl_specifier_seq
(cp_parser *, cp_parser_flags, cp_decl_specifier_seq *, int *);
static tree cp_parser_storage_class_specifier_opt
/* Declarators [gram.dcl.decl] */
static tree cp_parser_init_declarator
- (cp_parser *, cp_decl_specifier_seq *, VEC (deferred_access_check,gc)*, bool, bool, int, bool *);
+ (cp_parser *, cp_decl_specifier_seq *, VEC (deferred_access_check,gc)*, bool, bool, int, bool *, tree *);
static cp_declarator *cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, int *, bool *, bool);
static cp_declarator *cp_parser_direct_declarator
/* We are not parsing a function body. */
parser->in_function_body = false;
+ /* We can correct until told otherwise. */
+ parser->colon_corrects_to_scope_p = true;
+
/* The unparsed function queue is empty. */
push_unparsed_function_queues (parser);
template-id), nor a `::', then we are not looking at a
nested-name-specifier. */
token = cp_lexer_peek_nth_token (parser->lexer, 2);
+
+ if (token->type == CPP_COLON
+ && parser->colon_corrects_to_scope_p
+ && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_NAME)
+ {
+ error_at (token->location,
+ "found %<:%> in nested-name-specifier, expected %<::%>");
+ token->type = CPP_SCOPE;
+ }
+
if (token->type != CPP_SCOPE
&& !cp_parser_nth_token_starts_template_argument_list_p
(parser, 2))
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-id )
+ alignof ( type-id ) [C++0x]
new-expression
delete-expression
__extension__ cast-expression
__alignof__ unary-expression
__alignof__ ( type-id )
+ alignof unary-expression [C++0x]
__real__ cast-expression
__imag__ cast-expression
&& identifier
if (TYPE_P (operand))
return cxx_sizeof_or_alignof_type (operand, op, true);
else
- return cxx_sizeof_or_alignof_expr (operand, op, true);
+ {
+ /* ISO C++ defines alignof only with types, not with
+ expressions. So pedwarn if alignof is used with a non-
+ type expression. However, __alignof__ is ok. */
+ if (!strcmp (IDENTIFIER_POINTER (token->u.value), "alignof"))
+ pedwarn (token->location, OPT_pedantic,
+ "ISO C++ does not allow %<alignof%> "
+ "with a non-type");
+
+ return cxx_sizeof_or_alignof_expr (operand, op, true);
+ }
}
case RID_NEW:
}
else
{
+ bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+ parser->colon_corrects_to_scope_p = false;
/* Parse the expression. */
c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_false_node;
expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
c_inhibit_evaluation_warnings +=
((logical_or_expr == truthvalue_true_node)
- (logical_or_expr == truthvalue_false_node));
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
}
/* The next token should be a `:'. */
{
cp_token *token;
tree label = NULL_TREE;
+ bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
/* The next token should be an identifier. */
token = cp_lexer_peek_token (parser->lexer);
return;
}
+ parser->colon_corrects_to_scope_p = false;
switch (token->keyword)
{
case RID_CASE:
else
cplus_decl_attributes (&label, attrs, 0);
}
+
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
}
/* Parse an expression-statement.
return cp_parser_expression (parser, /*cast_p=*/false, NULL);
}
-/* Parses a traditional for-statement until the closing ')', not included. */
+/* Parses a for-statement or range-for-statement until the closing ')',
+ not included. */
static tree
-cp_parser_c_for (cp_parser *parser)
+cp_parser_for (cp_parser *parser)
{
- /* Normal for loop */
- tree stmt;
- tree condition = NULL_TREE;
- tree expression = NULL_TREE;
+ tree init, scope, decl;
+ bool is_range_for;
/* Begin the for-statement. */
- stmt = begin_for_stmt ();
+ scope = begin_for_scope (&init);
/* Parse the initialization. */
- cp_parser_for_init_statement (parser);
+ is_range_for = cp_parser_for_init_statement (parser, &decl);
+
+ if (is_range_for)
+ return cp_parser_range_for (parser, scope, init, decl);
+ else
+ return cp_parser_c_for (parser, scope, init);
+}
+
+static tree
+cp_parser_c_for (cp_parser *parser, tree scope, tree init)
+{
+ /* Normal for loop */
+ tree condition = NULL_TREE;
+ tree expression = NULL_TREE;
+ tree stmt;
+
+ stmt = begin_for_stmt (scope, init);
+ /* The for-init-statement has already been parsed in
+ cp_parser_for_init_statement, so no work is needed here. */
finish_for_init_stmt (stmt);
/* If there's a condition, process it. */
/* Tries to parse a range-based for-statement:
range-based-for:
- type-specifier-seq declarator : expression
+ decl-specifier-seq declarator : expression
- If succesful, assigns to *DECL the DECLARATOR and to *EXPR the
- expression. Note that the *DECL is returned unfinished, so
- later you should call cp_finish_decl().
-
- Returns TRUE iff a range-based for is parsed. */
+ The decl-specifier-seq declarator and the `:' are already parsed by
+ cp_parser_for_init_statement. If processing_template_decl it returns a
+ newly created RANGE_FOR_STMT; if not, it is converted to a
+ regular FOR_STMT. */
static tree
-cp_parser_range_for (cp_parser *parser)
+cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl)
{
- tree stmt, range_decl, range_expr;
- cp_decl_specifier_seq type_specifiers;
- cp_declarator *declarator;
- const char *saved_message;
- tree attributes, pushed_scope;
+ tree stmt, range_expr;
- cp_parser_parse_tentatively (parser);
- /* New types are not allowed in the type-specifier-seq for a
- range-based for loop. */
- saved_message = parser->type_definition_forbidden_message;
- parser->type_definition_forbidden_message
- = G_("types may not be defined in range-based for loops");
- /* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, /*is_declaration==*/true,
- /*is_trailing_return=*/false,
- &type_specifiers);
- /* Restore the saved message. */
- parser->type_definition_forbidden_message = saved_message;
- /* If all is well, we might be looking at a declaration. */
- if (cp_parser_error_occurred (parser))
- {
- cp_parser_abort_tentative_parse (parser);
- return NULL_TREE;
- }
- /* Parse the declarator. */
- declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
- /*ctor_dtor_or_conv_p=*/NULL,
- /*parenthesized_p=*/NULL,
- /*member_p=*/false);
- /* Parse the attributes. */
- attributes = cp_parser_attributes_opt (parser);
- /* The next token should be `:'. */
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
- cp_parser_simulate_error (parser);
-
- /* Check if it is a range-based for */
- if (!cp_parser_parse_definitely (parser))
- return NULL_TREE;
-
- cp_parser_require (parser, CPP_COLON, RT_COLON);
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
bool expr_non_constant_p;
else
range_expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
- /* If in template, STMT is converted to a normal for-statements
+ /* If in template, STMT is converted to a normal for-statement
at instantiation. If not, it is done just ahead. */
if (processing_template_decl)
- stmt = begin_range_for_stmt ();
- else
- stmt = begin_for_stmt ();
-
- /* Create the declaration. It must be after begin{,_range}_for_stmt(). */
- range_decl = start_decl (declarator, &type_specifiers,
- /*initialized_p=*/SD_INITIALIZED,
- attributes, /*prefix_attributes=*/NULL_TREE,
- &pushed_scope);
- /* No scope allowed here */
- pop_scope (pushed_scope);
-
- if (TREE_CODE (stmt) == RANGE_FOR_STMT)
- finish_range_for_decl (stmt, range_decl, range_expr);
+ {
+ stmt = begin_range_for_stmt (scope, init);
+ finish_range_for_decl (stmt, range_decl, range_expr);
+ }
else
- /* Convert the range-based for loop into a normal for-statement. */
- stmt = cp_convert_range_for (stmt, range_decl, range_expr);
-
+ {
+ stmt = begin_for_stmt (scope, init);
+ stmt = cp_convert_range_for (stmt, range_decl, range_expr);
+ }
return stmt;
}
tree iter_type, begin_expr, end_expr;
tree condition, expression;
- /* Find out the type deduced by the declaration
- * `auto &&__range = range_expr' */
- range_type = cp_build_reference_type (make_auto (), true);
- range_type = do_auto_deduction (range_type, range_expr,
- type_uses_auto (range_type));
-
- /* Create the __range variable */
- range_temp = build_decl (input_location, VAR_DECL,
- get_identifier ("__for_range"), range_type);
- TREE_USED (range_temp) = 1;
- DECL_ARTIFICIAL (range_temp) = 1;
- pushdecl (range_temp);
- cp_finish_decl (range_temp, range_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
-
- range_temp = convert_from_reference (range_temp);
-
- if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE)
- {
- /* If RANGE_TEMP is an array we will use pointer arithmetic */
- iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_temp)));
- begin_expr = range_temp;
- end_expr
- = build_binary_op (input_location, PLUS_EXPR,
- range_temp,
- array_type_nelts_top (TREE_TYPE (range_temp)), 0);
- }
+ if (range_decl == error_mark_node || range_expr == error_mark_node)
+ /* If an error happened previously do nothing or else a lot of
+ unhelpful errors would be issued. */
+ begin_expr = end_expr = iter_type = error_mark_node;
else
{
- /* If it is not an array, we must call begin(__range)/end__range() */
- VEC(tree,gc) *vec;
-
- begin_expr = get_identifier ("begin");
- vec = make_tree_vector ();
- VEC_safe_push (tree, gc, vec, range_temp);
- begin_expr = perform_koenig_lookup (begin_expr, vec,
- /*include_std=*/true);
- begin_expr = finish_call_expr (begin_expr, &vec, false, true,
- tf_warning_or_error);
- release_tree_vector (vec);
-
- end_expr = get_identifier ("end");
- vec = make_tree_vector ();
- VEC_safe_push (tree, gc, vec, range_temp);
- end_expr = perform_koenig_lookup (end_expr, vec,
- /*include_std=*/true);
- end_expr = finish_call_expr (end_expr, &vec, false, true,
- tf_warning_or_error);
- release_tree_vector (vec);
-
- /* The unqualified type of the __begin and __end temporaries should
- * be the same as required by the multiple auto declaration */
- iter_type = cv_unqualified (TREE_TYPE (begin_expr));
- if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (end_expr))))
- error ("inconsistent begin/end types in range-based for: %qT and %qT",
- TREE_TYPE (begin_expr), TREE_TYPE (end_expr));
+ /* Find out the type deduced by the declaration
+ * `auto &&__range = range_expr' */
+ range_type = cp_build_reference_type (make_auto (), true);
+ range_type = do_auto_deduction (range_type, range_expr,
+ type_uses_auto (range_type));
+
+ /* Create the __range variable */
+ range_temp = build_decl (input_location, VAR_DECL,
+ get_identifier ("__for_range"), range_type);
+ TREE_USED (range_temp) = 1;
+ DECL_ARTIFICIAL (range_temp) = 1;
+ pushdecl (range_temp);
+ cp_finish_decl (range_temp, range_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+
+ range_temp = convert_from_reference (range_temp);
+
+ if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE)
+ {
+ /* If RANGE_TEMP is an array we will use pointer arithmetic */
+ iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_temp)));
+ begin_expr = range_temp;
+ end_expr
+ = build_binary_op (input_location, PLUS_EXPR,
+ range_temp,
+ array_type_nelts_top (TREE_TYPE (range_temp)),
+ 0);
+ }
+ else
+ {
+ /* If it is not an array, we must call begin(__range)/end__range() */
+ VEC(tree,gc) *vec;
+
+ begin_expr = get_identifier ("begin");
+ vec = make_tree_vector ();
+ VEC_safe_push (tree, gc, vec, range_temp);
+ begin_expr = perform_koenig_lookup (begin_expr, vec,
+ /*include_std=*/true);
+ begin_expr = finish_call_expr (begin_expr, &vec, false, true,
+ tf_warning_or_error);
+ release_tree_vector (vec);
+
+ end_expr = get_identifier ("end");
+ vec = make_tree_vector ();
+ VEC_safe_push (tree, gc, vec, range_temp);
+ end_expr = perform_koenig_lookup (end_expr, vec,
+ /*include_std=*/true);
+ end_expr = finish_call_expr (end_expr, &vec, false, true,
+ tf_warning_or_error);
+ release_tree_vector (vec);
+
+ /* The unqualified type of the __begin and __end temporaries should
+ * be the same as required by the multiple auto declaration */
+ iter_type = cv_unqualified (TREE_TYPE (begin_expr));
+ if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (end_expr))))
+ error ("inconsistent begin/end types in range-based for: %qT and %qT",
+ TREE_TYPE (begin_expr), TREE_TYPE (end_expr));
+ }
}
/* The new for initialization statement */
/* Look for the `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
- if (cxx_dialect == cxx0x)
- statement = cp_parser_range_for (parser);
- else
- statement = NULL_TREE;
- if (statement == NULL_TREE)
- statement = cp_parser_c_for (parser);
+ statement = cp_parser_for (parser);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
return statement;
}
-/* Parse a for-init-statement.
+/* Parse a for-init-statement or the declarator of a range-based-for.
+ Returns true if a range-based-for declaration is seen.
for-init-statement:
expression-statement
simple-declaration */
-static void
-cp_parser_for_init_statement (cp_parser* parser)
+static bool
+cp_parser_for_init_statement (cp_parser* parser, tree *decl)
{
/* If the next token is a `;', then we have an empty
expression-statement. Grammatically, this is also a
declaration. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
+ bool is_range_for = false;
+ bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+
+ parser->colon_corrects_to_scope_p = false;
+
/* We're going to speculatively look for a declaration, falling back
to an expression, if necessary. */
cp_parser_parse_tentatively (parser);
/* Parse the declaration. */
cp_parser_simple_declaration (parser,
- /*function_definition_allowed_p=*/false);
+ /*function_definition_allowed_p=*/false,
+ decl);
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+ {
+ /* It is a range-for, consume the ':' */
+ cp_lexer_consume_token (parser->lexer);
+ is_range_for = true;
+ if (cxx_dialect < cxx0x)
+ {
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "range-based-for loops are not allowed "
+ "in C++98 mode");
+ *decl = error_mark_node;
+ }
+ }
+ else
+ /* The ';' is not consumed yet because we told
+ cp_parser_simple_declaration not to. */
+ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+
+ if (cp_parser_parse_definitely (parser))
+ return is_range_for;
/* If the tentative parse failed, then we shall need to look for an
expression-statement. */
- if (cp_parser_parse_definitely (parser))
- return;
}
-
+ /* If we are here, it is an expression-statement. */
cp_parser_expression_statement (parser, NULL_TREE);
+ return false;
}
/* Parse a jump-statement.
cp_parser_static_assert (parser, /*member_p=*/false);
/* Anything else must be a simple-declaration. */
else
- cp_parser_simple_declaration (parser, !statement_p);
+ cp_parser_simple_declaration (parser, !statement_p,
+ /*maybe_range_for_decl*/NULL);
}
/* Parse a simple-declaration.
init-declarator-list , init-declarator
If FUNCTION_DEFINITION_ALLOWED_P is TRUE, then we also recognize a
- function-definition as a simple-declaration. */
+ function-definition as a simple-declaration.
+
+ If MAYBE_RANGE_FOR_DECL is not NULL, the pointed tree will be set to the
+ parsed declaration if it is an uninitialized single declarator not followed
+ by a `;', or to error_mark_node otherwise. Either way, the trailing `;',
+ if present, will not be consumed. */
static void
cp_parser_simple_declaration (cp_parser* parser,
- bool function_definition_allowed_p)
+ bool function_definition_allowed_p,
+ tree *maybe_range_for_decl)
{
cp_decl_specifier_seq decl_specifiers;
int declares_class_or_enum;
bool saw_declarator;
+ if (maybe_range_for_decl)
+ *maybe_range_for_decl = NULL_TREE;
+
/* Defer access checks until we know what is being declared; the
checks for names appearing in the decl-specifier-seq should be
done as if we were in the scope of the thing being declared. */
token = cp_lexer_peek_token (parser->lexer);
gcc_assert (token->type == CPP_COMMA);
cp_lexer_consume_token (parser->lexer);
+ if (maybe_range_for_decl)
+ *maybe_range_for_decl = error_mark_node;
}
else
saw_declarator = true;
function_definition_allowed_p,
/*member_p=*/false,
declares_class_or_enum,
- &function_definition_p);
+ &function_definition_p,
+ maybe_range_for_decl);
/* If an error occurred while parsing tentatively, exit quickly.
(That usually happens when in the body of a function; each
statement is treated as a declaration-statement until proven
return;
}
}
+ if (maybe_range_for_decl && *maybe_range_for_decl == NULL_TREE)
+ *maybe_range_for_decl = decl;
/* The next token should be either a `,' or a `;'. */
token = cp_lexer_peek_token (parser->lexer);
/* If it's a `,', there are more declarators to come. */
if (token->type == CPP_COMMA)
/* will be consumed next time around */;
/* If it's a `;', we are done. */
- else if (token->type == CPP_SEMICOLON)
+ else if (token->type == CPP_SEMICOLON || maybe_range_for_decl)
break;
/* Anything else is an error. */
else
}
/* Consume the `;'. */
- cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+ if (!maybe_range_for_decl)
+ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
done:
pop_deferring_access_checks ();
bool is_anonymous = false;
tree underlying_type = NULL_TREE;
cp_token *type_start_token = NULL;
+ bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+
+ parser->colon_corrects_to_scope_p = false;
/* Parse tentatively so that we can back up if we don't find a
enum-specifier. */
{
cp_parser_error (parser, "expected %<{%>");
if (has_underlying_type)
- return NULL_TREE;
+ {
+ type = NULL_TREE;
+ goto out;
+ }
}
/* An opaque-enum-specifier must have a ';' here. */
if ((scoped_enum_p || underlying_type)
{
cp_parser_error (parser, "expected %<;%> or %<{%>");
if (has_underlying_type)
- return NULL_TREE;
+ {
+ type = NULL_TREE;
+ goto out;
+ }
}
}
pop_nested_namespace (nested_name_specifier);
}
}
+ out:
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
return type;
}
have been completely parsed.
FUNCTION_DEFINITION_P may be NULL if FUNCTION_DEFINITION_ALLOWED_P
- is FALSE. */
+ is FALSE.
+
+ If MAYBE_RANGE_FOR_DECL is not NULL, the pointed tree will be set to the
+ parsed declaration if it is an uninitialized single declarator not followed
+ by a `;', or to error_mark_node otherwise. Either way, the trailing `;',
+ if present, will not be consumed. If returned, this declarator will be
+ created with SD_INITIALIZED but will not call cp_finish_decl. */
static tree
cp_parser_init_declarator (cp_parser* parser,
bool function_definition_allowed_p,
bool member_p,
int declares_class_or_enum,
- bool* function_definition_p)
+ bool* function_definition_p,
+ tree* maybe_range_for_decl)
{
cp_token *token = NULL, *asm_spec_start_token = NULL,
*attributes_start_token = NULL;
int ctor_dtor_or_conv_p;
bool friend_p;
tree pushed_scope = NULL;
+ bool range_for_decl_p = false;
/* Gather the attributes that were provided with the
decl-specifiers. */
{
is_initialized = SD_INITIALIZED;
initialization_kind = token->type;
+ if (maybe_range_for_decl)
+ *maybe_range_for_decl = error_mark_node;
if (token->type == CPP_EQ
&& function_declarator_p (declarator))
if (token->type != CPP_COMMA
&& token->type != CPP_SEMICOLON)
{
- cp_parser_error (parser, "expected initializer");
- return error_mark_node;
+ if (maybe_range_for_decl && *maybe_range_for_decl != error_mark_node)
+ range_for_decl_p = true;
+ else
+ {
+ cp_parser_error (parser, "expected initializer");
+ return error_mark_node;
+ }
}
is_initialized = SD_UNINITIALIZED;
initialization_kind = CPP_EOF;
if (parser->in_unbraced_linkage_specification_p)
decl_specifiers->storage_class = sc_extern;
decl = start_decl (declarator, decl_specifiers,
- is_initialized, attributes, prefix_attributes,
+ range_for_decl_p? SD_INITIALIZED : is_initialized,
+ attributes, prefix_attributes,
&pushed_scope);
/* Adjust location of decl if declarator->id_loc is more appropriate:
set, and decl wasn't merged with another decl, in which case its
/* Finish processing the declaration. But, skip friend
declarations. */
- if (!friend_p && decl && decl != error_mark_node)
+ if (!friend_p && decl && decl != error_mark_node && !range_for_decl_p)
{
cp_finish_decl (decl,
initializer, !is_non_constant_init,
class Z { }
static const <type> var = ...; */
case CPP_KEYWORD:
- if (keyword_is_storage_class_specifier (token->keyword)
- || keyword_is_type_qualifier (token->keyword))
+ if (keyword_is_decl_specifier (token->keyword))
{
cp_token *lookahead = cp_lexer_peek_nth_token (parser->lexer, 2);
- if (lookahead->type == CPP_KEYWORD
- && !keyword_begins_type_specifier (lookahead->keyword))
- want_semicolon = false;
- else if (lookahead->type == CPP_NAME)
- /* Handling user-defined types here would be nice, but
- very tricky. */
- want_semicolon = false;
+ /* Handling user-defined types here would be nice, but very
+ tricky. */
+ want_semicolon
+ = (lookahead->type == CPP_KEYWORD
+ && keyword_begins_type_specifier (lookahead->keyword));
}
break;
default:
bool qualified_p = false;
bool invalid_nested_name_p = false;
bool invalid_explicit_specialization_p = false;
+ bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
tree pushed_scope = NULL_TREE;
unsigned num_templates;
cp_token *type_start_token = NULL, *nested_name_specifier_token_start = NULL;
/* Assume no template parameter lists will be used in defining the
type. */
num_templates = 0;
+ parser->colon_corrects_to_scope_p = false;
*bases = NULL_TREE;
if (!cp_parser_next_token_starts_class_definition_p (parser))
{
cp_parser_error (parser, "expected %<{%> or %<:%>");
- return error_mark_node;
+ type = error_mark_node;
+ goto out;
}
/* At this point, we're going ahead with the class-specifier, even
{
cp_parser_error (parser,
"global qualification of class name is invalid");
- return error_mark_node;
+ type = error_mark_node;
+ goto out;
}
else if (invalid_nested_name_p)
{
cp_parser_error (parser,
"qualified name does not name a class");
- return error_mark_node;
+ type = error_mark_node;
+ goto out;
}
else if (nested_name_specifier)
{
if (type)
DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
*attributes_p = attributes;
+ out:
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
return type;
}
cp_token *decl_spec_token_start = NULL;
cp_token *initializer_token_start = NULL;
int saved_pedantic;
+ bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
/* Check for the `__extension__' keyword. */
if (cp_parser_extension_opt (parser, &saved_pedantic))
return;
}
+ parser->colon_corrects_to_scope_p = false;
+
if (cp_parser_using_declaration (parser, /*access_declaration=*/true))
- return;
+ goto out;
/* Parse the decl-specifier-seq. */
decl_spec_token_start = cp_lexer_peek_token (parser->lexer);
/* Check for an invalid type-name. */
if (!decl_specifiers.any_type_specifiers_p
&& cp_parser_parse_and_diagnose_invalid_type_name (parser))
- return;
+ goto out;
/* If there is no declarator, then the decl-specifier-seq should
specify a type. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
if (cp_lexer_next_token_is (parser->lexer,
CPP_SEMICOLON))
cp_lexer_consume_token (parser->lexer);
- return;
+ goto out;
}
if (declares_class_or_enum & 2)
/* If the next token is a semicolon, consume it. */
if (token->type == CPP_SEMICOLON)
cp_lexer_consume_token (parser->lexer);
- return;
+ goto out;
}
else
if (declarator->kind == cdk_function)
}
if (assume_semicolon)
- return;
+ goto out;
}
}
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+ out:
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
}
/* Parse a pure-specifier.
parameter_list = NULL_TREE;
}
else
- /* Parse the template parameters. */
- parameter_list = cp_parser_template_parameter_list (parser);
+ {
+ /* Parse the template parameters. */
+ parameter_list = cp_parser_template_parameter_list (parser);
+ fixup_template_parms ();
+ }
/* Get the deferred access checks from the parameter list. These
will be checked once we know what is being declared, as for a
/*function_definition_allowed_p=*/true,
member_p,
declares_class_or_enum,
- &function_definition_p);
+ &function_definition_p,
+ NULL);
/* 7.1.1-1 [dcl.stc]
/* An ObjC type name may consist of just protocol qualifiers, in which
case the type shall default to 'id'. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
- cp_type = cp_parser_type_id (parser);
+ {
+ cp_type = cp_parser_type_id (parser);
+
+ /* If the type could not be parsed, an error has already
+ been produced. For error recovery, behave as if it had
+ not been specified, which will use the default type
+ 'id'. */
+ if (cp_type == error_mark_node)
+ {
+ cp_type = NULL_TREE;
+ /* We need to skip to the closing parenthesis as
+ cp_parser_type_id() does not seem to do it for
+ us. */
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/false);
+ }
+ }
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
type_name = build_tree_list (proto_quals, cp_type);
cp_parser_require_keyword (parser, RID_AT_TRY, RT_AT_TRY);
location = cp_lexer_peek_token (parser->lexer)->location;
+ objc_maybe_warn_exceptions (location);
/* NB: The @try block needs to be wrapped in its own STATEMENT_LIST
node, lest it get absorbed into the surrounding block. */
stmt = push_stmt_list ();
cp_parser_require_keyword (parser, RID_AT_SYNCHRONIZED, RT_AT_SYNCHRONIZED);
location = cp_lexer_peek_token (parser->lexer)->location;
+ objc_maybe_warn_exceptions (location);
cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
lock = cp_parser_expression (parser, false, NULL);
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
case RID_SETTER:
if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ))
{
- cp_parser_error (parser,
- "getter/setter/ivar attribute must be followed by %<=%>");
+ if (keyword == RID_GETTER)
+ cp_parser_error (parser,
+ "missing %<=%> (after %<getter%> attribute)");
+ else
+ cp_parser_error (parser,
+ "missing %<=%> (after %<setter%> attribute)");
syntax_error = true;
break;
}
if (syntax_error)
break;
-
+
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
else
break;
}
+ /* FIXME: "@property (setter, assign);" will generate a spurious
+ "error: expected ‘)’ before ‘,’ token". This is because
+ cp_parser_require, unlike the C counterpart, will produce an
+ error even if we are in error recovery. */
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
{
cp_parser_skip_to_closing_parenthesis (parser,