X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fc-parser.c;h=56134c24e50a27d3ad47ade5c919d24b0fe25d3e;hb=3cb4b8e201bbdc2105b79eb5995ddd5e6c88c56b;hp=dc5ea8d52ec9d076b150a8550672ddf3afa6b7a7;hpb=069761fbf4b005ff86f4e2bc2b53e70efaf5b89f;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/c-parser.c b/gcc/c-parser.c index dc5ea8d52ec..56134c24e50 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -1,7 +1,7 @@ /* 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 - Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Parser actions based on the old Bison parser; structure somewhat influenced by and fragments based on the C++ parser. @@ -50,9 +50,9 @@ along with GCC; see the file COPYING3. If not see #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" @@ -185,11 +185,22 @@ typedef struct GTY(()) c_parser { /* 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; + /* Nonzero if we're processing a __transaction statement. The value + is 1 | TM_STMT_ATTR_*. */ + unsigned int in_transaction : 4; + /* 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; @@ -245,17 +256,48 @@ c_lex_one_token (c_parser *parser, c_token *token) /* 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; token->keyword = rid_code; break; } + else if (parser->objc_could_be_foreach_context + && rid_code == RID_IN) + { + /* 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. + 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 () @@ -268,8 +310,7 @@ c_lex_one_token (c_parser *parser, c_token *token) 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 @@ -296,8 +337,7 @@ c_lex_one_token (c_parser *parser, c_token *token) 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; @@ -391,6 +431,22 @@ c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword) 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 @@ -455,13 +511,87 @@ c_token_starts_typename (c_token *token) } } +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 @@ -494,6 +624,7 @@ c_token_starts_declspecs (c_token *token) case RID_REGISTER: case RID_TYPEDEF: case RID_INLINE: + case RID_NORETURN: case RID_AUTO: case RID_THREAD: case RID_UNSIGNED: @@ -522,6 +653,7 @@ c_token_starts_declspecs (c_token *token) case RID_FRACT: case RID_ACCUM: case RID_SAT: + case RID_ALIGNAS: return true; default: return false; @@ -554,32 +686,48 @@ static inline bool 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. */ + /* 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; -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]; + /* 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. */ @@ -901,13 +1049,15 @@ disable_extension_diagnostics (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; } @@ -923,6 +1073,7 @@ restore_extension_diagnostics (int flags) 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. */ @@ -944,18 +1095,36 @@ typedef enum c_dtr_syn { C_DTR_PARM } c_dtr_syn; +/* The binary operation precedence levels, where 0 is a dummy lowest level + used for the bottom of the stack. */ +enum c_parser_prec { + PREC_NONE, + PREC_LOGOR, + PREC_LOGAND, + PREC_BITOR, + PREC_BITXOR, + PREC_BITAND, + PREC_EQ, + PREC_REL, + PREC_SHIFT, + PREC_ADD, + PREC_MULT, + NUM_PRECS +}; + 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 *); static struct c_typespec c_parser_typeof_specifier (c_parser *); +static tree c_parser_alignas_specifier (c_parser *); static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn, bool *); static struct c_declarator *c_parser_direct_declarator (c_parser *, bool, @@ -964,7 +1133,8 @@ static struct c_declarator *c_parser_direct_declarator_inner (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 *); @@ -991,7 +1161,8 @@ static tree c_parser_asm_clobbers (c_parser *); static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *); static struct c_expr c_parser_conditional_expression (c_parser *, struct c_expr *); -static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *); +static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, + enum c_parser_prec); static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); static struct c_expr c_parser_unary_expression (c_parser *); static struct c_expr c_parser_sizeof_expression (c_parser *); @@ -1003,6 +1174,9 @@ static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *, static struct c_expr c_parser_postfix_expression_after_primary (c_parser *, location_t loc, struct c_expr); +static tree c_parser_transaction (c_parser *, enum rid); +static struct c_expr c_parser_transaction_expression (c_parser *, enum rid); +static tree c_parser_transaction_cancel (c_parser *); static struct c_expr c_parser_expression (c_parser *); static struct c_expr c_parser_expression_conv (c_parser *); static VEC(tree,gc) *c_parser_expr_list (c_parser *, bool, bool, @@ -1012,6 +1186,7 @@ static void c_parser_omp_threadprivate (c_parser *); static void c_parser_omp_barrier (c_parser *); static void c_parser_omp_flush (c_parser *); static void c_parser_omp_taskwait (c_parser *); +static void c_parser_omp_taskyield (c_parser *); enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; static bool c_parser_pragma (c_parser *, enum pragma_context); @@ -1023,21 +1198,24 @@ 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 *, tree); -static enum tree_code c_parser_objc_method_type (c_parser *); +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 *, 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 *); 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 bool c_parser_objc_diagnose_bad_element_prefix +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). @@ -1136,6 +1314,18 @@ c_parser_external_declaration (c_parser *parser) gcc_assert (c_dialect_objc ()); 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 ()); c_parser_consume_token (parser); @@ -1170,7 +1360,7 @@ c_parser_external_declaration (c_parser *parser) 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); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL); break; } } @@ -1189,6 +1379,8 @@ c_parser_external_declaration (c_parser *parser) (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] ; @@ -1235,6 +1427,10 @@ c_parser_external_declaration (c_parser *parser) 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: @@ -1243,7 +1439,8 @@ c_parser_external_declaration (c_parser *parser) 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; @@ -1258,7 +1455,27 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, 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); @@ -1283,6 +1500,19 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, 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. */ @@ -1346,6 +1576,16 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, 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; } @@ -1359,12 +1599,14 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, { 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 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) { @@ -1375,7 +1617,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, || 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; @@ -1421,7 +1664,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, 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)) { @@ -1438,6 +1689,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, 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 %<;%>"); @@ -1469,6 +1729,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, 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 @@ -1484,7 +1751,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, 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; @@ -1507,6 +1774,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, add_stmt (fnbody); finish_function (); } + + timevar_pop (tv); break; } } @@ -1527,7 +1796,7 @@ c_parser_asm_definition (c_parser *parser) c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } -/* Parse a static assertion (C1X N1425 6.7.10). +/* Parse a static assertion (C11 6.7.10). static_assert-declaration: static_assert-declaration-no-semi ; @@ -1542,7 +1811,7 @@ c_parser_static_assert_declaration (c_parser *parser) c_parser_skip_to_end_of_block_or_statement (parser); } -/* Parse a static assertion (C1X N1425 6.7.10), without the trailing +/* Parse a static assertion (C11 6.7.10), without the trailing semicolon. static_assert-declaration-no-semi: @@ -1558,7 +1827,7 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)); assert_loc = c_parser_peek_token (parser)->location; - if (!flag_isoc1x) + if (!flag_isoc11) { if (flag_isoc99) pedwarn (assert_loc, OPT_pedantic, @@ -1629,9 +1898,11 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) type-specifier declaration-specifiers[opt] type-qualifier declaration-specifiers[opt] function-specifier declaration-specifiers[opt] + alignment-specifier declaration-specifiers[opt] Function specifiers (inline) are from C99, and are currently - handled as storage class specifiers, as is __thread. + handled as storage class specifiers, as is __thread. Alignment + specifiers are from C11. C90 6.5.1, C99 6.7.1: storage-class-specifier: @@ -1644,6 +1915,9 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) C99 6.7.4: function-specifier: inline + _Noreturn + + (_Noreturn is new in C11.) C90 6.5.2, C99 6.7.2: type-specifier: @@ -1712,17 +1986,33 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) 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))) { struct c_typespec t; tree attrs; + tree align; 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; @@ -1738,25 +2028,34 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, 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 { @@ -1766,9 +2065,9 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, 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; } @@ -1796,12 +2095,13 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, case RID_REGISTER: case RID_TYPEDEF: case RID_INLINE: + case RID_NORETURN: case RID_AUTO: case RID_THREAD: if (!scspec_ok) goto out; attrs_ok = true; - /* TODO: Distinguish between function specifiers (inline) + /* TODO: Distinguish between function specifiers (inline, noreturn) and storage class specifiers, either here or in declspecs_add_scspec. */ declspecs_add_scspec (specs, c_parser_peek_token (parser)->value); @@ -1880,6 +2180,10 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, attrs = c_parser_attributes (parser); declspecs_add_attrs (specs, attrs); break; + case RID_ALIGNAS: + align = c_parser_alignas_specifier (parser); + declspecs_add_alignas (specs, align); + break; default: goto out; } @@ -1935,11 +2239,14 @@ c_parser_enum_specifier (c_parser *parser) { /* 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) { @@ -2003,6 +2310,7 @@ c_parser_enum_specifier (c_parser *parser) ret.kind = ctsk_tagdef; ret.expr = NULL_TREE; ret.expr_const_operands = true; + timevar_pop (TV_PARSE_ENUM); return ret; } else if (!ident) @@ -2116,7 +2424,9 @@ c_parser_struct_or_union_specifier (c_parser *parser) 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) }));. */ @@ -2184,12 +2494,17 @@ c_parser_struct_or_union_specifier (c_parser *parser) 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); @@ -2198,6 +2513,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) ret.kind = ctsk_tagdef; ret.expr = NULL_TREE; ret.expr_const_operands = true; + timevar_pop (TV_PARSE_STRUCT); return ret; } else if (!ident) @@ -2270,7 +2586,7 @@ c_parser_struct_declaration (c_parser *parser) } 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) @@ -2279,10 +2595,11 @@ c_parser_struct_declaration (c_parser *parser) return NULL_TREE; } finish_declspecs (specs); - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { tree ret; - if (!specs->type_seen_p) + if (specs->typespec_kind == ctsk_none) { pedwarn (decl_loc, OPT_pedantic, "ISO C forbids member declarations with no members"); @@ -2304,6 +2621,19 @@ c_parser_struct_declaration (c_parser *parser) } 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; @@ -2317,7 +2647,8 @@ c_parser_struct_declaration (c_parser *parser) 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) { @@ -2401,7 +2732,7 @@ c_parser_typeof_specifier (c_parser *parser) 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--; @@ -2435,6 +2766,45 @@ c_parser_typeof_specifier (c_parser *parser) return ret; } +/* Parse an alignment-specifier. + + C11 6.7.5: + + alignment-specifier: + _Alignas ( type-name ) + _Alignas ( constant-expression ) +*/ + +static tree +c_parser_alignas_specifier (c_parser * parser) +{ + tree ret = error_mark_node; + location_t loc = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNAS)); + c_parser_consume_token (parser); + if (!flag_isoc11) + { + if (flag_isoc99) + pedwarn (loc, OPT_pedantic, + "ISO C99 does not support %<_Alignas%>"); + else + pedwarn (loc, OPT_pedantic, + "ISO C90 does not support %<_Alignas%>"); + } + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return ret; + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + struct c_type_name *type = c_parser_type_name (parser); + if (type != NULL) + ret = c_alignof (loc, groktypename (type, NULL, NULL)); + } + else + ret = c_parser_expr_no_commas (parser, NULL).value; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return ret; +} + /* Parse a declarator, possibly an abstract declarator (C90 6.5.4, 6.5.5, C99 6.7.5, 6.7.6). If TYPE_SEEN_P then a typedef name may be redeclared; otherwise it may not. KIND indicates which kind of @@ -2522,7 +2892,7 @@ c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, 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; @@ -2674,12 +3044,12 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present, 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. @@ -2767,7 +3137,13 @@ c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs) 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) @@ -2804,7 +3180,8 @@ c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs) } 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; } @@ -2812,12 +3189,15 @@ c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs) /* 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 @@ -2833,10 +3213,19 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) { 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, - "ISO C requires a named argument before %<...%>"); + + if (flag_allow_parameterless_variadic_functions) + { + /* F (...) is allowed. */ + ret->types = NULL_TREE; + } + else + { + /* Suppress -Wold-style-definition for this case. */ + ret->types = error_mark_node; + error_at (c_parser_peek_token (parser)->location, + "ISO C requires a named argument before %<...%>"); + } c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { @@ -2861,31 +3250,27 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) 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)) @@ -2895,18 +3280,14 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) { 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; } } @@ -2930,9 +3311,7 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs) 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; @@ -2951,12 +3330,13 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs) 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) { @@ -2984,6 +3364,8 @@ static tree 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; @@ -3001,6 +3383,7 @@ c_parser_asm_string_literal (c_parser *parser) c_parser_error (parser, "expected string literal"); str = NULL_TREE; } + warn_overlength_strings = save_flag; return str; } @@ -3036,6 +3419,66 @@ c_parser_simple_asm_expr (c_parser *parser) return str; } +static tree +c_parser_attribute_any_word (c_parser *parser) +{ + tree attr_name = NULL_TREE; + + if (c_parser_next_token_is (parser, CPP_KEYWORD)) + { + /* ??? See comment above about what keywords are accepted here. */ + bool ok; + switch (c_parser_peek_token (parser)->keyword) + { + case RID_STATIC: + case RID_UNSIGNED: + case RID_LONG: + case RID_INT128: + case RID_CONST: + case RID_EXTERN: + case RID_REGISTER: + case RID_TYPEDEF: + case RID_SHORT: + case RID_INLINE: + case RID_NORETURN: + case RID_VOLATILE: + case RID_SIGNED: + case RID_AUTO: + case RID_RESTRICT: + case RID_COMPLEX: + case RID_THREAD: + case RID_INT: + case RID_CHAR: + case RID_FLOAT: + case RID_DOUBLE: + case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: + case RID_BOOL: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_CANCEL: + ok = true; + break; + default: + ok = false; + break; + } + if (!ok) + return NULL_TREE; + + /* Accept __attribute__((__const)) as __attribute__((const)) etc. */ + attr_name = ridpointers[(int) c_parser_peek_token (parser)->keyword]; + } + else if (c_parser_next_token_is (parser, CPP_NAME)) + attr_name = c_parser_peek_token (parser)->value; + + return attr_name; +} + /* Parse (possibly empty) attributes. This is a GNU extension. attributes: @@ -3096,56 +3539,10 @@ c_parser_attributes (c_parser *parser) c_parser_consume_token (parser); continue; } - if (c_parser_next_token_is (parser, CPP_KEYWORD)) - { - /* ??? See comment above about what keywords are - accepted here. */ - bool ok; - switch (c_parser_peek_token (parser)->keyword) - { - case RID_STATIC: - case RID_UNSIGNED: - case RID_LONG: - case RID_INT128: - case RID_CONST: - case RID_EXTERN: - case RID_REGISTER: - case RID_TYPEDEF: - case RID_SHORT: - case RID_INLINE: - case RID_VOLATILE: - case RID_SIGNED: - case RID_AUTO: - case RID_RESTRICT: - case RID_COMPLEX: - case RID_THREAD: - case RID_INT: - case RID_CHAR: - case RID_FLOAT: - case RID_DOUBLE: - case RID_VOID: - case RID_DFLOAT32: - case RID_DFLOAT64: - case RID_DFLOAT128: - case RID_BOOL: - case RID_FRACT: - case RID_ACCUM: - case RID_SAT: - ok = true; - break; - default: - ok = false; - break; - } - if (!ok) - break; - /* Accept __attribute__((__const)) as __attribute__((const)) - etc. */ - attr_name - = ridpointers[(int) c_parser_peek_token (parser)->keyword]; - } - else - attr_name = c_parser_peek_token (parser)->value; + + attr_name = c_parser_attribute_any_word (parser); + if (attr_name == NULL) + break; c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) { @@ -3157,9 +3554,12 @@ c_parser_attributes (c_parser *parser) /* 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))) @@ -3237,15 +3637,19 @@ c_parser_type_name (c_parser *parser) 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; @@ -3499,7 +3903,7 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) 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 @@ -3739,11 +4143,11 @@ c_parser_compound_statement_nostart (c_parser *parser) 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) @@ -3771,7 +4175,7 @@ c_parser_compound_statement_nostart (c_parser *parser) 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); @@ -3901,9 +4305,7 @@ c_parser_label (c_parser *parser) } 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 " @@ -3911,7 +4313,7 @@ c_parser_label (c_parser *parser) 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); } } } @@ -4011,7 +4413,14 @@ c_parser_label (c_parser *parser) atomic-directive expression-statement ordered-construct: - ordered-directive structured-block */ + ordered-directive structured-block + + Transactional Memory: + + statement: + transaction-statement + transaction-cancel-statement +*/ static void c_parser_statement (c_parser *parser) @@ -4066,9 +4475,12 @@ c_parser_statement_after_labels (c_parser *parser) } 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 %<*%>"); @@ -4099,6 +4511,14 @@ c_parser_statement_after_labels (c_parser *parser) case RID_ASM: stmt = c_parser_asm_statement (parser); break; + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + stmt = c_parser_transaction (parser, + c_parser_peek_token (parser)->keyword); + break; + case RID_TRANSACTION_CANCEL: + stmt = c_parser_transaction_cancel (parser); + goto expect_semicolon; case RID_AT_THROW: gcc_assert (c_dialect_objc ()); c_parser_consume_token (parser); @@ -4117,7 +4537,7 @@ c_parser_statement_after_labels (c_parser *parser) 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 ()); @@ -4427,29 +4847,92 @@ c_parser_do_statement (c_parser *parser) 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)) + else if (c_parser_next_tokens_start_declaration (parser)) { - c_parser_declaration_or_fndef (parser, true, true, true, true, true); - check_for_loop_decls (for_loc); + 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)) { @@ -4467,9 +4950,19 @@ c_parser_for_statement (c_parser *parser) 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; @@ -4477,39 +4970,74 @@ c_parser_for_statement (c_parser *parser) else { init_expr: - c_finish_expr_stmt (loc, c_parser_expression (parser).value); - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + { + 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. */ - if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + /* 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) { - c_parser_consume_token (parser); - cond = NULL_TREE; + 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 %<;%>"); + } } - else + /* 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)) { - cond = c_parser_condition (parser); - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + 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); } - /* 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; } @@ -4896,7 +5424,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) gcc_assert (!after || c_dialect_objc ()); - cond = c_parser_binary_expression (parser, after); + cond = c_parser_binary_expression (parser, after, PREC_NONE); if (c_parser_next_token_is_not (parser, CPP_QUERY)) return cond; @@ -4981,7 +5509,8 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) /* Parse a binary expression; that is, a logical-OR-expression (C90 6.3.5-6.3.14, C99 6.5.5-6.5.14). If AFTER is not NULL then it is an Objective-C message expression which is the primary-expression - starting the expression as an initializer. + starting the expression as an initializer. PREC is the starting + precedence, usually PREC_NONE. multiplicative-expression: cast-expression @@ -5033,7 +5562,8 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) */ static struct c_expr -c_parser_binary_expression (c_parser *parser, struct c_expr *after) +c_parser_binary_expression (c_parser *parser, struct c_expr *after, + enum c_parser_prec prec) { /* A binary expression is parsed using operator-precedence parsing, with the operands being cast expressions. All the binary @@ -5056,28 +5586,12 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) expressions, we also need to adjust c_inhibit_evaluation_warnings as appropriate when the operators are pushed and popped. */ - /* The precedence levels, where 0 is a dummy lowest level used for - the bottom of the stack. */ - enum prec { - PREC_NONE, - PREC_LOGOR, - PREC_LOGAND, - PREC_BITOR, - PREC_BITXOR, - PREC_BITAND, - PREC_EQ, - PREC_REL, - PREC_SHIFT, - PREC_ADD, - PREC_MULT, - NUM_PRECS - }; struct { /* The expression at this stack level. */ struct c_expr expr; /* The precedence of the operator on its left, PREC_NONE at the bottom of the stack. */ - enum prec prec; + enum c_parser_prec prec; /* The operation on its left. */ enum tree_code op; /* The source location of this operation. */ @@ -5116,11 +5630,11 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) gcc_assert (!after || c_dialect_objc ()); stack[0].loc = c_parser_peek_token (parser)->location; stack[0].expr = c_parser_cast_expression (parser, after); - stack[0].prec = PREC_NONE; + stack[0].prec = prec; sp = 0; while (true) { - enum prec oprec; + enum c_parser_prec oprec; enum tree_code ocode; if (parser->error) goto out; @@ -5204,9 +5718,13 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) goto out; } binary_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); while (oprec <= stack[sp].prec) - POP; + { + if (sp == 0) + goto out; + POP; + } + c_parser_consume_token (parser); switch (ocode) { case TRUTH_ANDIF_EXPR: @@ -5264,7 +5782,8 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) /* 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))) { @@ -5322,9 +5841,16 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) __alignof__ ( type-name ) && identifier + (C11 permits _Alignof with type names only.) + unary-operator: one of __extension__ __real__ __imag__ + Transactional Memory: + + unary-expression: + transaction-expression + In addition, the GNU syntax treats ++ and -- as unary operators, so they may be applied to cast expressions with errors for non-lvalues given later. */ @@ -5432,6 +5958,10 @@ c_parser_unary_expression (c_parser *parser) op = c_parser_cast_expression (parser, NULL); op = default_function_array_conversion (exp_loc, op); return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + return c_parser_transaction_expression (parser, + c_parser_peek_token (parser)->keyword); default: return c_parser_postfix_expression (parser); } @@ -5505,7 +6035,21 @@ c_parser_alignof_expression (c_parser *parser) { struct c_expr expr; location_t loc = c_parser_peek_token (parser)->location; + tree alignof_spelling = c_parser_peek_token (parser)->value; gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF)); + /* A diagnostic is not required for the use of this identifier in + the implementation namespace; only diagnose it for the C11 + spelling because of existing code using the other spellings. */ + if (!flag_isoc11 + && strcmp (IDENTIFIER_POINTER (alignof_spelling), "_Alignof") == 0) + { + if (flag_isoc99) + pedwarn (loc, OPT_pedantic, "ISO C99 does not support %qE", + alignof_spelling); + else + pedwarn (loc, OPT_pedantic, "ISO C90 does not support %qE", + alignof_spelling); + } c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; in_alignof++; @@ -5554,6 +6098,8 @@ c_parser_alignof_expression (c_parser *parser) mark_exp_read (expr.value); c_inhibit_evaluation_warnings--; in_alignof--; + pedwarn (loc, OPT_pedantic, "ISO C does not allow %<%E (expression)%>", + alignof_spelling); ret.value = c_alignof_expr (loc, expr.value); ret.original_code = ERROR_MARK; ret.original_type = NULL; @@ -5561,6 +6107,52 @@ c_parser_alignof_expression (c_parser *parser) } } +/* Helper function to read arguments of builtins which are interfaces + for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and + others. The name of the builtin is passed using BNAME parameter. + Function returns true if there were no errors while parsing and + stores the arguments in CEXPR_LIST. */ +static bool +c_parser_get_builtin_args (c_parser *parser, const char *bname, + VEC(c_expr_t,gc) **ret_cexpr_list) +{ + location_t loc = c_parser_peek_token (parser)->location; + VEC (c_expr_t,gc) *cexpr_list; + c_expr_t expr; + + *ret_cexpr_list = NULL; + if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) + { + error_at (loc, "cannot take address of %qs", bname); + return false; + } + + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + return true; + } + + expr = c_parser_expr_no_commas (parser, NULL); + cexpr_list = VEC_alloc (c_expr_t, gc, 1); + C_EXPR_APPEND (cexpr_list, expr); + while (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + expr = c_parser_expr_no_commas (parser, NULL); + C_EXPR_APPEND (cexpr_list, expr); + } + + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return false; + + *ret_cexpr_list = cexpr_list; + return true; +} + + /* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2). postfix-expression: @@ -5598,6 +6190,11 @@ c_parser_alignof_expression (c_parser *parser) assignment-expression , assignment-expression ) __builtin_types_compatible_p ( type-name , type-name ) + __builtin_complex ( assignment-expression , assignment-expression ) + __builtin_shuffle ( assignment-expression , assignment-expression ) + __builtin_shuffle ( assignment-expression , + assignment-expression , + assignment-expression, ) offsetof-member-designator: identifier @@ -5612,12 +6209,13 @@ c_parser_alignof_expression (c_parser *parser) @protocol ( identifier ) @encode ( type-name ) objc-string-literal + Classname . identifier */ static struct c_expr c_parser_postfix_expression (c_parser *parser) { - struct c_expr expr, e1, e2, e3; + struct c_expr expr, e1; struct c_type_name *t1, *t2; location_t loc = c_parser_peek_token (parser)->location;; expr.original_code = ERROR_MARK; @@ -5658,20 +6256,48 @@ c_parser_postfix_expression (c_parser *parser) 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 @@ -5684,7 +6310,7 @@ c_parser_postfix_expression (c_parser *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"); @@ -5797,16 +6423,16 @@ c_parser_postfix_expression (c_parser *parser) } 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; @@ -5871,49 +6497,48 @@ c_parser_postfix_expression (c_parser *parser) c_parser_error (parser, "expected identifier"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - expr.value = fold_offsetof (offsetof_ref, NULL_TREE); + expr.value = fold_offsetof (offsetof_ref); } break; case RID_CHOOSE_EXPR: - c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - expr.value = error_mark_node; - break; - } - loc = c_parser_peek_token (parser)->location; - e1 = c_parser_expr_no_commas (parser, NULL); - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.value = error_mark_node; - break; - } - e2 = c_parser_expr_no_commas (parser, NULL); - if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - expr.value = error_mark_node; - break; - } - e3 = c_parser_expr_no_commas (parser, NULL); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); { + VEC (c_expr_t, gc) *cexpr_list; + c_expr_t *e1_p, *e2_p, *e3_p; tree c; - c = e1.value; - mark_exp_read (e2.value); - mark_exp_read (e3.value); + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_choose_expr", + &cexpr_list)) + { + expr.value = error_mark_node; + break; + } + + if (VEC_length (c_expr_t, cexpr_list) != 3) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_choose_expr%>"); + expr.value = error_mark_node; + break; + } + + e1_p = VEC_index (c_expr_t, cexpr_list, 0); + e2_p = VEC_index (c_expr_t, cexpr_list, 1); + e3_p = VEC_index (c_expr_t, cexpr_list, 2); + + c = e1_p->value; + mark_exp_read (e2_p->value); + mark_exp_read (e3_p->value); if (TREE_CODE (c) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (c))) error_at (loc, "first argument to %<__builtin_choose_expr%> not" " a constant"); constant_expression_warning (c); - expr = integer_zerop (c) ? e3 : e2; + expr = integer_zerop (c) ? *e3_p : *e2_p; + break; } - break; case RID_TYPES_COMPATIBLE_P: c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) @@ -5943,14 +6568,120 @@ c_parser_postfix_expression (c_parser *parser) "expected %<)%>"); { tree e1, e2; + e1 = groktypename (t1, NULL, NULL); + e2 = groktypename (t2, NULL, NULL); + if (e1 == error_mark_node || e2 == error_mark_node) + { + expr.value = error_mark_node; + break; + } - e1 = TYPE_MAIN_VARIANT (groktypename (t1, NULL, NULL)); - e2 = TYPE_MAIN_VARIANT (groktypename (t2, NULL, NULL)); + e1 = TYPE_MAIN_VARIANT (e1); + e2 = TYPE_MAIN_VARIANT (e2); expr.value = comptypes (e1, e2) ? integer_one_node : integer_zero_node; } break; + case RID_BUILTIN_COMPLEX: + { + VEC(c_expr_t, gc) *cexpr_list; + c_expr_t *e1_p, *e2_p; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_complex", + &cexpr_list)) + { + expr.value = error_mark_node; + break; + } + + if (VEC_length (c_expr_t, cexpr_list) != 2) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_complex%>"); + expr.value = error_mark_node; + break; + } + + e1_p = VEC_index (c_expr_t, cexpr_list, 0); + e2_p = VEC_index (c_expr_t, cexpr_list, 1); + + mark_exp_read (e1_p->value); + if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR) + e1_p->value = convert (TREE_TYPE (e1_p->value), + TREE_OPERAND (e1_p->value, 0)); + mark_exp_read (e2_p->value); + if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR) + e2_p->value = convert (TREE_TYPE (e2_p->value), + TREE_OPERAND (e2_p->value, 0)); + if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) + || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) + || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2_p->value)) + || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2_p->value))) + { + error_at (loc, "%<__builtin_complex%> operand " + "not of real binary floating-point type"); + expr.value = error_mark_node; + break; + } + if (TYPE_MAIN_VARIANT (TREE_TYPE (e1_p->value)) + != TYPE_MAIN_VARIANT (TREE_TYPE (e2_p->value))) + { + error_at (loc, + "%<__builtin_complex%> operands of different types"); + expr.value = error_mark_node; + break; + } + if (!flag_isoc99) + pedwarn (loc, OPT_pedantic, + "ISO C90 does not support complex types"); + expr.value = build2 (COMPLEX_EXPR, + build_complex_type + (TYPE_MAIN_VARIANT + (TREE_TYPE (e1_p->value))), + e1_p->value, e2_p->value); + break; + } + case RID_BUILTIN_SHUFFLE: + { + VEC(c_expr_t,gc) *cexpr_list; + unsigned int i; + c_expr_t *p; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_shuffle", + &cexpr_list)) + { + expr.value = error_mark_node; + break; + } + + FOR_EACH_VEC_ELT (c_expr_t, cexpr_list, i, p) + mark_exp_read (p->value); + + if (VEC_length (c_expr_t, cexpr_list) == 2) + expr.value = + c_build_vec_perm_expr + (loc, VEC_index (c_expr_t, cexpr_list, 0)->value, + NULL_TREE, VEC_index (c_expr_t, cexpr_list, 1)->value); + + else if (VEC_length (c_expr_t, cexpr_list) == 3) + expr.value = + c_build_vec_perm_expr + (loc, VEC_index (c_expr_t, cexpr_list, 0)->value, + VEC_index (c_expr_t, cexpr_list, 1)->value, + VEC_index (c_expr_t, cexpr_list, 2)->value); + else + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_shuffle%>"); + expr.value = error_mark_node; + } + break; + } case RID_AT_SELECTOR: gcc_assert (c_dialect_objc ()); c_parser_consume_token (parser); @@ -6027,8 +6758,7 @@ c_parser_postfix_expression (c_parser *parser) 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. */ @@ -6359,6 +7089,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, 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: @@ -6393,17 +7125,29 @@ c_parser_objc_class_definition (c_parser *parser, tree attributes) 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) { @@ -6490,7 +7234,7 @@ c_parser_objc_class_instance_variables (c_parser *parser) 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; } @@ -6504,19 +7248,25 @@ c_parser_objc_class_instance_variables (c_parser *parser) if (c_parser_next_token_is_keyword (parser, RID_AT_PRIVATE)) { c_parser_consume_token (parser); - objc_set_visibility (2); + 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 (0); + objc_set_visibility (OBJC_IVAR_VIS_PROTECTED); continue; } else if (c_parser_next_token_is_keyword (parser, RID_AT_PUBLIC)) { c_parser_consume_token (parser); - objc_set_visibility (1); + objc_set_visibility (OBJC_IVAR_VIS_PUBLIC); + continue; + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_PACKAGE)) + { + c_parser_consume_token (parser); + objc_set_visibility (OBJC_IVAR_VIS_PACKAGE); continue; } else if (c_parser_next_token_is (parser, CPP_PRAGMA)) @@ -6527,13 +7277,34 @@ c_parser_objc_class_instance_variables (c_parser *parser) /* 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 %<;%>"); } } @@ -6547,7 +7318,6 @@ c_parser_objc_class_instance_variables (c_parser *parser) 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 @@ -6558,10 +7328,12 @@ c_parser_objc_class_declaration (c_parser *parser) 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)); + objc_declare_class (id); c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); @@ -6569,7 +7341,6 @@ c_parser_objc_class_declaration (c_parser *parser) break; } c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - objc_declare_class (list); } /* Parse an objc-alias-declaration. @@ -6629,7 +7400,6 @@ c_parser_objc_protocol_definition (c_parser *parser, tree attributes) 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) @@ -6641,7 +7411,7 @@ c_parser_objc_protocol_definition (c_parser *parser, tree attributes) 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); @@ -6649,7 +7419,6 @@ c_parser_objc_protocol_definition (c_parser *parser, tree attributes) break; } c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - objc_declare_protocols (list); } else { @@ -6672,19 +7441,21 @@ c_parser_objc_protocol_definition (c_parser *parser, tree attributes) objc-method-type: + - -*/ -static enum tree_code + Return true if it is a class method (+) and false if it is + an instance method (-). +*/ +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 (); } @@ -6699,11 +7470,11 @@ c_parser_objc_method_type (c_parser *parser) static void c_parser_objc_method_definition (c_parser *parser) { - enum tree_code type = c_parser_objc_method_type (parser); - tree decl, attributes = NULL_TREE; - objc_set_method_type (type); + bool is_class_method = c_parser_objc_method_type (parser); + tree decl, attributes = NULL_TREE, expr = NULL_TREE; parser->objc_pq_context = true; - decl = c_parser_objc_method_decl (parser, &attributes); + decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, + &expr); if (decl == error_mark_node) return; /* Bail here. */ @@ -6721,7 +7492,7 @@ c_parser_objc_method_definition (c_parser *parser) } parser->objc_pq_context = false; - if (objc_start_method_definition (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); @@ -6729,8 +7500,9 @@ c_parser_objc_method_definition (c_parser *parser) else { /* This code is executed when we find a method definition - outside of an @implementation context. Parse the method (to - keep going) but do not emit any code. + 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); } @@ -6777,6 +7549,8 @@ c_parser_objc_methodprotolist (c_parser *parser) default: if (c_parser_next_token_is_keyword (parser, RID_AT_END)) return; + 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); @@ -6789,7 +7563,7 @@ c_parser_objc_methodprotolist (c_parser *parser) } else c_parser_declaration_or_fndef (parser, false, false, true, - false, true); + false, true, NULL); break; } } @@ -6804,12 +7578,13 @@ c_parser_objc_methodprotolist (c_parser *parser) static void c_parser_objc_methodproto (c_parser *parser) { - enum tree_code type = c_parser_objc_method_type (parser); + bool is_class_method = c_parser_objc_method_type (parser); tree decl, attributes = NULL_TREE; - objc_set_method_type (type); + /* Remember protocol qualifiers in prototypes. */ parser->objc_pq_context = true; - decl = c_parser_objc_method_decl (parser, &attributes); + decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, + NULL); /* Forget protocol qualifiers now. */ parser->objc_pq_context = false; @@ -6822,7 +7597,7 @@ c_parser_objc_methodproto (c_parser *parser) } if (decl != error_mark_node) - objc_add_method_declaration (decl, attributes); + objc_add_method_declaration (is_class_method, decl, attributes); c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } @@ -6895,7 +7670,8 @@ c_parser_objc_maybe_method_attributes (c_parser* parser, tree* attributes) */ static tree -c_parser_objc_method_decl (c_parser *parser, tree *attributes) +c_parser_objc_method_decl (c_parser *parser, bool is_class_method, + tree *attributes, tree *expr) { tree type = NULL_TREE; tree sel; @@ -6970,7 +7746,7 @@ c_parser_objc_method_decl (c_parser *parser, tree *attributes) if (parm == NULL) break; parms = chainon (parms, - build_tree_list (NULL_TREE, grokparm (parm))); + build_tree_list (NULL_TREE, grokparm (parm, expr))); } sel = list; } @@ -6986,7 +7762,7 @@ c_parser_objc_method_decl (c_parser *parser, tree *attributes) if (attr_err) return error_mark_node; - return objc_build_method_signature (type, sel, parms, ellipsis); + return objc_build_method_signature (is_class_method, type, sel, parms, ellipsis); } /* Parse an objc-type-name. @@ -7020,16 +7796,24 @@ c_parser_objc_type_name (c_parser *parser) || 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); } @@ -7067,53 +7851,98 @@ c_parser_objc_protocol_refs (c_parser *parser) 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)); - if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + 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 (); } @@ -7132,6 +7961,7 @@ c_parser_objc_synchronized_statement (c_parser *parser) 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; @@ -7343,7 +8173,8 @@ static bool c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, struct c_declspecs *specs) { - if (!specs->declspecs_seen_p || specs->type_seen_p || specs->non_sc_seen_p) + if (!specs->declspecs_seen_p || specs->non_sc_seen_p + || specs->typespec_kind != ctsk_none) { c_parser_error (parser, "no type or storage class may be specified here,"); @@ -7352,6 +8183,306 @@ c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, } 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 % attribute)"); + else + c_parser_error (parser, + "missing %<=%> (after % 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 % 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 % 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 @@ -7401,6 +8532,17 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_omp_taskwait (parser); return false; + case PRAGMA_OMP_TASKYIELD: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp taskyield%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_taskyield (parser); + return false; + case PRAGMA_OMP_THREADPRIVATE: c_parser_omp_threadprivate (parser); return false; @@ -7516,13 +8658,19 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; break; case 'f': - if (!strcmp ("firstprivate", p)) + if (!strcmp ("final", p)) + result = PRAGMA_OMP_CLAUSE_FINAL; + else if (!strcmp ("firstprivate", p)) result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; break; case 'l': if (!strcmp ("lastprivate", p)) result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; break; + case 'm': + if (!strcmp ("mergeable", p)) + result = PRAGMA_OMP_CLAUSE_MERGEABLE; + break; case 'n': if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; @@ -7764,6 +8912,31 @@ c_parser_omp_clause_firstprivate (c_parser *parser, tree list) return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list); } +/* OpenMP 3.1: + final ( expression ) */ + +static tree +c_parser_omp_clause_final (c_parser *parser, tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + tree t = c_parser_paren_condition (parser); + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_FINAL, "final"); + + c = build_omp_clause (loc, OMP_CLAUSE_FINAL); + OMP_CLAUSE_FINAL_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + else + c_parser_error (parser, "expected %<(%>"); + + return list; +} + /* OpenMP 2.5: if ( expression ) */ @@ -7798,6 +8971,24 @@ c_parser_omp_clause_lastprivate (c_parser *parser, tree list) return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list); } +/* OpenMP 3.1: + mergeable */ + +static tree +c_parser_omp_clause_mergeable (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + /* FIXME: Should we allow duplicates? */ + check_no_duplicate_clause (list, OMP_CLAUSE_MERGEABLE, "mergeable"); + + c = build_omp_clause (c_parser_peek_token (parser)->location, + OMP_CLAUSE_MERGEABLE); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + /* OpenMP 2.5: nowait */ @@ -7825,6 +9016,7 @@ c_parser_omp_clause_num_threads (c_parser *parser, tree list) { location_t expr_loc = c_parser_peek_token (parser)->location; tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); t = c_fully_fold (t, false, NULL); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); @@ -7888,7 +9080,12 @@ c_parser_omp_clause_private (c_parser *parser, tree list) reduction ( reduction-operator : variable-list ) reduction-operator: - One of: + * - & ^ | && || */ + One of: + * - & ^ | && || + + OpenMP 3.1: + + reduction-operator: + One of: + * - & ^ | && || max min */ static tree c_parser_omp_clause_reduction (c_parser *parser, tree list) @@ -7924,10 +9121,26 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) case CPP_OR_OR: code = TRUTH_ORIF_EXPR; break; + case CPP_NAME: + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "min") == 0) + { + code = MIN_EXPR; + break; + } + if (strcmp (p, "max") == 0) + { + code = MAX_EXPR; + break; + } + } + /* FALLTHRU */ default: c_parser_error (parser, "expected %<+%>, %<*%>, %<-%>, %<&%>, " - "%<^%>, %<|%>, %<&&%>, or %<||%>"); + "%<^%>, %<|%>, %<&&%>, %<||%>, % or %"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); return list; } @@ -8011,6 +9224,7 @@ c_parser_omp_clause_schedule (c_parser *parser, tree list) here = c_parser_peek_token (parser)->location; t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); t = c_fully_fold (t, false, NULL); if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) @@ -8115,6 +9329,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, clauses = c_parser_omp_clause_firstprivate (parser, clauses); c_name = "firstprivate"; break; + case PRAGMA_OMP_CLAUSE_FINAL: + clauses = c_parser_omp_clause_final (parser, clauses); + c_name = "final"; + break; case PRAGMA_OMP_CLAUSE_IF: clauses = c_parser_omp_clause_if (parser, clauses); c_name = "if"; @@ -8123,6 +9341,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, clauses = c_parser_omp_clause_lastprivate (parser, clauses); c_name = "lastprivate"; break; + case PRAGMA_OMP_CLAUSE_MERGEABLE: + clauses = c_parser_omp_clause_mergeable (parser, clauses); + c_name = "mergeable"; + break; case PRAGMA_OMP_CLAUSE_NOWAIT: clauses = c_parser_omp_clause_nowait (parser, clauses); c_name = "nowait"; @@ -8202,38 +9424,158 @@ c_parser_omp_structured_block (c_parser *parser) where x is an lvalue expression with scalar type. + OpenMP 3.1: + # pragma omp atomic new-line + update-stmt + + # pragma omp atomic read new-line + read-stmt + + # pragma omp atomic write new-line + write-stmt + + # pragma omp atomic update new-line + update-stmt + + # pragma omp atomic capture new-line + capture-stmt + + # pragma omp atomic capture new-line + capture-block + + read-stmt: + v = x + write-stmt: + x = expr + update-stmt: + expression-stmt | x = x binop expr + capture-stmt: + v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } + + where x and v are lvalue expressions with scalar type. + LOC is the location of the #pragma token. */ static void c_parser_omp_atomic (location_t loc, c_parser *parser) { - tree lhs, rhs; - tree stmt; - enum tree_code code; + tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE; + tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; + tree stmt, orig_lhs; + enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; struct c_expr rhs_expr; + bool structured_block = false; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (!strcmp (p, "read")) + code = OMP_ATOMIC_READ; + else if (!strcmp (p, "write")) + code = NOP_EXPR; + else if (!strcmp (p, "update")) + code = OMP_ATOMIC; + else if (!strcmp (p, "capture")) + code = OMP_ATOMIC_CAPTURE_NEW; + else + p = NULL; + if (p) + c_parser_consume_token (parser); + } c_parser_skip_to_pragma_eol (parser); + switch (code) + { + case OMP_ATOMIC_READ: + case NOP_EXPR: /* atomic write */ + v = c_parser_unary_expression (parser).value; + v = c_fully_fold (v, false, NULL); + if (v == error_mark_node) + goto saw_error; + loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + if (code == NOP_EXPR) + lhs = c_parser_expression (parser).value; + else + lhs = c_parser_unary_expression (parser).value; + lhs = c_fully_fold (lhs, false, NULL); + if (lhs == error_mark_node) + goto saw_error; + if (code == NOP_EXPR) + { + /* atomic write is represented by OMP_ATOMIC with NOP_EXPR + opcode. */ + code = OMP_ATOMIC; + rhs = lhs; + lhs = v; + v = NULL_TREE; + } + goto done; + case OMP_ATOMIC_CAPTURE_NEW: + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + c_parser_consume_token (parser); + structured_block = true; + } + else + { + v = c_parser_unary_expression (parser).value; + v = c_fully_fold (v, false, NULL); + if (v == error_mark_node) + goto saw_error; + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + } + break; + default: + break; + } + + /* For structured_block case we don't know yet whether + old or new x should be captured. */ +restart: lhs = c_parser_unary_expression (parser).value; lhs = c_fully_fold (lhs, false, NULL); + orig_lhs = lhs; switch (TREE_CODE (lhs)) { case ERROR_MARK: saw_error: c_parser_skip_to_end_of_block_or_statement (parser); + if (structured_block) + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + c_parser_consume_token (parser); + else if (code == OMP_ATOMIC_CAPTURE_NEW) + { + c_parser_skip_to_end_of_block_or_statement (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + c_parser_consume_token (parser); + } + } return; - case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: + if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) + code = OMP_ATOMIC_CAPTURE_OLD; + /* FALLTHROUGH */ + case PREINCREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); - code = PLUS_EXPR; + opcode = PLUS_EXPR; rhs = integer_one_node; break; - case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: + if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) + code = OMP_ATOMIC_CAPTURE_OLD; + /* FALLTHROUGH */ + case PREDECREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); - code = MINUS_EXPR; + opcode = MINUS_EXPR; rhs = integer_one_node; break; @@ -8258,7 +9600,11 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* This is pre or post increment. */ rhs = TREE_OPERAND (lhs, 1); lhs = TREE_OPERAND (lhs, 0); - code = NOP_EXPR; + opcode = NOP_EXPR; + if (code == OMP_ATOMIC_CAPTURE_NEW + && !structured_block + && TREE_CODE (orig_lhs) == COMPOUND_EXPR) + code = OMP_ATOMIC_CAPTURE_OLD; break; } if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR @@ -8268,7 +9614,11 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* This is pre or post decrement. */ rhs = TREE_OPERAND (lhs, 1); lhs = TREE_OPERAND (lhs, 0); - code = NOP_EXPR; + opcode = NOP_EXPR; + if (code == OMP_ATOMIC_CAPTURE_NEW + && !structured_block + && TREE_CODE (orig_lhs) == COMPOUND_EXPR) + code = OMP_ATOMIC_CAPTURE_OLD; break; } } @@ -8277,38 +9627,123 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) switch (c_parser_peek_token (parser)->type) { case CPP_MULT_EQ: - code = MULT_EXPR; + opcode = MULT_EXPR; break; case CPP_DIV_EQ: - code = TRUNC_DIV_EXPR; + opcode = TRUNC_DIV_EXPR; break; case CPP_PLUS_EQ: - code = PLUS_EXPR; + opcode = PLUS_EXPR; break; case CPP_MINUS_EQ: - code = MINUS_EXPR; + opcode = MINUS_EXPR; break; case CPP_LSHIFT_EQ: - code = LSHIFT_EXPR; + opcode = LSHIFT_EXPR; break; case CPP_RSHIFT_EQ: - code = RSHIFT_EXPR; + opcode = RSHIFT_EXPR; break; case CPP_AND_EQ: - code = BIT_AND_EXPR; + opcode = BIT_AND_EXPR; break; case CPP_OR_EQ: - code = BIT_IOR_EXPR; + opcode = BIT_IOR_EXPR; break; case CPP_XOR_EQ: - code = BIT_XOR_EXPR; + opcode = BIT_XOR_EXPR; break; + case CPP_EQ: + if (structured_block || code == OMP_ATOMIC) + { + location_t aloc = c_parser_peek_token (parser)->location; + location_t rhs_loc; + enum c_parser_prec oprec = PREC_NONE; + + c_parser_consume_token (parser); + rhs1 = c_parser_unary_expression (parser).value; + rhs1 = c_fully_fold (rhs1, false, NULL); + if (rhs1 == error_mark_node) + goto saw_error; + switch (c_parser_peek_token (parser)->type) + { + case CPP_SEMICOLON: + if (code == OMP_ATOMIC_CAPTURE_NEW) + { + code = OMP_ATOMIC_CAPTURE_OLD; + v = lhs; + lhs = NULL_TREE; + lhs1 = rhs1; + rhs1 = NULL_TREE; + c_parser_consume_token (parser); + goto restart; + } + c_parser_error (parser, + "invalid form of %<#pragma omp atomic%>"); + goto saw_error; + case CPP_MULT: + opcode = MULT_EXPR; + oprec = PREC_MULT; + break; + case CPP_DIV: + opcode = TRUNC_DIV_EXPR; + oprec = PREC_MULT; + break; + case CPP_PLUS: + opcode = PLUS_EXPR; + oprec = PREC_ADD; + break; + case CPP_MINUS: + opcode = MINUS_EXPR; + oprec = PREC_ADD; + break; + case CPP_LSHIFT: + opcode = LSHIFT_EXPR; + oprec = PREC_SHIFT; + break; + case CPP_RSHIFT: + opcode = RSHIFT_EXPR; + oprec = PREC_SHIFT; + break; + case CPP_AND: + opcode = BIT_AND_EXPR; + oprec = PREC_BITAND; + break; + case CPP_OR: + opcode = BIT_IOR_EXPR; + oprec = PREC_BITOR; + break; + case CPP_XOR: + opcode = BIT_XOR_EXPR; + oprec = PREC_BITXOR; + break; + default: + c_parser_error (parser, + "invalid operator for %<#pragma omp atomic%>"); + goto saw_error; + } + loc = aloc; + c_parser_consume_token (parser); + rhs_loc = c_parser_peek_token (parser)->location; + if (commutative_tree_code (opcode)) + oprec = (enum c_parser_prec) (oprec - 1); + rhs_expr = c_parser_binary_expression (parser, NULL, oprec); + rhs_expr = default_function_array_read_conversion (rhs_loc, + rhs_expr); + rhs = rhs_expr.value; + rhs = c_fully_fold (rhs, false, NULL); + goto stmt_done; + } + /* FALLTHROUGH */ default: c_parser_error (parser, "invalid operator for %<#pragma omp atomic%>"); 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; @@ -8319,10 +9754,34 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) rhs = c_fully_fold (rhs, false, NULL); break; } - stmt = c_finish_omp_atomic (loc, code, lhs, rhs); +stmt_done: + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + goto saw_error; + v = c_parser_unary_expression (parser).value; + v = c_fully_fold (v, false, NULL); + if (v == error_mark_node) + goto saw_error; + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + goto saw_error; + lhs1 = c_parser_unary_expression (parser).value; + lhs1 = c_fully_fold (lhs1, false, NULL); + if (lhs1 == error_mark_node) + goto saw_error; + } + if (structured_block) + { + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); + } +done: + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1); if (stmt != error_mark_node) add_stmt (stmt); - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + + if (!structured_block) + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } @@ -8434,12 +9893,12 @@ c_parser_omp_for_loop (location_t loc, goto pop_scopes; /* Parse the initialization declaration or expression. */ - if (c_parser_next_token_starts_declaration (parser)) + if (c_parser_next_tokens_start_declaration (parser)) { if (i > 0) VEC_safe_push (tree, gc, for_block, c_begin_compound_stmt (true)); - c_parser_declaration_or_fndef (parser, true, true, true, true, true); - decl = check_for_loop_decls (for_loc); + 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) @@ -8485,7 +9944,8 @@ c_parser_omp_for_loop (location_t loc, if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) { location_t cond_loc = c_parser_peek_token (parser)->location; - struct c_expr cond_expr = c_parser_binary_expression (parser, NULL); + struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, + PREC_NONE); cond = cond_expr.value; cond = c_objc_common_truthvalue_conversion (cond_loc, cond); @@ -8982,7 +10442,9 @@ c_parser_omp_single (location_t loc, c_parser *parser) | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED)) + | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ + | (1u << PRAGMA_OMP_CLAUSE_FINAL) \ + | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE)) static tree c_parser_omp_task (location_t loc, c_parser *parser) @@ -9011,6 +10473,20 @@ c_parser_omp_taskwait (c_parser *parser) c_finish_omp_taskwait (loc); } +/* OpenMP 3.1: + # pragma omp taskyield new-line +*/ + +static void +c_parser_omp_taskyield (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_taskyield (loc); +} + /* Main entry point to parsing most OpenMP pragmas. */ static void @@ -9116,6 +10592,217 @@ c_parser_omp_threadprivate (c_parser *parser) c_parser_skip_to_pragma_eol (parser); } +/* Parse a transaction attribute (GCC Extension). + + transaction-attribute: + attributes + [ [ any-word ] ] + + The transactional memory language description is written for C++, + and uses the C++0x attribute syntax. For compatibility, allow the + bracket style for transactions in C as well. */ + +static tree +c_parser_transaction_attributes (c_parser *parser) +{ + tree attr_name, attr = NULL; + + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + return c_parser_attributes (parser); + + if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + return NULL_TREE; + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) + goto error1; + + attr_name = c_parser_attribute_any_word (parser); + if (attr_name) + { + c_parser_consume_token (parser); + attr = build_tree_list (attr_name, NULL_TREE); + } + else + c_parser_error (parser, "expected identifier"); + + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + error1: + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + return attr; +} + +/* Parse a __transaction_atomic or __transaction_relaxed statement + (GCC Extension). + + transaction-statement: + __transaction_atomic transaction-attribute[opt] compound-statement + __transaction_relaxed compound-statement + + Note that the only valid attribute is: "outer". +*/ + +static tree +c_parser_transaction (c_parser *parser, enum rid keyword) +{ + unsigned int old_in = parser->in_transaction; + unsigned int this_in = 1, new_in; + location_t loc = c_parser_peek_token (parser)->location; + tree stmt, attrs; + + gcc_assert ((keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED) + && c_parser_next_token_is_keyword (parser, keyword)); + c_parser_consume_token (parser); + + if (keyword == RID_TRANSACTION_RELAXED) + this_in |= TM_STMT_ATTR_RELAXED; + else + { + attrs = c_parser_transaction_attributes (parser); + if (attrs) + this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); + } + + /* Keep track if we're in the lexical scope of an outer transaction. */ + new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); + + parser->in_transaction = new_in; + stmt = c_parser_compound_statement (parser); + parser->in_transaction = old_in; + + if (flag_tm) + stmt = c_finish_transaction (loc, stmt, this_in); + else + error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? + "%<__transaction_atomic%> without transactional memory support enabled" + : "%<__transaction_relaxed %> " + "without transactional memory support enabled")); + + return stmt; +} + +/* Parse a __transaction_atomic or __transaction_relaxed expression + (GCC Extension). + + transaction-expression: + __transaction_atomic ( expression ) + __transaction_relaxed ( expression ) +*/ + +static struct c_expr +c_parser_transaction_expression (c_parser *parser, enum rid keyword) +{ + struct c_expr ret; + unsigned int old_in = parser->in_transaction; + unsigned int this_in = 1; + location_t loc = c_parser_peek_token (parser)->location; + tree attrs; + + gcc_assert ((keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED) + && c_parser_next_token_is_keyword (parser, keyword)); + c_parser_consume_token (parser); + + if (keyword == RID_TRANSACTION_RELAXED) + this_in |= TM_STMT_ATTR_RELAXED; + else + { + attrs = c_parser_transaction_attributes (parser); + if (attrs) + this_in |= parse_tm_stmt_attr (attrs, 0); + } + + parser->in_transaction = this_in; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + tree expr = c_parser_expression (parser).value; + ret.original_type = TREE_TYPE (expr); + ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr); + if (this_in & TM_STMT_ATTR_RELAXED) + TRANSACTION_EXPR_RELAXED (ret.value) = 1; + SET_EXPR_LOCATION (ret.value, loc); + ret.original_code = TRANSACTION_EXPR; + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + goto error; + } + } + else + { + error: + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + } + parser->in_transaction = old_in; + + if (!flag_tm) + error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? + "%<__transaction_atomic%> without transactional memory support enabled" + : "%<__transaction_relaxed %> " + "without transactional memory support enabled")); + + return ret; +} + +/* Parse a __transaction_cancel statement (GCC Extension). + + transaction-cancel-statement: + __transaction_cancel transaction-attribute[opt] ; + + Note that the only valid attribute is "outer". +*/ + +static tree +c_parser_transaction_cancel(c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree attrs; + bool is_outer = false; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRANSACTION_CANCEL)); + c_parser_consume_token (parser); + + attrs = c_parser_transaction_attributes (parser); + if (attrs) + is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0); + + if (!flag_tm) + { + error_at (loc, "%<__transaction_cancel%> without " + "transactional memory support enabled"); + goto ret_error; + } + else if (parser->in_transaction & TM_STMT_ATTR_RELAXED) + { + error_at (loc, "%<__transaction_cancel%> within a " + "%<__transaction_relaxed%>"); + goto ret_error; + } + else if (is_outer) + { + if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0 + && !is_tm_may_cancel_outer (current_function_decl)) + { + error_at (loc, "outer %<__transaction_cancel%> not " + "within outer %<__transaction_atomic%>"); + error_at (loc, " or a % function"); + goto ret_error; + } + } + else if (parser->in_transaction == 0) + { + error_at (loc, "%<__transaction_cancel%> not within " + "%<__transaction_atomic%>"); + goto ret_error; + } + + return add_stmt (build_tm_abort_call (loc, is_outer)); + + ret_error: + return build1 (NOP_EXPR, void_type_node, error_mark_node); +} /* Parse a single source file. */