X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fc-parser.c;h=56134c24e50a27d3ad47ade5c919d24b0fe25d3e;hb=9a34200da273acd28cd55db9db5194395ea568c0;hp=09b635990eed43c7e7349b43858d289c96a47dd6;hpb=3cc31756fce2c612cab8af652dc2e2c1f778e19c;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 09b635990ee..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 - 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. @@ -40,150 +40,25 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" +#include "tm.h" /* For rtl.h: needs enum reg_class. */ #include "tree.h" -#include "rtl.h" #include "langhooks.h" #include "input.h" #include "cpplib.h" #include "timevar.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" #include "c-tree.h" #include "flags.h" #include "output.h" -#include "toplev.h" #include "ggc.h" -#include "c-common.h" +#include "c-family/c-common.h" +#include "c-family/c-objc.h" #include "vec.h" #include "target.h" #include "cgraph.h" +#include "plugin.h" -/* The reserved keyword table. */ -struct resword -{ - const char *word; - ENUM_BITFIELD(rid) rid : 16; - unsigned int disable : 16; -}; - -/* Disable mask. Keywords are disabled if (reswords[i].disable & - mask) is _true_. */ -#define D_C89 0x01 /* not in C89 */ -#define D_EXT 0x02 /* GCC extension */ -#define D_EXT89 0x04 /* GCC extension incorporated in C99 */ -#define D_OBJC 0x08 /* Objective C only */ - -static const struct resword reswords[] = -{ - { "_Bool", RID_BOOL, 0 }, - { "_Complex", RID_COMPLEX, 0 }, - { "_Decimal32", RID_DFLOAT32, D_EXT }, - { "_Decimal64", RID_DFLOAT64, D_EXT }, - { "_Decimal128", RID_DFLOAT128, D_EXT }, - { "_Fract", RID_FRACT, D_EXT }, - { "_Accum", RID_ACCUM, D_EXT }, - { "_Sat", RID_SAT, D_EXT }, - { "__FUNCTION__", RID_FUNCTION_NAME, 0 }, - { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 }, - { "__alignof", RID_ALIGNOF, 0 }, - { "__alignof__", RID_ALIGNOF, 0 }, - { "__asm", RID_ASM, 0 }, - { "__asm__", RID_ASM, 0 }, - { "__attribute", RID_ATTRIBUTE, 0 }, - { "__attribute__", RID_ATTRIBUTE, 0 }, - { "__builtin_choose_expr", RID_CHOOSE_EXPR, 0 }, - { "__builtin_offsetof", RID_OFFSETOF, 0 }, - { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, 0 }, - { "__builtin_va_arg", RID_VA_ARG, 0 }, - { "__complex", RID_COMPLEX, 0 }, - { "__complex__", RID_COMPLEX, 0 }, - { "__const", RID_CONST, 0 }, - { "__const__", RID_CONST, 0 }, - { "__extension__", RID_EXTENSION, 0 }, - { "__func__", RID_C99_FUNCTION_NAME, 0 }, - { "__imag", RID_IMAGPART, 0 }, - { "__imag__", RID_IMAGPART, 0 }, - { "__inline", RID_INLINE, 0 }, - { "__inline__", RID_INLINE, 0 }, - { "__label__", RID_LABEL, 0 }, - { "__real", RID_REALPART, 0 }, - { "__real__", RID_REALPART, 0 }, - { "__restrict", RID_RESTRICT, 0 }, - { "__restrict__", RID_RESTRICT, 0 }, - { "__signed", RID_SIGNED, 0 }, - { "__signed__", RID_SIGNED, 0 }, - { "__thread", RID_THREAD, 0 }, - { "__typeof", RID_TYPEOF, 0 }, - { "__typeof__", RID_TYPEOF, 0 }, - { "__volatile", RID_VOLATILE, 0 }, - { "__volatile__", RID_VOLATILE, 0 }, - { "asm", RID_ASM, D_EXT }, - { "auto", RID_AUTO, 0 }, - { "break", RID_BREAK, 0 }, - { "case", RID_CASE, 0 }, - { "char", RID_CHAR, 0 }, - { "const", RID_CONST, 0 }, - { "continue", RID_CONTINUE, 0 }, - { "default", RID_DEFAULT, 0 }, - { "do", RID_DO, 0 }, - { "double", RID_DOUBLE, 0 }, - { "else", RID_ELSE, 0 }, - { "enum", RID_ENUM, 0 }, - { "extern", RID_EXTERN, 0 }, - { "float", RID_FLOAT, 0 }, - { "for", RID_FOR, 0 }, - { "goto", RID_GOTO, 0 }, - { "if", RID_IF, 0 }, - { "inline", RID_INLINE, D_EXT89 }, - { "int", RID_INT, 0 }, - { "long", RID_LONG, 0 }, - { "register", RID_REGISTER, 0 }, - { "restrict", RID_RESTRICT, D_C89 }, - { "return", RID_RETURN, 0 }, - { "short", RID_SHORT, 0 }, - { "signed", RID_SIGNED, 0 }, - { "sizeof", RID_SIZEOF, 0 }, - { "static", RID_STATIC, 0 }, - { "struct", RID_STRUCT, 0 }, - { "switch", RID_SWITCH, 0 }, - { "typedef", RID_TYPEDEF, 0 }, - { "typeof", RID_TYPEOF, D_EXT }, - { "union", RID_UNION, 0 }, - { "unsigned", RID_UNSIGNED, 0 }, - { "void", RID_VOID, 0 }, - { "volatile", RID_VOLATILE, 0 }, - { "while", RID_WHILE, 0 }, - /* These Objective-C keywords are recognized only immediately after - an '@'. */ - { "class", RID_AT_CLASS, D_OBJC }, - { "compatibility_alias", RID_AT_ALIAS, D_OBJC }, - { "defs", RID_AT_DEFS, D_OBJC }, - { "encode", RID_AT_ENCODE, D_OBJC }, - { "end", RID_AT_END, D_OBJC }, - { "implementation", RID_AT_IMPLEMENTATION, D_OBJC }, - { "interface", RID_AT_INTERFACE, D_OBJC }, - { "private", RID_AT_PRIVATE, D_OBJC }, - { "protected", RID_AT_PROTECTED, D_OBJC }, - { "protocol", RID_AT_PROTOCOL, D_OBJC }, - { "public", RID_AT_PUBLIC, D_OBJC }, - { "selector", RID_AT_SELECTOR, D_OBJC }, - { "throw", RID_AT_THROW, D_OBJC }, - { "try", RID_AT_TRY, D_OBJC }, - { "catch", RID_AT_CATCH, D_OBJC }, - { "finally", RID_AT_FINALLY, D_OBJC }, - { "synchronized", RID_AT_SYNCHRONIZED, D_OBJC }, - /* These are recognized only in protocol-qualifier context - (see above) */ - { "bycopy", RID_BYCOPY, D_OBJC }, - { "byref", RID_BYREF, D_OBJC }, - { "in", RID_IN, D_OBJC }, - { "inout", RID_INOUT, D_OBJC }, - { "oneway", RID_ONEWAY, D_OBJC }, - { "out", RID_OUT, D_OBJC }, -}; -#define N_reswords (sizeof reswords / sizeof (struct resword)) - /* Initialization routine for this file. */ void @@ -193,24 +68,45 @@ c_parse_init (void) identifiers. */ unsigned int i; tree id; - int mask = (flag_isoc99 ? 0 : D_C89) - | (flag_no_asm ? (flag_isoc99 ? D_EXT : D_EXT|D_EXT89) : 0); + int mask = 0; + + /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in + the c_token structure. */ + gcc_assert (RID_MAX <= 255); + mask |= D_CXXONLY; + if (!flag_isoc99) + mask |= D_C99; + if (flag_no_asm) + { + mask |= D_ASM | D_EXT; + if (!flag_isoc99) + mask |= D_EXT89; + } if (!c_dialect_objc ()) - mask |= D_OBJC; + mask |= D_OBJC | D_CXX_OBJC; - ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX); - for (i = 0; i < N_reswords; i++) + ridpointers = ggc_alloc_cleared_vec_tree ((int) RID_MAX); + for (i = 0; i < num_c_common_reswords; i++) { /* If a keyword is disabled, do not enter it into the table and so create a canonical spelling that isn't a keyword. */ - if (reswords[i].disable & mask) - continue; + if (c_common_reswords[i].disable & mask) + { + if (warn_cxx_compat + && (c_common_reswords[i].disable & D_CXXWARN)) + { + id = get_identifier (c_common_reswords[i].word); + C_SET_RID_CODE (id, RID_CXX_COMPAT_WARN); + C_IS_RESERVED_WORD (id) = 1; + } + continue; + } - id = get_identifier (reswords[i].word); - C_RID_CODE (id) = reswords[i].rid; + id = get_identifier (c_common_reswords[i].word); + C_SET_RID_CODE (id, c_common_reswords[i].rid); C_IS_RESERVED_WORD (id) = 1; - ridpointers [(int) reswords[i].rid] = id; + ridpointers [(int) c_common_reswords[i].rid] = id; } } @@ -238,14 +134,15 @@ typedef enum c_id_kind { C_ID_TYPENAME, /* An identifier declared as an Objective-C class name. */ C_ID_CLASSNAME, + /* An address space identifier. */ + C_ID_ADDRSPACE, /* Not an identifier. */ C_ID_NONE } c_id_kind; /* A single C token after string literal concatenation and conversion of preprocessing tokens to tokens. */ -typedef struct c_token GTY (()) -{ +typedef struct GTY (()) c_token { /* The kind of token. */ ENUM_BITFIELD (cpp_ttype) type : 8; /* If this token is a CPP_NAME, this value indicates whether also @@ -256,20 +153,17 @@ typedef struct c_token GTY (()) ENUM_BITFIELD (rid) keyword : 8; /* If this token is a CPP_PRAGMA, this indicates the pragma that was seen. Otherwise it is PRAGMA_NONE. */ - ENUM_BITFIELD (pragma_kind) pragma_kind : 7; - /* True if this token is from a system header. */ - BOOL_BITFIELD in_system_header : 1; - /* The value associated with this token, if any. */ - tree value; + ENUM_BITFIELD (pragma_kind) pragma_kind : 8; /* The location at which this token was found. */ location_t location; + /* The value associated with this token, if any. */ + tree value; } c_token; /* A parser structure recording information about the state and context of parsing. Includes lexer information with up to two tokens of look-ahead; more are not needed for C. */ -typedef struct c_parser GTY(()) -{ +typedef struct GTY(()) c_parser { /* The look-ahead tokens. */ c_token tokens[2]; /* How many look-ahead tokens are available (0, 1 or 2). */ @@ -285,13 +179,28 @@ typedef struct c_parser GTY(()) BOOL_BITFIELD in_if_block : 1; /* True if we want to lex an untranslated string. */ BOOL_BITFIELD lex_untranslated_string : 1; + /* Objective-C specific parser/lexer information. */ + + /* True if we are in a context where the Objective-C "PQ" keywords + are considered keywords. */ BOOL_BITFIELD objc_pq_context : 1; + /* True if we are parsing a (potential) Objective-C foreach + statement. This is set to true after we parsed 'for (' and while + we wait for 'in' or ';' to decide if it's a standard C for loop or an + Objective-C foreach loop. */ + BOOL_BITFIELD objc_could_be_foreach_context : 1; /* The following flag is needed to contextualize Objective-C lexical analysis. In some cases (e.g., 'int NSObject;'), it is undesirable to bind an identifier to an Objective-C class, even if a class with that name exists. */ BOOL_BITFIELD objc_need_raw_identifier : 1; + /* 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; @@ -300,7 +209,6 @@ typedef struct c_parser GTY(()) static GTY (()) c_parser *the_parser; - /* Read in and lex a single token, storing it in *TOKEN. */ static void @@ -314,7 +222,6 @@ c_lex_one_token (c_parser *parser, c_token *token) token->id_kind = C_ID_NONE; token->keyword = RID_MAX; token->pragma_kind = PRAGMA_NONE; - token->in_system_header = in_system_header; switch (token->type) { @@ -330,23 +237,84 @@ c_lex_one_token (c_parser *parser, c_token *token) { enum rid rid_code = C_RID_CODE (token->value); - if (c_dialect_objc ()) + if (rid_code == RID_CXX_COMPAT_WARN) + { + warning_at (token->location, + OPT_Wc___compat, + "identifier %qE conflicts with C++ keyword", + token->value); + } + else if (rid_code >= RID_FIRST_ADDR_SPACE + && rid_code <= RID_LAST_ADDR_SPACE) + { + token->id_kind = C_ID_ADDRSPACE; + token->keyword = rid_code; + break; + } + else if (c_dialect_objc () && OBJC_IS_PQ_KEYWORD (rid_code)) + { + /* We found an Objective-C "pq" keyword (in, out, + inout, bycopy, byref, oneway). They need special + care because the interpretation depends on the + context. */ + if (parser->objc_pq_context) + { + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + else if (parser->objc_could_be_foreach_context + && rid_code == RID_IN) + { + /* We are in Objective-C, inside a (potential) + foreach context (which means after having + parsed 'for (', but before having parsed ';'), + and we found 'in'. We consider it the keyword + which terminates the declaration at the + beginning of a foreach-statement. Note that + this means you can't use 'in' for anything else + in that context; in particular, in Objective-C + you can't use 'in' as the name of the running + variable in a C for loop. We could potentially + try to add code here to disambiguate, but it + seems a reasonable limitation. */ + token->type = CPP_KEYWORD; + token->keyword = rid_code; + break; + } + /* Else, "pq" keywords outside of the "pq" context are + not keywords, and we fall through to the code for + normal tokens. */ + } + else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code)) { - if (!OBJC_IS_AT_KEYWORD (rid_code) - && (!OBJC_IS_PQ_KEYWORD (rid_code) - || parser->objc_pq_context)) + /* 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) { - /* Return the canonical spelling for this keyword. */ - token->value = ridpointers[(int) rid_code]; token->type = CPP_KEYWORD; token->keyword = rid_code; break; } + /* Else they are not special keywords. + */ + } + else if (c_dialect_objc () + && (OBJC_IS_AT_KEYWORD (rid_code) + || OBJC_IS_CXX_KEYWORD (rid_code))) + { + /* We found one of the Objective-C "@" keywords (defs, + selector, synchronized, etc) or one of the + Objective-C "cxx" keywords (class, private, + protected, public, try, catch, throw) without a + preceding '@' sign. Do nothing and fall through to + the code for normal tokens (in C++ we would still + consider the CXX ones keywords, but not in C). */ + ; } else { - /* Return the canonical spelling for this keyword. */ - token->value = ridpointers[(int) rid_code]; token->type = CPP_KEYWORD; token->keyword = rid_code; break; @@ -369,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; @@ -383,7 +350,25 @@ c_lex_one_token (c_parser *parser, c_token *token) case CPP_AT_NAME: /* This only happens in Objective-C; it must be a keyword. */ token->type = CPP_KEYWORD; - token->keyword = C_RID_CODE (token->value); + switch (C_RID_CODE (token->value)) + { + /* Replace 'class' with '@class', 'private' with '@private', + etc. This prevents confusion with the C++ keyword + 'class', and makes the tokens consistent with other + Objective-C 'AT' keywords. For example '@class' is + reported as RID_AT_CLASS which is consistent with + '@synchronized', which is reported as + RID_AT_SYNCHRONIZED. + */ + case RID_CLASS: token->keyword = RID_AT_CLASS; break; + case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break; + case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break; + case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break; + case RID_THROW: token->keyword = RID_AT_THROW; break; + case RID_TRY: token->keyword = RID_AT_TRY; break; + case RID_CATCH: token->keyword = RID_AT_CATCH; break; + default: token->keyword = C_RID_CODE (token->value); + } break; case CPP_COLON: case CPP_COMMA: @@ -396,7 +381,7 @@ c_lex_one_token (c_parser *parser, c_token *token) break; case CPP_PRAGMA: /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */ - token->pragma_kind = TREE_INT_CST_LOW (token->value); + token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value); token->value = NULL; break; default: @@ -446,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 @@ -458,6 +459,8 @@ c_token_starts_typename (c_token *token) { case C_ID_ID: return false; + case C_ID_ADDRSPACE: + return true; case C_ID_TYPENAME: return true; case C_ID_CLASSNAME: @@ -471,6 +474,7 @@ c_token_starts_typename (c_token *token) { case RID_UNSIGNED: case RID_LONG: + case RID_INT128: case RID_SHORT: case RID_SIGNED: case RID_COMPLEX: @@ -507,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 @@ -528,6 +606,8 @@ c_token_starts_declspecs (c_token *token) { case C_ID_ID: return false; + case C_ID_ADDRSPACE: + return true; case C_ID_TYPENAME: return true; case C_ID_CLASSNAME: @@ -544,10 +624,12 @@ 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: case RID_LONG: + case RID_INT128: case RID_SHORT: case RID_SIGNED: case RID_COMPLEX: @@ -571,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; @@ -584,29 +667,67 @@ c_token_starts_declspecs (c_token *token) } } + +/* Return true if TOKEN can start declaration specifiers or a static + assertion, false otherwise. */ +static bool +c_token_starts_declaration (c_token *token) +{ + if (c_token_starts_declspecs (token) + || token->keyword == RID_STATIC_ASSERT) + return true; + else + return false; +} + /* Return true if the next token from PARSER can start declaration specifiers, false otherwise. */ 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 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) +/* Return true if the next tokens from PARSER can start declaration + specifiers or a static assertion, false otherwise. */ +static inline bool +c_parser_next_tokens_start_declaration (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]; + c_token *token = c_parser_peek_token (parser); + + /* Same as above. */ + if (c_dialect_objc () + && token->type == CPP_NAME + && token->id_kind == C_ID_CLASSNAME + && c_parser_peek_2nd_token (parser)->type == CPP_DOT) + return false; + + /* Labels do not start declarations. */ + if (token->type == CPP_NAME + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + return false; + + if (c_token_starts_declaration (token)) + return true; + + if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl)) + return true; + + return false; } /* Consume the next token from PARSER. */ @@ -646,7 +767,6 @@ c_parser_set_source_position_from_token (c_token *token) if (token->type != CPP_EOF) { input_location = token->location; - in_system_header = token->in_system_header; } } @@ -679,7 +799,11 @@ c_parser_error (c_parser *parser, const char *gmsgid) CPP_KEYWORD, keywords are treated like identifiers. */ (token->type == CPP_KEYWORD ? CPP_NAME : token->type), - token->value); + /* ??? The C parser does not save the cpp flags of a + token, we need to pass 0 here and we will not get + the source spelling of some tokens but rather the + canonical spelling. */ + token->value, /*flags=*/0); } /* If the next token is of the indicated TYPE, consume it. Otherwise, @@ -912,6 +1036,9 @@ c_parser_skip_to_end_of_block_or_statement (c_parser *parser) parser->error = false; } +/* CPP's options (initialized by c-opts.c). */ +extern cpp_options *cpp_opts; + /* Save the warning flags which are controlled by __extension__. */ static inline int @@ -920,11 +1047,17 @@ disable_extension_diagnostics (void) int ret = (pedantic | (warn_pointer_arith << 1) | (warn_traditional << 2) - | (flag_iso << 3)); - pedantic = 0; + | (flag_iso << 3) + | (warn_long_long << 4) + | (warn_cxx_compat << 5) + | (warn_overlength_strings << 6)); + cpp_opts->cpp_pedantic = pedantic = 0; warn_pointer_arith = 0; - warn_traditional = 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; } @@ -934,10 +1067,13 @@ disable_extension_diagnostics (void) static inline void restore_extension_diagnostics (int flags) { - pedantic = flags & 1; + cpp_opts->cpp_pedantic = pedantic = flags & 1; warn_pointer_arith = (flags >> 1) & 1; - warn_traditional = (flags >> 2) & 1; + cpp_opts->cpp_warn_traditional = warn_traditional = (flags >> 2) & 1; 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. */ @@ -959,15 +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); +static void c_parser_declaration_or_fndef (c_parser *, 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, @@ -976,15 +1133,17 @@ 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 *); static struct c_type_name *c_parser_type_name (c_parser *); static struct c_expr c_parser_initializer (c_parser *); static struct c_expr c_parser_braced_init (c_parser *, tree, bool); -static void c_parser_initelt (c_parser *); -static void c_parser_initval (c_parser *, struct c_expr *); +static void c_parser_initelt (c_parser *, struct obstack *); +static void c_parser_initval (c_parser *, struct c_expr *, + struct obstack *); static tree c_parser_compound_statement (c_parser *); static void c_parser_compound_statement_nostart (c_parser *); static void c_parser_label (c_parser *); @@ -997,52 +1156,67 @@ static void c_parser_do_statement (c_parser *); static void c_parser_for_statement (c_parser *); static tree c_parser_asm_statement (c_parser *); static tree c_parser_asm_operands (c_parser *, bool); +static tree c_parser_asm_goto_operands (c_parser *); 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 *); static struct c_expr c_parser_alignof_expression (c_parser *); static struct c_expr c_parser_postfix_expression (c_parser *); static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *, - struct c_type_name *); + struct c_type_name *, + location_t); 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 tree c_parser_expr_list (c_parser *, bool); +static VEC(tree,gc) *c_parser_expr_list (c_parser *, bool, bool, + VEC(tree,gc) **); static void c_parser_omp_construct (c_parser *); 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); /* These Objective-C parser functions are only ever called when compiling Objective-C. */ -static void c_parser_objc_class_definition (c_parser *); +static void c_parser_objc_class_definition (c_parser *, tree); static void c_parser_objc_class_instance_variables (c_parser *); static void c_parser_objc_class_declaration (c_parser *); static void c_parser_objc_alias_declaration (c_parser *); -static void c_parser_objc_protocol_definition (c_parser *); -static enum tree_code c_parser_objc_method_type (c_parser *); +static void c_parser_objc_protocol_definition (c_parser *, tree); +static bool c_parser_objc_method_type (c_parser *); static void c_parser_objc_method_definition (c_parser *); static void c_parser_objc_methodprotolist (c_parser *); static void c_parser_objc_methodproto (c_parser *); -static tree c_parser_objc_method_decl (c_parser *); +static tree c_parser_objc_method_decl (c_parser *, bool, tree *, tree *); static tree c_parser_objc_type_name (c_parser *); static tree c_parser_objc_protocol_refs (c_parser *); -static void c_parser_objc_try_catch_statement (c_parser *); +static void c_parser_objc_try_catch_finally_statement (c_parser *); static void c_parser_objc_synchronized_statement (c_parser *); static tree c_parser_objc_selector (c_parser *); static tree c_parser_objc_selector_arg (c_parser *); static tree c_parser_objc_receiver (c_parser *); static tree c_parser_objc_message_args (c_parser *); static tree c_parser_objc_keywordexpr (c_parser *); +static void c_parser_objc_at_property_declaration (c_parser *); +static void c_parser_objc_at_synthesize_declaration (c_parser *); +static void c_parser_objc_at_dynamic_declaration (c_parser *); +static bool c_parser_objc_diagnose_bad_element_prefix + (c_parser *, struct c_declspecs *); /* Parse a translation unit (C90 6.7, C99 6.9). @@ -1064,13 +1238,13 @@ c_parser_translation_unit (c_parser *parser) { if (c_parser_next_token_is (parser, CPP_EOF)) { - if (pedantic) - pedwarn ("%HISO C forbids an empty translation unit", - &c_parser_peek_token (parser)->location); + pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + "ISO C forbids an empty translation unit"); } else { void *obstack_position = obstack_alloc (&parser_obstack, 0); + mark_valid_location_for_stdc_pragma (false); do { ggc_collect (); @@ -1126,7 +1300,7 @@ c_parser_external_declaration (c_parser *parser) case RID_AT_INTERFACE: case RID_AT_IMPLEMENTATION: gcc_assert (c_dialect_objc ()); - c_parser_objc_class_definition (parser); + c_parser_objc_class_definition (parser, NULL_TREE); break; case RID_AT_CLASS: gcc_assert (c_dialect_objc ()); @@ -1138,7 +1312,19 @@ c_parser_external_declaration (c_parser *parser) break; case RID_AT_PROTOCOL: gcc_assert (c_dialect_objc ()); - c_parser_objc_protocol_definition (parser); + c_parser_objc_protocol_definition (parser, NULL_TREE); + break; + case RID_AT_PROPERTY: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_property_declaration (parser); + break; + case RID_AT_SYNTHESIZE: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_synthesize_declaration (parser); + break; + case RID_AT_DYNAMIC: + gcc_assert (c_dialect_objc ()); + c_parser_objc_at_dynamic_declaration (parser); break; case RID_AT_END: gcc_assert (c_dialect_objc ()); @@ -1150,13 +1336,14 @@ c_parser_external_declaration (c_parser *parser) } break; case CPP_SEMICOLON: - if (pedantic) - pedwarn ("%HISO C does not allow extra %<;%> outside of a function", - &c_parser_peek_token (parser)->location); + pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + "ISO C does not allow extra %<;%> outside of a function"); c_parser_consume_token (parser); break; case CPP_PRAGMA: + mark_valid_location_for_stdc_pragma (true); c_parser_pragma (parser, pragma_external); + mark_valid_location_for_stdc_pragma (false); break; case CPP_PLUS: case CPP_MINUS: @@ -1169,30 +1356,35 @@ c_parser_external_declaration (c_parser *parser) as a declaration or function definition. */ default: decl_or_fndef: - /* A declaration or a function definition. We can only tell - which after parsing the declaration specifiers, if any, and - the first declarator. */ - c_parser_declaration_or_fndef (parser, true, true, false, true); + /* A declaration or a function definition (or, in Objective-C, + an @interface or @protocol with prefix attributes). We can + only tell which after parsing the declaration specifiers, if + any, and the first declarator. */ + c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL); break; } } - /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 6.7, 6.9.1). If FNDEF_OK is true, a function definition is accepted; otherwise (old-style parameter declarations) only other - declarations are accepted. If NESTED is true, we are inside a - function or parsing old-style parameter declarations; any functions - encountered are nested functions and declaration specifiers are - required; otherwise we are at top level and functions are normal - functions and declaration specifiers may be optional. If EMPTY_OK - is true, empty declarations are OK (subject to all other - constraints); otherwise (old-style parameter declarations) they are - diagnosed. If START_ATTR_OK is true, the declaration specifiers - may start with attributes; otherwise they may not. + declarations are accepted. If STATIC_ASSERT_OK is true, a static + assertion is accepted; otherwise (old-style parameter declarations) + it is not. If NESTED is true, we are inside a function or parsing + old-style parameter declarations; any functions encountered are + nested functions and declaration specifiers are required; otherwise + we are at top level and functions are normal functions and + declaration specifiers may be optional. If EMPTY_OK is true, empty + declarations are OK (subject to all other constraints); otherwise + (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] ; + static_assert-declaration function-definition: declaration-specifiers[opt] declarator declaration-list[opt] @@ -1216,6 +1408,11 @@ c_parser_external_declaration (c_parser *parser) declaration-specifiers declarator declaration-list[opt] compound-statement + Objective-C: + attributes objc-class-definition + attributes objc-category-definition + attributes objc-protocol-definition + The simple-asm-expr and attributes are GNU extensions. This function does not handle __extension__; that is handled in its @@ -1229,15 +1426,21 @@ c_parser_external_declaration (c_parser *parser) C we also allow but diagnose declarations without declaration 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: threadprivate-directive */ static void -c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, - bool nested, bool start_attr_ok) +c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, + bool static_assert_ok, bool empty_ok, + bool nested, bool start_attr_ok, + tree *objc_foreach_object_declaration) { struct c_declspecs *specs; tree prefix_attrs; @@ -1245,8 +1448,34 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, bool diagnosed_no_specs = false; location_t here = c_parser_peek_token (parser)->location; + if (static_assert_ok + && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) + { + c_parser_static_assert_declaration (parser); + 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); @@ -1266,11 +1495,102 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, else { shadow_tag_warned (specs, 1); - pedwarn ("%Hempty declaration", &here); + pedwarn (here, 0, "empty declaration"); } c_parser_consume_token (parser); return; } + + /* Provide better error recovery. Note that a type name here is usually + better diagnosed as a redeclaration. */ + if (empty_ok + && specs->typespec_kind == ctsk_tagdef + && c_parser_next_token_starts_declspecs (parser) + && !c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected %<;%>, identifier or %<(%>"); + parser->error = false; + shadow_tag_warned (specs, 1); + return; + } + else if (c_dialect_objc ()) + { + /* Prefix attributes are an error on method decls. */ + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + case CPP_MINUS: + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + if (specs->attrs) + { + warning_at (c_parser_peek_token (parser)->location, + OPT_Wattributes, + "prefix attributes are ignored for methods"); + specs->attrs = NULL_TREE; + } + if (fndef_ok) + c_parser_objc_method_definition (parser); + else + c_parser_objc_methodproto (parser); + return; + break; + default: + break; + } + /* This is where we parse 'attributes @interface ...', + 'attributes @implementation ...', 'attributes @protocol ...' + (where attributes could be, for example, __attribute__ + ((deprecated)). + */ + switch (c_parser_peek_token (parser)->keyword) + { + case RID_AT_INTERFACE: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + c_parser_objc_class_definition (parser, specs->attrs); + return; + } + break; + case RID_AT_IMPLEMENTATION: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + if (specs->attrs) + { + warning_at (c_parser_peek_token (parser)->location, + OPT_Wattributes, + "prefix attributes are ignored for implementations"); + specs->attrs = NULL_TREE; + } + c_parser_objc_class_definition (parser, NULL_TREE); + return; + } + break; + case RID_AT_PROTOCOL: + { + if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) + return; + c_parser_objc_protocol_definition (parser, specs->attrs); + return; + } + break; + case RID_AT_ALIAS: + case RID_AT_CLASS: + case RID_AT_END: + case RID_AT_PROPERTY: + if (specs->attrs) + { + c_parser_error (parser, "unexpected attribute"); + specs->attrs = NULL; + } + break; + default: + break; + } + } + pending_xref_error (); prefix_attrs = specs->attrs; all_prefix_attrs = prefix_attrs; @@ -1279,12 +1599,14 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_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) { @@ -1295,15 +1617,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_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; if (!diagnosed_no_specs && !specs->declspecs_seen_p) { diagnosed_no_specs = true; - pedwarn ("%Hdata definition has no type or storage class", - &here); + pedwarn (here, 0, "data definition has no type or storage class"); } /* Having seen a data definition, there cannot now be a function definition. */ @@ -1316,6 +1638,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, { tree d; struct c_expr init; + location_t init_loc; c_parser_consume_token (parser); /* The declaration of the variable is in effect while its initializer is parsed. */ @@ -1324,12 +1647,14 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, if (!d) d = error_mark_node; start_init (d, asm_name, global_bindings_p ()); + init_loc = c_parser_peek_token (parser)->location; init = c_parser_initializer (parser); finish_init (); if (d != error_mark_node) { maybe_warn_string_init (TREE_TYPE (d), init); - finish_decl (d, init.value, asm_name); + finish_decl (d, init_loc, init.value, + init.original_type, asm_name); } } else @@ -1338,7 +1663,16 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, chainon (postfix_attrs, all_prefix_attrs)); if (d) - finish_decl (d, NULL_TREE, asm_name); + finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, + 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)) { @@ -1355,6 +1689,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_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 %<;%>"); @@ -1372,8 +1715,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, /* Function definition (nested or otherwise). */ if (nested) { - if (pedantic) - pedwarn ("%HISO C forbids nested functions", &here); + pedwarn (here, OPT_pedantic, "ISO C forbids nested functions"); c_push_function_context (); } if (!start_function (specs, declarator, all_prefix_attrs)) @@ -1387,6 +1729,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_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 @@ -1401,24 +1750,32 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, function definitions either. */ 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, true, false); - DECL_SOURCE_LOCATION (current_function_decl) - = c_parser_peek_token (parser)->location; + c_parser_declaration_or_fndef (parser, false, false, false, + true, false, NULL); store_parm_decls (); + DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus + = c_parser_peek_token (parser)->location; fnbody = c_parser_compound_statement (parser); if (nested) { tree decl = current_function_decl; + /* Mark nested functions as needing static-chain initially. + lower_nested_functions will recompute it but the + DECL_STATIC_CHAIN flag is also used before that happens, + by initializer_constant_valid_p. See gcc.dg/nested-fn-2.c. */ + DECL_STATIC_CHAIN (decl) = 1; add_stmt (fnbody); finish_function (); c_pop_function_context (); - add_stmt (build_stmt (DECL_EXPR, decl)); + add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); } else { add_stmt (fnbody); finish_function (); } + + timevar_pop (tv); break; } } @@ -1439,40 +1796,136 @@ c_parser_asm_definition (c_parser *parser) c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } -/* Parse some declaration specifiers (possibly none) (C90 6.5, C99 - 6.7), adding them to SPECS (which may already include some). - Storage class specifiers are accepted iff SCSPEC_OK; type - specifiers are accepted iff TYPESPEC_OK; attributes are accepted at - the start iff START_ATTR_OK. +/* Parse a static assertion (C11 6.7.10). - declaration-specifiers: - storage-class-specifier declaration-specifiers[opt] - type-specifier declaration-specifiers[opt] - type-qualifier declaration-specifiers[opt] - function-specifier declaration-specifiers[opt] + static_assert-declaration: + static_assert-declaration-no-semi ; +*/ - Function specifiers (inline) are from C99, and are currently - handled as storage class specifiers, as is __thread. +static void +c_parser_static_assert_declaration (c_parser *parser) +{ + c_parser_static_assert_declaration_no_semi (parser); + if (parser->error + || !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + c_parser_skip_to_end_of_block_or_statement (parser); +} - C90 6.5.1, C99 6.7.1: - storage-class-specifier: - typedef - extern - static - auto - register +/* Parse a static assertion (C11 6.7.10), without the trailing + semicolon. - C99 6.7.4: - function-specifier: - inline + static_assert-declaration-no-semi: + _Static_assert ( constant-expression , string-literal ) +*/ - C90 6.5.2, C99 6.7.2: - type-specifier: - void - char - short - int - long +static void +c_parser_static_assert_declaration_no_semi (c_parser *parser) +{ + location_t assert_loc, value_loc; + tree value; + tree string; + + gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)); + assert_loc = c_parser_peek_token (parser)->location; + if (!flag_isoc11) + { + if (flag_isoc99) + pedwarn (assert_loc, OPT_pedantic, + "ISO C99 does not support %<_Static_assert%>"); + else + pedwarn (assert_loc, OPT_pedantic, + "ISO C90 does not support %<_Static_assert%>"); + } + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return; + value_loc = c_parser_peek_token (parser)->location; + value = c_parser_expr_no_commas (parser, NULL).value; + parser->lex_untranslated_string = true; + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) + { + parser->lex_untranslated_string = false; + return; + } + switch (c_parser_peek_token (parser)->type) + { + case CPP_STRING: + case CPP_STRING16: + case CPP_STRING32: + case CPP_WSTRING: + case CPP_UTF8STRING: + string = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + parser->lex_untranslated_string = false; + break; + default: + c_parser_error (parser, "expected string literal"); + parser->lex_untranslated_string = false; + return; + } + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (value))) + { + error_at (value_loc, "expression in static assertion is not an integer"); + return; + } + if (TREE_CODE (value) != INTEGER_CST) + { + value = c_fully_fold (value, false, NULL); + if (TREE_CODE (value) == INTEGER_CST) + pedwarn (value_loc, OPT_pedantic, "expression in static assertion " + "is not an integer constant expression"); + } + if (TREE_CODE (value) != INTEGER_CST) + { + error_at (value_loc, "expression in static assertion is not constant"); + return; + } + constant_expression_warning (value); + if (integer_zerop (value)) + error_at (assert_loc, "static assertion failed: %E", string); +} + +/* Parse some declaration specifiers (possibly none) (C90 6.5, C99 + 6.7), adding them to SPECS (which may already include some). + Storage class specifiers are accepted iff SCSPEC_OK; type + specifiers are accepted iff TYPESPEC_OK; attributes are accepted at + the start iff START_ATTR_OK. + + declaration-specifiers: + storage-class-specifier declaration-specifiers[opt] + 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. Alignment + specifiers are from C11. + + C90 6.5.1, C99 6.7.1: + storage-class-specifier: + typedef + extern + static + auto + register + + C99 6.7.4: + function-specifier: + inline + _Noreturn + + (_Noreturn is new in C11.) + + C90 6.5.2, C99 6.7.2: + type-specifier: + void + char + short + int + long float double signed @@ -1492,6 +1945,7 @@ c_parser_asm_definition (c_parser *parser) const restrict volatile + address-space-qualifier (restrict is new in C99.) @@ -1500,11 +1954,18 @@ c_parser_asm_definition (c_parser *parser) declaration-specifiers: attributes declaration-specifiers[opt] + type-qualifier: + address-space + + address-space: + identifier recognized by the target + storage-class-specifier: __thread type-specifier: typeof-specifier + __int128 _Decimal32 _Decimal64 _Decimal128 @@ -1525,32 +1986,71 @@ c_parser_asm_definition (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; c_id_kind kind = c_parser_peek_token (parser)->id_kind; - /* 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)) + + if (kind == C_ID_ADDRSPACE) + { + addr_space_t as + = c_parser_peek_token (parser)->keyword - RID_FIRST_ADDR_SPACE; + declspecs_add_addrspace (specs, as); + c_parser_consume_token (parser); + attrs_ok = true; + continue; + } + + 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. @@ -1566,7 +2066,9 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, proto = c_parser_objc_protocol_refs (parser); t.spec = objc_get_protocol_qualified_type (value, proto); } - declspecs_add_type (specs, t); + t.expr = NULL_TREE; + t.expr_const_operands = true; + declspecs_add_type (loc, specs, t); continue; } if (c_parser_next_token_is (parser, CPP_LESS)) @@ -1580,7 +2082,9 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, proto = c_parser_objc_protocol_refs (parser); t.kind = ctsk_objc; t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto); - declspecs_add_type (specs, t); + t.expr = NULL_TREE; + t.expr_const_operands = true; + declspecs_add_type (loc, specs, t); continue; } gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD)); @@ -1591,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); @@ -1604,6 +2109,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, break; case RID_UNSIGNED: case RID_LONG: + case RID_INT128: case RID_SHORT: case RID_SIGNED: case RID_COMPLEX: @@ -1627,7 +2133,9 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, parser->objc_need_raw_identifier = true; t.kind = ctsk_resword; t.spec = c_parser_peek_token (parser)->value; - declspecs_add_type (specs, t); + t.expr = NULL_TREE; + t.expr_const_operands = true; + declspecs_add_type (loc, specs, t); c_parser_consume_token (parser); break; case RID_ENUM: @@ -1636,7 +2144,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, attrs_ok = true; seen_type = true; t = c_parser_enum_specifier (parser); - declspecs_add_type (specs, t); + declspecs_add_type (loc, specs, t); break; case RID_STRUCT: case RID_UNION: @@ -1645,7 +2153,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, attrs_ok = true; seen_type = true; t = c_parser_struct_or_union_specifier (parser); - declspecs_add_type (specs, t); + invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec); + declspecs_add_type (loc, specs, t); break; case RID_TYPEOF: /* ??? The old parser rejected typeof after other type @@ -1656,7 +2165,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, attrs_ok = true; seen_type = true; t = c_parser_typeof_specifier (parser); - declspecs_add_type (specs, t); + declspecs_add_type (loc, specs, t); break; case RID_CONST: case RID_VOLATILE: @@ -1671,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; } @@ -1706,27 +2219,34 @@ c_parser_enum_specifier (c_parser *parser) struct c_typespec ret; tree attrs; tree ident = NULL_TREE; - location_t ident_loc; + location_t enum_loc; + location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); + enum_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); attrs = c_parser_attributes (parser); + enum_loc = c_parser_peek_token (parser)->location; /* Set the location in case we create a decl now. */ c_parser_set_source_position_from_token (c_parser_peek_token (parser)); if (c_parser_next_token_is (parser, CPP_NAME)) { ident = c_parser_peek_token (parser)->value; ident_loc = c_parser_peek_token (parser)->location; + enum_loc = ident_loc; c_parser_consume_token (parser); } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { /* Parse an enum definition. */ struct c_enum_contents the_enum; - tree type = start_enum (&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) { @@ -1735,7 +2255,8 @@ c_parser_enum_specifier (c_parser *parser) tree enum_decl; bool seen_comma; c_token *token; - location_t comma_loc; + location_t comma_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + location_t decl_loc, value_loc; if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); @@ -1747,15 +2268,18 @@ c_parser_enum_specifier (c_parser *parser) enum_id = token->value; /* Set the location in case we create a decl now. */ c_parser_set_source_position_from_token (token); + decl_loc = value_loc = token->location; c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_EQ)) { c_parser_consume_token (parser); + value_loc = c_parser_peek_token (parser)->location; enum_value = c_parser_expr_no_commas (parser, NULL).value; } else enum_value = NULL_TREE; - enum_decl = build_enumerator (&the_enum, enum_id, enum_value); + enum_decl = build_enumerator (decl_loc, value_loc, + &the_enum, enum_id, enum_value); TREE_CHAIN (enum_decl) = values; values = enum_decl; seen_comma = false; @@ -1767,8 +2291,8 @@ c_parser_enum_specifier (c_parser *parser) } if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { - if (seen_comma && pedantic && !flag_isoc99) - pedwarn ("%Hcomma at end of enumerator list", &comma_loc); + if (seen_comma && !flag_isoc99) + pedwarn (comma_loc, OPT_pedantic, "comma at end of enumerator list"); c_parser_consume_token (parser); break; } @@ -1784,6 +2308,9 @@ c_parser_enum_specifier (c_parser *parser) ret.spec = finish_enum (type, nreverse (values), chainon (attrs, postfix_attrs)); ret.kind = ctsk_tagdef; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + timevar_pop (TV_PARSE_ENUM); return ret; } else if (!ident) @@ -1791,16 +2318,18 @@ c_parser_enum_specifier (c_parser *parser) c_parser_error (parser, "expected %<{%>"); ret.spec = error_mark_node; ret.kind = ctsk_tagref; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; return ret; } - ret = parser_xref_tag (ENUMERAL_TYPE, ident); + ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident); /* In ISO C, enumerated types can be referred to only if already defined. */ if (pedantic && !COMPLETE_TYPE_P (ret.spec)) { gcc_assert (ident); - pedwarn ("%HISO C forbids forward references to % types", - &ident_loc); + pedwarn (enum_loc, OPT_pedantic, + "ISO C forbids forward references to % types"); } return ret; } @@ -1850,6 +2379,8 @@ c_parser_struct_or_union_specifier (c_parser *parser) struct c_typespec ret; tree attrs; tree ident = NULL_TREE; + location_t struct_loc; + location_t ident_loc = UNKNOWN_LOCATION; enum tree_code code; switch (c_parser_peek_token (parser)->keyword) { @@ -1862,20 +2393,26 @@ c_parser_struct_or_union_specifier (c_parser *parser) default: gcc_unreachable (); } + struct_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); attrs = c_parser_attributes (parser); + /* Set the location in case we create a decl now. */ c_parser_set_source_position_from_token (c_parser_peek_token (parser)); + if (c_parser_next_token_is (parser, CPP_NAME)) { ident = c_parser_peek_token (parser)->value; + ident_loc = c_parser_peek_token (parser)->location; + struct_loc = ident_loc; c_parser_consume_token (parser); } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { /* Parse a struct or union definition. Start the scope of the tag before parsing components. */ - tree type = start_struct (code, ident); + struct c_struct_parse_info *struct_info; + tree type = start_struct (struct_loc, code, ident, &struct_info); tree postfix_attrs; /* We chain the components in reverse order, then put them in forward order at the end. Each struct-declaration may @@ -1887,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) }));. */ @@ -1924,9 +2463,8 @@ c_parser_struct_or_union_specifier (c_parser *parser) /* Parse any stray semicolon. */ if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - if (pedantic) - pedwarn ("%Hextra semicolon in struct or union specified", - &c_parser_peek_token (parser)->location); + pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + "extra semicolon in struct or union specified"); c_parser_consume_token (parser); continue; } @@ -1954,20 +2492,28 @@ c_parser_struct_or_union_specifier (c_parser *parser) else { if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - pedwarn ("%Hno semicolon at end of struct or union", - &c_parser_peek_token (parser)->location); - else + pedwarn (c_parser_peek_token (parser)->location, 0, + "no semicolon at end of struct or union"); + 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); - ret.spec = finish_struct (type, nreverse (contents), - chainon (attrs, postfix_attrs)); + ret.spec = finish_struct (struct_loc, type, nreverse (contents), + chainon (attrs, postfix_attrs), struct_info); ret.kind = ctsk_tagdef; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + timevar_pop (TV_PARSE_STRUCT); return ret; } else if (!ident) @@ -1975,9 +2521,11 @@ c_parser_struct_or_union_specifier (c_parser *parser) c_parser_error (parser, "expected %<{%>"); ret.spec = error_mark_node; ret.kind = ctsk_tagref; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; return ret; } - ret = parser_xref_tag (code, ident); + ret = parser_xref_tag (ident_loc, code, ident); return ret; } @@ -1986,6 +2534,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) struct-declaration: specifier-qualifier-list struct-declarator-list + static_assert-declaration-no-semi specifier-qualifier-list: type-specifier specifier-qualifier-list[opt] @@ -2030,9 +2579,14 @@ c_parser_struct_declaration (c_parser *parser) restore_extension_diagnostics (ext); return decl; } + if (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) + { + c_parser_static_assert_declaration_no_semi (parser); + return NULL_TREE; + } 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) @@ -2041,14 +2595,14 @@ 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) { - if (pedantic) - pedwarn ("%HISO C forbids member declarations with no members", - &decl_loc); + pedwarn (decl_loc, OPT_pedantic, + "ISO C forbids member declarations with no members"); shadow_tag_warned (specs, pedantic); ret = NULL_TREE; } @@ -2058,13 +2612,28 @@ c_parser_struct_declaration (c_parser *parser) structs or unions (which is [a] useful and [b] supports MS P-SDK). */ tree attrs = NULL; - ret = grokfield (build_id_declarator (NULL_TREE), specs, + + ret = grokfield (c_parser_peek_token (parser)->location, + build_id_declarator (NULL_TREE), specs, NULL_TREE, &attrs); if (ret) decl_attributes (&ret, attrs, 0); } 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; @@ -2078,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) { @@ -2101,10 +2671,11 @@ c_parser_struct_declaration (c_parser *parser) } if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) postfix_attrs = c_parser_attributes (parser); - d = grokfield (declarator, specs, width, &all_prefix_attrs); + d = grokfield (c_parser_peek_token (parser)->location, + declarator, specs, width, &all_prefix_attrs); decl_attributes (&d, chainon (postfix_attrs, all_prefix_attrs), 0); - TREE_CHAIN (d) = decls; + DECL_CHAIN (d) = decls; decls = d; if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) all_prefix_attrs = chainon (c_parser_attributes (parser), @@ -2149,24 +2720,26 @@ c_parser_typeof_specifier (c_parser *parser) struct c_typespec ret; ret.kind = ctsk_typeof; ret.spec = error_mark_node; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF)); c_parser_consume_token (parser); - skip_evaluation++; + c_inhibit_evaluation_warnings++; in_typeof++; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - skip_evaluation--; + c_inhibit_evaluation_warnings--; 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); - skip_evaluation--; + c_inhibit_evaluation_warnings--; in_typeof--; if (type != NULL) { - ret.spec = groktypename (type); + ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands); pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE)); } } @@ -2175,32 +2748,59 @@ c_parser_typeof_specifier (c_parser *parser) bool was_vm; location_t here = c_parser_peek_token (parser)->location; struct c_expr expr = c_parser_expression (parser); - skip_evaluation--; + c_inhibit_evaluation_warnings--; in_typeof--; if (TREE_CODE (expr.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) - error ("%H% applied to a bit-field", &here); + error_at (here, "% applied to a bit-field"); + mark_exp_read (expr.value); ret.spec = TREE_TYPE (expr.value); was_vm = variably_modified_type_p (ret.spec, NULL_TREE); - /* This should be returned with the type so that when the type - is evaluated, this can be evaluated. For now, we avoid - evaluation when the context might. */ - if (!skip_evaluation && was_vm) - { - tree e = expr.value; + /* This is returned with the type so that when the type is + evaluated, this can be evaluated. */ + if (was_vm) + ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands); + pop_maybe_used (was_vm); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return ret; +} - /* If the expression is not of a type to which we cannot assign a line - number, wrap the thing in a no-op NOP_EXPR. */ - if (DECL_P (e) || CONSTANT_CLASS_P (e)) - e = build1 (NOP_EXPR, void_type_node, e); +/* Parse an alignment-specifier. - if (CAN_HAVE_LOCATION_P (e)) - SET_EXPR_LOCATION (e, input_location); + C11 6.7.5: - add_stmt (e); - } - pop_maybe_used (was_vm); + 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; } @@ -2292,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; @@ -2348,7 +2948,8 @@ c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, if (kind != C_DTR_ABSTRACT && c_parser_next_token_is (parser, CPP_NAME) && ((type_seen_p - && c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME) + && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME + || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) || c_parser_peek_token (parser)->id_kind == C_ID_ID)) { struct c_declarator *inner @@ -2436,18 +3037,19 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present, /* Parse a sequence of array declarators and parameter lists. */ if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) { + location_t brace_loc = c_parser_peek_token (parser)->location; struct c_declarator *declarator; struct c_declspecs *quals_attrs = build_null_declspecs (); bool static_seen; 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. @@ -2493,8 +3095,10 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present, "expected %<]%>"); return NULL; } - declarator = build_array_declarator (dimen, quals_attrs, static_seen, - star_seen); + if (dimen) + mark_exp_read (dimen); + declarator = build_array_declarator (brace_loc, dimen, quals_attrs, + static_seen, star_seen); if (declarator == NULL) return NULL; inner = set_array_declarator_inner (declarator, inner); @@ -2533,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) @@ -2554,13 +3164,8 @@ c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs) } if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { - struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = 0; - ret->tags = 0; + struct c_arg_info *ret = build_arg_info (); ret->types = list; - ret->others = 0; - ret->pending_sizes = 0; - ret->had_vla_unspec = 0; c_parser_consume_token (parser); pop_scope (); return ret; @@ -2575,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; } @@ -2583,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 good_parm = false; + bool bad_parm = false; + /* ??? Following the old parser, forward parameter declarations may use abstract declarators, and if no real parameter declarations follow the forward declarations then this is not diagnosed. Also @@ -2597,28 +3206,26 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) declarations. */ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { - struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = 0; - ret->tags = 0; - ret->types = 0; - ret->others = 0; - ret->pending_sizes = 0; - ret->had_vla_unspec = 0; + struct c_arg_info *ret = build_arg_info (); c_parser_consume_token (parser); return ret; } if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) { - struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = 0; - ret->tags = 0; - ret->others = 0; - ret->pending_sizes = 0; - ret->had_vla_unspec = 0; - /* Suppress -Wold-style-definition for this case. */ - ret->types = error_mark_node; - error ("%HISO C requires a named argument before %<...%>", - &c_parser_peek_token (parser)->location); + struct c_arg_info *ret = build_arg_info (); + + 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)) { @@ -2640,36 +3247,25 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) /* Parse a parameter. */ struct c_parm *parm = c_parser_parameter_declaration (parser, attrs); attrs = NULL_TREE; - if (parm != NULL) - { - good_parm = true; - push_parm_decl (parm); - } + if (parm == NULL) + bad_parm = true; + else + push_parm_decl (parm, &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 (good_parm) - return get_parm_info (false); + if (bad_parm) + return NULL; else - { - struct c_arg_info *ret - = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = 0; - ret->tags = 0; - ret->types = 0; - ret->others = 0; - ret->pending_sizes = 0; - ret->had_vla_unspec = 0; - return ret; - } + return get_parm_info (false, expr); } if (!c_parser_require (parser, CPP_COMMA, "expected %<;%>, %<,%> or %<)%>")) @@ -2683,20 +3279,10 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { c_parser_consume_token (parser); - if (good_parm) - return get_parm_info (true); + if (bad_parm) + return NULL; else - { - struct c_arg_info *ret - = XOBNEW (&parser_obstack, struct c_arg_info); - ret->parms = 0; - ret->tags = 0; - ret->types = 0; - ret->others = 0; - ret->pending_sizes = 0; - ret->had_vla_unspec = 0; - return ret; - } + return get_parm_info (true, expr); } else { @@ -2721,10 +3307,20 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs) bool dummy = false; if (!c_parser_next_token_starts_declspecs (parser)) { + c_token *token = c_parser_peek_token (parser); + if (parser->error) + return NULL; + c_parser_set_source_position_from_token (token); + if (c_parser_next_tokens_start_typename (parser, cla_prefer_type)) + { + error ("unknown type name %qE", token->value); + parser->error = true; + } /* ??? In some Objective-C cases '...' isn't applicable so there should be a different message. */ - c_parser_error (parser, - "expected declaration specifiers or %<...%>"); + else + c_parser_error (parser, + "expected declaration specifiers or %<...%>"); c_parser_skip_to_end_of_parameter (parser); return NULL; } @@ -2734,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) { @@ -2767,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; @@ -2774,8 +3373,8 @@ c_parser_asm_string_literal (c_parser *parser) } else if (c_parser_next_token_is (parser, CPP_WSTRING)) { - error ("%Hwide string literal in %", - &c_parser_peek_token (parser)->location); + error_at (c_parser_peek_token (parser)->location, + "wide string literal in %"); str = build_string (1, ""); c_parser_consume_token (parser); } @@ -2784,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; } @@ -2819,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: @@ -2873,55 +3533,16 @@ c_parser_attributes (c_parser *parser) || c_parser_next_token_is (parser, CPP_KEYWORD)) { tree attr, attr_name, attr_args; + VEC(tree,gc) *expr_list; if (c_parser_next_token_is (parser, CPP_COMMA)) { 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_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; - } - 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)) { @@ -2933,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))) @@ -2946,9 +3570,12 @@ c_parser_attributes (c_parser *parser) attr_args = build_tree_list (NULL_TREE, arg1); else { + tree tree_list; c_parser_consume_token (parser); - attr_args = tree_cons (NULL_TREE, arg1, - c_parser_expr_list (parser, false)); + expr_list = c_parser_expr_list (parser, false, true, NULL); + tree_list = build_tree_list_vec (expr_list); + attr_args = tree_cons (NULL_TREE, arg1, tree_list); + release_tree_vector (expr_list); } } else @@ -2956,7 +3583,11 @@ c_parser_attributes (c_parser *parser) if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) attr_args = NULL_TREE; else - attr_args = c_parser_expr_list (parser, false); + { + expr_list = c_parser_expr_list (parser, false, true, NULL); + attr_args = build_tree_list_vec (expr_list); + release_tree_vector (expr_list); + } } attr = build_tree_list (attr_name, attr_args); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) @@ -3006,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; @@ -3075,10 +3710,11 @@ c_parser_initializer (c_parser *parser) else { struct c_expr ret; + location_t loc = c_parser_peek_token (parser)->location; ret = c_parser_expr_no_commas (parser, NULL); if (TREE_CODE (ret.value) != STRING_CST && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR) - ret = default_function_array_conversion (ret); + ret = default_function_array_read_conversion (loc, ret); return ret; } } @@ -3092,17 +3728,19 @@ c_parser_initializer (c_parser *parser) static struct c_expr c_parser_braced_init (c_parser *parser, tree type, bool nested_p) { + struct c_expr ret; + struct obstack braced_init_obstack; location_t brace_loc = c_parser_peek_token (parser)->location; + gcc_obstack_init (&braced_init_obstack); gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); c_parser_consume_token (parser); if (nested_p) - push_init_level (0); + push_init_level (0, &braced_init_obstack); else really_start_incremental_init (type); if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { - if (pedantic) - pedwarn ("%HISO C forbids empty initializer braces", &brace_loc); + pedwarn (brace_loc, OPT_pedantic, "ISO C forbids empty initializer braces"); } else { @@ -3110,7 +3748,7 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p) comma. */ while (true) { - c_parser_initelt (parser); + c_parser_initelt (parser, &braced_init_obstack); if (parser->error) break; if (c_parser_next_token_is (parser, CPP_COMMA)) @@ -3123,20 +3761,24 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p) } if (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) { - struct c_expr ret; ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>"); + pop_init_level (0, &braced_init_obstack); + obstack_free (&braced_init_obstack, NULL); return ret; } c_parser_consume_token (parser); - return pop_init_level (0); + ret = pop_init_level (0, &braced_init_obstack); + obstack_free (&braced_init_obstack, NULL); + return ret; } /* Parse a nested initializer, including designators. */ static void -c_parser_initelt (c_parser *parser) +c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) { /* Parse any designator or designator list. A single array designator may have the subsequent "=" omitted in GNU C, but a @@ -3145,13 +3787,11 @@ c_parser_initelt (c_parser *parser) && c_parser_peek_2nd_token (parser)->type == CPP_COLON) { /* Old-style structure member designator. */ - set_init_label (c_parser_peek_token (parser)->value); - if (pedantic) - { - /* Use the colon as the error location. */ - pedwarn ("%Hobsolete use of designated initializer with %<:%>", - &c_parser_peek_2nd_token (parser)->location); - } + set_init_label (c_parser_peek_token (parser)->value, + braced_init_obstack); + /* Use the colon as the error location. */ + pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_pedantic, + "obsolete use of designated initializer with %<:%>"); c_parser_consume_token (parser); c_parser_consume_token (parser); } @@ -3161,7 +3801,7 @@ c_parser_initelt (c_parser *parser) has been a single array designator and 2 otherwise. */ int des_seen = 0; /* Location of a designator. */ - location_t des_loc; + location_t des_loc = UNKNOWN_LOCATION; /* Quiet warning. */ while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE) || c_parser_next_token_is (parser, CPP_DOT)) { @@ -3176,7 +3816,8 @@ c_parser_initelt (c_parser *parser) c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_NAME)) { - set_init_label (c_parser_peek_token (parser)->value); + set_init_label (c_parser_peek_token (parser)->value, + braced_init_obstack); c_parser_consume_token (parser); } else @@ -3184,16 +3825,17 @@ c_parser_initelt (c_parser *parser) struct c_expr init; init.value = error_mark_node; init.original_code = ERROR_MARK; + init.original_type = NULL; c_parser_error (parser, "expected identifier"); c_parser_skip_until_found (parser, CPP_COMMA, NULL); - process_init_element (init); + process_init_element (init, false, braced_init_obstack); return; } } else { tree first, second; - location_t ellipsis_loc; + location_t ellipsis_loc = UNKNOWN_LOCATION; /* Quiet warning. */ /* ??? Following the old parser, [ objc-receiver objc-message-args ] is accepted as an initializer, being distinguished from a designator by what follows @@ -3235,6 +3877,7 @@ c_parser_initelt (c_parser *parser) goto parse_message_args; } first = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (first); if (c_parser_next_token_is (parser, CPP_ELLIPSIS) || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) goto array_desig_after_first; @@ -3245,10 +3888,14 @@ c_parser_initelt (c_parser *parser) while (c_parser_next_token_is (parser, CPP_COMMA)) { struct c_expr next; + location_t comma_loc, exp_loc; + comma_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; next = c_parser_expr_no_commas (parser, NULL); - next = default_function_array_conversion (next); - rec = build_compound_expr (rec, next.value); + next = default_function_array_read_conversion (exp_loc, + next); + rec = build_compound_expr (comma_loc, rec, next.value); } parse_message_args: /* Now parse the objc-message-args. */ @@ -3256,32 +3903,35 @@ c_parser_initelt (c_parser *parser) 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 initializer, starting with this message expression as a primary-expression. */ - c_parser_initval (parser, &mexpr); + c_parser_initval (parser, &mexpr, braced_init_obstack); return; } c_parser_consume_token (parser); first = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (first); array_desig_after_first: if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) { ellipsis_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); second = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (second); } else second = NULL_TREE; if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) { c_parser_consume_token (parser); - set_init_index (first, second); - if (pedantic && second) - pedwarn ("%HISO C forbids specifying range of " - "elements to initialize", &ellipsis_loc); + set_init_index (first, second, braced_init_obstack); + if (second) + pedwarn (ellipsis_loc, OPT_pedantic, + "ISO C forbids specifying range of elements to initialize"); } else c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, @@ -3292,34 +3942,31 @@ c_parser_initelt (c_parser *parser) { if (c_parser_next_token_is (parser, CPP_EQ)) { - if (pedantic && !flag_isoc99) - pedwarn ("%HISO C90 forbids specifying subobject " - "to initialize", &des_loc); + if (!flag_isoc99) + pedwarn (des_loc, OPT_pedantic, + "ISO C90 forbids specifying subobject to initialize"); c_parser_consume_token (parser); } else { if (des_seen == 1) - { - if (pedantic) - pedwarn ("%Hobsolete use of designated initializer " - "without %<=%>", - &c_parser_peek_token (parser)->location); - } + pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + "obsolete use of designated initializer without %<=%>"); else { struct c_expr init; init.value = error_mark_node; init.original_code = ERROR_MARK; + init.original_type = NULL; c_parser_error (parser, "expected %<=%>"); c_parser_skip_until_found (parser, CPP_COMMA, NULL); - process_init_element (init); + process_init_element (init, false, braced_init_obstack); return; } } } } - c_parser_initval (parser, NULL); + c_parser_initval (parser, NULL, braced_init_obstack); } /* Parse a nested initializer; as c_parser_initializer but parses @@ -3329,7 +3976,8 @@ c_parser_initelt (c_parser *parser) initializer. */ static void -c_parser_initval (c_parser *parser, struct c_expr *after) +c_parser_initval (c_parser *parser, struct c_expr *after, + struct obstack * braced_init_obstack) { struct c_expr init; gcc_assert (!after || c_dialect_objc ()); @@ -3337,13 +3985,14 @@ c_parser_initval (c_parser *parser, struct c_expr *after) init = c_parser_braced_init (parser, NULL_TREE, true); else { + location_t loc = c_parser_peek_token (parser)->location; init = c_parser_expr_no_commas (parser, after); if (init.value != NULL_TREE && TREE_CODE (init.value) != STRING_CST && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR) - init = default_function_array_conversion (init); + init = default_function_array_read_conversion (loc, init); } - process_init_element (init); + process_init_element (init, false, braced_init_obstack); } /* Parse a compound statement (possibly a function body) (C90 6.6.2, @@ -3389,9 +4038,9 @@ c_parser_initval (c_parser *parser, struct c_expr *after) old parser in requiring something after label declarations. Although they are erroneous if the labels declared aren't defined, is it useful for the syntax to be this way? - + OpenMP: - + block-item: openmp-directive @@ -3403,11 +4052,19 @@ static tree c_parser_compound_statement (c_parser *parser) { tree stmt; + location_t brace_loc; + brace_loc = c_parser_peek_token (parser)->location; if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) - return error_mark_node; + { + /* Ensure a scope is entered and left anyway to avoid confusion + if we have just prepared to enter a function body. */ + stmt = c_begin_compound_stmt (true); + c_end_compound_stmt (brace_loc, stmt, true); + return error_mark_node; + } stmt = c_begin_compound_stmt (true); c_parser_compound_statement_nostart (parser); - return c_end_compound_stmt (stmt, true); + return c_end_compound_stmt (brace_loc, stmt, true); } /* Parse a compound statement except for the opening brace. This is @@ -3419,19 +4076,22 @@ c_parser_compound_statement_nostart (c_parser *parser) { bool last_stmt = false; bool last_label = false; - location_t label_loc; + bool save_valid_for_pragma = valid_location_for_stdc_pragma_p (); + location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { c_parser_consume_token (parser); return; } + mark_valid_location_for_stdc_pragma (true); if (c_parser_next_token_is_keyword (parser, RID_LABEL)) { - location_t err_loc = c_parser_peek_token (parser)->location; /* Read zero or more forward-declarations for labels that nested functions can jump to. */ + mark_valid_location_for_stdc_pragma (false); while (c_parser_next_token_is_keyword (parser, RID_LABEL)) { + label_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); /* Any identifiers, including those declared as type names, are OK here. */ @@ -3446,7 +4106,7 @@ c_parser_compound_statement_nostart (c_parser *parser) label = declare_label (c_parser_peek_token (parser)->value); C_DECLARED_LABEL_FLAG (label) = 1; - add_stmt (build_stmt (DECL_EXPR, label)); + add_stmt (build_stmt (label_loc, DECL_EXPR, label)); c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); @@ -3455,12 +4115,12 @@ c_parser_compound_statement_nostart (c_parser *parser) } c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } - if (pedantic) - pedwarn ("%HISO C forbids label declarations", &err_loc); + pedwarn (label_loc, OPT_pedantic, "ISO C forbids label declarations"); } /* We must now have at least one statement, label or declaration. */ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); c_parser_error (parser, "expected declaration or statement"); c_parser_consume_token (parser); return; @@ -3479,18 +4139,21 @@ c_parser_compound_statement_nostart (c_parser *parser) label_loc = c_parser_peek_token (parser)->location; last_label = true; last_stmt = false; + mark_valid_location_for_stdc_pragma (false); c_parser_label (parser); } else if (!last_label - && c_parser_next_token_starts_declspecs (parser)) + && c_parser_next_tokens_start_declaration (parser)) { last_label = false; - c_parser_declaration_or_fndef (parser, true, true, true, true); - if (last_stmt - && ((pedantic && !flag_isoc99) - || warn_declaration_after_statement)) - pedwarn_c90 ("%HISO C90 forbids mixed declarations and code", - &loc); + mark_valid_location_for_stdc_pragma (false); + c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); + if (last_stmt) + pedwarn_c90 (loc, + (pedantic && !flag_isoc99) + ? OPT_pedantic + : OPT_Wdeclaration_after_statement, + "ISO C90 forbids mixed declarations and code"); last_stmt = false; } else if (!last_label @@ -3504,21 +4167,23 @@ c_parser_compound_statement_nostart (c_parser *parser) && (c_parser_peek_2nd_token (parser)->keyword == RID_EXTENSION)) c_parser_consume_token (parser); - if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser))) + if (c_token_starts_declaration (c_parser_peek_2nd_token (parser))) { int ext; ext = disable_extension_diagnostics (); c_parser_consume_token (parser); last_label = false; - c_parser_declaration_or_fndef (parser, true, true, true, true); + mark_valid_location_for_stdc_pragma (false); + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, NULL); /* Following the old parser, __extension__ does not disable this diagnostic. */ restore_extension_diagnostics (ext); - if (last_stmt - && ((pedantic && !flag_isoc99) - || warn_declaration_after_statement)) - pedwarn_c90 ("%HISO C90 forbids mixed declarations and code", - &loc); + if (last_stmt) + pedwarn_c90 (loc, (pedantic && !flag_isoc99) + ? OPT_pedantic + : OPT_Wdeclaration_after_statement, + "ISO C90 forbids mixed declarations and code"); last_stmt = false; } else @@ -3536,19 +4201,21 @@ c_parser_compound_statement_nostart (c_parser *parser) } else if (c_parser_next_token_is (parser, CPP_EOF)) { + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); c_parser_error (parser, "expected declaration or statement"); return; } else if (c_parser_next_token_is_keyword (parser, RID_ELSE)) { - if (parser->in_if_block) + if (parser->in_if_block) { - error ("%H""expected %<}%> before %", &loc); + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); + error_at (loc, """expected %<}%> before %"); return; } - else + else { - error ("%H% without a previous %", &loc); + error_at (loc, "% without a previous %"); c_parser_consume_token (parser); continue; } @@ -3558,14 +4225,17 @@ c_parser_compound_statement_nostart (c_parser *parser) statement: last_label = false; last_stmt = true; + mark_valid_location_for_stdc_pragma (false); c_parser_statement_after_labels (parser); } parser->error = false; } if (last_label) - error ("%Hlabel at end of compound statement", &label_loc); + error_at (label_loc, "label at end of compound statement"); c_parser_consume_token (parser); + /* Restore the value we started with. */ + mark_valid_location_for_stdc_pragma (save_valid_for_pragma); } /* Parse a label (C90 6.6.1, C99 6.8.1). @@ -3597,14 +4267,14 @@ c_parser_label (c_parser *parser) if (c_parser_next_token_is (parser, CPP_COLON)) { c_parser_consume_token (parser); - label = do_case (exp1, NULL_TREE); + label = do_case (loc1, exp1, NULL_TREE); } else if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) { c_parser_consume_token (parser); exp2 = c_parser_expr_no_commas (parser, NULL).value; if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) - label = do_case (exp1, exp2); + label = do_case (loc1, exp1, exp2); } else c_parser_error (parser, "expected %<:%> or %<...%>"); @@ -3613,7 +4283,7 @@ c_parser_label (c_parser *parser) { c_parser_consume_token (parser); if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) - label = do_case (NULL_TREE, NULL_TREE); + label = do_case (loc1, NULL_TREE, NULL_TREE); } else { @@ -3630,22 +4300,20 @@ c_parser_label (c_parser *parser) if (tlab) { decl_attributes (&tlab, attrs, 0); - label = add_stmt (build_stmt (LABEL_EXPR, tlab)); + label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab)); } } if (label) { - SET_EXPR_LOCATION (label, loc1); - if (c_parser_next_token_starts_declspecs (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 ("%Ha label can only be part of a statement and " - "a declaration is not a statement", - &c_parser_peek_token (parser)->location); - c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false, + error_at (c_parser_peek_token (parser)->location, + "a label can only be part of a statement and " + "a declaration is not a statement"); + 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); } } } @@ -3745,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) @@ -3794,59 +4469,75 @@ c_parser_statement_after_labels (c_parser *parser) c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_NAME)) { - stmt = c_finish_goto_label (c_parser_peek_token (parser)->value); + stmt = c_finish_goto_label (loc, + c_parser_peek_token (parser)->value); c_parser_consume_token (parser); } else if (c_parser_next_token_is (parser, CPP_MULT)) { + tree val; + c_parser_consume_token (parser); - stmt = c_finish_goto_ptr (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 %<*%>"); goto expect_semicolon; case RID_CONTINUE: c_parser_consume_token (parser); - stmt = c_finish_bc_stmt (&c_cont_label, false); + stmt = c_finish_bc_stmt (loc, &c_cont_label, false); goto expect_semicolon; case RID_BREAK: c_parser_consume_token (parser); - stmt = c_finish_bc_stmt (&c_break_label, true); + stmt = c_finish_bc_stmt (loc, &c_break_label, true); goto expect_semicolon; case RID_RETURN: c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - stmt = c_finish_return (NULL_TREE); + stmt = c_finish_return (loc, NULL_TREE, NULL_TREE); c_parser_consume_token (parser); } else { - stmt = c_finish_return (c_parser_expression_conv (parser).value); + struct c_expr expr = c_parser_expression_conv (parser); + mark_exp_read (expr.value); + stmt = c_finish_return (loc, expr.value, expr.original_type); goto expect_semicolon; } break; 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); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - stmt = objc_build_throw_stmt (NULL_TREE); + stmt = objc_build_throw_stmt (loc, NULL_TREE); c_parser_consume_token (parser); } else { - stmt - = objc_build_throw_stmt (c_parser_expression (parser).value); + tree expr = c_parser_expression (parser).value; + expr = c_fully_fold (expr, false, NULL); + stmt = objc_build_throw_stmt (loc, expr); goto expect_semicolon; } 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 ()); @@ -3873,7 +4564,7 @@ c_parser_statement_after_labels (c_parser *parser) break; default: expr_stmt: - stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value); + stmt = c_finish_expr_stmt (loc, c_parser_expression_conv (parser).value); expect_semicolon: c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); break; @@ -3888,12 +4579,28 @@ c_parser_statement_after_labels (c_parser *parser) (recursively) all of the component statements should already have line numbers assigned. ??? Can we discard no-op statements earlier? */ - if (stmt && CAN_HAVE_LOCATION_P (stmt)) + if (CAN_HAVE_LOCATION_P (stmt) + && EXPR_LOCATION (stmt) == UNKNOWN_LOCATION) SET_EXPR_LOCATION (stmt, loc); parser->in_if_block = in_if_block; } +/* Parse the condition from an if, do, while or for statements. */ + +static tree +c_parser_condition (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree cond; + cond = c_parser_expression_conv (parser).value; + cond = c_objc_common_truthvalue_conversion (loc, cond); + cond = c_fully_fold (cond, false, NULL); + if (warn_sequence_point) + verify_sequence_points (cond); + return cond; +} + /* Parse a parenthesized condition from an if, do or while statement. condition: @@ -3902,15 +4609,10 @@ c_parser_statement_after_labels (c_parser *parser) static tree c_parser_paren_condition (c_parser *parser) { - location_t loc; tree cond; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return error_mark_node; - loc = c_parser_peek_token (parser)->location; - cond = c_objc_common_truthvalue_conversion - (c_parser_expression_conv (parser).value); - if (CAN_HAVE_LOCATION_P (cond)) - SET_EXPR_LOCATION (cond, loc); + cond = c_parser_condition (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return cond; } @@ -3921,8 +4623,9 @@ static tree c_parser_c99_block_statement (c_parser *parser) { tree block = c_begin_compound_stmt (flag_isoc99); + location_t loc = c_parser_peek_token (parser)->location; c_parser_statement (parser); - return c_end_compound_stmt (block, flag_isoc99); + return c_end_compound_stmt (loc, block, flag_isoc99); } /* Parse the body of an if statement. This is just parsing a @@ -3937,6 +4640,7 @@ static tree c_parser_if_body (c_parser *parser, bool *if_p) { tree block = c_begin_compound_stmt (flag_isoc99); + location_t body_loc = c_parser_peek_token (parser)->location; while (c_parser_next_token_is_keyword (parser, RID_CASE) || c_parser_next_token_is_keyword (parser, RID_DEFAULT) || (c_parser_next_token_is (parser, CPP_NAME) @@ -3945,14 +4649,18 @@ c_parser_if_body (c_parser *parser, bool *if_p) *if_p = c_parser_next_token_is_keyword (parser, RID_IF); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - add_stmt (build_empty_stmt ()); + location_t loc = c_parser_peek_token (parser)->location; + add_stmt (build_empty_stmt (loc)); c_parser_consume_token (parser); + if (!c_parser_next_token_is_keyword (parser, RID_ELSE)) + warning_at (loc, OPT_Wempty_body, + "suggest braces around empty body in an % statement"); } else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) add_stmt (c_parser_compound_statement (parser)); else c_parser_statement_after_labels (parser); - return c_end_compound_stmt (block, flag_isoc99); + return c_end_compound_stmt (body_loc, block, flag_isoc99); } /* Parse the else body of an if statement. This is just parsing a @@ -3962,6 +4670,7 @@ c_parser_if_body (c_parser *parser, bool *if_p) static tree c_parser_else_body (c_parser *parser) { + location_t else_loc = c_parser_peek_token (parser)->location; tree block = c_begin_compound_stmt (flag_isoc99); while (c_parser_next_token_is_keyword (parser, RID_CASE) || c_parser_next_token_is_keyword (parser, RID_DEFAULT) @@ -3970,12 +4679,16 @@ c_parser_else_body (c_parser *parser) c_parser_label (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - add_stmt (build_empty_stmt ()); + location_t loc = c_parser_peek_token (parser)->location; + warning_at (loc, + OPT_Wempty_body, + "suggest braces around empty body in an % statement"); + add_stmt (build_empty_stmt (loc)); c_parser_consume_token (parser); } - else + else c_parser_statement_after_labels (parser); - return c_end_compound_stmt (block, flag_isoc99); + return c_end_compound_stmt (else_loc, block, flag_isoc99); } /* Parse an if statement (C90 6.6.4, C99 6.8.4). @@ -4012,7 +4725,7 @@ c_parser_if_statement (c_parser *parser) else second_body = NULL_TREE; c_finish_if_stmt (loc, cond, first_body, second_body, first_if); - add_stmt (c_end_compound_stmt (block, flag_isoc99)); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); } /* Parse a switch statement (C90 6.6.4, C99 6.8.4). @@ -4025,25 +4738,36 @@ static void c_parser_switch_statement (c_parser *parser) { tree block, expr, body, save_break; + location_t switch_loc = c_parser_peek_token (parser)->location; + location_t switch_cond_loc; gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH)); c_parser_consume_token (parser); block = c_begin_compound_stmt (flag_isoc99); if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { + switch_cond_loc = c_parser_peek_token (parser)->location; expr = c_parser_expression (parser).value; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } else - expr = error_mark_node; - c_start_case (expr); + { + switch_cond_loc = UNKNOWN_LOCATION; + expr = error_mark_node; + } + c_start_case (switch_loc, switch_cond_loc, expr); save_break = c_break_label; c_break_label = NULL_TREE; body = c_parser_c99_block_statement (parser); c_finish_case (body); if (c_break_label) - add_stmt (build1 (LABEL_EXPR, void_type_node, c_break_label)); + { + location_t here = c_parser_peek_token (parser)->location; + tree t = build1 (LABEL_EXPR, void_type_node, c_break_label); + SET_EXPR_LOCATION (t, here); + add_stmt (t); + } c_break_label = save_break; - add_stmt (c_end_compound_stmt (block, flag_isoc99)); + add_stmt (c_end_compound_stmt (switch_loc, block, flag_isoc99)); } /* Parse a while statement (C90 6.6.5, C99 6.8.5). @@ -4068,7 +4792,7 @@ c_parser_while_statement (c_parser *parser) c_cont_label = NULL_TREE; body = c_parser_c99_block_statement (parser); c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true); - add_stmt (c_end_compound_stmt (block, flag_isoc99)); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); c_break_label = save_break; c_cont_label = save_cont; } @@ -4087,9 +4811,9 @@ c_parser_do_statement (c_parser *parser) gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO)); c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - warning (OPT_Wempty_body, - "%Hsuggest braces around empty body in % statement", - &c_parser_peek_token (parser)->location); + warning_at (c_parser_peek_token (parser)->location, + OPT_Wempty_body, + "suggest braces around empty body in % statement"); block = c_begin_compound_stmt (flag_isoc99); loc = c_parser_peek_token (parser)->location; save_break = c_break_label; @@ -4106,7 +4830,7 @@ c_parser_do_statement (c_parser *parser) if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) c_parser_skip_to_end_of_block_or_statement (parser); c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false); - add_stmt (c_end_compound_stmt (block, flag_isoc99)); + add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); } /* Parse a for statement (C90 6.6.5, C99 6.8.5). @@ -4123,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; - location_t loc; + /* 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)); - loc = c_parser_peek_token (parser)->location; 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 (NULL_TREE); + c_finish_expr_stmt (loc, NULL_TREE); } - else if (c_parser_next_token_starts_declspecs (parser)) + else if (c_parser_next_tokens_start_declaration (parser)) { - c_parser_declaration_or_fndef (parser, true, true, true, true); - check_for_loop_decls (); + 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)) { @@ -4157,14 +4944,25 @@ c_parser_for_statement (c_parser *parser) && (c_parser_peek_2nd_token (parser)->keyword == RID_EXTENSION)) c_parser_consume_token (parser); - if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser))) + if (c_token_starts_declaration (c_parser_peek_2nd_token (parser))) { int ext; ext = disable_extension_diagnostics (); c_parser_consume_token (parser); - c_parser_declaration_or_fndef (parser, true, true, true, true); + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, &object_expression); + parser->objc_could_be_foreach_context = false; + restore_extension_diagnostics (ext); - check_for_loop_decls (); + 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; @@ -4172,43 +4970,74 @@ c_parser_for_statement (c_parser *parser) else { init_expr: - c_finish_expr_stmt (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. */ - loc = c_parser_peek_token (parser)->location; - 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)) { - tree ocond = c_parser_expression_conv (parser).value; - cond = c_objc_common_truthvalue_conversion (ocond); - if (CAN_HAVE_LOCATION_P (cond)) - SET_EXPR_LOCATION (cond, loc); - 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 (NULL_TREE); else - incr = c_process_expr_stmt (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 (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; } @@ -4219,12 +5048,17 @@ c_parser_for_statement (c_parser *parser) asm-statement: asm type-qualifier[opt] ( asm-argument ) ; + asm type-qualifier[opt] goto ( asm-goto-argument ) ; asm-argument: asm-string-literal asm-string-literal : asm-operands[opt] asm-string-literal : asm-operands[opt] : asm-operands[opt] - asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers + asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers[opt] + + asm-goto-argument: + asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \ + : asm-goto-operands Qualifiers other than volatile are accepted in the syntax but warned for. */ @@ -4232,8 +5066,11 @@ c_parser_for_statement (c_parser *parser) static tree c_parser_asm_statement (c_parser *parser) { - tree quals, str, outputs, inputs, clobbers, ret; - bool simple; + tree quals, str, outputs, inputs, clobbers, labels, ret; + bool simple, is_goto; + location_t asm_loc = c_parser_peek_token (parser)->location; + int section, nsections; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); c_parser_consume_token (parser); if (c_parser_next_token_is_keyword (parser, RID_VOLATILE)) @@ -4244,87 +5081,105 @@ c_parser_asm_statement (c_parser *parser) else if (c_parser_next_token_is_keyword (parser, RID_CONST) || c_parser_next_token_is_keyword (parser, RID_RESTRICT)) { - warning (0, "%H%E qualifier ignored on asm", - &c_parser_peek_token (parser)->location, - c_parser_peek_token (parser)->value); + warning_at (c_parser_peek_token (parser)->location, + 0, + "%E qualifier ignored on asm", + c_parser_peek_token (parser)->value); quals = NULL_TREE; c_parser_consume_token (parser); } else quals = NULL_TREE; + + is_goto = false; + if (c_parser_next_token_is_keyword (parser, RID_GOTO)) + { + c_parser_consume_token (parser); + is_goto = true; + } + /* ??? Follow the C++ parser rather than using the lex_untranslated_string kludge. */ parser->lex_untranslated_string = true; + ret = NULL; + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - { - parser->lex_untranslated_string = false; - return NULL_TREE; - } + goto error; + str = c_parser_asm_string_literal (parser); - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - simple = true; - outputs = NULL_TREE; - inputs = NULL_TREE; - clobbers = NULL_TREE; - goto done_asm; - } - if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")) - { - parser->lex_untranslated_string = false; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return NULL_TREE; - } - simple = false; - /* Parse outputs. */ - if (c_parser_next_token_is (parser, CPP_COLON) - || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - outputs = NULL_TREE; - else - outputs = c_parser_asm_operands (parser, false); - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - inputs = NULL_TREE; - clobbers = NULL_TREE; - goto done_asm; - } - if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")) - { - parser->lex_untranslated_string = false; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return NULL_TREE; - } - /* Parse inputs. */ - if (c_parser_next_token_is (parser, CPP_COLON) - || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - inputs = NULL_TREE; - else - inputs = c_parser_asm_operands (parser, true); - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - clobbers = NULL_TREE; - goto done_asm; - } - if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")) - { - parser->lex_untranslated_string = false; - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return NULL_TREE; + if (str == NULL_TREE) + goto error_close_paren; + + simple = true; + outputs = NULL_TREE; + inputs = NULL_TREE; + clobbers = NULL_TREE; + labels = NULL_TREE; + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto) + goto done_asm; + + /* Parse each colon-delimited section of operands. */ + nsections = 3 + is_goto; + for (section = 0; section < nsections; ++section) + { + if (!c_parser_require (parser, CPP_COLON, + is_goto + ? "expected %<:%>" + : "expected %<:%> or %<)%>")) + goto error_close_paren; + + /* Once past any colon, we're no longer a simple asm. */ + simple = false; + + if ((!c_parser_next_token_is (parser, CPP_COLON) + && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + || section == 3) + switch (section) + { + case 0: + /* For asm goto, we don't allow output operands, but reserve + the slot for a future extension that does allow them. */ + if (!is_goto) + outputs = c_parser_asm_operands (parser, false); + break; + case 1: + inputs = c_parser_asm_operands (parser, true); + break; + case 2: + clobbers = c_parser_asm_clobbers (parser); + break; + case 3: + labels = c_parser_asm_goto_operands (parser); + break; + default: + gcc_unreachable (); + } + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto) + goto done_asm; } - /* Parse clobbers. */ - clobbers = c_parser_asm_clobbers (parser); + done_asm: - parser->lex_untranslated_string = false; if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return NULL_TREE; + goto error; } + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) c_parser_skip_to_end_of_block_or_statement (parser); - ret = build_asm_stmt (quals, build_asm_expr (str, outputs, inputs, - clobbers, simple)); + + ret = build_asm_stmt (quals, build_asm_expr (asm_loc, str, outputs, inputs, + clobbers, labels, simple)); + + error: + parser->lex_untranslated_string = false; return ret; + + error_close_paren: + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + goto error; } /* Parse asm operands, a GNU extension. If CONVERT_P (for inputs but @@ -4344,6 +5199,7 @@ static tree c_parser_asm_operands (c_parser *parser, bool convert_p) { tree list = NULL_TREE; + location_t loc; while (true) { tree name, str; @@ -4378,9 +5234,12 @@ c_parser_asm_operands (c_parser *parser, bool convert_p) parser->lex_untranslated_string = true; return NULL_TREE; } + loc = c_parser_peek_token (parser)->location; expr = c_parser_expression (parser); + mark_exp_read (expr.value); if (convert_p) - expr = default_function_array_conversion (expr); + expr = default_function_array_conversion (loc, expr); + expr.value = c_fully_fold (expr.value, false, NULL); parser->lex_untranslated_string = true; if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) { @@ -4423,6 +5282,45 @@ c_parser_asm_clobbers (c_parser *parser) return list; } +/* Parse asm goto labels, a GNU extension. + + asm-goto-operands: + identifier + asm-goto-operands , identifier +*/ + +static tree +c_parser_asm_goto_operands (c_parser *parser) +{ + tree list = NULL_TREE; + while (true) + { + tree name, label; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + c_token *tok = c_parser_peek_token (parser); + name = tok->value; + label = lookup_label_for_goto (tok->location, name); + c_parser_consume_token (parser); + TREE_USED (label) = 1; + } + else + { + c_parser_error (parser, "expected identifier"); + return NULL_TREE; + } + + name = build_string (IDENTIFIER_LENGTH (name), + IDENTIFIER_POINTER (name)); + list = tree_cons (name, label, list); + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + return nreverse (list); + } +} + /* Parse an expression other than a compound expression; that is, an assignment expression (C90 6.3.16, C99 6.5.16). If AFTER is not NULL then it is an Objective-C message expression which is the @@ -4444,8 +5342,10 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) { struct c_expr lhs, rhs, ret; enum tree_code code; + location_t op_location, exp_location; gcc_assert (!after || c_dialect_objc ()); lhs = c_parser_conditional_expression (parser, after); + op_location = c_parser_peek_token (parser)->location; switch (c_parser_peek_token (parser)->type) { case CPP_EQ: @@ -4485,9 +5385,12 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) return lhs; } c_parser_consume_token (parser); + exp_location = c_parser_peek_token (parser)->location; rhs = c_parser_expr_no_commas (parser, NULL); - rhs = default_function_array_conversion (rhs); - ret.value = build_modify_expr (lhs.value, code, rhs.value); + rhs = default_function_array_read_conversion (exp_location, rhs); + ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type, + code, exp_location, rhs.value, + rhs.original_type); if (code == NOP_EXPR) ret.original_code = MODIFY_EXPR; else @@ -4495,6 +5398,7 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) TREE_NO_WARNING (ret.value) = 1; ret.original_code = ERROR_MARK; } + ret.original_type = NULL; return ret; } @@ -4516,51 +5420,97 @@ static struct c_expr c_parser_conditional_expression (c_parser *parser, struct c_expr *after) { struct c_expr cond, exp1, exp2, ret; + location_t cond_loc, colon_loc, middle_loc; + 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; - cond = default_function_array_conversion (cond); + cond_loc = c_parser_peek_token (parser)->location; + cond = default_function_array_read_conversion (cond_loc, cond); c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_COLON)) { - if (pedantic) - pedwarn ("%HISO C forbids omitting the middle term of a ?: expression", - &c_parser_peek_token (parser)->location); + tree eptype = NULL_TREE; + + middle_loc = c_parser_peek_token (parser)->location; + pedwarn (middle_loc, OPT_pedantic, + "ISO C forbids omitting the middle term of a ?: expression"); + warn_for_omitted_condop (middle_loc, cond.value); + if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR) + { + eptype = TREE_TYPE (cond.value); + cond.value = TREE_OPERAND (cond.value, 0); + } /* Make sure first operand is calculated only once. */ - exp1.value = save_expr (default_conversion (cond.value)); - cond.value = c_objc_common_truthvalue_conversion (exp1.value); - skip_evaluation += cond.value == truthvalue_true_node; + exp1.value = c_save_expr (default_conversion (cond.value)); + if (eptype) + exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value); + exp1.original_type = NULL; + cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value); + c_inhibit_evaluation_warnings += cond.value == truthvalue_true_node; } else { cond.value = c_objc_common_truthvalue_conversion - (default_conversion (cond.value)); - skip_evaluation += cond.value == truthvalue_false_node; + (cond_loc, default_conversion (cond.value)); + c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node; exp1 = c_parser_expression_conv (parser); - skip_evaluation += ((cond.value == truthvalue_true_node) - - (cond.value == truthvalue_false_node)); + mark_exp_read (exp1.value); + c_inhibit_evaluation_warnings += + ((cond.value == truthvalue_true_node) + - (cond.value == truthvalue_false_node)); } + + colon_loc = c_parser_peek_token (parser)->location; if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) { - skip_evaluation -= cond.value == truthvalue_true_node; + c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } - exp2 = c_parser_conditional_expression (parser, NULL); - exp2 = default_function_array_conversion (exp2); - skip_evaluation -= cond.value == truthvalue_true_node; - ret.value = build_conditional_expr (cond.value, exp1.value, exp2.value); + { + location_t exp2_loc = c_parser_peek_token (parser)->location; + exp2 = c_parser_conditional_expression (parser, NULL); + exp2 = default_function_array_read_conversion (exp2_loc, exp2); + } + c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; + ret.value = build_conditional_expr (colon_loc, cond.value, + cond.original_code == C_MAYBE_CONST_EXPR, + exp1.value, exp1.original_type, + exp2.value, exp2.original_type); ret.original_code = ERROR_MARK; + if (exp1.value == error_mark_node || exp2.value == error_mark_node) + ret.original_type = NULL; + else + { + tree t1, t2; + + /* If both sides are enum type, the default conversion will have + made the type of the result be an integer type. We want to + remember the enum types we started with. */ + t1 = exp1.original_type ? exp1.original_type : TREE_TYPE (exp1.value); + t2 = exp2.original_type ? exp2.original_type : TREE_TYPE (exp2.value); + ret.original_type = ((t1 != error_mark_node + && t2 != error_mark_node + && (TYPE_MAIN_VARIANT (t1) + == TYPE_MAIN_VARIANT (t2))) + ? t1 + : NULL); + } return ret; } /* 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 @@ -4612,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 @@ -4632,64 +5583,58 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) the stack has lower precedence than the new operator or there is only one element on the stack; then the top expression is the LHS of the new operator. In the case of logical AND and OR - expressions, we also need to adjust skip_evaluation 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 - }; + expressions, we also need to adjust c_inhibit_evaluation_warnings + as appropriate when the operators are pushed and popped. */ + 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. */ + location_t loc; } stack[NUM_PRECS]; int sp; + /* Location of the binary operator. */ + location_t binary_loc = UNKNOWN_LOCATION; /* Quiet warning. */ #define POP \ do { \ switch (stack[sp].op) \ { \ case TRUTH_ANDIF_EXPR: \ - skip_evaluation -= stack[sp - 1].expr.value == truthvalue_false_node; \ + c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ + == truthvalue_false_node); \ break; \ case TRUTH_ORIF_EXPR: \ - skip_evaluation -= stack[sp - 1].expr.value == truthvalue_true_node; \ + c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ + == truthvalue_true_node); \ break; \ default: \ break; \ } \ stack[sp - 1].expr \ - = default_function_array_conversion (stack[sp - 1].expr); \ + = default_function_array_read_conversion (stack[sp - 1].loc, \ + stack[sp - 1].expr); \ stack[sp].expr \ - = default_function_array_conversion (stack[sp].expr); \ - stack[sp - 1].expr = parser_build_binary_op (stack[sp].op, \ + = default_function_array_read_conversion (stack[sp].loc, \ + stack[sp].expr); \ + stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ + stack[sp].op, \ stack[sp - 1].expr, \ stack[sp].expr); \ sp--; \ } while (0) 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; @@ -4772,32 +5717,43 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) expression. */ goto out; } - c_parser_consume_token (parser); + binary_loc = c_parser_peek_token (parser)->location; while (oprec <= stack[sp].prec) - POP; + { + if (sp == 0) + goto out; + POP; + } + c_parser_consume_token (parser); switch (ocode) { case TRUTH_ANDIF_EXPR: stack[sp].expr - = default_function_array_conversion (stack[sp].expr); + = default_function_array_read_conversion (stack[sp].loc, + stack[sp].expr); stack[sp].expr.value = c_objc_common_truthvalue_conversion - (default_conversion (stack[sp].expr.value)); - skip_evaluation += stack[sp].expr.value == truthvalue_false_node; + (stack[sp].loc, default_conversion (stack[sp].expr.value)); + c_inhibit_evaluation_warnings += (stack[sp].expr.value + == truthvalue_false_node); break; case TRUTH_ORIF_EXPR: stack[sp].expr - = default_function_array_conversion (stack[sp].expr); + = default_function_array_read_conversion (stack[sp].loc, + stack[sp].expr); stack[sp].expr.value = c_objc_common_truthvalue_conversion - (default_conversion (stack[sp].expr.value)); - skip_evaluation += stack[sp].expr.value == truthvalue_true_node; + (stack[sp].loc, default_conversion (stack[sp].expr.value)); + c_inhibit_evaluation_warnings += (stack[sp].expr.value + == truthvalue_true_node); break; default: break; } sp++; + stack[sp].loc = binary_loc; stack[sp].expr = c_parser_cast_expression (parser, NULL); stack[sp].prec = oprec; stack[sp].op = ocode; + stack[sp].loc = binary_loc; } out: while (sp > 0) @@ -4818,13 +5774,16 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) static struct c_expr c_parser_cast_expression (c_parser *parser, struct c_expr *after) { + location_t cast_loc = c_parser_peek_token (parser)->location; gcc_assert (!after || c_dialect_objc ()); if (after) - return c_parser_postfix_expression_after_primary (parser, *after); + return c_parser_postfix_expression_after_primary (parser, + cast_loc, *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))) { @@ -4838,6 +5797,7 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) { ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } @@ -4845,12 +5805,16 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) used_types_insert (type_name->specs->type); if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - return c_parser_postfix_expression_after_paren_type (parser, - type_name); - expr = c_parser_cast_expression (parser, NULL); - expr = default_function_array_conversion (expr); - ret.value = c_cast_expr (type_name, expr.value); + return c_parser_postfix_expression_after_paren_type (parser, type_name, + cast_loc); + { + location_t expr_loc = c_parser_peek_token (parser)->location; + expr = c_parser_cast_expression (parser, NULL); + expr = default_function_array_read_conversion (expr_loc, expr); + } + ret.value = c_cast_expr (cast_loc, type_name, expr.value); ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } else @@ -4877,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. */ @@ -4889,60 +5860,71 @@ c_parser_unary_expression (c_parser *parser) { int ext; struct c_expr ret, op; + location_t op_loc = c_parser_peek_token (parser)->location; + location_t exp_loc; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; switch (c_parser_peek_token (parser)->type) { case CPP_PLUS_PLUS: c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (op); - return parser_build_unary_op (PREINCREMENT_EXPR, op); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op); case CPP_MINUS_MINUS: c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (op); - return parser_build_unary_op (PREDECREMENT_EXPR, op); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); case CPP_AND: c_parser_consume_token (parser); - return parser_build_unary_op (ADDR_EXPR, - c_parser_cast_expression (parser, NULL)); + op = c_parser_cast_expression (parser, NULL); + mark_exp_read (op.value); + return parser_build_unary_op (op_loc, ADDR_EXPR, op); case CPP_MULT: c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (op); - ret.value = build_indirect_ref (op.value, "unary *"); - ret.original_code = ERROR_MARK; + op = default_function_array_read_conversion (exp_loc, op); + ret.value = build_indirect_ref (op_loc, op.value, RO_UNARY_STAR); return ret; case CPP_PLUS: if (!c_dialect_objc () && !in_system_header) - warning (OPT_Wtraditional, - "%Htraditional C rejects the unary plus operator", - &c_parser_peek_token (parser)->location); + warning_at (op_loc, + OPT_Wtraditional, + "traditional C rejects the unary plus operator"); c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (op); - return parser_build_unary_op (CONVERT_EXPR, op); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, CONVERT_EXPR, op); case CPP_MINUS: c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (op); - return parser_build_unary_op (NEGATE_EXPR, op); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, NEGATE_EXPR, op); case CPP_COMPL: c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (op); - return parser_build_unary_op (BIT_NOT_EXPR, op); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); case CPP_NOT: c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (op); - return parser_build_unary_op (TRUTH_NOT_EXPR, op); + op = default_function_array_read_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op); case CPP_AND_AND: /* Refer to the address of a label as a pointer. */ c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_NAME)) { ret.value = finish_label_address_expr - (c_parser_peek_token (parser)->value); + (c_parser_peek_token (parser)->value, op_loc); c_parser_consume_token (parser); } else @@ -4950,7 +5932,6 @@ c_parser_unary_expression (c_parser *parser) c_parser_error (parser, "expected identifier"); ret.value = error_mark_node; } - ret.original_code = ERROR_MARK; return ret; case CPP_KEYWORD: switch (c_parser_peek_token (parser)->keyword) @@ -4967,14 +5948,20 @@ c_parser_unary_expression (c_parser *parser) return ret; case RID_REALPART: c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (op); - return parser_build_unary_op (REALPART_EXPR, op); + op = default_function_array_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, REALPART_EXPR, op); case RID_IMAGPART: c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (op); - return parser_build_unary_op (IMAGPART_EXPR, op); + 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); } @@ -4992,7 +5979,7 @@ c_parser_sizeof_expression (c_parser *parser) location_t expr_loc; gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); c_parser_consume_token (parser); - skip_evaluation++; + c_inhibit_evaluation_warnings++; in_sizeof++; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) && c_token_starts_typename (c_parser_peek_2nd_token (parser))) @@ -5007,41 +5994,37 @@ c_parser_sizeof_expression (c_parser *parser) if (type_name == NULL) { struct c_expr ret; - skip_evaluation--; + c_inhibit_evaluation_warnings--; in_sizeof--; ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { expr = c_parser_postfix_expression_after_paren_type (parser, - type_name); + type_name, + expr_loc); goto sizeof_expr; } /* sizeof ( type-name ). */ - skip_evaluation--; + c_inhibit_evaluation_warnings--; in_sizeof--; - if (type_name->declarator->kind == cdk_array - && type_name->declarator->u.array.vla_unspec_p) - { - /* C99 6.7.5.2p4 */ - error ("%H%<[*]%> not allowed in other than a declaration", - &expr_loc); - } - return c_expr_sizeof_type (type_name); + return c_expr_sizeof_type (expr_loc, type_name); } else { expr_loc = c_parser_peek_token (parser)->location; expr = c_parser_unary_expression (parser); sizeof_expr: - skip_evaluation--; + c_inhibit_evaluation_warnings--; in_sizeof--; + mark_exp_read (expr.value); if (TREE_CODE (expr.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) - error ("%H% applied to a bit-field", &expr_loc); - return c_expr_sizeof_expr (expr); + error_at (expr_loc, "% applied to a bit-field"); + return c_expr_sizeof_expr (expr_loc, expr); } } @@ -5051,40 +6034,60 @@ static struct c_expr 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); - skip_evaluation++; + c_inhibit_evaluation_warnings++; in_alignof++; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) && c_token_starts_typename (c_parser_peek_2nd_token (parser))) { /* Either __alignof__ ( type-name ) or __alignof__ unary-expression starting with a compound literal. */ + location_t loc; struct c_type_name *type_name; struct c_expr ret; c_parser_consume_token (parser); + loc = c_parser_peek_token (parser)->location; type_name = c_parser_type_name (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); if (type_name == NULL) { struct c_expr ret; - skip_evaluation--; + c_inhibit_evaluation_warnings--; in_alignof--; ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { expr = c_parser_postfix_expression_after_paren_type (parser, - type_name); + type_name, + loc); goto alignof_expr; } /* alignof ( type-name ). */ - skip_evaluation--; + c_inhibit_evaluation_warnings--; in_alignof--; - ret.value = c_alignof (groktypename (type_name)); + ret.value = c_alignof (loc, groktypename (type_name, NULL, NULL)); ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } else @@ -5092,14 +6095,64 @@ c_parser_alignof_expression (c_parser *parser) struct c_expr ret; expr = c_parser_unary_expression (parser); alignof_expr: - skip_evaluation--; + mark_exp_read (expr.value); + c_inhibit_evaluation_warnings--; in_alignof--; - ret.value = c_alignof_expr (expr.value); + 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; return ret; } } +/* 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: @@ -5137,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 @@ -5151,25 +6209,42 @@ 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; + location_t loc = c_parser_peek_token (parser)->location;; + expr.original_code = ERROR_MARK; + expr.original_type = NULL; switch (c_parser_peek_token (parser)->type) { case CPP_NUMBER: + expr.value = c_parser_peek_token (parser)->value; + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + if (TREE_CODE (expr.value) == FIXED_CST + && !targetm.fixed_point_supported_p ()) + { + error_at (loc, "fixed-point types not supported for this target"); + expr.value = error_mark_node; + } + break; case CPP_CHAR: + case CPP_CHAR16: + case CPP_CHAR32: case CPP_WCHAR: expr.value = c_parser_peek_token (parser)->value; - expr.original_code = ERROR_MARK; c_parser_consume_token (parser); break; case CPP_STRING: + case CPP_STRING16: + case CPP_STRING32: case CPP_WSTRING: + case CPP_UTF8STRING: expr.value = c_parser_peek_token (parser)->value; expr.original_code = STRING_CST; c_parser_consume_token (parser); @@ -5178,26 +6253,51 @@ c_parser_postfix_expression (c_parser *parser) gcc_assert (c_dialect_objc ()); expr.value = objc_build_string_object (c_parser_peek_token (parser)->value); - expr.original_code = ERROR_MARK; 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; - expr.original_code = ERROR_MARK; break; } - { - tree id = c_parser_peek_token (parser)->value; - location_t loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - expr.value = build_external_ref (id, - (c_parser_peek_token (parser)->type - == CPP_OPEN_PAREN), loc); - expr.original_code = ERROR_MARK; - } break; case CPP_OPEN_PAREN: /* A parenthesized expression, statement expression or compound @@ -5206,29 +6306,28 @@ c_parser_postfix_expression (c_parser *parser) { /* A statement expression. */ tree stmt; - location_t here = c_parser_peek_token (parser)->location; + location_t brace_loc; 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 ("%Hbraced-group within expression allowed " - "only inside a function", &here); + error_at (loc, "braced-group within expression allowed " + "only inside a function"); parser->error = true; c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } stmt = c_begin_stmt_expr (); c_parser_compound_statement_nostart (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - if (pedantic) - pedwarn ("%HISO C forbids braced-groups within expressions", - &here); - expr.value = c_finish_stmt_expr (stmt); - expr.original_code = ERROR_MARK; + pedwarn (loc, OPT_pedantic, + "ISO C forbids braced-groups within expressions"); + expr.value = c_finish_stmt_expr (brace_loc, stmt); + mark_exp_read (expr.value); } else if (c_token_starts_typename (c_parser_peek_2nd_token (parser))) { @@ -5236,19 +6335,21 @@ c_parser_postfix_expression (c_parser *parser) than going directly to c_parser_postfix_expression_after_paren_type from elsewhere? */ + location_t loc; struct c_type_name *type_name; c_parser_consume_token (parser); + loc = c_parser_peek_token (parser)->location; type_name = c_parser_type_name (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); if (type_name == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; } else expr = c_parser_postfix_expression_after_paren_type (parser, - type_name); + type_name, + loc); } else { @@ -5257,7 +6358,9 @@ c_parser_postfix_expression (c_parser *parser) expr = c_parser_expression (parser); if (TREE_CODE (expr.value) == MODIFY_EXPR) TREE_NO_WARNING (expr.value) = 1; - expr.original_code = ERROR_MARK; + if (expr.original_code != C_MAYBE_CONST_EXPR) + expr.original_code = ERROR_MARK; + /* Don't change EXPR.ORIGINAL_TYPE. */ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } @@ -5268,9 +6371,9 @@ c_parser_postfix_expression (c_parser *parser) case RID_FUNCTION_NAME: case RID_PRETTY_FUNCTION_NAME: case RID_C99_FUNCTION_NAME: - expr.value = fname_decl (c_parser_peek_token (parser)->keyword, + expr.value = fname_decl (loc, + c_parser_peek_token (parser)->keyword, c_parser_peek_token (parser)->value); - expr.original_code = ERROR_MARK; c_parser_consume_token (parser); break; case RID_VA_ARG: @@ -5278,29 +6381,37 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } e1 = c_parser_expr_no_commas (parser, NULL); + mark_exp_read (e1.value); + e1.value = c_fully_fold (e1.value, false, NULL); if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } + loc = c_parser_peek_token (parser)->location; t1 = c_parser_type_name (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); if (t1 == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; } else { - expr.value = build_va_arg (e1.value, groktypename (t1)); - expr.original_code = ERROR_MARK; + tree type_expr = NULL_TREE; + expr.value = c_build_va_arg (loc, e1.value, + groktypename (t1, &type_expr, NULL)); + if (type_expr) + { + expr.value = build2 (C_MAYBE_CONST_EXPR, + TREE_TYPE (expr.value), type_expr, + expr.value); + C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true; + } } break; case RID_OFFSETOF: @@ -5308,44 +6419,55 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } t1 = c_parser_type_name (parser); if (t1 == NULL) - { - expr.value = error_mark_node; - expr.original_code = ERROR_MARK; - 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; - expr.original_code = ERROR_MARK; break; } + { - tree type = groktypename (t1); + tree type = groktypename (t1, NULL, NULL); tree offsetof_ref; if (type == error_mark_node) offsetof_ref = error_mark_node; else - offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node); + { + offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node); + SET_EXPR_LOCATION (offsetof_ref, loc); + } /* Parse the second argument to __builtin_offsetof. We must have one identifier, and beyond that we want to accept sub structure and sub array references. */ if (c_parser_next_token_is (parser, CPP_NAME)) { offsetof_ref = build_component_ref - (offsetof_ref, c_parser_peek_token (parser)->value); + (loc, offsetof_ref, c_parser_peek_token (parser)->value); c_parser_consume_token (parser); while (c_parser_next_token_is (parser, CPP_DOT) || c_parser_next_token_is (parser, - CPP_OPEN_SQUARE)) + CPP_OPEN_SQUARE) + || c_parser_next_token_is (parser, + CPP_DEREF)) { - if (c_parser_next_token_is (parser, CPP_DOT)) + if (c_parser_next_token_is (parser, CPP_DEREF)) + { + loc = c_parser_peek_token (parser)->location; + offsetof_ref = build_array_ref (loc, + offsetof_ref, + integer_zero_node); + goto do_dot; + } + else if (c_parser_next_token_is (parser, CPP_DOT)) { + do_dot: c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_NAME)) @@ -5354,18 +6476,20 @@ c_parser_postfix_expression (c_parser *parser) break; } offsetof_ref = build_component_ref - (offsetof_ref, + (loc, offsetof_ref, c_parser_peek_token (parser)->value); c_parser_consume_token (parser); } else { tree idx; + loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); idx = c_parser_expression (parser).value; + idx = c_fully_fold (idx, false, NULL); c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); - offsetof_ref = build_array_ref (offsetof_ref, idx); + offsetof_ref = build_array_ref (loc, offsetof_ref, idx); } } } @@ -5373,106 +6497,204 @@ 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.original_code = ERROR_MARK; + 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; - expr.original_code = ERROR_MARK; - 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; - expr.original_code = ERROR_MARK; - 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; - expr.original_code = ERROR_MARK; - 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 = fold (e1.value); - if (TREE_CODE (c) != INTEGER_CST) - error ("%Hfirst argument to %<__builtin_choose_expr%> not" - " a constant", &loc); - expr = integer_zerop (c) ? e3 : e2; + 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_p : *e2_p; + break; } - break; case RID_TYPES_COMPATIBLE_P: c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } t1 = c_parser_type_name (parser); if (t1 == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } t2 = c_parser_type_name (parser); if (t2 == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "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)); - e2 = TYPE_MAIN_VARIANT (groktypename (t2)); + e1 = TYPE_MAIN_VARIANT (e1); + e2 = TYPE_MAIN_VARIANT (e2); - expr.value = comptypes (e1, e2) - ? build_int_cst (NULL_TREE, 1) - : build_int_cst (NULL_TREE, 0); - expr.original_code = ERROR_MARK; + 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); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } { tree sel = c_parser_objc_selector_arg (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - expr.value = objc_build_selector_expr (sel); - expr.original_code = ERROR_MARK; + expr.value = objc_build_selector_expr (loc, sel); } break; case RID_AT_PROTOCOL: @@ -5481,7 +6703,6 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } if (c_parser_next_token_is_not (parser, CPP_NAME)) @@ -5489,7 +6710,6 @@ c_parser_postfix_expression (c_parser *parser) c_parser_error (parser, "expected identifier"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } { @@ -5498,7 +6718,6 @@ c_parser_postfix_expression (c_parser *parser) c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); expr.value = objc_build_protocol_expr (id); - expr.original_code = ERROR_MARK; } break; case RID_AT_ENCODE: @@ -5508,29 +6727,25 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } t1 = c_parser_type_name (parser); if (t1 == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); break; } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); { - tree type = groktypename (t1); + tree type = groktypename (t1, NULL, NULL); expr.value = objc_build_encode_expr (type); - expr.original_code = ERROR_MARK; } break; default: c_parser_error (parser, "expected expression"); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } break; @@ -5543,19 +6758,16 @@ 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.original_code = ERROR_MARK; + expr.value = objc_build_message_expr (receiver, args); break; } /* Else fall through to report error. */ default: c_parser_error (parser, "expected expression"); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } - return c_parser_postfix_expression_after_primary (parser, expr); + return c_parser_postfix_expression_after_primary (parser, loc, expr); } /* Parse a postfix expression after a parenthesized type name: the @@ -5564,45 +6776,86 @@ c_parser_postfix_expression (c_parser *parser) possible to tell until after the type name whether a cast expression has a cast or a compound literal, or whether the operand of sizeof is a parenthesized type name or starts with a compound - literal. */ + literal. TYPE_LOC is the location where TYPE_NAME starts--the + location of the first token after the parentheses around the type + name. */ static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *parser, - struct c_type_name *type_name) + struct c_type_name *type_name, + location_t type_loc) { tree type; struct c_expr init; + bool non_const; struct c_expr expr; location_t start_loc; + tree type_expr = NULL_TREE; + bool type_expr_const = true; + check_compound_literal_type (type_loc, type_name); start_init (NULL_TREE, NULL, 0); - type = groktypename (type_name); + type = groktypename (type_name, &type_expr, &type_expr_const); start_loc = c_parser_peek_token (parser)->location; if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) { - error ("%Hcompound literal has variable size", &start_loc); + error_at (type_loc, "compound literal has variable size"); type = error_mark_node; } init = c_parser_braced_init (parser, type, false); finish_init (); maybe_warn_string_init (type, init); - if (pedantic && !flag_isoc99) - pedwarn ("%HISO C90 forbids compound literals", &start_loc); - expr.value = build_compound_literal (type, init.value); + if (type != error_mark_node + && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)) + && current_function_decl) + { + error ("compound literal qualified by address-space qualifier"); + type = error_mark_node; + } + + if (!flag_isoc99) + pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals"); + non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) + ? CONSTRUCTOR_NON_CONST (init.value) + : init.original_code == C_MAYBE_CONST_EXPR); + non_const |= !type_expr_const; + expr.value = build_compound_literal (start_loc, type, init.value, non_const); expr.original_code = ERROR_MARK; - return c_parser_postfix_expression_after_primary (parser, expr); + expr.original_type = NULL; + if (type_expr) + { + if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR) + { + gcc_assert (C_MAYBE_CONST_EXPR_PRE (expr.value) == NULL_TREE); + C_MAYBE_CONST_EXPR_PRE (expr.value) = type_expr; + } + else + { + gcc_assert (!non_const); + expr.value = build2 (C_MAYBE_CONST_EXPR, type, + type_expr, expr.value); + } + } + return c_parser_postfix_expression_after_primary (parser, start_loc, expr); } /* Parse a postfix expression after the initial primary or compound - literal; that is, parse a series of postfix operators. */ + literal; that is, parse a series of postfix operators. + + EXPR_LOC is the location of the primary expression. */ static struct c_expr c_parser_postfix_expression_after_primary (c_parser *parser, + location_t expr_loc, struct c_expr expr) { - tree ident, idx, exprlist; + struct c_expr orig_expr; + tree ident, idx; + VEC(tree,gc) *exprlist; + VEC(tree,gc) *origtypes; while (true) { + location_t op_loc = c_parser_peek_token (parser)->location; switch (c_parser_peek_token (parser)->type) { case CPP_OPEN_SQUARE: @@ -5611,25 +6864,42 @@ c_parser_postfix_expression_after_primary (c_parser *parser, idx = c_parser_expression (parser).value; c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); - expr.value = build_array_ref (expr.value, idx); + expr.value = build_array_ref (op_loc, expr.value, idx); expr.original_code = ERROR_MARK; + expr.original_type = NULL; break; case CPP_OPEN_PAREN: /* Function call. */ c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - exprlist = NULL_TREE; + exprlist = NULL; else - exprlist = c_parser_expr_list (parser, true); + exprlist = c_parser_expr_list (parser, true, false, &origtypes); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - expr.value = build_function_call (expr.value, exprlist); + orig_expr = expr; + mark_exp_read (expr.value); + /* FIXME diagnostics: Ideally we want the FUNCNAME, not the + "(" after the FUNCNAME, which is what we have now. */ + expr.value = build_function_call_vec (op_loc, expr.value, exprlist, + origtypes); expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) == INTEGER_CST + && TREE_CODE (orig_expr.value) == FUNCTION_DECL + && DECL_BUILT_IN_CLASS (orig_expr.value) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (orig_expr.value) == BUILT_IN_CONSTANT_P) + expr.original_code = C_MAYBE_CONST_EXPR; + expr.original_type = NULL; + if (exprlist != NULL) + { + release_tree_vector (exprlist); + release_tree_vector (origtypes); + } break; case CPP_DOT: /* Structure element reference. */ c_parser_consume_token (parser); - expr = default_function_array_conversion (expr); + expr = default_function_array_conversion (expr_loc, expr); if (c_parser_next_token_is (parser, CPP_NAME)) ident = c_parser_peek_token (parser)->value; else @@ -5637,16 +6907,28 @@ c_parser_postfix_expression_after_primary (c_parser *parser, c_parser_error (parser, "expected identifier"); expr.value = error_mark_node; expr.original_code = ERROR_MARK; + expr.original_type = NULL; return expr; } c_parser_consume_token (parser); - expr.value = build_component_ref (expr.value, ident); + expr.value = build_component_ref (op_loc, expr.value, ident); expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } break; case CPP_DEREF: /* Structure element reference. */ c_parser_consume_token (parser); - expr = default_function_array_conversion (expr); + expr = default_function_array_conversion (expr_loc, expr); if (c_parser_next_token_is (parser, CPP_NAME)) ident = c_parser_peek_token (parser)->value; else @@ -5654,26 +6936,45 @@ c_parser_postfix_expression_after_primary (c_parser *parser, c_parser_error (parser, "expected identifier"); expr.value = error_mark_node; expr.original_code = ERROR_MARK; + expr.original_type = NULL; return expr; } c_parser_consume_token (parser); - expr.value = build_component_ref (build_indirect_ref (expr.value, - "->"), ident); + expr.value = build_component_ref (op_loc, + build_indirect_ref (op_loc, + expr.value, + RO_ARROW), + ident); expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } break; case CPP_PLUS_PLUS: /* Postincrement. */ c_parser_consume_token (parser); - expr = default_function_array_conversion (expr); - expr.value = build_unary_op (POSTINCREMENT_EXPR, expr.value, 0); + expr = default_function_array_read_conversion (expr_loc, expr); + expr.value = build_unary_op (op_loc, + POSTINCREMENT_EXPR, expr.value, 0); expr.original_code = ERROR_MARK; + expr.original_type = NULL; break; case CPP_MINUS_MINUS: /* Postdecrement. */ c_parser_consume_token (parser); - expr = default_function_array_conversion (expr); - expr.value = build_unary_op (POSTDECREMENT_EXPR, expr.value, 0); + expr = default_function_array_read_conversion (expr_loc, expr); + expr.value = build_unary_op (op_loc, + POSTDECREMENT_EXPR, expr.value, 0); expr.original_code = ERROR_MARK; + expr.original_type = NULL; break; default: return expr; @@ -5696,11 +6997,21 @@ c_parser_expression (c_parser *parser) while (c_parser_next_token_is (parser, CPP_COMMA)) { struct c_expr next; + tree lhsval; + location_t loc = c_parser_peek_token (parser)->location; + location_t expr_loc; c_parser_consume_token (parser); + expr_loc = c_parser_peek_token (parser)->location; + lhsval = expr.value; + while (TREE_CODE (lhsval) == COMPOUND_EXPR) + lhsval = TREE_OPERAND (lhsval, 1); + if (DECL_P (lhsval) || handled_component_p (lhsval)) + mark_exp_read (lhsval); next = c_parser_expr_no_commas (parser, NULL); - next = default_function_array_conversion (next); - expr.value = build_compound_expr (expr.value, next.value); + next = default_function_array_conversion (expr_loc, next); + expr.value = build_compound_expr (loc, expr.value, next.value); expr.original_code = COMPOUND_EXPR; + expr.original_type = next.original_type; } return expr; } @@ -5712,39 +7023,60 @@ static struct c_expr c_parser_expression_conv (c_parser *parser) { struct c_expr expr; + location_t loc = c_parser_peek_token (parser)->location; expr = c_parser_expression (parser); - expr = default_function_array_conversion (expr); + expr = default_function_array_conversion (loc, expr); return expr; } /* Parse a non-empty list of expressions. If CONVERT_P, convert - functions and arrays to pointers. + functions and arrays to pointers. If FOLD_P, fold the expressions. nonempty-expr-list: assignment-expression nonempty-expr-list , assignment-expression */ -static tree -c_parser_expr_list (c_parser *parser, bool convert_p) +static VEC(tree,gc) * +c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, + VEC(tree,gc) **p_orig_types) { + VEC(tree,gc) *ret; + VEC(tree,gc) *orig_types; struct c_expr expr; - tree ret, cur; + location_t loc = c_parser_peek_token (parser)->location; + + ret = make_tree_vector (); + if (p_orig_types == NULL) + orig_types = NULL; + else + orig_types = make_tree_vector (); + expr = c_parser_expr_no_commas (parser, NULL); if (convert_p) - expr = default_function_array_conversion (expr); - ret = cur = build_tree_list (NULL_TREE, expr.value); + expr = default_function_array_read_conversion (loc, expr); + if (fold_p) + expr.value = c_fully_fold (expr.value, false, NULL); + VEC_quick_push (tree, ret, expr.value); + if (orig_types != NULL) + VEC_quick_push (tree, orig_types, expr.original_type); while (c_parser_next_token_is (parser, CPP_COMMA)) { c_parser_consume_token (parser); + loc = c_parser_peek_token (parser)->location; expr = c_parser_expr_no_commas (parser, NULL); if (convert_p) - expr = default_function_array_conversion (expr); - cur = TREE_CHAIN (cur) = build_tree_list (NULL_TREE, expr.value); - } + expr = default_function_array_read_conversion (loc, expr); + if (fold_p) + expr.value = c_fully_fold (expr.value, false, NULL); + VEC_safe_push (tree, gc, ret, expr.value); + if (orig_types != NULL) + VEC_safe_push (tree, gc, orig_types, expr.original_type); + } + if (orig_types != NULL) + *p_orig_types = orig_types; return ret; } - /* Parse Objective-C-specific constructs. */ @@ -5757,6 +7089,8 @@ c_parser_expr_list (c_parser *parser, bool convert_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: @@ -5769,7 +7103,7 @@ c_parser_expr_list (c_parser *parser, bool convert_p) objc-protocol-refs and objc-class-instance-variables are omitted. */ static void -c_parser_objc_class_definition (c_parser *parser) +c_parser_objc_class_definition (c_parser *parser, tree attributes) { bool iface_p; tree id1; @@ -5780,6 +7114,7 @@ c_parser_objc_class_definition (c_parser *parser) iface_p = false; else gcc_unreachable (); + c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_NAME)) { @@ -5790,17 +7125,29 @@ c_parser_objc_class_definition (c_parser *parser) 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) { @@ -5809,7 +7156,7 @@ c_parser_objc_class_definition (c_parser *parser) } if (c_parser_next_token_is (parser, CPP_LESS)) proto = c_parser_objc_protocol_refs (parser); - objc_start_category_interface (id1, id2, proto); + objc_start_category_interface (id1, id2, proto, attributes); c_parser_objc_methodprotolist (parser); c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); objc_finish_interface (); @@ -5833,7 +7180,7 @@ c_parser_objc_class_definition (c_parser *parser) tree proto = NULL_TREE; if (c_parser_next_token_is (parser, CPP_LESS)) proto = c_parser_objc_protocol_refs (parser); - objc_start_class_interface (id1, superclass, proto); + objc_start_class_interface (id1, superclass, proto, attributes); } else objc_start_class_implementation (id1, superclass); @@ -5886,9 +7233,8 @@ c_parser_objc_class_instance_variables (c_parser *parser) /* Parse any stray semicolon. */ if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - if (pedantic) - pedwarn ("%Hextra semicolon in struct or union specified", - &c_parser_peek_token (parser)->location); + pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + "extra semicolon"); c_parser_consume_token (parser); continue; } @@ -5902,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)) @@ -5925,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 = TREE_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 %<;%>"); } } @@ -5945,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 @@ -5956,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); @@ -5967,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. @@ -6014,9 +7387,10 @@ c_parser_objc_alias_declaration (c_parser *parser) omitted. */ static void -c_parser_objc_protocol_definition (c_parser *parser) +c_parser_objc_protocol_definition (c_parser *parser, tree attributes) { gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL)); + c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_NAME)) { @@ -6026,7 +7400,6 @@ c_parser_objc_protocol_definition (c_parser *parser) 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) @@ -6038,7 +7411,7 @@ c_parser_objc_protocol_definition (c_parser *parser) 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); @@ -6046,7 +7419,6 @@ c_parser_objc_protocol_definition (c_parser *parser) break; } c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - objc_declare_protocols (list); } else { @@ -6056,7 +7428,7 @@ c_parser_objc_protocol_definition (c_parser *parser) if (c_parser_next_token_is (parser, CPP_LESS)) proto = c_parser_objc_protocol_refs (parser); parser->objc_pq_context = true; - objc_start_protocol (id, proto); + objc_start_protocol (id, proto, attributes); c_parser_objc_methodprotolist (parser); c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); parser->objc_pq_context = false; @@ -6069,19 +7441,21 @@ c_parser_objc_protocol_definition (c_parser *parser) 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 (); } @@ -6096,27 +7470,42 @@ 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; - 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); + decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, + &expr); + if (decl == error_mark_node) + return; /* Bail here. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { c_parser_consume_token (parser); - if (pedantic) - pedwarn ("%Hextra semicolon in method definition specified", - &c_parser_peek_token (parser)->location); + pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + "extra semicolon in method definition specified"); } + if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { c_parser_error (parser, "expected %<{%>"); return; } + parser->objc_pq_context = false; - objc_start_method_definition (decl); - add_stmt (c_parser_compound_statement (parser)); - objc_finish_method_definition (current_function_decl); + if (objc_start_method_definition (is_class_method, decl, attributes, expr)) + { + add_stmt (c_parser_compound_statement (parser)); + objc_finish_method_definition (current_function_decl); + } + else + { + /* This code is executed when we find a method definition + outside of an @implementation context (or invalid for other + reasons). Parse the method (to keep going) but do not emit + any code. + */ + c_parser_compound_statement (parser); + } } /* Parse an objc-methodprotolist. @@ -6126,6 +7515,8 @@ c_parser_objc_method_definition (c_parser *parser) objc-methodprotolist objc-methodproto objc-methodprotolist declaration objc-methodprotolist ; + @optional + @required The declaration is a data definition, which may be missing declaration specifiers under the same rules and diagnostics as @@ -6142,10 +7533,8 @@ c_parser_objc_methodprotolist (c_parser *parser) switch (c_parser_peek_token (parser)->type) { case CPP_SEMICOLON: - if (pedantic) - pedwarn ("%HISO C does not allow extra %<;%> " - "outside of a function", - &c_parser_peek_token (parser)->location); + pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + "ISO C does not allow extra %<;%> outside of a function"); c_parser_consume_token (parser); break; case CPP_PLUS: @@ -6160,7 +7549,21 @@ c_parser_objc_methodprotolist (c_parser *parser) default: if (c_parser_next_token_is_keyword (parser, RID_AT_END)) return; - c_parser_declaration_or_fndef (parser, false, true, false, true); + else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)) + c_parser_objc_at_property_declaration (parser); + else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL)) + { + objc_set_method_opt (true); + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is_keyword (parser, RID_AT_REQUIRED)) + { + objc_set_method_opt (false); + c_parser_consume_token (parser); + } + else + c_parser_declaration_or_fndef (parser, false, false, true, + false, true, NULL); break; } } @@ -6175,18 +7578,66 @@ 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); - tree decl; - objc_set_method_type (type); + bool is_class_method = c_parser_objc_method_type (parser); + tree decl, attributes = NULL_TREE; + /* Remember protocol qualifiers in prototypes. */ parser->objc_pq_context = true; - decl = c_parser_objc_method_decl (parser); - /* Forget protocol qualifiers here. */ + decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, + NULL); + /* Forget protocol qualifiers now. */ parser->objc_pq_context = false; - objc_add_method_declaration (decl); + + /* Do not allow the presence of attributes to hide an erroneous + method implementation in the interface section. */ + if (!c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + c_parser_error (parser, "expected %<;%>"); + return; + } + + if (decl != error_mark_node) + objc_add_method_declaration (is_class_method, decl, attributes); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } +/* If we are at a position that method attributes may be present, check that + there are not any parsed already (a syntax error) and then collect any + specified at the current location. Finally, if new attributes were present, + check that the next token is legal ( ';' for decls and '{' for defs). */ + +static bool +c_parser_objc_maybe_method_attributes (c_parser* parser, tree* attributes) +{ + bool bad = false; + if (*attributes) + { + c_parser_error (parser, + "method attributes must be specified at the end only"); + *attributes = NULL_TREE; + bad = true; + } + + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + *attributes = c_parser_attributes (parser); + + /* If there were no attributes here, just report any earlier error. */ + if (*attributes == NULL_TREE || bad) + return bad; + + /* If the attributes are followed by a ; or {, then just report any earlier + error. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + || c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + return bad; + + /* We've got attributes, but not at the end. */ + c_parser_error (parser, + "expected %<;%> or %<{%> after method attribute definition"); + return true; +} + /* Parse an objc-method-decl. objc-method-decl: @@ -6194,6 +7645,7 @@ c_parser_objc_methodproto (c_parser *parser) objc-selector ( objc-type-name ) objc-keyword-selector objc-optparmlist objc-keyword-selector objc-optparmlist + attributes objc-keyword-selector: objc-keyword-decl @@ -6218,13 +7670,16 @@ c_parser_objc_methodproto (c_parser *parser) */ static tree -c_parser_objc_method_decl (c_parser *parser) +c_parser_objc_method_decl (c_parser *parser, bool is_class_method, + tree *attributes, tree *expr) { tree type = NULL_TREE; tree sel; tree parms = NULL_TREE; bool ellipsis = false; + bool attr_err = false; + *attributes = NULL_TREE; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { c_parser_consume_token (parser); @@ -6242,6 +7697,7 @@ c_parser_objc_method_decl (c_parser *parser) while (true) { tree atype = NULL_TREE, id, keyworddecl; + tree param_attr = NULL_TREE; if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) break; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) @@ -6251,6 +7707,9 @@ c_parser_objc_method_decl (c_parser *parser) c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } + /* New ObjC allows attributes on method parameters. */ + if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + param_attr = c_parser_attributes (parser); if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); @@ -6258,12 +7717,15 @@ c_parser_objc_method_decl (c_parser *parser) } id = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); - keyworddecl = objc_build_keyword_decl (tsel, atype, id); + keyworddecl = objc_build_keyword_decl (tsel, atype, id, param_attr); list = chainon (list, keyworddecl); tsel = c_parser_objc_selector (parser); if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON)) break; } + + attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; + /* Parse the optional parameter list. Optional Objective-C method parameters follow the C syntax, and may include '...' to denote a variable number of arguments. */ @@ -6276,17 +7738,31 @@ c_parser_objc_method_decl (c_parser *parser) { ellipsis = true; c_parser_consume_token (parser); + attr_err |= c_parser_objc_maybe_method_attributes + (parser, attributes) ; break; } parm = c_parser_parameter_declaration (parser, NULL_TREE); if (parm == NULL) break; parms = chainon (parms, - build_tree_list (NULL_TREE, grokparm (parm))); + build_tree_list (NULL_TREE, grokparm (parm, expr))); } sel = list; } - return objc_build_method_signature (type, sel, parms, ellipsis); + else + attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; + + if (sel == NULL) + { + c_parser_error (parser, "objective-c method declaration is expected"); + return error_mark_node; + } + + if (attr_err) + return error_mark_node; + + return objc_build_method_signature (is_class_method, type, sel, parms, ellipsis); } /* Parse an objc-type-name. @@ -6307,7 +7783,7 @@ static tree c_parser_objc_type_name (c_parser *parser) { tree quals = NULL_TREE; - struct c_type_name *typename = NULL; + struct c_type_name *type_name = NULL; tree type = NULL_TREE; while (true) { @@ -6320,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)) - typename = c_parser_type_name (parser); - if (typename) - type = groktypename (typename); + 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); } @@ -6367,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)); + 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 (); } @@ -6432,9 +7961,11 @@ 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; + expr = c_fully_fold (expr, false, NULL); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } else @@ -6492,6 +8023,7 @@ c_parser_objc_selector (c_parser *parser) case RID_ALIGNOF: case RID_UNSIGNED: case RID_LONG: + case RID_INT128: case RID_CONST: case RID_SHORT: case RID_VOLATILE: @@ -6570,7 +8102,7 @@ c_parser_objc_receiver (c_parser *parser) c_parser_consume_token (parser); return objc_get_class_reference (id); } - return c_parser_expression (parser).value; + return c_fully_fold (c_parser_expression (parser).value, false, NULL); } /* Parse objc-message-args. @@ -6599,7 +8131,7 @@ c_parser_objc_message_args (c_parser *parser) { tree keywordexpr; if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - return list; + return error_mark_node; keywordexpr = c_parser_objc_keywordexpr (parser); list = chainon (list, build_tree_list (sel, keywordexpr)); sel = c_parser_objc_selector (parser); @@ -6618,42 +8150,361 @@ c_parser_objc_message_args (c_parser *parser) static tree c_parser_objc_keywordexpr (c_parser *parser) { - tree list = c_parser_expr_list (parser, true); - if (TREE_CHAIN (list) == NULL_TREE) + tree ret; + VEC(tree,gc) *expr_list = c_parser_expr_list (parser, true, true, NULL); + if (VEC_length (tree, expr_list) == 1) { /* Just return the expression, remove a level of indirection. */ - return TREE_VALUE (list); + ret = VEC_index (tree, expr_list, 0); } else { /* We have a comma expression, we will collapse later. */ - return list; + ret = build_tree_list_vec (expr_list); } + release_tree_vector (expr_list); + return ret; } - -/* Handle pragmas. Some OpenMP pragmas are associated with, and therefore - should be considered, statements. ALLOW_STMT is true if we're within - the context of a function and such pragmas are to be allowed. Returns - true if we actually parsed such a pragma. */ - +/* A check, needed in several places, that ObjC interface, implementation or + method definitions are not prefixed by incorrect items. */ static bool -c_parser_pragma (c_parser *parser, enum pragma_context context) +c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, + struct c_declspecs *specs) { - unsigned int id; + if (!specs->declspecs_seen_p || specs->non_sc_seen_p + || specs->typespec_kind != ctsk_none) + { + c_parser_error (parser, + "no type or storage class may be specified here,"); + c_parser_skip_to_end_of_block_or_statement (parser); + return true; + } + return false; +} - id = c_parser_peek_token (parser)->pragma_kind; - gcc_assert (id != PRAGMA_NONE); +/* Parse an Objective-C @property declaration. The syntax is: - switch (id) - { - case PRAGMA_OMP_BARRIER: - if (context != pragma_compound) - { - if (context == pragma_stmt) - c_parser_error (parser, "%<#pragma omp barrier%> may only be " - "used in compound statements"); + 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 + the context of a function and such pragmas are to be allowed. Returns + true if we actually parsed such a pragma. */ + +static bool +c_parser_pragma (c_parser *parser, enum pragma_context context) +{ + unsigned int id; + + id = c_parser_peek_token (parser)->pragma_kind; + gcc_assert (id != PRAGMA_NONE); + + switch (id) + { + case PRAGMA_OMP_BARRIER: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp barrier%> may only be " + "used in compound statements"); goto bad_stmt; } c_parser_omp_barrier (parser); @@ -6670,14 +8521,36 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_omp_flush (parser); return false; + case PRAGMA_OMP_TASKWAIT: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp taskwait%> may only be " + "used in compound statements"); + goto bad_stmt; + } + 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; case PRAGMA_OMP_SECTION: - error ("%H%<#pragma omp section%> may only be used in " - "%<#pragma omp sections%> construct", - &c_parser_peek_token (parser)->location); + error_at (c_parser_peek_token (parser)->location, + "%<#pragma omp section%> may only be used in " + "%<#pragma omp sections%> construct"); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; @@ -6705,7 +8578,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_consume_pragma (parser); c_invoke_pragma_handler (id); - /* Skip to EOL, but suppress any error message. Those will have been + /* Skip to EOL, but suppress any error message. Those will have been generated by the handler routine through calling error, as opposed to calling c_parser_error. */ parser->error = true; @@ -6777,19 +8650,27 @@ c_parser_omp_clause_name (c_parser *parser) switch (p[0]) { case 'c': - if (!strcmp ("copyin", p)) + if (!strcmp ("collapse", p)) + result = PRAGMA_OMP_CLAUSE_COLLAPSE; + else if (!strcmp ("copyin", p)) result = PRAGMA_OMP_CLAUSE_COPYIN; else if (!strcmp ("copyprivate", p)) 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; @@ -6814,6 +8695,10 @@ c_parser_omp_clause_name (c_parser *parser) else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; break; + case 'u': + if (!strcmp ("untied", p)) + result = PRAGMA_OMP_CLAUSE_UNTIED; + break; } } @@ -6826,14 +8711,16 @@ c_parser_omp_clause_name (c_parser *parser) /* Validate that a clause of the given type does not already exist. */ static void -check_no_duplicate_clause (tree clauses, enum tree_code code, const char *name) +check_no_duplicate_clause (tree clauses, enum omp_clause_code code, + const char *name) { tree c; for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == code) { - error ("too many %qs clauses", name); + location_t loc = OMP_CLAUSE_LOCATION (c); + error_at (loc, "too many %qs clauses", name); break; } } @@ -6843,14 +8730,17 @@ check_no_duplicate_clause (tree clauses, enum tree_code code, const char *name) identifier variable-list , identifier - If KIND is nonzero, create the appropriate node and install the decl - in OMP_CLAUSE_DECL and add the node to the head of the list. + If KIND is nonzero, create the appropriate node and install the + decl in OMP_CLAUSE_DECL and add the node to the head of the list. + If KIND is nonzero, CLAUSE_LOC is the location of the clause. If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; return the list created. */ static tree -c_parser_omp_variable_list (c_parser *parser, enum omp_clause_code kind, +c_parser_omp_variable_list (c_parser *parser, + location_t clause_loc, + enum omp_clause_code kind, tree list) { if (c_parser_next_token_is_not (parser, CPP_NAME) @@ -6863,13 +8753,13 @@ c_parser_omp_variable_list (c_parser *parser, enum omp_clause_code kind, tree t = lookup_name (c_parser_peek_token (parser)->value); if (t == NULL_TREE) - undeclared_variable (c_parser_peek_token (parser)->value, - c_parser_peek_token (parser)->location); + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); else if (t == error_mark_node) ; else if (kind != 0) { - tree u = build_omp_clause (kind); + tree u = build_omp_clause (clause_loc, kind); OMP_CLAUSE_DECL (u) = t; OMP_CLAUSE_CHAIN (u) = list; list = u; @@ -6892,16 +8782,55 @@ c_parser_omp_variable_list (c_parser *parser, enum omp_clause_code kind, common case for omp clauses. */ static tree -c_parser_omp_var_list_parens (c_parser *parser, enum tree_code kind, tree list) +c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, + tree list) { + /* The clauses location. */ + location_t loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - list = c_parser_omp_variable_list (parser, kind, list); + list = c_parser_omp_variable_list (parser, loc, kind, list); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } return list; } +/* OpenMP 3.0: + collapse ( constant-expression ) */ + +static tree +c_parser_omp_clause_collapse (c_parser *parser, tree list) +{ + tree c, num = error_mark_node; + HOST_WIDE_INT n; + location_t loc; + + check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse"); + + loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + num = c_parser_expr_no_commas (parser, NULL).value; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + if (num == error_mark_node) + return list; + if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) + || !host_integerp (num, 0) + || (n = tree_low_cst (num, 0)) <= 0 + || (int) n != n) + { + error_at (loc, + "collapse argument needs positive constant integer expression"); + return list; + } + c = build_omp_clause (loc, OMP_CLAUSE_COLLAPSE); + OMP_CLAUSE_COLLAPSE_EXPR (c) = num; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + /* OpenMP 2.5: copyin ( variable-list ) */ @@ -6927,6 +8856,7 @@ static tree c_parser_omp_clause_default (c_parser *parser, tree list) { enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; + location_t loc = c_parser_peek_token (parser)->location; tree c; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) @@ -6966,7 +8896,7 @@ c_parser_omp_clause_default (c_parser *parser, tree list) return list; check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default"); - c = build_omp_clause (OMP_CLAUSE_DEFAULT); + c = build_omp_clause (loc, OMP_CLAUSE_DEFAULT); OMP_CLAUSE_CHAIN (c) = list; OMP_CLAUSE_DEFAULT_KIND (c) = kind; @@ -6982,12 +8912,38 @@ 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 ) */ static tree c_parser_omp_clause_if (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); @@ -6995,7 +8951,7 @@ c_parser_omp_clause_if (c_parser *parser, tree list) check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if"); - c = build_omp_clause (OMP_CLAUSE_IF); + c = build_omp_clause (loc, OMP_CLAUSE_IF); OMP_CLAUSE_IF_EXPR (c) = t; OMP_CLAUSE_CHAIN (c) = list; list = c; @@ -7015,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 */ @@ -7022,10 +8996,11 @@ static tree c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) { tree c; + location_t loc = c_parser_peek_token (parser)->location; check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait"); - c = build_omp_clause (OMP_CLAUSE_NOWAIT); + c = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); OMP_CLAUSE_CHAIN (c) = list; return c; } @@ -7036,10 +9011,13 @@ c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) static tree c_parser_omp_clause_num_threads (c_parser *parser, tree list) { + location_t num_threads_loc = c_parser_peek_token (parser)->location; if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { 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 %<)%>"); @@ -7050,17 +9028,20 @@ c_parser_omp_clause_num_threads (c_parser *parser, tree list) } /* Attempt to statically determine when the number isn't positive. */ - c = fold_build2 (LE_EXPR, boolean_type_node, t, + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); if (c == boolean_true_node) { - warning (0, "%H% value must be positive", &expr_loc); + warning_at (expr_loc, 0, + "% value must be positive"); t = integer_one_node; } check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads"); - c = build_omp_clause (OMP_CLAUSE_NUM_THREADS); + c = build_omp_clause (num_threads_loc, OMP_CLAUSE_NUM_THREADS); OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; OMP_CLAUSE_CHAIN (c) = list; list = c; @@ -7073,14 +9054,16 @@ c_parser_omp_clause_num_threads (c_parser *parser, tree list) ordered */ static tree -c_parser_omp_clause_ordered (c_parser *parser ATTRIBUTE_UNUSED, tree list) +c_parser_omp_clause_ordered (c_parser *parser, tree list) { tree c; check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered"); - c = build_omp_clause (OMP_CLAUSE_ORDERED); + c = build_omp_clause (c_parser_peek_token (parser)->location, + OMP_CLAUSE_ORDERED); OMP_CLAUSE_CHAIN (c) = list; + return c; } @@ -7097,11 +9080,17 @@ 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) { + location_t clause_loc = c_parser_peek_token (parser)->location; if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { enum tree_code code; @@ -7132,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; } @@ -7144,7 +9149,8 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) { tree nl, c; - nl = c_parser_omp_variable_list (parser, OMP_CLAUSE_REDUCTION, list); + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_REDUCTION, list); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_REDUCTION_CODE (c) = code; @@ -7160,18 +9166,19 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) schedule ( schedule-kind , expression ) schedule-kind: - static | dynamic | guided | runtime + static | dynamic | guided | runtime | auto */ static tree c_parser_omp_clause_schedule (c_parser *parser, tree list) { tree c, t; + location_t loc = c_parser_peek_token (parser)->location; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return list; - c = build_omp_clause (OMP_CLAUSE_SCHEDULE); + c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE); if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -7204,6 +9211,8 @@ c_parser_omp_clause_schedule (c_parser *parser, tree list) } else if (c_parser_next_token_is_keyword (parser, RID_STATIC)) OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; + else if (c_parser_next_token_is_keyword (parser, RID_AUTO)) + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO; else goto invalid_kind; @@ -7215,10 +9224,16 @@ 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) - error ("%Hschedule % does not take " - "a % parameter", &here); + error_at (here, "schedule % does not take " + "a % parameter"); + else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO) + error_at (here, + "schedule % does not take " + "a % parameter"); else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE) OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; else @@ -7249,6 +9264,24 @@ c_parser_omp_clause_shared (c_parser *parser, tree list) return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list); } +/* OpenMP 3.0: + untied */ + +static tree +c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + /* FIXME: Should we allow duplicates? */ + check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied"); + + c = build_omp_clause (c_parser_peek_token (parser)->location, + OMP_CLAUSE_UNTIED); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + /* Parse all OpenMP clauses. The set clauses allowed by the directive is a bitmask in MASK. Return the list of clauses found; the result of clause default goes in *pdefault. */ @@ -7276,6 +9309,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, switch (c_kind) { + case PRAGMA_OMP_CLAUSE_COLLAPSE: + clauses = c_parser_omp_clause_collapse (parser, clauses); + c_name = "collapse"; + break; case PRAGMA_OMP_CLAUSE_COPYIN: clauses = c_parser_omp_clause_copyin (parser, clauses); c_name = "copyin"; @@ -7292,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"; @@ -7300,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"; @@ -7328,6 +9373,10 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, clauses = c_parser_omp_clause_shared (parser, clauses); c_name = "shared"; break; + case PRAGMA_OMP_CLAUSE_UNTIED: + clauses = c_parser_omp_clause_untied (parser, clauses); + c_name = "untied"; + break; default: c_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; @@ -7338,7 +9387,7 @@ c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, /* Remove the invalid clause(s) from the list to avoid confusing the rest of the compiler. */ clauses = prev; - error ("%H%qs is not valid for %qs", &here, c_name, where); + error_at (here, "%qs is not valid for %qs", c_name, where); } } @@ -7373,86 +9422,366 @@ c_parser_omp_structured_block (c_parser *parser) binop: +, *, -, /, &, ^, |, <<, >> - where x is an lvalue expression with scalar type. */ + 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 (c_parser *parser) +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; + case COMPOUND_EXPR: + if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR + && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR + && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND + (TREE_OPERAND (lhs, 1), 0), 0))) + == BOOLEAN_TYPE) + /* Undo effects of boolean_increment for post {in,de}crement. */ + lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0); + /* FALLTHRU */ + case MODIFY_EXPR: + if (TREE_CODE (lhs) == MODIFY_EXPR + && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE) + { + /* Undo effects of boolean_increment. */ + if (integer_onep (TREE_OPERAND (lhs, 1))) + { + /* This is pre or post increment. */ + rhs = TREE_OPERAND (lhs, 1); + lhs = TREE_OPERAND (lhs, 0); + 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 + && TREE_OPERAND (lhs, 0) + == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) + { + /* This is pre or post decrement. */ + rhs = TREE_OPERAND (lhs, 1); + lhs = TREE_OPERAND (lhs, 0); + opcode = NOP_EXPR; + if (code == OMP_ATOMIC_CAPTURE_NEW + && !structured_block + && TREE_CODE (orig_lhs) == COMPOUND_EXPR) + code = OMP_ATOMIC_CAPTURE_OLD; + break; + } + } + /* FALLTHRU */ default: 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); - rhs_expr = c_parser_expression (parser); - rhs_expr = default_function_array_conversion (rhs_expr); + { + location_t rhs_loc = c_parser_peek_token (parser)->location; + rhs_expr = c_parser_expression (parser); + rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr); + } rhs = rhs_expr.value; + rhs = c_fully_fold (rhs, false, NULL); break; } - stmt = c_finish_omp_atomic (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 %<;%>"); } @@ -7463,19 +9792,21 @@ c_parser_omp_atomic (c_parser *parser) static void c_parser_omp_barrier (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_barrier (); + c_finish_omp_barrier (loc); } /* OpenMP 2.5: # pragma omp critical [(name)] new-line structured-block -*/ + + LOC is the location of the #pragma itself. */ static tree -c_parser_omp_critical (c_parser *parser) +c_parser_omp_critical (location_t loc, c_parser *parser) { tree stmt, name = NULL; @@ -7496,7 +9827,7 @@ c_parser_omp_critical (c_parser *parser) c_parser_skip_to_pragma_eol (parser); stmt = c_parser_omp_structured_block (parser); - return c_finish_omp_critical (stmt, name); + return c_finish_omp_critical (loc, stmt, name); } /* OpenMP 2.5: @@ -7508,112 +9839,311 @@ c_parser_omp_critical (c_parser *parser) static void c_parser_omp_flush (c_parser *parser) { + location_t loc = c_parser_peek_token (parser)->location; c_parser_consume_pragma (parser); if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - c_parser_omp_var_list_parens (parser, 0, NULL); + c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) c_parser_error (parser, "expected %<(%> or end of line"); c_parser_skip_to_pragma_eol (parser); - c_finish_omp_flush (); + c_finish_omp_flush (loc); } -/* Parse the restricted form of the for statment allowed by OpenMP. +/* Parse the restricted form of the for statement allowed by OpenMP. The real trick here is to determine the loop control variable early - so that we can push a new decl if necessary to make it private. */ + so that we can push a new decl if necessary to make it private. + LOC is the location of the OMP in "#pragma omp". */ static tree -c_parser_omp_for_loop (c_parser *parser) +c_parser_omp_for_loop (location_t loc, + c_parser *parser, tree clauses, tree *par_clauses) { - tree decl, cond, incr, save_break, save_cont, body, init; - location_t loc; + tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl; + tree declv, condv, incrv, initv, ret = NULL; + bool fail = false, open_brace_parsed = false; + int i, collapse = 1, nbraces = 0; + location_t for_loc; + VEC(tree,gc) *for_block = make_tree_vector (); + + for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) + if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) + collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0); + + gcc_assert (collapse >= 1); + + declv = make_tree_vec (collapse); + initv = make_tree_vec (collapse); + condv = make_tree_vec (collapse); + incrv = make_tree_vec (collapse); if (!c_parser_next_token_is_keyword (parser, RID_FOR)) { c_parser_error (parser, "for statement expected"); return NULL; } - loc = c_parser_peek_token (parser)->location; + for_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return NULL; - - /* Parse the initialization declaration or expression. */ - if (c_parser_next_token_starts_declspecs (parser)) + for (i = 0; i < collapse; i++) { - c_parser_declaration_or_fndef (parser, true, true, true, true); - decl = check_for_loop_decls (); - if (decl == NULL) - goto error_init; - if (DECL_INITIAL (decl) == error_mark_node) - decl = error_mark_node; - init = decl; - } - else if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_EQ) - { - decl = c_parser_postfix_expression (parser).value; + int bracecount = 0; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + goto pop_scopes; + + /* Parse the initialization declaration or expression. */ + 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, NULL); + decl = check_for_loop_decls (for_loc, flag_isoc99); + if (decl == NULL) + goto error_init; + if (DECL_INITIAL (decl) == error_mark_node) + decl = error_mark_node; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + struct c_expr decl_exp; + struct c_expr init_exp; + location_t init_loc; + + decl_exp = c_parser_postfix_expression (parser); + decl = decl_exp.value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init_loc = c_parser_peek_token (parser)->location; + init_exp = c_parser_expr_no_commas (parser, NULL); + init_exp = default_function_array_read_conversion (init_loc, + init_exp); + init = build_modify_expr (init_loc, decl, decl_exp.original_type, + NOP_EXPR, init_loc, init_exp.value, + init_exp.original_type); + init = c_process_expr_stmt (init_loc, init); - c_parser_require (parser, CPP_EQ, "expected %<=%>"); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + error_init: + c_parser_error (parser, + "expected iteration declaration or initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + fail = true; + goto parse_next; + } - init = c_parser_expr_no_commas (parser, NULL).value; - init = build_modify_expr (decl, NOP_EXPR, init); - init = c_process_expr_stmt (init); + /* Parse the loop condition. */ + cond = NULL_TREE; + 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, + PREC_NONE); + cond = cond_expr.value; + cond = c_objc_common_truthvalue_conversion (cond_loc, cond); + cond = c_fully_fold (cond, false, NULL); + switch (cond_expr.original_code) + { + case GT_EXPR: + case GE_EXPR: + case LT_EXPR: + case LE_EXPR: + break; + default: + /* Can't be cond = error_mark_node, because we want to preserve + the location until c_finish_omp_for. */ + cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node); + break; + } + protected_set_expr_location (cond, cond_loc); + } c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - } - else - goto error_init; - /* Parse the loop condition. */ - cond = NULL_TREE; - if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) - { - cond = c_parser_expression_conv (parser).value; - cond = c_objc_common_truthvalue_conversion (cond); - if (CAN_HAVE_LOCATION_P (cond)) - SET_EXPR_LOCATION (cond, input_location); - } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + /* Parse the increment expression. */ + incr = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + location_t incr_loc = c_parser_peek_token (parser)->location; - /* Parse the increment expression. */ - incr = NULL_TREE; - if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) - incr = c_process_expr_stmt (c_parser_expression (parser).value); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + incr = c_process_expr_stmt (incr_loc, + c_parser_expression (parser).value); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (decl == NULL || decl == error_mark_node || init == error_mark_node) + fail = true; + else + { + TREE_VEC_ELT (declv, i) = decl; + TREE_VEC_ELT (initv, i) = init; + TREE_VEC_ELT (condv, i) = cond; + TREE_VEC_ELT (incrv, i) = incr; + } + + parse_next: + if (i == collapse - 1) + break; + + /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed + in between the collapsed for loops to be still considered perfectly + nested. Hopefully the final version clarifies this. + For now handle (multiple) {'s and empty statements. */ + do + { + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + { + c_parser_consume_token (parser); + break; + } + else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + c_parser_consume_token (parser); + bracecount++; + } + else if (bracecount + && c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "not enough perfectly nested loops"); + if (bracecount) + { + open_brace_parsed = true; + bracecount--; + } + fail = true; + collapse = 0; + break; + } + } + while (1); + + nbraces += bracecount; + } - parse_body: save_break = c_break_label; c_break_label = size_one_node; save_cont = c_cont_label; c_cont_label = NULL_TREE; body = push_stmt_list (); - add_stmt (c_parser_c99_block_statement (parser)); + if (open_brace_parsed) + { + location_t here = c_parser_peek_token (parser)->location; + stmt = c_begin_compound_stmt (true); + c_parser_compound_statement_nostart (parser); + add_stmt (c_end_compound_stmt (here, stmt, true)); + } + else + add_stmt (c_parser_c99_block_statement (parser)); if (c_cont_label) - add_stmt (build1 (LABEL_EXPR, void_type_node, c_cont_label)); + { + tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label); + SET_EXPR_LOCATION (t, loc); + add_stmt (t); + } body = pop_stmt_list (body); c_break_label = save_break; c_cont_label = save_cont; + while (nbraces) + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + { + c_parser_consume_token (parser); + nbraces--; + } + else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "collapsed loops not perfectly nested"); + while (nbraces) + { + location_t here = c_parser_peek_token (parser)->location; + stmt = c_begin_compound_stmt (true); + add_stmt (body); + c_parser_compound_statement_nostart (parser); + body = c_end_compound_stmt (here, stmt, true); + nbraces--; + } + goto pop_scopes; + } + } + /* Only bother calling c_finish_omp_for if we haven't already generated an error from the initialization parsing. */ - if (decl != NULL && decl != error_mark_node && init != error_mark_node) - return c_finish_omp_for (loc, decl, init, cond, incr, body, NULL); - return NULL; - - error_init: - c_parser_error (parser, "expected iteration declaration or initialization"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - decl = init = cond = incr = NULL_TREE; - goto parse_body; + if (!fail) + { + stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL); + if (stmt) + { + if (par_clauses != NULL) + { + tree *c; + for (c = par_clauses; *c ; ) + if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE) + c = &OMP_CLAUSE_CHAIN (*c); + else + { + for (i = 0; i < collapse; i++) + if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c)) + break; + if (i == collapse) + c = &OMP_CLAUSE_CHAIN (*c); + else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE) + { + error_at (loc, + "iteration variable %qD should not be firstprivate", + OMP_CLAUSE_DECL (*c)); + *c = OMP_CLAUSE_CHAIN (*c); + } + else + { + /* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES, + change it to shared (decl) in + OMP_PARALLEL_CLAUSES. */ + tree l = build_omp_clause (OMP_CLAUSE_LOCATION (*c), + OMP_CLAUSE_LASTPRIVATE); + OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c); + OMP_CLAUSE_CHAIN (l) = clauses; + clauses = l; + OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED); + } + } + } + OMP_FOR_CLAUSES (stmt) = clauses; + } + ret = stmt; + } +pop_scopes: + while (!VEC_empty (tree, for_block)) + { + /* FIXME diagnostics: LOC below should be the actual location of + this particular for block. We need to build a list of + locations to go along with FOR_BLOCK. */ + stmt = c_end_compound_stmt (loc, VEC_pop (tree, for_block), true); + add_stmt (stmt); + } + release_tree_vector (for_block); + return ret; } /* OpenMP 2.5: #pragma omp for for-clause[optseq] new-line for-loop + + LOC is the location of the #pragma token. */ #define OMP_FOR_CLAUSE_MASK \ @@ -7623,10 +10153,11 @@ c_parser_omp_for_loop (c_parser *parser) | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE) \ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree -c_parser_omp_for (c_parser *parser) +c_parser_omp_for (location_t loc, c_parser *parser) { tree block, clauses, ret; @@ -7634,10 +10165,8 @@ c_parser_omp_for (c_parser *parser) "#pragma omp for"); block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (parser); - if (ret) - OMP_FOR_CLAUSES (ret) = clauses; - block = c_end_compound_stmt (block, true); + ret = c_parser_omp_for_loop (loc, parser, clauses, NULL); + block = c_end_compound_stmt (loc, block, true); add_stmt (block); return ret; @@ -7646,25 +10175,29 @@ c_parser_omp_for (c_parser *parser) /* OpenMP 2.5: # pragma omp master new-line structured-block + + LOC is the location of the #pragma token. */ static tree -c_parser_omp_master (c_parser *parser) +c_parser_omp_master (location_t loc, c_parser *parser) { c_parser_skip_to_pragma_eol (parser); - return c_finish_omp_master (c_parser_omp_structured_block (parser)); + return c_finish_omp_master (loc, c_parser_omp_structured_block (parser)); } /* OpenMP 2.5: # pragma omp ordered new-line structured-block + + LOC is the location of the #pragma itself. */ static tree -c_parser_omp_ordered (c_parser *parser) +c_parser_omp_ordered (location_t loc, c_parser *parser) { c_parser_skip_to_pragma_eol (parser); - return c_finish_omp_ordered (c_parser_omp_structured_block (parser)); + return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser)); } /* OpenMP 2.5: @@ -7674,15 +10207,18 @@ c_parser_omp_ordered (c_parser *parser) section-sequence: section-directive[opt] structured-block - section-sequence section-directive structured-block */ + section-sequence section-directive structured-block + + SECTIONS_LOC is the location of the #pragma omp sections. */ static tree -c_parser_omp_sections_scope (c_parser *parser) +c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) { tree stmt, substmt; bool error_suppress = false; location_t loc; + loc = c_parser_peek_token (parser)->location; if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) { /* Avoid skipping until the end of the block. */ @@ -7692,7 +10228,6 @@ c_parser_omp_sections_scope (c_parser *parser) stmt = push_stmt_list (); - loc = c_parser_peek_token (parser)->location; if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION) { substmt = push_stmt_list (); @@ -7731,8 +10266,7 @@ c_parser_omp_sections_scope (c_parser *parser) } else if (!error_suppress) { - error ("%Hexpected %<#pragma omp section%> or %<}%>", - &loc); + error_at (loc, "expected %<#pragma omp section%> or %<}%>"); error_suppress = true; } @@ -7747,6 +10281,7 @@ c_parser_omp_sections_scope (c_parser *parser) substmt = pop_stmt_list (stmt); stmt = make_node (OMP_SECTIONS); + SET_EXPR_LOCATION (stmt, sections_loc); TREE_TYPE (stmt) = void_type_node; OMP_SECTIONS_BODY (stmt) = substmt; @@ -7756,6 +10291,8 @@ c_parser_omp_sections_scope (c_parser *parser) /* OpenMP 2.5: # pragma omp sections sections-clause[optseq] newline sections-scope + + LOC is the location of the #pragma token. */ #define OMP_SECTIONS_CLAUSE_MASK \ @@ -7766,7 +10303,7 @@ c_parser_omp_sections_scope (c_parser *parser) | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree -c_parser_omp_sections (c_parser *parser) +c_parser_omp_sections (location_t loc, c_parser *parser) { tree block, clauses, ret; @@ -7774,10 +10311,10 @@ c_parser_omp_sections (c_parser *parser) "#pragma omp sections"); block = c_begin_compound_stmt (true); - ret = c_parser_omp_sections_scope (parser); + ret = c_parser_omp_sections_scope (loc, parser); if (ret) OMP_SECTIONS_CLAUSES (ret) = clauses; - block = c_end_compound_stmt (block, true); + block = c_end_compound_stmt (loc, block, true); add_stmt (block); return ret; @@ -7787,6 +10324,8 @@ c_parser_omp_sections (c_parser *parser) # pragma parallel parallel-clause new-line # pragma parallel for parallel-for-clause new-line # pragma parallel sections parallel-sections-clause new-line + + LOC is the location of the #pragma token. */ #define OMP_PARALLEL_CLAUSE_MASK \ @@ -7800,7 +10339,7 @@ c_parser_omp_sections (c_parser *parser) | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) static tree -c_parser_omp_parallel (c_parser *parser) +c_parser_omp_parallel (location_t loc, c_parser *parser) { enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; const char *p_name = "#pragma omp parallel"; @@ -7835,26 +10374,24 @@ c_parser_omp_parallel (c_parser *parser) case PRAGMA_OMP_PARALLEL: block = c_begin_omp_parallel (); c_parser_statement (parser); - stmt = c_finish_omp_parallel (clauses, block); + stmt = c_finish_omp_parallel (loc, clauses, block); break; case PRAGMA_OMP_PARALLEL_FOR: block = c_begin_omp_parallel (); - c_split_parallel_clauses (clauses, &par_clause, &ws_clause); - stmt = c_parser_omp_for_loop (parser); - if (stmt) - OMP_FOR_CLAUSES (stmt) = ws_clause; - stmt = c_finish_omp_parallel (par_clause, block); + c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); + c_parser_omp_for_loop (loc, parser, ws_clause, &par_clause); + stmt = c_finish_omp_parallel (loc, par_clause, block); OMP_PARALLEL_COMBINED (stmt) = 1; break; case PRAGMA_OMP_PARALLEL_SECTIONS: block = c_begin_omp_parallel (); - c_split_parallel_clauses (clauses, &par_clause, &ws_clause); - stmt = c_parser_omp_sections_scope (parser); + c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); + stmt = c_parser_omp_sections_scope (loc, parser); if (stmt) OMP_SECTIONS_CLAUSES (stmt) = ws_clause; - stmt = c_finish_omp_parallel (par_clause, block); + stmt = c_finish_omp_parallel (loc, par_clause, block); OMP_PARALLEL_COMBINED (stmt) = 1; break; @@ -7868,6 +10405,8 @@ c_parser_omp_parallel (c_parser *parser) /* OpenMP 2.5: # pragma omp single single-clause[optseq] new-line structured-block + + LOC is the location of the #pragma. */ #define OMP_SINGLE_CLAUSE_MASK \ @@ -7877,9 +10416,10 @@ c_parser_omp_parallel (c_parser *parser) | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree -c_parser_omp_single (c_parser *parser) +c_parser_omp_single (location_t loc, c_parser *parser) { tree stmt = make_node (OMP_SINGLE); + SET_EXPR_LOCATION (stmt, loc); TREE_TYPE (stmt) = void_type_node; OMP_SINGLE_CLAUSES (stmt) @@ -7890,6 +10430,62 @@ c_parser_omp_single (c_parser *parser) return add_stmt (stmt); } +/* OpenMP 3.0: + # pragma omp task task-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_TASK_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_IF) \ + | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (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) +{ + tree clauses, block; + + clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, + "#pragma omp task"); + + block = c_begin_omp_task (); + c_parser_statement (parser); + return c_finish_omp_task (loc, clauses, block); +} + +/* OpenMP 3.0: + # pragma omp taskwait new-line +*/ + +static void +c_parser_omp_taskwait (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_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. */ @@ -7904,44 +10500,41 @@ c_parser_omp_construct (c_parser *parser) p_kind = c_parser_peek_token (parser)->pragma_kind; c_parser_consume_pragma (parser); - /* For all constructs below except #pragma omp atomic - MUST_NOT_THROW catch handlers are needed when exceptions - are enabled. */ - if (p_kind != PRAGMA_OMP_ATOMIC) - c_maybe_initialize_eh (); - switch (p_kind) { case PRAGMA_OMP_ATOMIC: - c_parser_omp_atomic (parser); + c_parser_omp_atomic (loc, parser); return; case PRAGMA_OMP_CRITICAL: - stmt = c_parser_omp_critical (parser); + stmt = c_parser_omp_critical (loc, parser); break; case PRAGMA_OMP_FOR: - stmt = c_parser_omp_for (parser); + stmt = c_parser_omp_for (loc, parser); break; case PRAGMA_OMP_MASTER: - stmt = c_parser_omp_master (parser); + stmt = c_parser_omp_master (loc, parser); break; case PRAGMA_OMP_ORDERED: - stmt = c_parser_omp_ordered (parser); + stmt = c_parser_omp_ordered (loc, parser); break; case PRAGMA_OMP_PARALLEL: - stmt = c_parser_omp_parallel (parser); + stmt = c_parser_omp_parallel (loc, parser); break; case PRAGMA_OMP_SECTIONS: - stmt = c_parser_omp_sections (parser); + stmt = c_parser_omp_sections (loc, parser); break; case PRAGMA_OMP_SINGLE: - stmt = c_parser_omp_single (parser); + stmt = c_parser_omp_single (loc, parser); + break; + case PRAGMA_OMP_TASK: + stmt = c_parser_omp_task (loc, parser); break; default: gcc_unreachable (); } if (stmt) - SET_EXPR_LOCATION (stmt, loc); + gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION); } @@ -7952,27 +10545,35 @@ static void c_parser_omp_threadprivate (c_parser *parser) { tree vars, t; + location_t loc; c_parser_consume_pragma (parser); - vars = c_parser_omp_var_list_parens (parser, 0, NULL); + loc = c_parser_peek_token (parser)->location; + vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); /* Mark every variable in VARS to be assigned thread local storage. */ for (t = vars; t; t = TREE_CHAIN (t)) { tree v = TREE_PURPOSE (t); + /* FIXME diagnostics: Ideally we should keep individual + locations for all the variables in the var list to make the + following errors more precise. Perhaps + c_parser_omp_var_list_parens() should construct a list of + locations to go along with the var list. */ + /* If V had already been marked threadprivate, it doesn't matter whether it had been used prior to this point. */ if (TREE_CODE (v) != VAR_DECL) - error ("%qD is not a variable", v); + error_at (loc, "%qD is not a variable", v); else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v)) - error ("%qE declared % after first use", v); + error_at (loc, "%qE declared % after first use", v); else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v)) - error ("automatic variable %qE cannot be %", v); + error_at (loc, "automatic variable %qE cannot be %", v); else if (TREE_TYPE (v) == error_mark_node) ; else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) - error ("% %qE has incomplete type", v); + error_at (loc, "% %qE has incomplete type", v); else { if (! DECL_THREAD_LOCAL_P (v)) @@ -7991,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. */ @@ -8008,9 +10820,13 @@ c_parse_file (void) if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) c_parser_pragma_pch_preprocess (&tparser); - the_parser = GGC_NEW (c_parser); + the_parser = ggc_alloc_c_parser (); *the_parser = tparser; + /* Initialize EH, if we've been told to do so. */ + if (flag_exceptions) + using_eh_for_cleanups (); + c_parser_translation_unit (the_parser); the_parser = NULL; }