/* Parser for C and Objective-C.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Parser actions based on the old Bison parser; structure somewhat
#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"
/* We found an Objective-C "pq" keyword (in, out,
inout, bycopy, byref, oneway). They need special
care because the interpretation depends on the
- context.
- */
+ context. */
if (parser->objc_pq_context)
{
token->type = CPP_KEYWORD;
you can't use 'in' as the name of the running
variable in a C for loop. We could potentially
try to add code here to disambiguate, but it
- seems a reasonable limitation.
- */
+ seems a reasonable limitation. */
token->type = CPP_KEYWORD;
token->keyword = rid_code;
break;
}
/* Else, "pq" keywords outside of the "pq" context are
not keywords, and we fall through to the code for
- normal tokens.
- */
+ normal tokens. */
}
else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code))
{
- /* We found an Objective-C "property attribute" keyword
- (readonly, copies, getter, setter, ivar). These are
+ /* We found an Objective-C "property attribute"
+ keyword (getter, setter, readonly, etc). These are
only valid in the property context. */
if (parser->objc_property_attr_context)
{
protected, public, try, catch, throw) without a
preceding '@' sign. Do nothing and fall through to
the code for normal tokens (in C++ we would still
- consider the CXX ones keywords, but not in C).
- */
+ consider the CXX ones keywords, but not in C). */
;
}
else
variables and typedefs, and hence are shadowed by local
declarations. */
if (objc_interface_decl
- && (global_bindings_p ()
- || (!objc_force_identifier && !decl)))
+ && (!objc_force_identifier || global_bindings_p ()))
{
token->value = objc_interface_decl;
token->id_kind = C_ID_CLASSNAME;
return c_parser_peek_token (parser)->keyword == keyword;
}
+/* Return a pointer to the next-but-one token from PARSER, reading it
+ in if necessary. The next token is already read in. */
+
+static c_token *
+c_parser_peek_2nd_token (c_parser *parser)
+{
+ if (parser->tokens_avail >= 2)
+ return &parser->tokens[1];
+ gcc_assert (parser->tokens_avail == 1);
+ gcc_assert (parser->tokens[0].type != CPP_EOF);
+ gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
+ c_lex_one_token (parser, &parser->tokens[1]);
+ parser->tokens_avail = 2;
+ return &parser->tokens[1];
+}
+
/* Return true if TOKEN can start a type name,
false otherwise. */
static bool
}
}
+enum c_lookahead_kind {
+ /* Always treat unknown identifiers as typenames. */
+ cla_prefer_type,
+
+ /* Could be parsing a nonabstract declarator. Only treat an identifier
+ as a typename if followed by another identifier or a star. */
+ cla_nonabstract_decl,
+
+ /* Never treat identifiers as typenames. */
+ cla_prefer_id
+};
+
/* Return true if the next token from PARSER can start a type name,
- false otherwise. */
+ false otherwise. LA specifies how to do lookahead in order to
+ detect unknown type names. If unsure, pick CLA_PREFER_ID. */
+
static inline bool
-c_parser_next_token_starts_typename (c_parser *parser)
+c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la)
{
c_token *token = c_parser_peek_token (parser);
- return c_token_starts_typename (token);
+ if (c_token_starts_typename (token))
+ return true;
+
+ /* Try a bit harder to detect an unknown typename. */
+ if (la != cla_prefer_id
+ && token->type == CPP_NAME
+ && token->id_kind == C_ID_ID
+
+ /* Do not try too hard when we could have "object in array". */
+ && !parser->objc_could_be_foreach_context
+
+ && (la == cla_prefer_type
+ || c_parser_peek_2nd_token (parser)->type == CPP_NAME
+ || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+
+ /* Only unknown identifiers. */
+ && !lookup_name (token->value))
+ return true;
+
+ return false;
}
/* Return true if TOKEN is a type qualifier, false otherwise. */
return false;
}
-static c_token *c_parser_peek_2nd_token (c_parser *parser);
-
/* Return true if the next token from PARSER can start declaration
specifiers, false otherwise. */
static inline bool
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)
+ if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl))
return true;
return false;
}
-/* Return a pointer to the next-but-one token from PARSER, reading it
- in if necessary. The next token is already read in. */
-
-static c_token *
-c_parser_peek_2nd_token (c_parser *parser)
-{
- if (parser->tokens_avail >= 2)
- return &parser->tokens[1];
- gcc_assert (parser->tokens_avail == 1);
- gcc_assert (parser->tokens[0].type != CPP_EOF);
- gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
- c_lex_one_token (parser, &parser->tokens[1]);
- parser->tokens_avail = 2;
- return &parser->tokens[1];
-}
-
/* Consume the next token from PARSER. */
static void
| (warn_traditional << 2)
| (flag_iso << 3)
| (warn_long_long << 4)
- | (warn_cxx_compat << 5));
+ | (warn_cxx_compat << 5)
+ | (warn_overlength_strings << 6));
cpp_opts->cpp_pedantic = pedantic = 0;
warn_pointer_arith = 0;
cpp_opts->cpp_warn_traditional = warn_traditional = 0;
flag_iso = 0;
cpp_opts->cpp_warn_long_long = warn_long_long = 0;
warn_cxx_compat = 0;
+ warn_overlength_strings = 0;
return ret;
}
flag_iso = (flags >> 3) & 1;
cpp_opts->cpp_warn_long_long = warn_long_long = (flags >> 4) & 1;
warn_cxx_compat = (flags >> 5) & 1;
+ warn_overlength_strings = (flags >> 6) & 1;
}
/* Possibly kinds of declarator to parse. */
static void c_parser_static_assert_declaration_no_semi (c_parser *);
static void c_parser_static_assert_declaration (c_parser *);
static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
- bool);
+ bool, enum c_lookahead_kind);
static struct c_typespec c_parser_enum_specifier (c_parser *);
static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
static tree c_parser_struct_declaration (c_parser *);
bool,
struct c_declarator *);
static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree);
-static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree);
+static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree,
+ tree);
static struct c_parm *c_parser_parameter_declaration (c_parser *, tree);
static tree c_parser_simple_asm_expr (c_parser *);
static tree c_parser_attributes (c_parser *);
static void c_parser_objc_method_definition (c_parser *);
static void c_parser_objc_methodprotolist (c_parser *);
static void c_parser_objc_methodproto (c_parser *);
-static tree c_parser_objc_method_decl (c_parser *, bool, tree *);
+static tree c_parser_objc_method_decl (c_parser *, bool, tree *, 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 *);
fndef_ok = !nested;
}
- c_parser_declspecs (parser, specs, true, true, start_attr_ok);
+ c_parser_declspecs (parser, specs, true, true, start_attr_ok, cla_nonabstract_decl);
if (parser->error)
{
c_parser_skip_to_end_of_block_or_statement (parser);
case RID_AT_PROPERTY:
if (specs->attrs)
{
- c_parser_error (parser,
- "attributes may not be specified before" );
+ c_parser_error (parser, "unexpected attribute");
specs->attrs = NULL;
}
break;
{
struct c_declarator *declarator;
bool dummy = false;
+ timevar_id_t tv;
tree fnbody;
/* Declaring either one or more declarators (in which case we
should diagnose if there were no declaration specifiers) or a
c_pop_function_context ();
break;
}
+
+ if (DECL_DECLARED_INLINE_P (current_function_decl))
+ tv = TV_PARSE_INLINE;
+ else
+ tv = TV_PARSE_FUNC;
+ timevar_push (tv);
+
/* Parse old-style parameter declarations. ??? Attributes are
not allowed to start declaration specifiers here because of a
syntax conflict between a function declaration with attribute
add_stmt (fnbody);
finish_function ();
}
+
+ timevar_pop (tv);
break;
}
}
static void
c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
- bool scspec_ok, bool typespec_ok, bool start_attr_ok)
+ bool scspec_ok, bool typespec_ok, bool start_attr_ok,
+ enum c_lookahead_kind la)
{
bool attrs_ok = start_attr_ok;
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)
+
+ if (!typespec_ok)
+ gcc_assert (la == cla_prefer_id);
+
+ while (c_parser_next_token_is (parser, CPP_NAME)
|| c_parser_next_token_is (parser, CPP_KEYWORD)
|| (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
{
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 we cannot accept a type, exit if the next token must start
+ one. Also, if we already have seen a tagged definition,
+ a typename would be an error anyway and likely the user
+ has simply forgotten a semicolon, so we exit. */
+ if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef)
+ && c_parser_next_tokens_start_typename (parser, la)
+ && !c_parser_next_token_is_qualifier (parser))
+ break;
if (c_parser_next_token_is (parser, CPP_NAME))
{
continue;
}
- /* Now at a C_ID_TYPENAME or C_ID_CLASSNAME. */
+ gcc_assert (!c_parser_next_token_is_qualifier (parser));
+
+ /* 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 (seen_type || !c_parser_next_tokens_start_typename (parser, la))
+ break;
+
+ /* Now at an unknown typename (C_ID_ID), a C_ID_TYPENAME or
+ a C_ID_CLASSNAME. */
c_parser_consume_token (parser);
seen_type = true;
attrs_ok = true;
- if (kind == C_ID_TYPENAME
- && (!c_dialect_objc ()
- || c_parser_next_token_is_not (parser, CPP_LESS)))
+ if (kind == C_ID_ID)
+ {
+ error ("unknown type name %qE", value);
+ t.kind = ctsk_typedef;
+ t.spec = error_mark_node;
+ }
+ else if (kind == C_ID_TYPENAME
+ && (!c_dialect_objc ()
+ || c_parser_next_token_is_not (parser, CPP_LESS)))
{
t.kind = ctsk_typedef;
/* For a typedef name, record the meaning, not the name.
In case of 'foo foo, bar;'. */
t.spec = lookup_name (value);
- t.expr = NULL_TREE;
- t.expr_const_operands = true;
}
else
{
if (c_parser_next_token_is (parser, CPP_LESS))
proto = c_parser_objc_protocol_refs (parser);
t.spec = objc_get_protocol_qualified_type (value, proto);
- t.expr = NULL_TREE;
- t.expr_const_operands = true;
}
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
declspecs_add_type (loc, specs, t);
continue;
}
{
/* Parse an enum definition. */
struct c_enum_contents the_enum;
- tree type = start_enum (enum_loc, &the_enum, ident);
+ tree type;
tree postfix_attrs;
/* We chain the enumerators in reverse order, then put them in
forward order at the end. */
- tree values = NULL_TREE;
+ tree values;
+ timevar_push (TV_PARSE_ENUM);
+ type = start_enum (enum_loc, &the_enum, ident);
+ values = NULL_TREE;
c_parser_consume_token (parser);
while (true)
{
ret.kind = ctsk_tagdef;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
+ timevar_pop (TV_PARSE_ENUM);
return ret;
}
else if (!ident)
semicolon separated fields than comma separated fields, and
so we'll be minimizing the number of node traversals required
by chainon. */
- tree contents = NULL_TREE;
+ tree contents;
+ timevar_push (TV_PARSE_STRUCT);
+ contents = NULL_TREE;
c_parser_consume_token (parser);
/* Handle the Objective-C @defs construct,
e.g. foo(sizeof(struct{ @defs(ClassName) }));. */
ret.kind = ctsk_tagdef;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
+ timevar_pop (TV_PARSE_STRUCT);
return ret;
}
else if (!ident)
}
specs = build_null_declspecs ();
decl_loc = c_parser_peek_token (parser)->location;
- c_parser_declspecs (parser, specs, false, true, true);
+ c_parser_declspecs (parser, specs, false, true, true, cla_nonabstract_decl);
if (parser->error)
return NULL_TREE;
if (!specs->declspecs_seen_p)
in_typeof--;
return ret;
}
- if (c_parser_next_token_starts_typename (parser))
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
{
struct c_type_name *type = c_parser_type_name (parser);
c_inhibit_evaluation_warnings--;
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. */
struct c_declspecs *quals_attrs = build_null_declspecs ();
struct c_declarator *inner;
c_parser_consume_token (parser);
- c_parser_declspecs (parser, quals_attrs, false, false, true);
+ c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
if (inner == NULL)
return NULL;
bool star_seen;
tree dimen;
c_parser_consume_token (parser);
- c_parser_declspecs (parser, quals_attrs, false, false, true);
+ c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
if (static_seen)
c_parser_consume_token (parser);
if (static_seen && !quals_attrs->declspecs_seen_p)
- c_parser_declspecs (parser, quals_attrs, false, false, true);
+ c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
if (!quals_attrs->declspecs_seen_p)
quals_attrs = NULL;
/* If "static" is present, there must be an array dimension.
if (id_list_ok
&& !attrs
&& 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
+
+ /* Look ahead to detect typos in type names. */
+ && c_parser_peek_2nd_token (parser)->type != CPP_NAME
+ && c_parser_peek_2nd_token (parser)->type != CPP_MULT
+ && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN
+ && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE)
{
tree list = NULL_TREE, *nextp = &list;
while (c_parser_next_token_is (parser, CPP_NAME)
}
else
{
- struct c_arg_info *ret = c_parser_parms_list_declarator (parser, attrs);
+ struct c_arg_info *ret = c_parser_parms_list_declarator (parser, attrs,
+ NULL);
pop_scope ();
return ret;
}
/* Parse a parameter list (possibly empty), including the closing
parenthesis but not the opening one. ATTRS are the attributes at
- the start of the list. */
+ the start of the list. EXPR is NULL or an expression that needs to
+ be evaluated for the side effects of array size expressions in the
+ parameters. */
static struct c_arg_info *
-c_parser_parms_list_declarator (c_parser *parser, tree attrs)
+c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr)
{
bool bad_parm = false;
+
/* ??? Following the old parser, forward parameter declarations may
use abstract declarators, and if no real parameter declarations
follow the forward declarations then this is not diagnosed. Also
if (parm == NULL)
bad_parm = true;
else
- push_parm_decl (parm);
+ push_parm_decl (parm, &expr);
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
tree new_attrs;
c_parser_consume_token (parser);
mark_forward_parm_decls ();
new_attrs = c_parser_attributes (parser);
- return c_parser_parms_list_declarator (parser, new_attrs);
+ return c_parser_parms_list_declarator (parser, new_attrs, expr);
}
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
{
c_parser_consume_token (parser);
if (bad_parm)
- {
- get_pending_sizes ();
- return NULL;
- }
+ return NULL;
else
- return get_parm_info (false);
+ return get_parm_info (false, expr);
}
if (!c_parser_require (parser, CPP_COMMA,
"expected %<;%>, %<,%> or %<)%>"))
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
- get_pending_sizes ();
return NULL;
}
if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
c_parser_consume_token (parser);
if (bad_parm)
- {
- get_pending_sizes ();
- return NULL;
- }
+ return NULL;
else
- return get_parm_info (true);
+ return get_parm_info (true, expr);
}
else
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
- get_pending_sizes ();
return NULL;
}
}
if (parser->error)
return NULL;
c_parser_set_source_position_from_token (token);
- if (token->type == CPP_NAME
- && c_parser_peek_2nd_token (parser)->type != CPP_COMMA
- && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN)
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
{
error ("unknown type name %qE", token->value);
parser->error = true;
declspecs_add_attrs (specs, attrs);
attrs = NULL_TREE;
}
- c_parser_declspecs (parser, specs, true, true, true);
+ c_parser_declspecs (parser, specs, true, true, true, cla_nonabstract_decl);
finish_declspecs (specs);
pending_xref_error ();
prefix_attrs = specs->attrs;
c_parser_asm_string_literal (c_parser *parser)
{
tree str;
+ int save_flag = warn_overlength_strings;
+ warn_overlength_strings = 0;
if (c_parser_next_token_is (parser, CPP_STRING))
{
str = c_parser_peek_token (parser)->value;
c_parser_error (parser, "expected string literal");
str = NULL_TREE;
}
+ warn_overlength_strings = save_flag;
return str;
}
struct c_declarator *declarator;
struct c_type_name *ret;
bool dummy = false;
- c_parser_declspecs (parser, specs, false, true, true);
+ c_parser_declspecs (parser, specs, false, true, true, cla_prefer_type);
if (!specs->declspecs_seen_p)
{
c_parser_error (parser, "expected specifier-qualifier-list");
return NULL;
}
- pending_xref_error ();
- finish_declspecs (specs);
+ if (specs->type != error_mark_node)
+ {
+ pending_xref_error ();
+ finish_declspecs (specs);
+ }
declarator = c_parser_declarator (parser,
specs->typespec_kind != ctsk_none,
C_DTR_ABSTRACT, &dummy);
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
mexpr.value
- = objc_build_message_expr (build_tree_list (rec, args));
+ = objc_build_message_expr (rec, args);
mexpr.original_code = ERROR_MARK;
mexpr.original_type = NULL;
/* Now parse and process the remainder of the
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 ());
{
tree block, cond, incr, save_break, save_cont, body;
/* The following are only used when parsing an ObjC foreach statement. */
- tree object_expression, collection_expression;
+ tree object_expression;
+ /* Silence the bogus uninitialized warning. */
+ tree collection_expression = NULL;
location_t loc = c_parser_peek_token (parser)->location;
location_t for_loc = c_parser_peek_token (parser)->location;
bool is_foreach_statement = false;
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
{
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);
}
/* If the expression begins with a parenthesized type name, it may
be either a cast or a compound literal; we need to see whether
the next character is '{' to tell the difference. If not, it is
- an unary expression. */
+ an unary expression. Full detection of unknown typenames here
+ would require a 3-token lookahead. */
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_typename (c_parser_peek_2nd_token (parser)))
{
c_parser_consume_token (parser);
brace_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
- if (cur_stmt_list == NULL)
+ if (!building_stmt_list_p ())
{
error_at (loc, "braced-group within expression allowed "
"only inside a function");
}
t1 = c_parser_type_name (parser);
if (t1 == NULL)
- {
- expr.value = error_mark_node;
- break;
- }
+ parser->error = true;
if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ gcc_assert (parser->error);
+ if (parser->error)
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
expr.value = error_mark_node;
break;
}
+
{
tree type = groktypename (t1, NULL, NULL);
tree offsetof_ref;
args = c_parser_objc_message_args (parser);
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
- expr.value = objc_build_message_expr (build_tree_list (receiver,
- args));
+ expr.value = objc_build_message_expr (receiver, args);
break;
}
/* Else fall through to report error. */
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)
{
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
- "extra semicolon in struct or union specified");
+ "extra semicolon");
c_parser_consume_token (parser);
continue;
}
/* Parse some comma-separated declarations. */
decls = c_parser_struct_declaration (parser);
- {
- /* Comma-separated instance variables are chained together in
- reverse order; add them one by one. */
- tree ivar = nreverse (decls);
- for (; ivar; ivar = DECL_CHAIN (ivar))
- objc_add_instance_variable (copy_node (ivar));
- }
+ if (decls == NULL)
+ {
+ /* There is a syntax error. We want to skip the offending
+ tokens up to the next ';' (included) or '}'
+ (excluded). */
+
+ /* First, skip manually a ')' or ']'. This is because they
+ reduce the nesting level, so c_parser_skip_until_found()
+ wouldn't be able to skip past them. */
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_CLOSE_PAREN || token->type == CPP_CLOSE_SQUARE)
+ c_parser_consume_token (parser);
+
+ /* Then, do the standard skipping. */
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+
+ /* We hopefully recovered. Start normal parsing again. */
+ parser->error = false;
+ continue;
+ }
+ else
+ {
+ /* Comma-separated instance variables are chained together
+ in reverse order; add them one by one. */
+ tree ivar = nreverse (decls);
+ for (; ivar; ivar = DECL_CHAIN (ivar))
+ objc_add_instance_variable (copy_node (ivar));
+ }
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
}
static void
c_parser_objc_class_declaration (c_parser *parser)
{
- tree list = NULL_TREE;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_CLASS));
c_parser_consume_token (parser);
/* Any identifiers, including those declared as type names, are OK
return;
}
id = c_parser_peek_token (parser)->value;
- list = chainon (list, build_tree_list (NULL_TREE, id));
+ objc_declare_class (id);
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
break;
}
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- objc_declare_class (list);
}
/* Parse an objc-alias-declaration.
if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA
|| c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON)
{
- tree list = NULL_TREE;
/* Any identifiers, including those declared as type names, are
OK here. */
while (true)
break;
}
id = c_parser_peek_token (parser)->value;
- list = chainon (list, build_tree_list (NULL_TREE, id));
+ objc_declare_protocol (id, attributes);
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
break;
}
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- objc_declare_protocols (list, attributes);
}
else
{
c_parser_objc_method_definition (c_parser *parser)
{
bool is_class_method = c_parser_objc_method_type (parser);
- tree decl, attributes = NULL_TREE;
+ tree decl, attributes = NULL_TREE, expr = NULL_TREE;
parser->objc_pq_context = true;
- decl = c_parser_objc_method_decl (parser, is_class_method, &attributes);
+ decl = c_parser_objc_method_decl (parser, is_class_method, &attributes,
+ &expr);
if (decl == error_mark_node)
return; /* Bail here. */
}
parser->objc_pq_context = false;
- if (objc_start_method_definition (is_class_method, decl, attributes))
+ if (objc_start_method_definition (is_class_method, decl, attributes, expr))
{
add_stmt (c_parser_compound_statement (parser));
objc_finish_method_definition (current_function_decl);
/* Remember protocol qualifiers in prototypes. */
parser->objc_pq_context = true;
- decl = c_parser_objc_method_decl (parser, is_class_method, &attributes);
+ decl = c_parser_objc_method_decl (parser, is_class_method, &attributes,
+ NULL);
/* Forget protocol qualifiers now. */
parser->objc_pq_context = false;
*/
static tree
-c_parser_objc_method_decl (c_parser *parser, bool is_class_method, tree *attributes)
+c_parser_objc_method_decl (c_parser *parser, bool is_class_method,
+ tree *attributes, tree *expr)
{
tree type = NULL_TREE;
tree sel;
if (parm == NULL)
break;
parms = chainon (parms,
- build_tree_list (NULL_TREE, grokparm (parm)));
+ build_tree_list (NULL_TREE, grokparm (parm, expr)));
}
sel = list;
}
else
break;
}
- if (c_parser_next_token_starts_typename (parser))
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
type_name = c_parser_type_name (parser);
if (type_name)
type = groktypename (type_name, NULL, NULL);
+
+ /* If the type is unknown, and error has already been produced and
+ we need to recover from the error. In that case, use NULL_TREE
+ for the type, as if no type had been specified; this will use the
+ default type ('id') which is good for error recovery. */
+ if (type == error_mark_node)
+ type = NULL_TREE;
+
return build_tree_list (quals, type);
}
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;
+ objc_maybe_warn_exceptions (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, NULL);
+ }
+ 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 ();
}
gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED));
c_parser_consume_token (parser);
loc = c_parser_peek_token (parser)->location;
+ objc_maybe_warn_exceptions (loc);
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
expr = c_parser_expression (parser).value;
case RID_SETTER:
if (c_parser_next_token_is_not (parser, CPP_EQ))
{
- c_parser_error (parser,
- "getter/setter attribute must be followed by %<=%>");
+ if (keyword == RID_GETTER)
+ c_parser_error (parser,
+ "missing %<=%> (after %<getter%> attribute)");
+ else
+ c_parser_error (parser,
+ "missing %<=%> (after %<setter%> attribute)");
syntax_error = true;
break;
}
goto saw_error;
}
+ /* Arrange to pass the location of the assignment operator to
+ c_finish_omp_atomic. */
+ loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
{
location_t rhs_loc = c_parser_peek_token (parser)->location;