#include "c-tree.h"
#include "flags.h"
#include "output.h"
-#include "toplev.h"
#include "ggc.h"
#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
#include "vec.h"
#include "target.h"
#include "cgraph.h"
return c_token_starts_typename (token);
}
+/* Return true if TOKEN is a type qualifier, false otherwise. */
+static bool
+c_token_is_qualifier (c_token *token)
+{
+ switch (token->type)
+ {
+ case CPP_NAME:
+ switch (token->id_kind)
+ {
+ case C_ID_ADDRSPACE:
+ return true;
+ default:
+ return false;
+ }
+ case CPP_KEYWORD:
+ switch (token->keyword)
+ {
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ case RID_ATTRIBUTE:
+ return true;
+ default:
+ return false;
+ }
+ case CPP_LESS:
+ return false;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return true if the next token from PARSER is a type qualifier,
+ false otherwise. */
+static inline bool
+c_parser_next_token_is_qualifier (c_parser *parser)
+{
+ c_token *token = c_parser_peek_token (parser);
+ return c_token_is_qualifier (token);
+}
+
/* Return true if TOKEN can start declaration specifiers, false
otherwise. */
static bool
return c_token_starts_declspecs (token);
}
-/* Return true if the next token from PARSER can start declaration
+/* Return true if the next tokens from PARSER can start declaration
specifiers or a static assertion, false otherwise. */
static inline bool
-c_parser_next_token_starts_declaration (c_parser *parser)
+c_parser_next_tokens_start_declaration (c_parser *parser)
{
c_token *token = c_parser_peek_token (parser);
&& c_parser_peek_2nd_token (parser)->type == CPP_DOT)
return false;
- return c_token_starts_declaration (token);
+ /* Labels do not start declarations. */
+ if (token->type == CPP_NAME
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ return false;
+
+ if (c_token_starts_declaration (token))
+ return true;
+
+ /* Try a bit harder to detect an unknown typename. */
+ if (token->type == CPP_NAME
+ && token->id_kind == C_ID_ID
+ && (c_parser_peek_2nd_token (parser)->type == CPP_NAME
+ || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+ && !lookup_name (token->value)
+
+ /* Do not try too hard when we could have "object in array". */
+ && !parser->objc_could_be_foreach_context)
+ return true;
+
+ return false;
}
/* Return a pointer to the next-but-one token from PARSER, reading it
static tree c_parser_objc_method_decl (c_parser *, bool, tree *);
static tree c_parser_objc_type_name (c_parser *);
static tree c_parser_objc_protocol_refs (c_parser *);
-static void c_parser_objc_try_catch_statement (c_parser *);
+static void c_parser_objc_try_catch_finally_statement (c_parser *);
static void c_parser_objc_synchronized_statement (c_parser *);
static tree c_parser_objc_selector (c_parser *);
static tree c_parser_objc_selector_arg (c_parser *);
return;
}
specs = build_null_declspecs ();
+
+ /* 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
+ && (c_parser_peek_2nd_token (parser)->type == CPP_NAME
+ || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+ && (!nested || !lookup_name (c_parser_peek_token (parser)->value)))
+ {
+ error_at (here, "unknown type name %qE",
+ c_parser_peek_token (parser)->value);
+
+ /* Parse declspecs normally to get a correct pointer type, but avoid
+ a further "fails to be a type name" error. Refuse nested functions
+ since it is not how the user likely wants us to recover. */
+ c_parser_peek_token (parser)->type = CPP_KEYWORD;
+ c_parser_peek_token (parser)->keyword = RID_VOID;
+ c_parser_peek_token (parser)->value = error_mark_node;
+ fndef_ok = !nested;
+ }
+
c_parser_declspecs (parser, specs, true, true, start_attr_ok);
if (parser->error)
{
c_parser_consume_token (parser);
return;
}
+
+ /* Provide better error recovery. Note that a type name here is usually
+ better diagnosed as a redeclaration. */
+ if (empty_ok
+ && specs->typespec_kind == ctsk_tagdef
+ && c_parser_next_token_starts_declspecs (parser)
+ && !c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
+ parser->error = false;
+ shadow_tag_warned (specs, 1);
+ return;
+ }
else if (c_dialect_objc ())
{
/* Prefix attributes are an error on method decls. */
should diagnose if there were no declaration specifiers) or a
function definition (in which case the diagnostic for
implicit int suffices). */
- declarator = c_parser_declarator (parser, specs->type_seen_p,
+ declarator = c_parser_declarator (parser,
+ specs->typespec_kind != ctsk_none,
C_DTR_NORMAL, &dummy);
if (declarator == NULL)
{
bool scspec_ok, bool typespec_ok, bool start_attr_ok)
{
bool attrs_ok = start_attr_ok;
- bool seen_type = specs->type_seen_p;
- while (c_parser_next_token_is (parser, CPP_NAME)
+ bool seen_type = specs->typespec_kind != ctsk_none;
+ while ((c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_token (parser)->id_kind != C_ID_ID)
|| c_parser_next_token_is (parser, CPP_KEYWORD)
|| (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
{
struct c_typespec t;
tree attrs;
location_t loc = c_parser_peek_token (parser)->location;
+
+ if (!c_parser_next_token_is_qualifier (parser))
+ {
+ /* Exit for TYPENAMEs after any type because they can appear as a
+ field name. */
+ if (seen_type && c_parser_next_token_is (parser, CPP_NAME))
+ break;
+
+ /* If we cannot accept a type, and the next token must start one,
+ exit. Do the same if we already have seen a tagged definition,
+ since it would be an error anyway and likely the user has simply
+ forgotten a semicolon. */
+ if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef)
+ && c_parser_next_token_starts_typename (parser))
+ break;
+ }
+
if (c_parser_next_token_is (parser, CPP_NAME))
{
tree value = c_parser_peek_token (parser)->value;
continue;
}
- /* This finishes the specifiers unless a type name is OK, it
- is declared as a type name and a type name hasn't yet
- been seen. */
- if (!typespec_ok || seen_type
- || (kind != C_ID_TYPENAME && kind != C_ID_CLASSNAME))
- break;
+ /* Now at a C_ID_TYPENAME or C_ID_CLASSNAME. */
c_parser_consume_token (parser);
seen_type = true;
attrs_ok = true;
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
pedwarn (c_parser_peek_token (parser)->location, 0,
"no semicolon at end of struct or union");
- else
+ else if (parser->error
+ || !c_parser_next_token_starts_declspecs (parser))
{
c_parser_error (parser, "expected %<;%>");
c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
break;
}
+
+ /* If we come here, we have already emitted an error
+ for an expected `;', identifier or `(', and we also
+ recovered already. Go on with the next field. */
}
}
postfix_attrs = c_parser_attributes (parser);
return NULL_TREE;
}
finish_declspecs (specs);
- if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+ || c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
tree ret;
- if (!specs->type_seen_p)
+ if (specs->typespec_kind == ctsk_none)
{
pedwarn (decl_loc, OPT_pedantic,
"ISO C forbids member declarations with no members");
}
return ret;
}
+
+ /* Provide better error recovery. Note that a type name here is valid,
+ and will be treated as a field name. */
+ if (specs->typespec_kind == ctsk_tagdef
+ && TREE_CODE (specs->type) != ENUMERAL_TYPE
+ && c_parser_next_token_starts_declspecs (parser)
+ && !c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
+ parser->error = false;
+ return NULL_TREE;
+ }
+
pending_xref_error ();
prefix_attrs = specs->attrs;
all_prefix_attrs = prefix_attrs;
if (c_parser_next_token_is (parser, CPP_COLON))
declarator = build_id_declarator (NULL_TREE);
else
- declarator = c_parser_declarator (parser, specs->type_seen_p,
+ declarator = c_parser_declarator (parser,
+ specs->typespec_kind != ctsk_none,
C_DTR_NORMAL, &dummy);
if (declarator == NULL)
{
error_at (here, "%<typeof%> applied to a bit-field");
mark_exp_read (expr.value);
ret.spec = TREE_TYPE (expr.value);
- if (c_dialect_objc()
- && ret.spec != error_mark_node
- && lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (ret.spec)))
- ret.spec = build_qualified_type
- (ret.spec, (TYPE_QUALS (ret.spec) & ~TYPE_QUAL_VOLATILE));
was_vm = variably_modified_type_p (ret.spec, NULL_TREE);
/* This is returned with the type so that when the type is
evaluated, this can be evaluated. */
pending_xref_error ();
prefix_attrs = specs->attrs;
specs->attrs = NULL_TREE;
- declarator = c_parser_declarator (parser, specs->type_seen_p,
+ declarator = c_parser_declarator (parser,
+ specs->typespec_kind != ctsk_none,
C_DTR_PARM, &dummy);
if (declarator == NULL)
{
/* Parse the attribute contents. If they start with an
identifier which is followed by a comma or close
parenthesis, then the arguments start with that
- identifier; otherwise they are an expression list. */
+ identifier; otherwise they are an expression list.
+ In objective-c the identifier may be a classname. */
if (c_parser_next_token_is (parser, CPP_NAME)
- && c_parser_peek_token (parser)->id_kind == C_ID_ID
+ && (c_parser_peek_token (parser)->id_kind == C_ID_ID
+ || (c_dialect_objc ()
+ && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
&& ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
|| (c_parser_peek_2nd_token (parser)->type
== CPP_CLOSE_PAREN)))
}
pending_xref_error ();
finish_declspecs (specs);
- declarator = c_parser_declarator (parser, specs->type_seen_p,
+ declarator = c_parser_declarator (parser,
+ specs->typespec_kind != ctsk_none,
C_DTR_ABSTRACT, &dummy);
if (declarator == NULL)
return NULL;
c_parser_label (parser);
}
else if (!last_label
- && c_parser_next_token_starts_declaration (parser))
+ && c_parser_next_tokens_start_declaration (parser))
{
last_label = false;
mark_valid_location_for_stdc_pragma (false);
}
if (label)
{
- if (c_parser_next_token_starts_declaration (parser)
- && !(c_parser_next_token_is (parser, CPP_NAME)
- && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+ if (c_parser_next_tokens_start_declaration (parser))
{
error_at (c_parser_peek_token (parser)->location,
"a label can only be part of a statement and "
break;
case RID_AT_TRY:
gcc_assert (c_dialect_objc ());
- c_parser_objc_try_catch_statement (parser);
+ c_parser_objc_try_catch_finally_statement (parser);
break;
case RID_AT_SYNCHRONIZED:
gcc_assert (c_dialect_objc ());
{
/* Parse the initialization declaration or expression. */
object_expression = error_mark_node;
+ parser->objc_could_be_foreach_context = c_dialect_objc ();
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
+ parser->objc_could_be_foreach_context = false;
c_parser_consume_token (parser);
c_finish_expr_stmt (loc, NULL_TREE);
}
- else if (c_parser_next_token_starts_declaration (parser))
+ else if (c_parser_next_tokens_start_declaration (parser))
{
- parser->objc_could_be_foreach_context = true;
c_parser_declaration_or_fndef (parser, true, true, true, true, true,
&object_expression);
parser->objc_could_be_foreach_context = false;
int ext;
ext = disable_extension_diagnostics ();
c_parser_consume_token (parser);
- parser->objc_could_be_foreach_context = true;
c_parser_declaration_or_fndef (parser, true, true, true, true,
true, &object_expression);
parser->objc_could_be_foreach_context = false;
init_expr:
{
tree init_expression;
- parser->objc_could_be_foreach_context = true;
init_expression = c_parser_expression (parser).value;
parser->objc_could_be_foreach_context = false;
if (c_parser_next_token_is_keyword (parser, RID_IN))
is_foreach_statement = true;
if (! lvalue_p (init_expression))
c_parser_error (parser, "invalid iterating variable in fast enumeration");
- object_expression = c_process_expr_stmt (loc, init_expression);
-
+ object_expression = c_fully_fold (init_expression, false, NULL);
}
else
{
}
/* Parse the loop condition. In the case of a foreach
statement, there is no loop condition. */
+ gcc_assert (!parser->objc_could_be_foreach_context);
if (!is_foreach_statement)
{
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
else
{
if (is_foreach_statement)
- collection_expression = c_process_expr_stmt (loc, c_parser_expression (parser).value);
+ collection_expression = c_fully_fold (c_parser_expression (parser).value,
+ false, NULL);
else
incr = c_process_expr_stmt (loc, c_parser_expression (parser).value);
}
objc-class-instance-variables[opt]
@interface identifier ( identifier ) objc-protocol-refs[opt]
objc-methodprotolist @end
+ @interface identifier ( ) objc-protocol-refs[opt]
+ objc-methodprotolist @end
@implementation identifier ( identifier )
objc-superclass:
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
{
+ /* We have a category or class extension. */
tree id2;
tree proto = NULL_TREE;
c_parser_consume_token (parser);
if (c_parser_next_token_is_not (parser, CPP_NAME))
{
- c_parser_error (parser, "expected identifier");
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- return;
+ if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ /* We have a class extension. */
+ id2 = NULL_TREE;
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier or %<)%>");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return;
+ }
+ }
+ else
+ {
+ id2 = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
}
- id2 = c_parser_peek_token (parser)->value;
- c_parser_consume_token (parser);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
if (!iface_p)
{
break;
}
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- objc_declare_protocols (list);
+ objc_declare_protocols (list, attributes);
}
else
{
return list;
}
-/* Parse an objc-try-catch-statement.
+/* Parse an objc-try-catch-finally-statement.
- objc-try-catch-statement:
+ objc-try-catch-finally-statement:
@try compound-statement objc-catch-list[opt]
@try compound-statement objc-catch-list[opt] @finally compound-statement
objc-catch-list:
- @catch ( parameter-declaration ) compound-statement
- objc-catch-list @catch ( parameter-declaration ) compound-statement
-*/
+ @catch ( objc-catch-parameter-declaration ) compound-statement
+ objc-catch-list @catch ( objc-catch-parameter-declaration ) compound-statement
+
+ objc-catch-parameter-declaration:
+ parameter-declaration
+ '...'
+
+ where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS.
+
+ PS: This function is identical to cp_parser_objc_try_catch_finally_statement
+ for C++. Keep them in sync. */
static void
-c_parser_objc_try_catch_statement (c_parser *parser)
+c_parser_objc_try_catch_finally_statement (c_parser *parser)
{
- location_t loc;
+ location_t location;
tree stmt;
+
gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY));
c_parser_consume_token (parser);
- loc = c_parser_peek_token (parser)->location;
+ location = c_parser_peek_token (parser)->location;
stmt = c_parser_compound_statement (parser);
- objc_begin_try_stmt (loc, stmt);
+ objc_begin_try_stmt (location, stmt);
+
while (c_parser_next_token_is_keyword (parser, RID_AT_CATCH))
{
struct c_parm *parm;
+ tree parameter_declaration = error_mark_node;
+ bool seen_open_paren = false;
+
c_parser_consume_token (parser);
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
- break;
- parm = c_parser_parameter_declaration (parser, NULL_TREE);
- if (parm == NULL)
+ seen_open_paren = true;
+ if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- break;
+ /* We have "@catch (...)" (where the '...' are literally
+ what is in the code). Skip the '...'.
+ parameter_declaration is set to NULL_TREE, and
+ objc_being_catch_clauses() knows that that means
+ '...'. */
+ c_parser_consume_token (parser);
+ parameter_declaration = NULL_TREE;
}
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
- objc_begin_catch_clause (grokparm (parm));
+ else
+ {
+ /* We have "@catch (NSException *exception)" or something
+ like that. Parse the parameter declaration. */
+ parm = c_parser_parameter_declaration (parser, NULL_TREE);
+ if (parm == NULL)
+ parameter_declaration = error_mark_node;
+ else
+ parameter_declaration = grokparm (parm);
+ }
+ if (seen_open_paren)
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ else
+ {
+ /* If there was no open parenthesis, we are recovering from
+ an error, and we are trying to figure out what mistake
+ the user has made. */
+
+ /* If there is an immediate closing parenthesis, the user
+ probably forgot the opening one (ie, they typed "@catch
+ NSException *e)". Parse the closing parenthesis and keep
+ going. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+
+ /* If these is no immediate closing parenthesis, the user
+ probably doesn't know that parenthesis are required at
+ all (ie, they typed "@catch NSException *e"). So, just
+ forget about the closing parenthesis and keep going. */
+ }
+ objc_begin_catch_clause (parameter_declaration);
if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
c_parser_compound_statement_nostart (parser);
objc_finish_catch_clause ();
}
if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY))
{
- location_t finloc;
- tree finstmt;
c_parser_consume_token (parser);
- finloc = c_parser_peek_token (parser)->location;
- finstmt = c_parser_compound_statement (parser);
- objc_build_finally_clause (finloc, finstmt);
+ location = c_parser_peek_token (parser)->location;
+ stmt = c_parser_compound_statement (parser);
+ objc_build_finally_clause (location, stmt);
}
objc_finish_try_stmt ();
}
c_parser_objc_diagnose_bad_element_prefix (c_parser *parser,
struct c_declspecs *specs)
{
- if (!specs->declspecs_seen_p || specs->type_seen_p || specs->non_sc_seen_p)
+ if (!specs->declspecs_seen_p || specs->non_sc_seen_p
+ || specs->typespec_kind != ctsk_none)
{
c_parser_error (parser,
"no type or storage class may be specified here,");
goto pop_scopes;
/* Parse the initialization declaration or expression. */
- if (c_parser_next_token_starts_declaration (parser))
+ if (c_parser_next_tokens_start_declaration (parser))
{
if (i > 0)
VEC_safe_push (tree, gc, for_block, c_begin_compound_stmt (true));