Mercurial > hg > CbC > CbC_gcc
diff gcc/c-parser.c @ 67:f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 22 Mar 2011 17:18:12 +0900 |
parents | b7f97abdc517 |
children | 1b10fe6932e1 |
line wrap: on
line diff
--- a/gcc/c-parser.c Tue May 25 18:58:51 2010 +0900 +++ b/gcc/c-parser.c Tue Mar 22 17:18:12 2011 +0900 @@ -1,6 +1,6 @@ /* 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 @@ -42,18 +42,17 @@ #include "coretypes.h" #include "tm.h" /* For rtl.h: needs enum reg_class. */ #include "tree.h" -#include "rtl.h" /* For decl_default_tls_model. */ #include "langhooks.h" #include "input.h" #include "cpplib.h" #include "timevar.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" #include "c-tree.h" #include "flags.h" #include "output.h" -#include "toplev.h" #include "ggc.h" -#include "c-common.h" +#include "c-family/c-common.h" +#include "c-family/c-objc.h" #include "vec.h" #include "target.h" #include "cgraph.h" @@ -87,7 +86,7 @@ if (!c_dialect_objc ()) mask |= D_OBJC | D_CXX_OBJC; - ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX); + ridpointers = ggc_alloc_cleared_vec_tree ((int) RID_MAX); for (i = 0; i < num_c_common_reswords; i++) { /* If a keyword is disabled, do not enter it into the table @@ -180,13 +179,25 @@ BOOL_BITFIELD in_if_block : 1; /* True if we want to lex an untranslated string. */ BOOL_BITFIELD lex_untranslated_string : 1; + /* Objective-C specific parser/lexer information. */ + + /* True if we are in a context where the Objective-C "PQ" keywords + are considered keywords. */ BOOL_BITFIELD objc_pq_context : 1; + /* True if we are parsing a (potential) Objective-C foreach + statement. This is set to true after we parsed 'for (' and while + we wait for 'in' or ';' to decide if it's a standard C for loop or an + Objective-C foreach loop. */ + BOOL_BITFIELD objc_could_be_foreach_context : 1; /* The following flag is needed to contextualize Objective-C lexical analysis. In some cases (e.g., 'int NSObject;'), it is undesirable to bind an identifier to an Objective-C class, even if a class with that name exists. */ BOOL_BITFIELD objc_need_raw_identifier : 1; + /* True if we are in a context where the Objective-C "Property attribute" + keywords are valid. */ + BOOL_BITFIELD objc_property_attr_context : 1; } c_parser; @@ -195,7 +206,6 @@ static GTY (()) c_parser *the_parser; - /* Read in and lex a single token, storing it in *TOKEN. */ static void @@ -238,18 +248,67 @@ token->keyword = rid_code; break; } - else if (c_dialect_objc ()) + else if (c_dialect_objc () && OBJC_IS_PQ_KEYWORD (rid_code)) { - if (!objc_is_reserved_word (token->value) - && (!OBJC_IS_PQ_KEYWORD (rid_code) - || parser->objc_pq_context)) + /* We found an Objective-C "pq" keyword (in, out, + inout, bycopy, byref, oneway). They need special + care because the interpretation depends on the + context. */ + if (parser->objc_pq_context) + { + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + else if (parser->objc_could_be_foreach_context + && rid_code == RID_IN) { - /* Return the canonical spelling for this keyword. */ - token->value = ridpointers[(int) rid_code]; + /* We are in Objective-C, inside a (potential) + foreach context (which means after having + parsed 'for (', but before having parsed ';'), + and we found 'in'. We consider it the keyword + which terminates the declaration at the + beginning of a foreach-statement. Note that + this means you can't use 'in' for anything else + in that context; in particular, in Objective-C + 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. */ 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. */ + } + else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code)) + { + /* 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) + { + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + /* Else they are not special keywords. + */ + } + else if (c_dialect_objc () + && (OBJC_IS_AT_KEYWORD (rid_code) + || OBJC_IS_CXX_KEYWORD (rid_code))) + { + /* We found one of the Objective-C "@" keywords (defs, + selector, synchronized, etc) or one of the + Objective-C "cxx" keywords (class, private, + 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). */ + ; } else { @@ -289,7 +348,25 @@ case CPP_AT_NAME: /* This only happens in Objective-C; it must be a keyword. */ token->type = CPP_KEYWORD; - token->keyword = C_RID_CODE (token->value); + switch (C_RID_CODE (token->value)) + { + /* Replace 'class' with '@class', 'private' with '@private', + etc. This prevents confusion with the C++ keyword + 'class', and makes the tokens consistent with other + Objective-C 'AT' keywords. For example '@class' is + reported as RID_AT_CLASS which is consistent with + '@synchronized', which is reported as + RID_AT_SYNCHRONIZED. + */ + case RID_CLASS: token->keyword = RID_AT_CLASS; break; + case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break; + case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break; + case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break; + case RID_THROW: token->keyword = RID_AT_THROW; break; + case RID_TRY: token->keyword = RID_AT_TRY; break; + case RID_CATCH: token->keyword = RID_AT_CATCH; break; + default: token->keyword = C_RID_CODE (token->value); + } break; case CPP_COLON: case CPP_COMMA: @@ -352,6 +429,22 @@ 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 @@ -379,6 +472,7 @@ { case RID_UNSIGNED: case RID_LONG: + case RID_INT128: case RID_SHORT: case RID_SIGNED: case RID_COMPLEX: @@ -415,13 +509,87 @@ } } +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. 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_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la) +{ + c_token *token = c_parser_peek_token (parser); + 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. */ +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_starts_typename (c_parser *parser) +c_parser_next_token_is_qualifier (c_parser *parser) { c_token *token = c_parser_peek_token (parser); - return c_token_starts_typename (token); + return c_token_is_qualifier (token); } /* Return true if TOKEN can start declaration specifiers, false @@ -458,6 +626,7 @@ case RID_THREAD: case RID_UNSIGNED: case RID_LONG: + case RID_INT128: case RID_SHORT: case RID_SIGNED: case RID_COMPLEX: @@ -513,32 +682,48 @@ c_parser_next_token_starts_declspecs (c_parser *parser) { c_token *token = c_parser_peek_token (parser); + + /* In Objective-C, a classname normally starts a declspecs unless it + is immediately followed by a dot. In that case, it is the + Objective-C 2.0 "dot-syntax" for class objects, ie, calls the + setter/getter on the class. c_token_starts_declspecs() can't + differentiate between the two cases because it only checks the + current token, so we have a special check here. */ + if (c_dialect_objc () + && token->type == CPP_NAME + && token->id_kind == C_ID_CLASSNAME + && c_parser_peek_2nd_token (parser)->type == CPP_DOT) + return false; + 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); - return c_token_starts_declaration (token); -} - -/* 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]; + + /* Same as above. */ + if (c_dialect_objc () + && token->type == CPP_NAME + && token->id_kind == C_ID_CLASSNAME + && c_parser_peek_2nd_token (parser)->type == CPP_DOT) + return false; + + /* 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; + + if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl)) + return true; + + return false; } /* Consume the next token from PARSER. */ @@ -861,11 +1046,11 @@ | (flag_iso << 3) | (warn_long_long << 4) | (warn_cxx_compat << 5)); - cpp_opts->pedantic = pedantic = 0; + cpp_opts->cpp_pedantic = pedantic = 0; warn_pointer_arith = 0; - cpp_opts->warn_traditional = warn_traditional = 0; + cpp_opts->cpp_warn_traditional = warn_traditional = 0; flag_iso = 0; - cpp_opts->warn_long_long = warn_long_long = 0; + cpp_opts->cpp_warn_long_long = warn_long_long = 0; warn_cxx_compat = 0; return ret; } @@ -876,11 +1061,11 @@ static inline void restore_extension_diagnostics (int flags) { - cpp_opts->pedantic = pedantic = flags & 1; + cpp_opts->cpp_pedantic = pedantic = flags & 1; warn_pointer_arith = (flags >> 1) & 1; - cpp_opts->warn_traditional = warn_traditional = (flags >> 2) & 1; + cpp_opts->cpp_warn_traditional = warn_traditional = (flags >> 2) & 1; flag_iso = (flags >> 3) & 1; - cpp_opts->warn_long_long = warn_long_long = (flags >> 4) & 1; + cpp_opts->cpp_warn_long_long = warn_long_long = (flags >> 4) & 1; warn_cxx_compat = (flags >> 5) & 1; } @@ -906,11 +1091,11 @@ static void c_parser_external_declaration (c_parser *); static void c_parser_asm_definition (c_parser *); static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, - bool, bool); + bool, bool, tree *); 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 *); @@ -977,25 +1162,30 @@ /* These Objective-C parser functions are only ever called when compiling Objective-C. */ -static void c_parser_objc_class_definition (c_parser *); +static void c_parser_objc_class_definition (c_parser *, tree); static void c_parser_objc_class_instance_variables (c_parser *); static void c_parser_objc_class_declaration (c_parser *); static void c_parser_objc_alias_declaration (c_parser *); -static void c_parser_objc_protocol_definition (c_parser *); -static enum tree_code c_parser_objc_method_type (c_parser *); +static void c_parser_objc_protocol_definition (c_parser *, tree); +static bool c_parser_objc_method_type (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 *); +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 *); static tree c_parser_objc_receiver (c_parser *); static tree c_parser_objc_message_args (c_parser *); static tree c_parser_objc_keywordexpr (c_parser *); +static void c_parser_objc_at_property_declaration (c_parser *); +static void c_parser_objc_at_synthesize_declaration (c_parser *); +static void c_parser_objc_at_dynamic_declaration (c_parser *); +static bool c_parser_objc_diagnose_bad_element_prefix + (c_parser *, struct c_declspecs *); /* Parse a translation unit (C90 6.7, C99 6.9). @@ -1079,9 +1269,9 @@ case RID_AT_INTERFACE: case RID_AT_IMPLEMENTATION: gcc_assert (c_dialect_objc ()); - c_parser_objc_class_definition (parser); - break; - case RID_CLASS: + c_parser_objc_class_definition (parser, NULL_TREE); + break; + case RID_AT_CLASS: gcc_assert (c_dialect_objc ()); c_parser_objc_class_declaration (parser); break; @@ -1091,7 +1281,19 @@ break; case RID_AT_PROTOCOL: gcc_assert (c_dialect_objc ()); - c_parser_objc_protocol_definition (parser); + c_parser_objc_protocol_definition (parser, NULL_TREE); + break; + case RID_AT_PROPERTY: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_property_declaration (parser); + break; + case RID_AT_SYNTHESIZE: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_synthesize_declaration (parser); + break; + case RID_AT_DYNAMIC: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_dynamic_declaration (parser); break; case RID_AT_END: gcc_assert (c_dialect_objc ()); @@ -1123,15 +1325,15 @@ as a declaration or function definition. */ default: decl_or_fndef: - /* A declaration or a function definition. We can only tell - which after parsing the declaration specifiers, if any, and - the first declarator. */ - c_parser_declaration_or_fndef (parser, true, true, true, false, true); + /* A declaration or a function definition (or, in Objective-C, + an @interface or @protocol with prefix attributes). We can + only tell which after parsing the declaration specifiers, if + any, and the first declarator. */ + c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL); break; } } - /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 6.7, 6.9.1). If FNDEF_OK is true, a function definition is accepted; otherwise (old-style parameter declarations) only other @@ -1146,6 +1348,8 @@ (old-style parameter declarations) they are diagnosed. If START_ATTR_OK is true, the declaration specifiers may start with attributes; otherwise they may not. + OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed + declaration when parsing an Objective-C foreach statement. declaration: declaration-specifiers init-declarator-list[opt] ; @@ -1173,6 +1377,11 @@ declaration-specifiers declarator declaration-list[opt] compound-statement + Objective-C: + attributes objc-class-definition + attributes objc-category-definition + attributes objc-protocol-definition + The simple-asm-expr and attributes are GNU extensions. This function does not handle __extension__; that is handled in its @@ -1187,6 +1396,10 @@ specifiers, but only at top level (elsewhere they conflict with other syntax). + In Objective-C, declarations of the looping variable in a foreach + statement are exceptionally terminated by 'in' (for example, 'for + (NSObject *object in array) { ... }'). + OpenMP: declaration: @@ -1195,7 +1408,8 @@ static void c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool static_assert_ok, bool empty_ok, - bool nested, bool start_attr_ok) + bool nested, bool start_attr_ok, + tree *objc_foreach_object_declaration) { struct c_declspecs *specs; tree prefix_attrs; @@ -1210,7 +1424,27 @@ return; } specs = build_null_declspecs (); - c_parser_declspecs (parser, specs, true, true, start_attr_ok); + + /* 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, cla_nonabstract_decl); if (parser->error) { c_parser_skip_to_end_of_block_or_statement (parser); @@ -1235,6 +1469,97 @@ 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. */ + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + case CPP_MINUS: + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + if (specs->attrs) + { + warning_at (c_parser_peek_token (parser)->location, + OPT_Wattributes, + "prefix attributes are ignored for methods"); + specs->attrs = NULL_TREE; + } + if (fndef_ok) + c_parser_objc_method_definition (parser); + else + c_parser_objc_methodproto (parser); + return; + break; + default: + break; + } + /* This is where we parse 'attributes @interface ...', + 'attributes @implementation ...', 'attributes @protocol ...' + (where attributes could be, for example, __attribute__ + ((deprecated)). + */ + switch (c_parser_peek_token (parser)->keyword) + { + case RID_AT_INTERFACE: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + c_parser_objc_class_definition (parser, specs->attrs); + return; + } + break; + case RID_AT_IMPLEMENTATION: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + if (specs->attrs) + { + warning_at (c_parser_peek_token (parser)->location, + OPT_Wattributes, + "prefix attributes are ignored for implementations"); + specs->attrs = NULL_TREE; + } + c_parser_objc_class_definition (parser, NULL_TREE); + return; + } + break; + case RID_AT_PROTOCOL: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + c_parser_objc_protocol_definition (parser, specs->attrs); + return; + } + break; + case RID_AT_ALIAS: + case RID_AT_CLASS: + case RID_AT_END: + case RID_AT_PROPERTY: + if (specs->attrs) + { + c_parser_error (parser, "unexpected attribute"); + specs->attrs = NULL; + } + break; + default: + break; + } + } + pending_xref_error (); prefix_attrs = specs->attrs; all_prefix_attrs = prefix_attrs; @@ -1248,7 +1573,8 @@ 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) { @@ -1259,7 +1585,8 @@ || c_parser_next_token_is (parser, CPP_COMMA) || c_parser_next_token_is (parser, CPP_SEMICOLON) || c_parser_next_token_is_keyword (parser, RID_ASM) - || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE) + || c_parser_next_token_is_keyword (parser, RID_IN)) { tree asm_name = NULL_TREE; tree postfix_attrs = NULL_TREE; @@ -1305,7 +1632,15 @@ all_prefix_attrs)); if (d) finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, - NULL_TREE, asm_name); + NULL_TREE, asm_name); + + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + if (d) + *objc_foreach_object_declaration = d; + else + *objc_foreach_object_declaration = error_mark_node; + } } if (c_parser_next_token_is (parser, CPP_COMMA)) { @@ -1322,6 +1657,15 @@ c_parser_consume_token (parser); return; } + else if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + /* This can only happen in Objective-C: we found the + 'in' that terminates the declaration inside an + Objective-C foreach statement. Do not consume the + token, so that the caller can use it to determine + that this indeed is a foreach context. */ + return; + } else { c_parser_error (parser, "expected %<,%> or %<;%>"); @@ -1368,7 +1712,7 @@ while (c_parser_next_token_is_not (parser, CPP_EOF) && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE)) c_parser_declaration_or_fndef (parser, false, false, false, - true, false); + true, false, NULL); store_parm_decls (); DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = c_parser_peek_token (parser)->location; @@ -1575,6 +1919,7 @@ type-specifier: typeof-specifier + __int128 _Decimal32 _Decimal64 _Decimal128 @@ -1595,10 +1940,15 @@ 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->type_seen_p; + bool seen_type = specs->typespec_kind != ctsk_none; + + 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))) @@ -1606,6 +1956,16 @@ struct c_typespec t; tree attrs; location_t loc = c_parser_peek_token (parser)->location; + + /* 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)) { tree value = c_parser_peek_token (parser)->value; @@ -1621,25 +1981,34 @@ 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)) + 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 { @@ -1649,9 +2018,9 @@ 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; } @@ -1692,6 +2061,7 @@ break; case RID_UNSIGNED: case RID_LONG: + case RID_INT128: case RID_SHORT: case RID_SIGNED: case RID_COMPLEX: @@ -1831,7 +2201,7 @@ bool seen_comma; c_token *token; location_t comma_loc = UNKNOWN_LOCATION; /* Quiet warning. */ - location_t value_loc; + location_t decl_loc, value_loc; if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); @@ -1843,7 +2213,7 @@ enum_id = token->value; /* Set the location in case we create a decl now. */ c_parser_set_source_position_from_token (token); - value_loc = token->location; + decl_loc = value_loc = token->location; c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_EQ)) { @@ -1853,7 +2223,7 @@ } else enum_value = NULL_TREE; - enum_decl = build_enumerator (value_loc, + enum_decl = build_enumerator (decl_loc, value_loc, &the_enum, enum_id, enum_value); TREE_CHAIN (enum_decl) = values; values = enum_decl; @@ -2066,12 +2436,17 @@ 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); @@ -2152,7 +2527,7 @@ } 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) @@ -2161,10 +2536,11 @@ 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"); @@ -2186,6 +2562,19 @@ } 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; @@ -2199,7 +2588,8 @@ 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) { @@ -2226,7 +2616,7 @@ declarator, specs, width, &all_prefix_attrs); decl_attributes (&d, chainon (postfix_attrs, all_prefix_attrs), 0); - TREE_CHAIN (d) = decls; + DECL_CHAIN (d) = decls; decls = d; if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) all_prefix_attrs = chainon (c_parser_attributes (parser), @@ -2283,7 +2673,7 @@ 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--; @@ -2404,7 +2794,7 @@ 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; @@ -2460,7 +2850,8 @@ if (kind != C_DTR_ABSTRACT && c_parser_next_token_is (parser, CPP_NAME) && ((type_seen_p - && c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME) + && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME + || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) || c_parser_peek_token (parser)->id_kind == C_ID_ID)) { struct c_declarator *inner @@ -2555,12 +2946,12 @@ 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. @@ -2648,7 +3039,13 @@ 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) @@ -2669,13 +3066,8 @@ } if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { - struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = 0; - ret->tags = 0; + struct c_arg_info *ret = build_arg_info (); ret->types = list; - ret->others = 0; - ret->pending_sizes = 0; - ret->had_vla_unspec = 0; c_parser_consume_token (parser); pop_scope (); return ret; @@ -2703,7 +3095,7 @@ static struct c_arg_info * c_parser_parms_list_declarator (c_parser *parser, tree attrs) { - bool good_parm = false; + 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 @@ -2712,24 +3104,13 @@ declarations. */ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { - struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = 0; - ret->tags = 0; - ret->types = 0; - ret->others = 0; - ret->pending_sizes = 0; - ret->had_vla_unspec = 0; + struct c_arg_info *ret = build_arg_info (); c_parser_consume_token (parser); return ret; } if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) { - struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = 0; - ret->tags = 0; - ret->others = 0; - ret->pending_sizes = 0; - ret->had_vla_unspec = 0; + struct c_arg_info *ret = build_arg_info (); /* Suppress -Wold-style-definition for this case. */ ret->types = error_mark_node; error_at (c_parser_peek_token (parser)->location, @@ -2755,11 +3136,10 @@ /* Parse a parameter. */ struct c_parm *parm = c_parser_parameter_declaration (parser, attrs); attrs = NULL_TREE; - if (parm != NULL) - { - good_parm = true; - push_parm_decl (parm); - } + if (parm == NULL) + bad_parm = true; + else + push_parm_decl (parm); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { tree new_attrs; @@ -2771,20 +3151,13 @@ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { c_parser_consume_token (parser); - if (good_parm) - return get_parm_info (false); + if (bad_parm) + { + get_pending_sizes (); + return NULL; + } else - { - struct c_arg_info *ret - = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = 0; - ret->tags = 0; - ret->types = 0; - ret->others = 0; - ret->pending_sizes = 0; - ret->had_vla_unspec = 0; - return ret; - } + return get_parm_info (false); } if (!c_parser_require (parser, CPP_COMMA, "expected %<;%>, %<,%> or %<)%>")) @@ -2799,20 +3172,13 @@ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { c_parser_consume_token (parser); - if (good_parm) - return get_parm_info (true); - else + if (bad_parm) { - struct c_arg_info *ret - = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = 0; - ret->tags = 0; - ret->types = 0; - ret->others = 0; - ret->pending_sizes = 0; - ret->had_vla_unspec = 0; - return ret; + get_pending_sizes (); + return NULL; } + else + return get_parm_info (true); } else { @@ -2838,10 +3204,20 @@ bool dummy = false; if (!c_parser_next_token_starts_declspecs (parser)) { + c_token *token = c_parser_peek_token (parser); + if (parser->error) + return NULL; + c_parser_set_source_position_from_token (token); + if (c_parser_next_tokens_start_typename (parser, cla_prefer_type)) + { + error ("unknown type name %qE", token->value); + parser->error = true; + } /* ??? In some Objective-C cases '...' isn't applicable so there should be a different message. */ - c_parser_error (parser, - "expected declaration specifiers or %<...%>"); + else + c_parser_error (parser, + "expected declaration specifiers or %<...%>"); c_parser_skip_to_end_of_parameter (parser); return NULL; } @@ -2851,12 +3227,13 @@ 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; 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) { @@ -3006,6 +3383,7 @@ case RID_STATIC: case RID_UNSIGNED: case RID_LONG: + case RID_INT128: case RID_CONST: case RID_EXTERN: case RID_REGISTER: @@ -3056,9 +3434,12 @@ /* 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))) @@ -3136,15 +3517,19 @@ 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); - declarator = c_parser_declarator (parser, specs->type_seen_p, + 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); if (declarator == NULL) return NULL; @@ -3638,11 +4023,11 @@ 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); - c_parser_declaration_or_fndef (parser, true, true, true, true, true); + c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); if (last_stmt) pedwarn_c90 (loc, (pedantic && !flag_isoc99) @@ -3670,7 +4055,7 @@ last_label = false; mark_valid_location_for_stdc_pragma (false); c_parser_declaration_or_fndef (parser, true, true, true, true, - true); + true, NULL); /* Following the old parser, __extension__ does not disable this diagnostic. */ restore_extension_diagnostics (ext); @@ -3800,9 +4185,7 @@ } 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 " @@ -3810,7 +4193,7 @@ c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false, /*static_assert_ok*/ true, /*nested*/ true, /*empty_ok*/ false, - /*start_attr_ok*/ true); + /*start_attr_ok*/ true, NULL); } } } @@ -3965,9 +4348,12 @@ } else if (c_parser_next_token_is (parser, CPP_MULT)) { + tree val; + c_parser_consume_token (parser); - stmt = c_finish_goto_ptr (loc, - c_parser_expression (parser).value); + val = c_parser_expression (parser).value; + mark_exp_read (val); + stmt = c_finish_goto_ptr (loc, val); } else c_parser_error (parser, "expected identifier or %<*%>"); @@ -3998,7 +4384,7 @@ case RID_ASM: stmt = c_parser_asm_statement (parser); break; - case RID_THROW: + case RID_AT_THROW: gcc_assert (c_dialect_objc ()); c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) @@ -4014,9 +4400,9 @@ goto expect_semicolon; } break; - case RID_TRY: + 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 ()); @@ -4326,29 +4712,92 @@ Note in particular that the nested function does not include a trailing ';', whereas the "declaration" production includes one. Also, can we reject bad declarations earlier and cheaper than - check_for_loop_decls? */ + check_for_loop_decls? + + In Objective-C, there are two additional variants: + + foreach-statement: + for ( expression in expresssion ) statement + for ( declaration in expression ) statement + + This is inconsistent with C, because the second variant is allowed + even if c99 is not enabled. + + The rest of the comment documents these Objective-C foreach-statement. + + Here is the canonical example of the first variant: + for (object in array) { do something with object } + we call the first expression ("object") the "object_expression" and + the second expression ("array") the "collection_expression". + object_expression must be an lvalue of type "id" (a generic Objective-C + object) because the loop works by assigning to object_expression the + various objects from the collection_expression. collection_expression + must evaluate to something of type "id" which responds to the method + countByEnumeratingWithState:objects:count:. + + The canonical example of the second variant is: + for (id object in array) { do something with object } + which is completely equivalent to + { + id object; + for (object in array) { do something with object } + } + Note that initizializing 'object' in some way (eg, "for ((object = + xxx) in array) { do something with object }") is possibly + technically valid, but completely pointless as 'object' will be + assigned to something else as soon as the loop starts. We should + most likely reject it (TODO). + + The beginning of the Objective-C foreach-statement looks exactly + like the beginning of the for-statement, and we can tell it is a + foreach-statement only because the initial declaration or + expression is terminated by 'in' instead of ';'. +*/ static void c_parser_for_statement (c_parser *parser) { tree block, cond, incr, save_break, save_cont, body; + /* The following are only used when parsing an ObjC foreach statement. */ + 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; gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); c_parser_consume_token (parser); - block = c_begin_compound_stmt (flag_isoc99); + /* Open a compound statement in Objective-C as well, just in case this is + as foreach expression. */ + block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ()); + cond = error_mark_node; + incr = error_mark_node; if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { /* 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)) - { - c_parser_declaration_or_fndef (parser, true, true, true, true, true); - check_for_loop_decls (for_loc); + else if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + &object_expression); + parser->objc_could_be_foreach_context = false; + + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + c_parser_consume_token (parser); + is_foreach_statement = true; + if (check_for_loop_decls (for_loc, true) == NULL_TREE) + c_parser_error (parser, "multiple iterating variables in fast enumeration"); + } + else + check_for_loop_decls (for_loc, flag_isoc99); } else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) { @@ -4366,9 +4815,19 @@ ext = disable_extension_diagnostics (); c_parser_consume_token (parser); c_parser_declaration_or_fndef (parser, true, true, true, true, - true); + true, &object_expression); + parser->objc_could_be_foreach_context = false; + restore_extension_diagnostics (ext); - check_for_loop_decls (for_loc); + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + c_parser_consume_token (parser); + is_foreach_statement = true; + if (check_for_loop_decls (for_loc, true) == NULL_TREE) + c_parser_error (parser, "multiple iterating variables in fast enumeration"); + } + else + check_for_loop_decls (for_loc, flag_isoc99); } else goto init_expr; @@ -4376,39 +4835,74 @@ else { init_expr: - c_finish_expr_stmt (loc, c_parser_expression (parser).value); - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - } - /* Parse the loop condition. */ - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - { - c_parser_consume_token (parser); - cond = NULL_TREE; + { + tree init_expression; + init_expression = c_parser_expression (parser).value; + parser->objc_could_be_foreach_context = false; + if (c_parser_next_token_is_keyword (parser, RID_IN)) + { + c_parser_consume_token (parser); + is_foreach_statement = true; + if (! lvalue_p (init_expression)) + c_parser_error (parser, "invalid iterating variable in fast enumeration"); + object_expression = c_fully_fold (init_expression, false, NULL); + } + else + { + c_finish_expr_stmt (loc, init_expression); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + } + } + /* 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)) + { + c_parser_consume_token (parser); + cond = NULL_TREE; + } + else + { + cond = c_parser_condition (parser); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + } + /* Parse the increment expression (the third expression in a + for-statement). In the case of a foreach-statement, this is + the expression that follows the 'in'. */ + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + if (is_foreach_statement) + { + c_parser_error (parser, "missing collection in fast enumeration"); + collection_expression = error_mark_node; + } + else + incr = c_process_expr_stmt (loc, NULL_TREE); } else { - cond = c_parser_condition (parser); - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - } - /* Parse the increment expression. */ - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - incr = c_process_expr_stmt (loc, NULL_TREE); - else - incr = c_process_expr_stmt (loc, c_parser_expression (parser).value); + if (is_foreach_statement) + collection_expression = c_fully_fold (c_parser_expression (parser).value, + false, NULL); + else + incr = c_process_expr_stmt (loc, c_parser_expression (parser).value); + } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } - else - { - cond = error_mark_node; - incr = error_mark_node; - } save_break = c_break_label; c_break_label = NULL_TREE; save_cont = c_cont_label; c_cont_label = NULL_TREE; body = c_parser_c99_block_statement (parser); - c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true); - add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); + if (is_foreach_statement) + objc_finish_foreach_loop (loc, object_expression, collection_expression, body, c_break_label, c_cont_label); + else + c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99 || c_dialect_objc ())); c_break_label = save_break; c_cont_label = save_cont; } @@ -4791,7 +5285,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) { struct c_expr cond, exp1, exp2, ret; - location_t cond_loc, colon_loc; + location_t cond_loc, colon_loc, middle_loc; gcc_assert (!after || c_dialect_objc ()); @@ -4805,8 +5299,11 @@ if (c_parser_next_token_is (parser, CPP_COLON)) { tree eptype = NULL_TREE; - pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + + middle_loc = c_parser_peek_token (parser)->location; + pedwarn (middle_loc, OPT_pedantic, "ISO C forbids omitting the middle term of a ?: expression"); + warn_for_omitted_condop (middle_loc, cond.value); if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR) { eptype = TREE_TYPE (cond.value); @@ -5160,7 +5657,8 @@ /* 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))) { @@ -5508,6 +6006,7 @@ @protocol ( identifier ) @encode ( type-name ) objc-string-literal + Classname . identifier */ static struct c_expr @@ -5554,20 +6053,48 @@ c_parser_consume_token (parser); break; case CPP_NAME: - if (c_parser_peek_token (parser)->id_kind != C_ID_ID) - { + switch (c_parser_peek_token (parser)->id_kind) + { + case C_ID_ID: + { + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + expr.value = build_external_ref (loc, id, + (c_parser_peek_token (parser)->type + == CPP_OPEN_PAREN), + &expr.original_type); + break; + } + case C_ID_CLASSNAME: + { + /* Here we parse the Objective-C 2.0 Class.name dot + syntax. */ + tree class_name = c_parser_peek_token (parser)->value; + tree component; + c_parser_consume_token (parser); + gcc_assert (c_dialect_objc ()); + if (!c_parser_require (parser, CPP_DOT, "expected %<.%>")) + { + expr.value = error_mark_node; + break; + } + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + expr.value = error_mark_node; + break; + } + component = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + expr.value = objc_build_class_component_ref (class_name, + component); + break; + } + default: c_parser_error (parser, "expected expression"); expr.value = error_mark_node; break; } - { - tree id = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); - expr.value = build_external_ref (loc, id, - (c_parser_peek_token (parser)->type - == CPP_OPEN_PAREN), - &expr.original_type); - } break; case CPP_OPEN_PAREN: /* A parenthesized expression, statement expression or compound @@ -5597,6 +6124,7 @@ pedwarn (loc, OPT_pedantic, "ISO C forbids braced-groups within expressions"); expr.value = c_finish_stmt_expr (brace_loc, stmt); + mark_exp_read (expr.value); } else if (c_token_starts_typename (c_parser_peek_2nd_token (parser))) { @@ -5692,16 +6220,16 @@ } 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; @@ -5842,9 +6370,8 @@ e1 = TYPE_MAIN_VARIANT (groktypename (t1, NULL, NULL)); e2 = TYPE_MAIN_VARIANT (groktypename (t2, NULL, NULL)); - expr.value = comptypes (e1, e2) - ? build_int_cst (NULL_TREE, 1) - : build_int_cst (NULL_TREE, 0); + expr.value + = comptypes (e1, e2) ? integer_one_node : integer_zero_node; } break; case RID_AT_SELECTOR: @@ -6255,6 +6782,8 @@ 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: @@ -6267,7 +6796,7 @@ objc-protocol-refs and objc-class-instance-variables are omitted. */ static void -c_parser_objc_class_definition (c_parser *parser) +c_parser_objc_class_definition (c_parser *parser, tree attributes) { bool iface_p; tree id1; @@ -6278,6 +6807,7 @@ iface_p = false; else gcc_unreachable (); + c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_NAME)) { @@ -6288,17 +6818,29 @@ 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; - } - id2 = c_parser_peek_token (parser)->value; - c_parser_consume_token (parser); + 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); + } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); if (!iface_p) { @@ -6307,7 +6849,7 @@ } if (c_parser_next_token_is (parser, CPP_LESS)) proto = c_parser_objc_protocol_refs (parser); - objc_start_category_interface (id1, id2, proto); + objc_start_category_interface (id1, id2, proto, attributes); c_parser_objc_methodprotolist (parser); c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); objc_finish_interface (); @@ -6331,7 +6873,7 @@ tree proto = NULL_TREE; if (c_parser_next_token_is (parser, CPP_LESS)) proto = c_parser_objc_protocol_refs (parser); - objc_start_class_interface (id1, superclass, proto); + objc_start_class_interface (id1, superclass, proto, attributes); } else objc_start_class_implementation (id1, superclass); @@ -6396,22 +6938,28 @@ break; } /* Parse any objc-visibility-spec. */ - if (c_parser_next_token_is_keyword (parser, RID_PRIVATE)) + if (c_parser_next_token_is_keyword (parser, RID_AT_PRIVATE)) + { + c_parser_consume_token (parser); + objc_set_visibility (OBJC_IVAR_VIS_PRIVATE); + continue; + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED)) { c_parser_consume_token (parser); - objc_set_visibility (2); + objc_set_visibility (OBJC_IVAR_VIS_PROTECTED); continue; } - else if (c_parser_next_token_is_keyword (parser, RID_PROTECTED)) + else if (c_parser_next_token_is_keyword (parser, RID_AT_PUBLIC)) { c_parser_consume_token (parser); - objc_set_visibility (0); + objc_set_visibility (OBJC_IVAR_VIS_PUBLIC); continue; } - else if (c_parser_next_token_is_keyword (parser, RID_PUBLIC)) + else if (c_parser_next_token_is_keyword (parser, RID_AT_PACKAGE)) { c_parser_consume_token (parser); - objc_set_visibility (1); + objc_set_visibility (OBJC_IVAR_VIS_PACKAGE); continue; } else if (c_parser_next_token_is (parser, CPP_PRAGMA)) @@ -6426,7 +6974,7 @@ /* Comma-separated instance variables are chained together in reverse order; add them one by one. */ tree ivar = nreverse (decls); - for (; ivar; ivar = TREE_CHAIN (ivar)) + for (; ivar; ivar = DECL_CHAIN (ivar)) objc_add_instance_variable (copy_node (ivar)); } c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); @@ -6443,7 +6991,7 @@ c_parser_objc_class_declaration (c_parser *parser) { tree list = NULL_TREE; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_CLASS)); + 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 here. */ @@ -6453,7 +7001,9 @@ if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); - break; + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; } id = c_parser_peek_token (parser)->value; list = chainon (list, build_tree_list (NULL_TREE, id)); @@ -6511,9 +7061,10 @@ omitted. */ static void -c_parser_objc_protocol_definition (c_parser *parser) +c_parser_objc_protocol_definition (c_parser *parser, tree attributes) { gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL)); + c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_NAME)) { @@ -6543,7 +7094,7 @@ break; } c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - objc_declare_protocols (list); + objc_declare_protocols (list, attributes); } else { @@ -6553,7 +7104,7 @@ if (c_parser_next_token_is (parser, CPP_LESS)) proto = c_parser_objc_protocol_refs (parser); parser->objc_pq_context = true; - objc_start_protocol (id, proto); + objc_start_protocol (id, proto, attributes); c_parser_objc_methodprotolist (parser); c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); parser->objc_pq_context = false; @@ -6566,19 +7117,21 @@ objc-method-type: + - + + Return true if it is a class method (+) and false if it is + an instance method (-). */ - -static enum tree_code +static inline bool c_parser_objc_method_type (c_parser *parser) { switch (c_parser_peek_token (parser)->type) { case CPP_PLUS: c_parser_consume_token (parser); - return PLUS_EXPR; + return true; case CPP_MINUS: c_parser_consume_token (parser); - return MINUS_EXPR; + return false; default: gcc_unreachable (); } @@ -6593,26 +7146,41 @@ static void c_parser_objc_method_definition (c_parser *parser) { - enum tree_code type = c_parser_objc_method_type (parser); - tree decl; - objc_set_method_type (type); + bool is_class_method = c_parser_objc_method_type (parser); + tree decl, attributes = NULL_TREE; parser->objc_pq_context = true; - decl = c_parser_objc_method_decl (parser); + decl = c_parser_objc_method_decl (parser, is_class_method, &attributes); + if (decl == error_mark_node) + return; /* Bail here. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { c_parser_consume_token (parser); pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, "extra semicolon in method definition specified"); } + if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { c_parser_error (parser, "expected %<{%>"); return; } + parser->objc_pq_context = false; - objc_start_method_definition (decl); - add_stmt (c_parser_compound_statement (parser)); - objc_finish_method_definition (current_function_decl); + if (objc_start_method_definition (is_class_method, decl, attributes)) + { + add_stmt (c_parser_compound_statement (parser)); + objc_finish_method_definition (current_function_decl); + } + else + { + /* This code is executed when we find a method definition + outside of an @implementation context (or invalid for other + reasons). Parse the method (to keep going) but do not emit + any code. + */ + c_parser_compound_statement (parser); + } } /* Parse an objc-methodprotolist. @@ -6622,6 +7190,8 @@ objc-methodprotolist objc-methodproto objc-methodprotolist declaration objc-methodprotolist ; + @optional + @required The declaration is a data definition, which may be missing declaration specifiers under the same rules and diagnostics as @@ -6654,8 +7224,21 @@ default: if (c_parser_next_token_is_keyword (parser, RID_AT_END)) return; - c_parser_declaration_or_fndef (parser, false, false, true, - false, true); + else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)) + c_parser_objc_at_property_declaration (parser); + else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL)) + { + objc_set_method_opt (true); + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_REQUIRED)) + { + objc_set_method_opt (false); + c_parser_consume_token (parser); + } + else + c_parser_declaration_or_fndef (parser, false, false, true, + false, true, NULL); break; } } @@ -6670,18 +7253,65 @@ static void c_parser_objc_methodproto (c_parser *parser) { - enum tree_code type = c_parser_objc_method_type (parser); - tree decl; - objc_set_method_type (type); + bool is_class_method = c_parser_objc_method_type (parser); + tree decl, attributes = NULL_TREE; + /* Remember protocol qualifiers in prototypes. */ parser->objc_pq_context = true; - decl = c_parser_objc_method_decl (parser); - /* Forget protocol qualifiers here. */ + decl = c_parser_objc_method_decl (parser, is_class_method, &attributes); + /* Forget protocol qualifiers now. */ parser->objc_pq_context = false; - objc_add_method_declaration (decl); + + /* Do not allow the presence of attributes to hide an erroneous + method implementation in the interface section. */ + if (!c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_parser_error (parser, "expected %<;%>"); + return; + } + + if (decl != error_mark_node) + objc_add_method_declaration (is_class_method, decl, attributes); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } +/* If we are at a position that method attributes may be present, check that + there are not any parsed already (a syntax error) and then collect any + specified at the current location. Finally, if new attributes were present, + check that the next token is legal ( ';' for decls and '{' for defs). */ + +static bool +c_parser_objc_maybe_method_attributes (c_parser* parser, tree* attributes) +{ + bool bad = false; + if (*attributes) + { + c_parser_error (parser, + "method attributes must be specified at the end only"); + *attributes = NULL_TREE; + bad = true; + } + + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + *attributes = c_parser_attributes (parser); + + /* If there were no attributes here, just report any earlier error. */ + if (*attributes == NULL_TREE || bad) + return bad; + + /* If the attributes are followed by a ; or {, then just report any earlier + error. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + return bad; + + /* We've got attributes, but not at the end. */ + c_parser_error (parser, + "expected %<;%> or %<{%> after method attribute definition"); + return true; +} + /* Parse an objc-method-decl. objc-method-decl: @@ -6689,6 +7319,7 @@ objc-selector ( objc-type-name ) objc-keyword-selector objc-optparmlist objc-keyword-selector objc-optparmlist + attributes objc-keyword-selector: objc-keyword-decl @@ -6713,13 +7344,15 @@ */ static tree -c_parser_objc_method_decl (c_parser *parser) +c_parser_objc_method_decl (c_parser *parser, bool is_class_method, tree *attributes) { tree type = NULL_TREE; tree sel; tree parms = NULL_TREE; bool ellipsis = false; - + bool attr_err = false; + + *attributes = NULL_TREE; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { c_parser_consume_token (parser); @@ -6737,6 +7370,7 @@ while (true) { tree atype = NULL_TREE, id, keyworddecl; + tree param_attr = NULL_TREE; if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) break; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) @@ -6746,6 +7380,9 @@ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } + /* New ObjC allows attributes on method parameters. */ + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + param_attr = c_parser_attributes (parser); if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); @@ -6753,12 +7390,15 @@ } id = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); - keyworddecl = objc_build_keyword_decl (tsel, atype, id); + keyworddecl = objc_build_keyword_decl (tsel, atype, id, param_attr); list = chainon (list, keyworddecl); tsel = c_parser_objc_selector (parser); if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON)) break; } + + attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; + /* Parse the optional parameter list. Optional Objective-C method parameters follow the C syntax, and may include '...' to denote a variable number of arguments. */ @@ -6771,6 +7411,8 @@ { ellipsis = true; c_parser_consume_token (parser); + attr_err |= c_parser_objc_maybe_method_attributes + (parser, attributes) ; break; } parm = c_parser_parameter_declaration (parser, NULL_TREE); @@ -6781,7 +7423,19 @@ } sel = list; } - return objc_build_method_signature (type, sel, parms, ellipsis); + else + attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; + + if (sel == NULL) + { + c_parser_error (parser, "objective-c method declaration is expected"); + return error_mark_node; + } + + if (attr_err) + return error_mark_node; + + return objc_build_method_signature (is_class_method, type, sel, parms, ellipsis); } /* Parse an objc-type-name. @@ -6815,16 +7469,24 @@ || token->keyword == RID_BYREF || token->keyword == RID_ONEWAY)) { - quals = chainon (quals, build_tree_list (NULL_TREE, token->value)); + quals = chainon (build_tree_list (NULL_TREE, token->value), quals); c_parser_consume_token (parser); } 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); } @@ -6862,53 +7524,98 @@ return list; } -/* Parse an objc-try-catch-statement. - - objc-try-catch-statement: +/* Parse an objc-try-catch-finally-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) -{ - location_t loc; +c_parser_objc_try_catch_finally_statement (c_parser *parser) +{ + location_t location; tree stmt; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRY)); + + 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); - while (c_parser_next_token_is_keyword (parser, RID_CATCH)) + 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) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - break; - } - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - objc_begin_catch_clause (grokparm (parm)); + seen_open_paren = true; + if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) + { + /* 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; + } + 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 (); } @@ -6927,6 +7634,7 @@ 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; @@ -6988,6 +7696,7 @@ case RID_ALIGNOF: case RID_UNSIGNED: case RID_LONG: + case RID_INT128: case RID_CONST: case RID_SHORT: case RID_VOLATILE: @@ -7131,6 +7840,322 @@ return ret; } +/* A check, needed in several places, that ObjC interface, implementation or + method definitions are not prefixed by incorrect items. */ +static bool +c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, + struct c_declspecs *specs) +{ + 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,"); + c_parser_skip_to_end_of_block_or_statement (parser); + return true; + } + return false; +} + +/* Parse an Objective-C @property declaration. The syntax is: + + objc-property-declaration: + '@property' objc-property-attributes[opt] struct-declaration ; + + objc-property-attributes: + '(' objc-property-attribute-list ')' + + objc-property-attribute-list: + objc-property-attribute + objc-property-attribute-list, objc-property-attribute + + objc-property-attribute + 'getter' = identifier + 'setter' = identifier + 'readonly' + 'readwrite' + 'assign' + 'retain' + 'copy' + 'nonatomic' + + For example: + @property NSString *name; + @property (readonly) id object; + @property (retain, nonatomic, getter=getTheName) id name; + @property int a, b, c; + + PS: This function is identical to cp_parser_objc_at_propery_declaration + for C++. Keep them in sync. */ +static void +c_parser_objc_at_property_declaration (c_parser *parser) +{ + /* The following variables hold the attributes of the properties as + parsed. They are 'false' or 'NULL_TREE' if the attribute was not + seen. When we see an attribute, we set them to 'true' (if they + are boolean properties) or to the identifier (if they have an + argument, ie, for getter and setter). Note that here we only + parse the list of attributes, check the syntax and accumulate the + attributes that we find. objc_add_property_declaration() will + then process the information. */ + bool property_assign = false; + bool property_copy = false; + tree property_getter_ident = NULL_TREE; + bool property_nonatomic = false; + bool property_readonly = false; + bool property_readwrite = false; + bool property_retain = false; + tree property_setter_ident = NULL_TREE; + + /* 'properties' is the list of properties that we read. Usually a + single one, but maybe more (eg, in "@property int a, b, c;" there + are three). */ + tree properties; + location_t loc; + + loc = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)); + + c_parser_consume_token (parser); /* Eat '@property'. */ + + /* Parse the optional attribute list... */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + /* Eat the '(' */ + c_parser_consume_token (parser); + + /* Property attribute keywords are valid now. */ + parser->objc_property_attr_context = true; + + while (true) + { + bool syntax_error = false; + c_token *token = c_parser_peek_token (parser); + enum rid keyword; + + if (token->type != CPP_KEYWORD) + { + if (token->type == CPP_CLOSE_PAREN) + c_parser_error (parser, "expected identifier"); + else + { + c_parser_consume_token (parser); + c_parser_error (parser, "unknown property attribute"); + } + break; + } + keyword = token->keyword; + c_parser_consume_token (parser); + switch (keyword) + { + case RID_ASSIGN: property_assign = true; break; + case RID_COPY: property_copy = true; break; + case RID_NONATOMIC: property_nonatomic = true; break; + case RID_READONLY: property_readonly = true; break; + case RID_READWRITE: property_readwrite = true; break; + case RID_RETAIN: property_retain = true; break; + + case RID_GETTER: + case RID_SETTER: + if (c_parser_next_token_is_not (parser, CPP_EQ)) + { + 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; + } + c_parser_consume_token (parser); /* eat the = */ + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + syntax_error = true; + break; + } + if (keyword == RID_SETTER) + { + if (property_setter_ident != NULL_TREE) + c_parser_error (parser, "the %<setter%> attribute may only be specified once"); + else + property_setter_ident = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_COLON)) + c_parser_error (parser, "setter name must terminate with %<:%>"); + else + c_parser_consume_token (parser); + } + else + { + if (property_getter_ident != NULL_TREE) + c_parser_error (parser, "the %<getter%> attribute may only be specified once"); + else + property_getter_ident = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + break; + default: + c_parser_error (parser, "unknown property attribute"); + syntax_error = true; + break; + } + + if (syntax_error) + break; + + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + parser->objc_property_attr_context = false; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + /* ... and the property declaration(s). */ + properties = c_parser_struct_declaration (parser); + + if (properties == error_mark_node) + { + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; + } + + if (properties == NULL_TREE) + c_parser_error (parser, "expected identifier"); + else + { + /* Comma-separated properties are chained together in + reverse order; add them one by one. */ + properties = nreverse (properties); + + for (; properties; properties = TREE_CHAIN (properties)) + objc_add_property_declaration (loc, copy_node (properties), + property_readonly, property_readwrite, + property_assign, property_retain, + property_copy, property_nonatomic, + property_getter_ident, property_setter_ident); + } + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + parser->error = false; +} + +/* Parse an Objective-C @synthesize declaration. The syntax is: + + objc-synthesize-declaration: + @synthesize objc-synthesize-identifier-list ; + + objc-synthesize-identifier-list: + objc-synthesize-identifier + objc-synthesize-identifier-list, objc-synthesize-identifier + + objc-synthesize-identifier + identifier + identifier = identifier + + For example: + @synthesize MyProperty; + @synthesize OneProperty, AnotherProperty=MyIvar, YetAnotherProperty; + + PS: This function is identical to cp_parser_objc_at_synthesize_declaration + for C++. Keep them in sync. +*/ +static void +c_parser_objc_at_synthesize_declaration (c_parser *parser) +{ + tree list = NULL_TREE; + location_t loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNTHESIZE)); + loc = c_parser_peek_token (parser)->location; + + c_parser_consume_token (parser); + while (true) + { + tree property, ivar; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + /* Once we find the semicolon, we can resume normal parsing. + We have to reset parser->error manually because + c_parser_skip_until_found() won't reset it for us if the + next token is precisely a semicolon. */ + parser->error = false; + return; + } + property = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_EQ)) + { + 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_SEMICOLON, NULL); + parser->error = false; + return; + } + ivar = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + ivar = NULL_TREE; + list = chainon (list, build_tree_list (ivar, property)); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + objc_add_synthesize_declaration (loc, list); +} + +/* Parse an Objective-C @dynamic declaration. The syntax is: + + objc-dynamic-declaration: + @dynamic identifier-list ; + + For example: + @dynamic MyProperty; + @dynamic MyProperty, AnotherProperty; + + PS: This function is identical to cp_parser_objc_at_dynamic_declaration + for C++. Keep them in sync. +*/ +static void +c_parser_objc_at_dynamic_declaration (c_parser *parser) +{ + tree list = NULL_TREE; + location_t loc; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_DYNAMIC)); + loc = c_parser_peek_token (parser)->location; + + c_parser_consume_token (parser); + while (true) + { + tree property; + if (c_parser_next_token_is_not (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); + parser->error = false; + return; + } + property = c_parser_peek_token (parser)->value; + list = chainon (list, build_tree_list (NULL_TREE, property)); + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + objc_add_dynamic_declaration (loc, list); +} + /* Handle pragmas. Some OpenMP pragmas are associated with, and therefore should be considered, statements. ALLOW_STMT is true if we're within @@ -8016,6 +9041,42 @@ rhs = integer_one_node; break; + case COMPOUND_EXPR: + if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR + && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR + && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND + (TREE_OPERAND (lhs, 1), 0), 0))) + == BOOLEAN_TYPE) + /* Undo effects of boolean_increment for post {in,de}crement. */ + lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0); + /* FALLTHRU */ + case MODIFY_EXPR: + if (TREE_CODE (lhs) == MODIFY_EXPR + && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE) + { + /* Undo effects of boolean_increment. */ + if (integer_onep (TREE_OPERAND (lhs, 1))) + { + /* This is pre or post increment. */ + rhs = TREE_OPERAND (lhs, 1); + lhs = TREE_OPERAND (lhs, 0); + code = NOP_EXPR; + break; + } + if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR + && TREE_OPERAND (lhs, 0) + == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) + { + /* This is pre or post decrement. */ + rhs = TREE_OPERAND (lhs, 1); + lhs = TREE_OPERAND (lhs, 0); + code = NOP_EXPR; + break; + } + } + /* FALLTHRU */ default: switch (c_parser_peek_token (parser)->type) { @@ -8052,6 +9113,9 @@ 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; @@ -8144,10 +9208,11 @@ c_parser *parser, tree clauses, tree *par_clauses) { tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl; - tree declv, condv, incrv, initv, for_block = NULL, ret = NULL; + tree declv, condv, incrv, initv, ret = NULL; bool fail = false, open_brace_parsed = false; int i, collapse = 1, nbraces = 0; location_t for_loc; + VEC(tree,gc) *for_block = make_tree_vector (); for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) @@ -8176,13 +9241,12 @@ 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) - for_block - = tree_cons (NULL, c_begin_compound_stmt (true), for_block); - c_parser_declaration_or_fndef (parser, true, true, true, true, true); - decl = check_for_loop_decls (for_loc); + VEC_safe_push (tree, gc, for_block, c_begin_compound_stmt (true)); + c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); + decl = check_for_loop_decls (for_loc, flag_isoc99); if (decl == NULL) goto error_init; if (DECL_INITIAL (decl) == error_mark_node) @@ -8410,15 +9474,15 @@ ret = stmt; } pop_scopes: - while (for_block) + while (!VEC_empty (tree, for_block)) { /* FIXME diagnostics: LOC below should be the actual location of this particular for block. We need to build a list of locations to go along with FOR_BLOCK. */ - stmt = c_end_compound_stmt (loc, TREE_VALUE (for_block), true); + stmt = c_end_compound_stmt (loc, VEC_pop (tree, for_block), true); add_stmt (stmt); - for_block = TREE_CHAIN (for_block); - } + } + release_tree_vector (for_block); return ret; } @@ -8876,7 +9940,7 @@ if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) c_parser_pragma_pch_preprocess (&tparser); - the_parser = GGC_NEW (c_parser); + the_parser = ggc_alloc_c_parser (); *the_parser = tparser; /* Initialize EH, if we've been told to do so. */