/* Parser for C and Objective-C. Copyright (C) 1987-2013 Free Software Foundation, Inc. Parser actions based on the old Bison parser; structure somewhat influenced by and fragments based on the C++ parser. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ /* TODO: Make sure all relevant comments, and all relevant code from all actions, brought over from old parser. Verify exact correspondence of syntax accepted. Add testcases covering every input symbol in every state in old and new parsers. Include full syntax for GNU C, including erroneous cases accepted with error messages, in syntax productions in comments. Make more diagnostics in the front end generally take an explicit location rather than implicitly using input_location. */ #include "config.h" #include "system.h" #include "coretypes.h" #include "tm.h" /* For rtl.h: needs enum reg_class. */ #include "tree.h" #include "langhooks.h" #include "input.h" #include "cpplib.h" #include "timevar.h" #include "c-family/c-pragma.h" #include "c-tree.h" #include "flags.h" #include "ggc.h" #include "c-family/c-common.h" #include "c-family/c-objc.h" #include "vec.h" #include "target.h" #include "cgraph.h" #include "plugin.h" /* Initialization routine for this file. */ void c_parse_init (void) { /* The only initialization required is of the reserved word identifiers. */ unsigned int i; tree id; 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 | D_CXX_OBJC; 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 (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 (c_common_reswords[i].word); C_SET_RID_CODE (id, c_common_reswords[i].rid); C_IS_RESERVED_WORD (id) = 1; ridpointers [(int) c_common_reswords[i].rid] = id; } } /* The C lexer intermediates between the lexer in cpplib and c-lex.c and the C parser. Unlike the C++ lexer, the parser structure stores the lexer information instead of using a separate structure. Identifiers are separated into ordinary identifiers, type names, keywords and some other Objective-C types of identifiers, and some look-ahead is maintained. ??? It might be a good idea to lex the whole file up front (as for C++). It would then be possible to share more of the C and C++ lexer code, if desired. */ /* The following local token type is used. */ /* A keyword. */ #define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1)) /* More information about the type of a CPP_NAME token. */ typedef enum c_id_kind { /* An ordinary identifier. */ C_ID_ID, /* An identifier declared as a typedef name. */ 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 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 declared as some kind of type. Otherwise, it is C_ID_NONE. */ ENUM_BITFIELD (c_id_kind) id_kind : 8; /* If this token is a keyword, this value indicates which keyword. Otherwise, this value is RID_MAX. */ 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 : 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 GTY(()) c_parser { /* The look-ahead tokens. */ c_token tokens[2]; /* How many look-ahead tokens are available (0, 1 or 2). */ short tokens_avail; /* True if a syntax error is being recovered from; false otherwise. c_parser_error sets this flag. It should clear this flag when enough tokens have been consumed to recover from the error. */ BOOL_BITFIELD error : 1; /* True if we're processing a pragma, and shouldn't automatically consume CPP_PRAGMA_EOL. */ BOOL_BITFIELD in_pragma : 1; /* True if we're parsing the outermost block of an if statement. */ 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; /* The actual parser and external interface. ??? Does this need to be garbage-collected? */ static GTY (()) c_parser *the_parser; /* Read in and lex a single token, storing it in *TOKEN. */ static void c_lex_one_token (c_parser *parser, c_token *token) { timevar_push (TV_LEX); token->type = c_lex_with_flags (&token->value, &token->location, NULL, (parser->lex_untranslated_string ? C_LEX_STRING_NO_TRANSLATE : 0)); token->id_kind = C_ID_NONE; token->keyword = RID_MAX; token->pragma_kind = PRAGMA_NONE; switch (token->type) { case CPP_NAME: { tree decl; bool objc_force_identifier = parser->objc_need_raw_identifier; if (c_dialect_objc ()) parser->objc_need_raw_identifier = false; if (C_IS_RESERVED_WORD (token->value)) { enum rid rid_code = C_RID_CODE (token->value); 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)) { /* We found an Objective-C "property attribute" keyword (getter, setter, readonly, etc). These are only valid in the property context. */ if (parser->objc_property_attr_context) { token->type = CPP_KEYWORD; token->keyword = rid_code; break; } /* Else they are not special keywords. */ } else if (c_dialect_objc () && (OBJC_IS_AT_KEYWORD (rid_code) || OBJC_IS_CXX_KEYWORD (rid_code))) { /* We found one of the Objective-C "@" keywords (defs, selector, synchronized, etc) or one of the Objective-C "cxx" keywords (class, private, protected, public, try, catch, throw) without a preceding '@' sign. Do nothing and fall through to the code for normal tokens (in C++ we would still consider the CXX ones keywords, but not in C). */ ; } else { token->type = CPP_KEYWORD; token->keyword = rid_code; break; } } decl = lookup_name (token->value); if (decl) { if (TREE_CODE (decl) == TYPE_DECL) { token->id_kind = C_ID_TYPENAME; break; } } else if (c_dialect_objc ()) { tree objc_interface_decl = objc_is_class_name (token->value); /* Objective-C class names are in the same namespace as variables and typedefs, and hence are shadowed by local declarations. */ if (objc_interface_decl && (!objc_force_identifier || global_bindings_p ())) { token->value = objc_interface_decl; token->id_kind = C_ID_CLASSNAME; break; } } token->id_kind = C_ID_ID; } break; case CPP_AT_NAME: /* This only happens in Objective-C; it must be a keyword. */ token->type = CPP_KEYWORD; 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: case CPP_CLOSE_PAREN: case CPP_SEMICOLON: /* These tokens may affect the interpretation of any identifiers following, if doing Objective-C. */ if (c_dialect_objc ()) parser->objc_need_raw_identifier = false; break; case CPP_PRAGMA: /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */ token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value); token->value = NULL; break; default: break; } timevar_pop (TV_LEX); } /* Return a pointer to the next token from PARSER, reading it in if necessary. */ static inline c_token * c_parser_peek_token (c_parser *parser) { if (parser->tokens_avail == 0) { c_lex_one_token (parser, &parser->tokens[0]); parser->tokens_avail = 1; } return &parser->tokens[0]; } /* Return true if the next token from PARSER has the indicated TYPE. */ static inline bool c_parser_next_token_is (c_parser *parser, enum cpp_ttype type) { return c_parser_peek_token (parser)->type == type; } /* Return true if the next token from PARSER does not have the indicated TYPE. */ static inline bool c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type) { return !c_parser_next_token_is (parser, type); } /* Return true if the next token from PARSER is the indicated KEYWORD. */ static inline bool 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 c_token_starts_typename (c_token *token) { switch (token->type) { case CPP_NAME: switch (token->id_kind) { case C_ID_ID: return false; case C_ID_ADDRSPACE: return true; case C_ID_TYPENAME: return true; case C_ID_CLASSNAME: gcc_assert (c_dialect_objc ()); return true; default: gcc_unreachable (); } case CPP_KEYWORD: switch (token->keyword) { case RID_UNSIGNED: case RID_LONG: case RID_INT128: case RID_SHORT: case RID_SIGNED: case RID_COMPLEX: 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_ENUM: case RID_STRUCT: case RID_UNION: case RID_TYPEOF: case RID_CONST: case RID_VOLATILE: case RID_RESTRICT: case RID_ATTRIBUTE: case RID_FRACT: case RID_ACCUM: case RID_SAT: return true; default: return false; } case CPP_LESS: if (c_dialect_objc ()) return true; return false; default: return false; } } 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_is_qualifier (c_parser *parser) { c_token *token = c_parser_peek_token (parser); return c_token_is_qualifier (token); } /* Return true if TOKEN can start declaration specifiers, false otherwise. */ static bool c_token_starts_declspecs (c_token *token) { switch (token->type) { case CPP_NAME: switch (token->id_kind) { case C_ID_ID: return false; case C_ID_ADDRSPACE: return true; case C_ID_TYPENAME: return true; case C_ID_CLASSNAME: gcc_assert (c_dialect_objc ()); return true; default: gcc_unreachable (); } case CPP_KEYWORD: switch (token->keyword) { case RID_STATIC: case RID_EXTERN: 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: 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_ENUM: case RID_STRUCT: case RID_UNION: case RID_TYPEOF: case RID_CONST: case RID_VOLATILE: case RID_RESTRICT: case RID_ATTRIBUTE: case RID_FRACT: case RID_ACCUM: case RID_SAT: case RID_ALIGNAS: return true; default: return false; } case CPP_LESS: if (c_dialect_objc ()) return true; return false; default: return false; } } /* 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 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) { 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. */ static void c_parser_consume_token (c_parser *parser) { gcc_assert (parser->tokens_avail >= 1); gcc_assert (parser->tokens[0].type != CPP_EOF); gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL); gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA); if (parser->tokens_avail == 2) parser->tokens[0] = parser->tokens[1]; parser->tokens_avail--; } /* Expect the current token to be a #pragma. Consume it and remember that we've begun parsing a pragma. */ static void c_parser_consume_pragma (c_parser *parser) { gcc_assert (!parser->in_pragma); gcc_assert (parser->tokens_avail >= 1); gcc_assert (parser->tokens[0].type == CPP_PRAGMA); if (parser->tokens_avail == 2) parser->tokens[0] = parser->tokens[1]; parser->tokens_avail--; parser->in_pragma = true; } /* Update the globals input_location and in_system_header from TOKEN. */ static inline void c_parser_set_source_position_from_token (c_token *token) { if (token->type != CPP_EOF) { input_location = token->location; } } /* Issue a diagnostic of the form FILE:LINE: MESSAGE before TOKEN where TOKEN is the next token in the input stream of PARSER. MESSAGE (specified by the caller) is usually of the form "expected OTHER-TOKEN". Do not issue a diagnostic if still recovering from an error. ??? This is taken from the C++ parser, but building up messages in this way is not i18n-friendly and some other approach should be used. */ static void c_parser_error (c_parser *parser, const char *gmsgid) { c_token *token = c_parser_peek_token (parser); if (parser->error) return; parser->error = true; if (!gmsgid) return; /* This diagnostic makes more sense if it is tagged to the line of the token we just peeked at. */ c_parser_set_source_position_from_token (token); c_parse_error (gmsgid, /* Because c_parse_error does not understand CPP_KEYWORD, keywords are treated like identifiers. */ (token->type == CPP_KEYWORD ? CPP_NAME : token->type), /* ??? 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, issue the error MSGID. If MSGID is NULL then a message has already been produced and no message will be produced this time. Returns true if found, false otherwise. */ static bool c_parser_require (c_parser *parser, enum cpp_ttype type, const char *msgid) { if (c_parser_next_token_is (parser, type)) { c_parser_consume_token (parser); return true; } else { c_parser_error (parser, msgid); return false; } } /* If the next token is the indicated keyword, consume it. Otherwise, issue the error MSGID. Returns true if found, false otherwise. */ static bool c_parser_require_keyword (c_parser *parser, enum rid keyword, const char *msgid) { if (c_parser_next_token_is_keyword (parser, keyword)) { c_parser_consume_token (parser); return true; } else { c_parser_error (parser, msgid); return false; } } /* Like c_parser_require, except that tokens will be skipped until the desired token is found. An error message is still produced if the next token is not as expected. If MSGID is NULL then a message has already been produced and no message will be produced this time. */ static void c_parser_skip_until_found (c_parser *parser, enum cpp_ttype type, const char *msgid) { unsigned nesting_depth = 0; if (c_parser_require (parser, type, msgid)) return; /* Skip tokens until the desired token is found. */ while (true) { /* Peek at the next token. */ c_token *token = c_parser_peek_token (parser); /* If we've reached the token we want, consume it and stop. */ if (token->type == type && !nesting_depth) { c_parser_consume_token (parser); break; } /* If we've run out of tokens, stop. */ if (token->type == CPP_EOF) return; if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) return; if (token->type == CPP_OPEN_BRACE || token->type == CPP_OPEN_PAREN || token->type == CPP_OPEN_SQUARE) ++nesting_depth; else if (token->type == CPP_CLOSE_BRACE || token->type == CPP_CLOSE_PAREN || token->type == CPP_CLOSE_SQUARE) { if (nesting_depth-- == 0) break; } /* Consume this token. */ c_parser_consume_token (parser); } parser->error = false; } /* Skip tokens until the end of a parameter is found, but do not consume the comma, semicolon or closing delimiter. */ static void c_parser_skip_to_end_of_parameter (c_parser *parser) { unsigned nesting_depth = 0; while (true) { c_token *token = c_parser_peek_token (parser); if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON) && !nesting_depth) break; /* If we've run out of tokens, stop. */ if (token->type == CPP_EOF) return; if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) return; if (token->type == CPP_OPEN_BRACE || token->type == CPP_OPEN_PAREN || token->type == CPP_OPEN_SQUARE) ++nesting_depth; else if (token->type == CPP_CLOSE_BRACE || token->type == CPP_CLOSE_PAREN || token->type == CPP_CLOSE_SQUARE) { if (nesting_depth-- == 0) break; } /* Consume this token. */ c_parser_consume_token (parser); } parser->error = false; } /* Expect to be at the end of the pragma directive and consume an end of line marker. */ static void c_parser_skip_to_pragma_eol (c_parser *parser) { gcc_assert (parser->in_pragma); parser->in_pragma = false; if (!c_parser_require (parser, CPP_PRAGMA_EOL, "expected end of line")) while (true) { c_token *token = c_parser_peek_token (parser); if (token->type == CPP_EOF) break; if (token->type == CPP_PRAGMA_EOL) { c_parser_consume_token (parser); break; } c_parser_consume_token (parser); } parser->error = false; } /* Skip tokens until we have consumed an entire block, or until we have consumed a non-nested ';'. */ static void c_parser_skip_to_end_of_block_or_statement (c_parser *parser) { unsigned nesting_depth = 0; bool save_error = parser->error; while (true) { c_token *token; /* Peek at the next token. */ token = c_parser_peek_token (parser); switch (token->type) { case CPP_EOF: return; case CPP_PRAGMA_EOL: if (parser->in_pragma) return; break; case CPP_SEMICOLON: /* If the next token is a ';', we have reached the end of the statement. */ if (!nesting_depth) { /* Consume the ';'. */ c_parser_consume_token (parser); goto finished; } break; case CPP_CLOSE_BRACE: /* If the next token is a non-nested '}', then we have reached the end of the current block. */ if (nesting_depth == 0 || --nesting_depth == 0) { c_parser_consume_token (parser); goto finished; } break; case CPP_OPEN_BRACE: /* If it the next token is a '{', then we are entering a new block. Consume the entire block. */ ++nesting_depth; break; case CPP_PRAGMA: /* If we see a pragma, consume the whole thing at once. We have some safeguards against consuming pragmas willy-nilly. Normally, we'd expect to be here with parser->error set, which disables these safeguards. But it's possible to get here for secondary error recovery, after parser->error has been cleared. */ c_parser_consume_pragma (parser); c_parser_skip_to_pragma_eol (parser); parser->error = save_error; continue; default: break; } c_parser_consume_token (parser); } finished: 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 disable_extension_diagnostics (void) { int ret = (pedantic | (warn_pointer_arith << 1) | (warn_traditional << 2) | (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; 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; } /* Restore the warning flags which are controlled by __extension__. FLAGS is the return value from disable_extension_diagnostics. */ static inline void restore_extension_diagnostics (int flags) { cpp_opts->cpp_pedantic = pedantic = flags & 1; warn_pointer_arith = (flags >> 1) & 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. */ typedef enum c_dtr_syn { /* A normal declarator with an identifier. */ C_DTR_NORMAL, /* An abstract declarator (maybe empty). */ C_DTR_ABSTRACT, /* A parameter declarator: may be either, but after a type name does not redeclare a typedef name as an identifier if it can alternatively be interpreted as a typedef name; see DR#009, applied in C90 TC1, omitted from C99 and reapplied in C99 TC2 following DR#249. For example, given a typedef T, "int T" and "int *T" are valid parameter declarations redeclaring T, while "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are abstract declarators rather than involving redundant parentheses; the same applies with attributes inside the parentheses before "T". */ C_DTR_PARM } c_dtr_syn; /* The binary operation precedence levels, where 0 is a dummy lowest level used for the bottom of the stack. */ enum c_parser_prec { PREC_NONE, PREC_LOGOR, PREC_LOGAND, PREC_BITOR, PREC_BITXOR, PREC_BITAND, PREC_EQ, PREC_REL, PREC_SHIFT, PREC_ADD, PREC_MULT, NUM_PRECS }; static void c_parser_external_declaration (c_parser *); static void c_parser_asm_definition (c_parser *); static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, bool, bool, 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, 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, c_dtr_syn, bool *); 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, 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 *, 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 *); static void c_parser_statement (c_parser *); static void c_parser_statement_after_labels (c_parser *); static void c_parser_if_statement (c_parser *); static void c_parser_switch_statement (c_parser *); static void c_parser_while_statement (c_parser *); 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 *); 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 *, 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 *, 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 vec *c_parser_expr_list (c_parser *, bool, bool, vec **, location_t *, tree *); 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 *, 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 *, 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 *, 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_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). translation-unit: external-declarations external-declarations: external-declaration external-declarations external-declaration GNU extensions: translation-unit: empty */ static void c_parser_translation_unit (c_parser *parser) { if (c_parser_next_token_is (parser, CPP_EOF)) { pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "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 (); c_parser_external_declaration (parser); obstack_free (&parser_obstack, obstack_position); } while (c_parser_next_token_is_not (parser, CPP_EOF)); } } /* Parse an external declaration (C90 6.7, C99 6.9). external-declaration: function-definition declaration GNU extensions: external-declaration: asm-definition ; __extension__ external-declaration Objective-C: external-declaration: objc-class-definition objc-class-declaration objc-alias-declaration objc-protocol-definition objc-method-definition @end */ static void c_parser_external_declaration (c_parser *parser) { int ext; switch (c_parser_peek_token (parser)->type) { case CPP_KEYWORD: switch (c_parser_peek_token (parser)->keyword) { case RID_EXTENSION: ext = disable_extension_diagnostics (); c_parser_consume_token (parser); c_parser_external_declaration (parser); restore_extension_diagnostics (ext); break; case RID_ASM: c_parser_asm_definition (parser); break; case RID_AT_INTERFACE: case RID_AT_IMPLEMENTATION: gcc_assert (c_dialect_objc ()); c_parser_objc_class_definition (parser, NULL_TREE); break; case RID_AT_CLASS: gcc_assert (c_dialect_objc ()); c_parser_objc_class_declaration (parser); break; case RID_AT_ALIAS: gcc_assert (c_dialect_objc ()); c_parser_objc_alias_declaration (parser); break; case RID_AT_PROTOCOL: gcc_assert (c_dialect_objc ()); c_parser_objc_protocol_definition (parser, NULL_TREE); break; case RID_AT_PROPERTY: gcc_assert (c_dialect_objc ()); c_parser_objc_at_property_declaration (parser); break; case RID_AT_SYNTHESIZE: gcc_assert (c_dialect_objc ()); c_parser_objc_at_synthesize_declaration (parser); break; case RID_AT_DYNAMIC: gcc_assert (c_dialect_objc ()); c_parser_objc_at_dynamic_declaration (parser); break; case RID_AT_END: gcc_assert (c_dialect_objc ()); c_parser_consume_token (parser); objc_finish_implementation (); break; default: goto decl_or_fndef; } break; case CPP_SEMICOLON: pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "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: if (c_dialect_objc ()) { c_parser_objc_method_definition (parser); break; } /* Else fall through, and yield a syntax error trying to parse as a declaration or function definition. */ default: decl_or_fndef: /* 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 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] compound-statement declaration-list: declaration declaration-list declaration init-declarator-list: init-declarator init-declarator-list , init-declarator init-declarator: declarator simple-asm-expr[opt] attributes[opt] declarator simple-asm-expr[opt] attributes[opt] = initializer GNU extensions: nested-function-definition: 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 callers. ??? Following the old parser, __extension__ may start external declarations, declarations in functions and declarations at the start of "for" loops, but not old-style parameter declarations. C99 requires declaration specifiers in a function definition; the absence is diagnosed through the diagnosis of implicit int. In GNU 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 static_assert_ok, bool empty_ok, bool nested, bool start_attr_ok, tree *objc_foreach_object_declaration) { struct c_declspecs *specs; tree prefix_attrs; tree all_prefix_attrs; 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 (); /* 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); return; } if (nested && !specs->declspecs_seen_p) { c_parser_error (parser, "expected declaration specifiers"); c_parser_skip_to_end_of_block_or_statement (parser); return; } finish_declspecs (specs); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { if (empty_ok) shadow_tag (specs); else { shadow_tag_warned (specs, 1); 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; specs->attrs = NULL_TREE; while (true) { 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->typespec_kind != ctsk_none, C_DTR_NORMAL, &dummy); if (declarator == NULL) { c_parser_skip_to_end_of_block_or_statement (parser); return; } if (c_parser_next_token_is (parser, CPP_EQ) || 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_IN)) { tree asm_name = NULL_TREE; tree postfix_attrs = NULL_TREE; if (!diagnosed_no_specs && !specs->declspecs_seen_p) { diagnosed_no_specs = true; pedwarn (here, 0, "data definition has no type or storage class"); } /* Having seen a data definition, there cannot now be a function definition. */ fndef_ok = false; if (c_parser_next_token_is_keyword (parser, RID_ASM)) asm_name = c_parser_simple_asm_expr (parser); if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) postfix_attrs = c_parser_attributes (parser); if (c_parser_next_token_is (parser, CPP_EQ)) { 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. */ d = start_decl (declarator, specs, true, chainon (postfix_attrs, all_prefix_attrs)); 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_loc, init.value, init.original_type, asm_name); } } else { tree d = start_decl (declarator, specs, false, chainon (postfix_attrs, all_prefix_attrs)); if (d) 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)) { c_parser_consume_token (parser); if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) all_prefix_attrs = chainon (c_parser_attributes (parser), prefix_attrs); else all_prefix_attrs = prefix_attrs; continue; } else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { 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 %<;%>"); c_parser_skip_to_end_of_block_or_statement (parser); return; } } else if (!fndef_ok) { c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, " "% or %<__attribute__%>"); c_parser_skip_to_end_of_block_or_statement (parser); return; } /* Function definition (nested or otherwise). */ if (nested) { pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions"); c_push_function_context (); } if (!start_function (specs, declarator, all_prefix_attrs)) { /* This can appear in many cases looking nothing like a function definition, so we don't give a more specific error suggesting there was one. */ c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, % " "or %<__attribute__%>"); if (nested) 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 suffix and a function definition with an attribute prefix on first old-style parameter declaration. Following the old parser, they are not accepted on subsequent old-style parameter declarations either. However, there is no ambiguity after the first declaration, nor indeed on the first as long as we don't allow postfix attributes after a declarator with a nonempty identifier list in a definition; and postfix attributes have never been accepted here in 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, 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_SOURCE_LOCATION (decl), DECL_EXPR, decl)); } else { add_stmt (fnbody); finish_function (); } timevar_pop (tv); break; } } /* Parse an asm-definition (asm() outside a function body). This is a GNU extension. asm-definition: simple-asm-expr ; */ static void c_parser_asm_definition (c_parser *parser) { tree asm_str = c_parser_simple_asm_expr (parser); if (asm_str) add_asm_node (asm_str); c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } /* Parse a static assertion (C11 6.7.10). static_assert-declaration: static_assert-declaration-no-semi ; */ 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); } /* Parse a static assertion (C11 6.7.10), without the trailing semicolon. static_assert-declaration-no-semi: _Static_assert ( constant-expression , string-literal ) */ 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_Wpedantic, "ISO C99 does not support %<_Static_assert%>"); else pedwarn (assert_loc, OPT_Wpedantic, "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_Wpedantic, "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 unsigned _Bool _Complex [_Imaginary removed in C99 TC2] struct-or-union-specifier enum-specifier typedef-name (_Bool and _Complex are new in C99.) C90 6.5.3, C99 6.7.3: type-qualifier: const restrict volatile address-space-qualifier (restrict is new in C99.) GNU extensions: 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 _Fract _Accum _Sat (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf) Objective-C: type-specifier: class-name objc-protocol-refs[opt] typedef-name objc-protocol-refs objc-protocol-refs */ static void c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, bool scspec_ok, bool typespec_ok, bool start_attr_ok, enum c_lookahead_kind la) { bool attrs_ok = start_attr_ok; bool seen_type = specs->typespec_kind != ctsk_none; 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)) { c_token *name_token = c_parser_peek_token (parser); tree value = name_token->value; c_id_kind kind = name_token->id_kind; if (kind == C_ID_ADDRSPACE) { addr_space_t as = name_token->keyword - RID_FIRST_ADDR_SPACE; declspecs_add_addrspace (name_token->location, 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_ID) { error ("unknown type name %qE", value); t.kind = ctsk_typedef; t.spec = error_mark_node; } else if (kind == C_ID_TYPENAME && (!c_dialect_objc () || c_parser_next_token_is_not (parser, CPP_LESS))) { t.kind = ctsk_typedef; /* For a typedef name, record the meaning, not the name. In case of 'foo foo, bar;'. */ t.spec = lookup_name (value); } else { tree proto = NULL_TREE; gcc_assert (c_dialect_objc ()); t.kind = ctsk_objc; if (c_parser_next_token_is (parser, CPP_LESS)) proto = c_parser_objc_protocol_refs (parser); t.spec = objc_get_protocol_qualified_type (value, proto); } t.expr = NULL_TREE; t.expr_const_operands = true; declspecs_add_type (name_token->location, specs, t); continue; } if (c_parser_next_token_is (parser, CPP_LESS)) { /* Make "" equivalent to "id " - nisse@lysator.liu.se. */ tree proto; gcc_assert (c_dialect_objc ()); if (!typespec_ok || seen_type) break; proto = c_parser_objc_protocol_refs (parser); t.kind = ctsk_objc; t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto); 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)); switch (c_parser_peek_token (parser)->keyword) { case RID_STATIC: case RID_EXTERN: 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, noreturn) and storage class specifiers, either here or in declspecs_add_scspec. */ declspecs_add_scspec (loc, specs, c_parser_peek_token (parser)->value); c_parser_consume_token (parser); break; case RID_UNSIGNED: case RID_LONG: case RID_INT128: case RID_SHORT: case RID_SIGNED: case RID_COMPLEX: 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: if (!typespec_ok) goto out; attrs_ok = true; seen_type = true; if (c_dialect_objc ()) parser->objc_need_raw_identifier = true; t.kind = ctsk_resword; t.spec = c_parser_peek_token (parser)->value; t.expr = NULL_TREE; t.expr_const_operands = true; declspecs_add_type (loc, specs, t); c_parser_consume_token (parser); break; case RID_ENUM: if (!typespec_ok) goto out; attrs_ok = true; seen_type = true; t = c_parser_enum_specifier (parser); declspecs_add_type (loc, specs, t); break; case RID_STRUCT: case RID_UNION: if (!typespec_ok) goto out; attrs_ok = true; seen_type = true; t = c_parser_struct_or_union_specifier (parser); 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 specifiers, but is a syntax error the best way of handling this? */ if (!typespec_ok || seen_type) goto out; attrs_ok = true; seen_type = true; t = c_parser_typeof_specifier (parser); declspecs_add_type (loc, specs, t); break; case RID_CONST: case RID_VOLATILE: case RID_RESTRICT: attrs_ok = true; declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value); c_parser_consume_token (parser); break; case RID_ATTRIBUTE: if (!attrs_ok) goto out; attrs = c_parser_attributes (parser); declspecs_add_attrs (loc, specs, attrs); break; case RID_ALIGNAS: align = c_parser_alignas_specifier (parser); declspecs_add_alignas (loc, specs, align); break; default: goto out; } } out: ; } /* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2). enum-specifier: enum attributes[opt] identifier[opt] { enumerator-list } attributes[opt] enum attributes[opt] identifier[opt] { enumerator-list , } attributes[opt] enum attributes[opt] identifier The form with trailing comma is new in C99. The forms with attributes are GNU extensions. In GNU C, we accept any expression without commas in the syntax (assignment expressions, not just conditional expressions); assignment expressions will be diagnosed as non-constant. enumerator-list: enumerator enumerator-list , enumerator enumerator: enumeration-constant enumeration-constant = constant-expression */ static struct c_typespec c_parser_enum_specifier (c_parser *parser) { struct c_typespec ret; tree attrs; tree ident = NULL_TREE; 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; tree postfix_attrs; /* We chain the enumerators in reverse order, then put them in forward order at the end. */ 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) { tree enum_id; tree enum_value; tree enum_decl; bool seen_comma; c_token *token; 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"); c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); values = error_mark_node; break; } token = c_parser_peek_token (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 (decl_loc, value_loc, &the_enum, enum_id, enum_value); TREE_CHAIN (enum_decl) = values; values = enum_decl; seen_comma = false; if (c_parser_next_token_is (parser, CPP_COMMA)) { comma_loc = c_parser_peek_token (parser)->location; seen_comma = true; c_parser_consume_token (parser); } if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { if (seen_comma && !flag_isoc99) pedwarn (comma_loc, OPT_Wpedantic, "comma at end of enumerator list"); c_parser_consume_token (parser); break; } if (!seen_comma) { c_parser_error (parser, "expected %<,%> or %<}%>"); c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); values = error_mark_node; break; } } postfix_attrs = c_parser_attributes (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) { 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 (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 (enum_loc, OPT_Wpedantic, "ISO C forbids forward references to % types"); } return ret; } /* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1). struct-or-union-specifier: struct-or-union attributes[opt] identifier[opt] { struct-contents } attributes[opt] struct-or-union attributes[opt] identifier struct-contents: struct-declaration-list struct-declaration-list: struct-declaration ; struct-declaration-list struct-declaration ; GNU extensions: struct-contents: empty struct-declaration struct-declaration-list struct-declaration struct-declaration-list: struct-declaration-list ; ; (Note that in the syntax here, unlike that in ISO C, the semicolons are included here rather than in struct-declaration, in order to describe the syntax with extra semicolons and missing semicolon at end.) Objective-C: struct-declaration-list: @defs ( class-name ) (Note this does not include a trailing semicolon, but can be followed by further declarations, and gets a pedwarn-if-pedantic when followed by a semicolon.) */ static struct c_typespec 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) { case RID_STRUCT: code = RECORD_TYPE; break; case RID_UNION: code = UNION_TYPE; break; 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. */ 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 declare multiple components (comma-separated), so we must use chainon to join them, although when parsing each struct-declaration we can use TREE_CHAIN directly. The theory behind all this is that there will be more semicolon separated fields than comma separated fields, and so we'll be minimizing the number of node traversals required by chainon. */ 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) }));. */ if (c_parser_next_token_is_keyword (parser, RID_AT_DEFS)) { tree name; gcc_assert (c_dialect_objc ()); c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) goto end_at_defs; if (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME) { name = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); } else { c_parser_error (parser, "expected class name"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); goto end_at_defs; } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); contents = nreverse (objc_get_class_ivars (name)); } end_at_defs: /* Parse the struct-declarations and semicolons. Problems with semicolons are diagnosed here; empty structures are diagnosed elsewhere. */ while (true) { tree decls; /* Parse any stray semicolon. */ if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "extra semicolon in struct or union specified"); c_parser_consume_token (parser); continue; } /* Stop if at the end of the struct or union contents. */ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { c_parser_consume_token (parser); break; } /* Accept #pragmas at struct scope. */ if (c_parser_next_token_is (parser, CPP_PRAGMA)) { c_parser_pragma (parser, pragma_external); continue; } /* Parse some comma-separated declarations, but not the trailing semicolon if any. */ decls = c_parser_struct_declaration (parser); contents = chainon (decls, contents); /* If no semicolon follows, either we have a parse error or are at the end of the struct or union and should pedwarn. */ if (c_parser_next_token_is (parser, CPP_SEMICOLON)) c_parser_consume_token (parser); else { if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) pedwarn (c_parser_peek_token (parser)->location, 0, "no semicolon at end of struct or union"); else 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 (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) { 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 (ident_loc, code, ident); return ret; } /* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1), *without* the trailing semicolon. struct-declaration: specifier-qualifier-list struct-declarator-list static_assert-declaration-no-semi specifier-qualifier-list: type-specifier specifier-qualifier-list[opt] type-qualifier specifier-qualifier-list[opt] attributes specifier-qualifier-list[opt] struct-declarator-list: struct-declarator struct-declarator-list , attributes[opt] struct-declarator struct-declarator: declarator attributes[opt] declarator[opt] : constant-expression attributes[opt] GNU extensions: struct-declaration: __extension__ struct-declaration specifier-qualifier-list Unlike the ISO C syntax, semicolons are handled elsewhere. The use of attributes where shown is a GNU extension. In GNU C, we accept any expression without commas in the syntax (assignment expressions, not just conditional expressions); assignment expressions will be diagnosed as non-constant. */ static tree c_parser_struct_declaration (c_parser *parser) { struct c_declspecs *specs; tree prefix_attrs; tree all_prefix_attrs; tree decls; location_t decl_loc; if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) { int ext; tree decl; ext = disable_extension_diagnostics (); c_parser_consume_token (parser); decl = c_parser_struct_declaration (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, cla_nonabstract_decl); if (parser->error) return NULL_TREE; if (!specs->declspecs_seen_p) { c_parser_error (parser, "expected specifier-qualifier-list"); return NULL_TREE; } finish_declspecs (specs); if (c_parser_next_token_is (parser, CPP_SEMICOLON) || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { tree ret; if (specs->typespec_kind == ctsk_none) { pedwarn (decl_loc, OPT_Wpedantic, "ISO C forbids member declarations with no members"); shadow_tag_warned (specs, pedantic); ret = NULL_TREE; } else { /* Support for unnamed structs or unions as members of structs or unions (which is [a] useful and [b] supports MS P-SDK). */ tree attrs = NULL; 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; specs->attrs = NULL_TREE; decls = NULL_TREE; while (true) { /* Declaring one or more declarators or un-named bit-fields. */ struct c_declarator *declarator; bool dummy = false; if (c_parser_next_token_is (parser, CPP_COLON)) declarator = build_id_declarator (NULL_TREE); else declarator = c_parser_declarator (parser, specs->typespec_kind != ctsk_none, C_DTR_NORMAL, &dummy); if (declarator == NULL) { c_parser_skip_to_end_of_block_or_statement (parser); break; } if (c_parser_next_token_is (parser, CPP_COLON) || c_parser_next_token_is (parser, CPP_COMMA) || c_parser_next_token_is (parser, CPP_SEMICOLON) || c_parser_next_token_is (parser, CPP_CLOSE_BRACE) || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) { tree postfix_attrs = NULL_TREE; tree width = NULL_TREE; tree d; if (c_parser_next_token_is (parser, CPP_COLON)) { c_parser_consume_token (parser); width = c_parser_expr_no_commas (parser, NULL).value; } if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) postfix_attrs = c_parser_attributes (parser); d = grokfield (c_parser_peek_token (parser)->location, declarator, specs, width, &all_prefix_attrs); decl_attributes (&d, chainon (postfix_attrs, all_prefix_attrs), 0); DECL_CHAIN (d) = decls; decls = d; if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) all_prefix_attrs = chainon (c_parser_attributes (parser), prefix_attrs); else all_prefix_attrs = prefix_attrs; if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); else if (c_parser_next_token_is (parser, CPP_SEMICOLON) || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { /* Semicolon consumed in caller. */ break; } else { c_parser_error (parser, "expected %<,%>, %<;%> or %<}%>"); break; } } else { c_parser_error (parser, "expected %<:%>, %<,%>, %<;%>, %<}%> or " "%<__attribute__%>"); break; } } return decls; } /* Parse a typeof specifier (a GNU extension). typeof-specifier: typeof ( expression ) typeof ( type-name ) */ static struct c_typespec 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); c_inhibit_evaluation_warnings++; in_typeof++; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { c_inhibit_evaluation_warnings--; in_typeof--; return ret; } if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) { struct c_type_name *type = c_parser_type_name (parser); c_inhibit_evaluation_warnings--; in_typeof--; if (type != NULL) { ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands); pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE)); } } else { bool was_vm; location_t here = c_parser_peek_token (parser)->location; struct c_expr expr = c_parser_expression (parser); c_inhibit_evaluation_warnings--; in_typeof--; if (TREE_CODE (expr.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) 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 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; } /* Parse an alignment-specifier. C11 6.7.5: alignment-specifier: _Alignas ( type-name ) _Alignas ( constant-expression ) */ static tree c_parser_alignas_specifier (c_parser * parser) { tree ret = error_mark_node; location_t loc = c_parser_peek_token (parser)->location; gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNAS)); c_parser_consume_token (parser); if (!flag_isoc11) { if (flag_isoc99) pedwarn (loc, OPT_Wpedantic, "ISO C99 does not support %<_Alignas%>"); else pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support %<_Alignas%>"); } if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return ret; if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) { struct c_type_name *type = c_parser_type_name (parser); if (type != NULL) ret = c_alignof (loc, groktypename (type, NULL, NULL)); } else ret = c_parser_expr_no_commas (parser, NULL).value; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return ret; } /* Parse a declarator, possibly an abstract declarator (C90 6.5.4, 6.5.5, C99 6.7.5, 6.7.6). If TYPE_SEEN_P then a typedef name may be redeclared; otherwise it may not. KIND indicates which kind of declarator is wanted. Returns a valid declarator except in the case of a syntax error in which case NULL is returned. *SEEN_ID is set to true if an identifier being declared is seen; this is used to diagnose bad forms of abstract array declarators and to determine whether an identifier list is syntactically permitted. declarator: pointer[opt] direct-declarator direct-declarator: identifier ( attributes[opt] declarator ) direct-declarator array-declarator direct-declarator ( parameter-type-list ) direct-declarator ( identifier-list[opt] ) pointer: * type-qualifier-list[opt] * type-qualifier-list[opt] pointer type-qualifier-list: type-qualifier attributes type-qualifier-list type-qualifier type-qualifier-list attributes parameter-type-list: parameter-list parameter-list , ... parameter-list: parameter-declaration parameter-list , parameter-declaration parameter-declaration: declaration-specifiers declarator attributes[opt] declaration-specifiers abstract-declarator[opt] attributes[opt] identifier-list: identifier identifier-list , identifier abstract-declarator: pointer pointer[opt] direct-abstract-declarator direct-abstract-declarator: ( attributes[opt] abstract-declarator ) direct-abstract-declarator[opt] array-declarator direct-abstract-declarator[opt] ( parameter-type-list[opt] ) GNU extensions: direct-declarator: direct-declarator ( parameter-forward-declarations parameter-type-list[opt] ) direct-abstract-declarator: direct-abstract-declarator[opt] ( parameter-forward-declarations parameter-type-list[opt] ) parameter-forward-declarations: parameter-list ; parameter-forward-declarations parameter-list ; The uses of attributes shown above are GNU extensions. Some forms of array declarator are not included in C99 in the syntax for abstract declarators; these are disallowed elsewhere. This may be a defect (DR#289). This function also accepts an omitted abstract declarator as being an abstract declarator, although not part of the formal syntax. */ static struct c_declarator * c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, bool *seen_id) { /* Parse any initial pointer part. */ if (c_parser_next_token_is (parser, CPP_MULT)) { 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, cla_prefer_id); inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); if (inner == NULL) return NULL; else return make_pointer_declarator (quals_attrs, inner); } /* Now we have a direct declarator, direct abstract declarator or nothing (which counts as a direct abstract declarator here). */ return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id); } /* Parse a direct declarator or direct abstract declarator; arguments as c_parser_declarator. */ static struct c_declarator * c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, bool *seen_id) { /* The direct declarator must start with an identifier (possibly omitted) or a parenthesized declarator (possibly abstract). In an ordinary declarator, initial parentheses must start a parenthesized declarator. In an abstract declarator or parameter declarator, they could start a parenthesized declarator or a parameter list. To tell which, the open parenthesis and any following attributes must be read. If a declaration specifier follows, then it is a parameter list; if the specifier is a typedef name, there might be an ambiguity about redeclaring it, which is resolved in the direction of treating it as a typedef name. If a close parenthesis follows, it is also an empty parameter list, as the syntax does not permit empty abstract declarators. Otherwise, it is a parenthesized declarator (in which case the analysis may be repeated inside it, recursively). ??? There is an ambiguity in a parameter declaration "int (__attribute__((foo)) x)", where x is not a typedef name: it could be an abstract declarator for a function, or declare x with parentheses. The proper resolution of this ambiguity needs documenting. At present we follow an accident of the old parser's implementation, whereby the first parameter must have some declaration specifiers other than just attributes. Thus as a parameter declaration it is treated as a parenthesized parameter named x, and as an abstract declarator it is rejected. ??? Also following the old parser, attributes inside an empty parameter list are ignored, making it a list not yielding a prototype, rather than giving an error or making it have one parameter with implicit type int. ??? Also following the old parser, typedef names may be redeclared in declarators, but not Objective-C class names. */ 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_CLASSNAME)) || c_parser_peek_token (parser)->id_kind == C_ID_ID)) { struct c_declarator *inner = build_id_declarator (c_parser_peek_token (parser)->value); *seen_id = true; inner->id_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); return c_parser_direct_declarator_inner (parser, *seen_id, inner); } if (kind != C_DTR_NORMAL && c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) { struct c_declarator *inner = build_id_declarator (NULL_TREE); return c_parser_direct_declarator_inner (parser, *seen_id, inner); } /* Either we are at the end of an abstract declarator, or we have parentheses. */ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { tree attrs; struct c_declarator *inner; c_parser_consume_token (parser); attrs = c_parser_attributes (parser); if (kind != C_DTR_NORMAL && (c_parser_next_token_starts_declspecs (parser) || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) { struct c_arg_info *args = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL, attrs); if (args == NULL) return NULL; else { inner = build_function_declarator (args, build_id_declarator (NULL_TREE)); return c_parser_direct_declarator_inner (parser, *seen_id, inner); } } /* A parenthesized declarator. */ inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); if (inner != NULL && attrs != NULL) inner = build_attrs_declarator (attrs, inner); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { c_parser_consume_token (parser); if (inner == NULL) return NULL; else return c_parser_direct_declarator_inner (parser, *seen_id, inner); } else { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return NULL; } } else { if (kind == C_DTR_NORMAL) { c_parser_error (parser, "expected identifier or %<(%>"); return NULL; } else return build_id_declarator (NULL_TREE); } } /* Parse part of a direct declarator or direct abstract declarator, given that some (in INNER) has already been parsed; ID_PRESENT is true if an identifier is present, false for an abstract declarator. */ static struct c_declarator * c_parser_direct_declarator_inner (c_parser *parser, bool id_present, struct c_declarator *inner) { /* 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, 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, cla_prefer_id); if (!quals_attrs->declspecs_seen_p) quals_attrs = NULL; /* If "static" is present, there must be an array dimension. Otherwise, there may be a dimension, "*", or no dimension. */ if (static_seen) { star_seen = false; dimen = c_parser_expr_no_commas (parser, NULL).value; } else { if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) { dimen = NULL_TREE; star_seen = false; } else if (c_parser_next_token_is (parser, CPP_MULT)) { if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE) { dimen = NULL_TREE; star_seen = true; c_parser_consume_token (parser); } else { star_seen = false; dimen = c_parser_expr_no_commas (parser, NULL).value; } } else { star_seen = false; dimen = c_parser_expr_no_commas (parser, NULL).value; } } if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) c_parser_consume_token (parser); else { c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); return NULL; } 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); return c_parser_direct_declarator_inner (parser, id_present, inner); } else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { tree attrs; struct c_arg_info *args; c_parser_consume_token (parser); attrs = c_parser_attributes (parser); args = c_parser_parms_declarator (parser, id_present, attrs); if (args == NULL) return NULL; else { inner = build_function_declarator (args, inner); return c_parser_direct_declarator_inner (parser, id_present, inner); } } return inner; } /* Parse a parameter list or identifier list, including the closing parenthesis but not the opening one. ATTRS are the attributes at the start of the list. ID_LIST_OK is true if an identifier list is acceptable; such a list must not have attributes at the start. */ static struct c_arg_info * c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs) { push_scope (); declare_parm_level (); /* If the list starts with an identifier, it is an identifier list. Otherwise, it is either a prototype list or an empty list. */ if (id_list_ok && !attrs && c_parser_next_token_is (parser, CPP_NAME) && 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) && c_parser_peek_token (parser)->id_kind == C_ID_ID) { *nextp = build_tree_list (NULL_TREE, c_parser_peek_token (parser)->value); nextp = & TREE_CHAIN (*nextp); c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_COMMA)) break; c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { c_parser_error (parser, "expected identifier"); break; } } if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { struct c_arg_info *ret = build_arg_info (); ret->types = list; c_parser_consume_token (parser); pop_scope (); return ret; } else { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); pop_scope (); return NULL; } } else { struct c_arg_info *ret = c_parser_parms_list_declarator (parser, attrs, NULL); pop_scope (); return ret; } } /* Parse a parameter list (possibly empty), including the closing parenthesis but not the opening one. ATTRS are the attributes at the start of the list. 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, tree expr) { bool bad_parm = false; /* ??? Following the old parser, forward parameter declarations may use abstract declarators, and if no real parameter declarations follow the forward declarations then this is not diagnosed. Also note as above that attributes are ignored as the only contents of the parentheses, or as the only contents after forward declarations. */ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { 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 = 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)) { c_parser_consume_token (parser); return ret; } else { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return NULL; } } /* Nonempty list of parameters, either terminated with semicolon (forward declarations; recurse) or with close parenthesis (normal function) or with ", ... )" (variadic function). */ while (true) { /* Parse a parameter. */ struct c_parm *parm = c_parser_parameter_declaration (parser, attrs); attrs = NULL_TREE; 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, expr); } if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { c_parser_consume_token (parser); if (bad_parm) return NULL; else return get_parm_info (false, expr); } if (!c_parser_require (parser, CPP_COMMA, "expected %<;%>, %<,%> or %<)%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return NULL; } if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) { c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { c_parser_consume_token (parser); if (bad_parm) return NULL; else return get_parm_info (true, expr); } else { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return NULL; } } } } /* Parse a parameter declaration. ATTRS are the attributes at the start of the declaration if it is the first parameter. */ static struct c_parm * c_parser_parameter_declaration (c_parser *parser, tree attrs) { struct c_declspecs *specs; struct c_declarator *declarator; tree prefix_attrs; tree postfix_attrs = NULL_TREE; bool dummy = false; /* Accept #pragmas between parameter declarations. */ while (c_parser_next_token_is (parser, CPP_PRAGMA)) c_parser_pragma (parser, pragma_external); 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. */ else c_parser_error (parser, "expected declaration specifiers or %<...%>"); c_parser_skip_to_end_of_parameter (parser); return NULL; } specs = build_null_declspecs (); if (attrs) { declspecs_add_attrs (input_location, specs, attrs); attrs = NULL_TREE; } 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->typespec_kind != ctsk_none, C_DTR_PARM, &dummy); if (declarator == NULL) { c_parser_skip_until_found (parser, CPP_COMMA, NULL); return NULL; } if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) postfix_attrs = c_parser_attributes (parser); return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs), declarator); } /* Parse a string literal in an asm expression. It should not be translated, and wide string literals are an error although permitted by the syntax. This is a GNU extension. asm-string-literal: string-literal ??? At present, following the old parser, the caller needs to have set lex_untranslated_string to 1. It would be better to follow the C++ parser rather than using this kludge. */ 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; c_parser_consume_token (parser); } else if (c_parser_next_token_is (parser, CPP_WSTRING)) { error_at (c_parser_peek_token (parser)->location, "wide string literal in %"); str = build_string (1, ""); c_parser_consume_token (parser); } else { c_parser_error (parser, "expected string literal"); str = NULL_TREE; } warn_overlength_strings = save_flag; return str; } /* Parse a simple asm expression. This is used in restricted contexts, where a full expression with inputs and outputs does not make sense. This is a GNU extension. simple-asm-expr: asm ( asm-string-literal ) */ static tree c_parser_simple_asm_expr (c_parser *parser) { tree str; gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); /* ??? Follow the C++ parser rather than using the lex_untranslated_string kludge. */ parser->lex_untranslated_string = true; c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { parser->lex_untranslated_string = false; return NULL_TREE; } str = c_parser_asm_string_literal (parser); 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; } 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: empty attributes attribute attribute: __attribute__ ( ( attribute-list ) ) attribute-list: attrib attribute_list , attrib attrib: empty any-word any-word ( identifier ) any-word ( identifier , nonempty-expr-list ) any-word ( expr-list ) where the "identifier" must not be declared as a type, and "any-word" may be any identifier (including one declared as a type), a reserved word storage class specifier, type specifier or type qualifier. ??? This still leaves out most reserved keywords (following the old parser), shouldn't we include them, and why not allow identifiers declared as types to start the arguments? */ static tree c_parser_attributes (c_parser *parser) { tree attrs = NULL_TREE; while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) { /* ??? Follow the C++ parser rather than using the lex_untranslated_string kludge. */ parser->lex_untranslated_string = true; c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { parser->lex_untranslated_string = false; return attrs; } if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return attrs; } /* Parse the attribute list. */ while (c_parser_next_token_is (parser, CPP_COMMA) || c_parser_next_token_is (parser, CPP_NAME) || c_parser_next_token_is (parser, CPP_KEYWORD)) { tree attr, attr_name, attr_args; vec *expr_list; if (c_parser_next_token_is (parser, CPP_COMMA)) { c_parser_consume_token (parser); continue; } 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)) { attr = build_tree_list (attr_name, NULL_TREE); attrs = chainon (attrs, attr); continue; } c_parser_consume_token (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. 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_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))) { tree arg1 = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) attr_args = build_tree_list (NULL_TREE, arg1); else { tree tree_list; c_parser_consume_token (parser); expr_list = c_parser_expr_list (parser, false, true, NULL, NULL, NULL); tree_list = build_tree_list_vec (expr_list); attr_args = tree_cons (NULL_TREE, arg1, tree_list); release_tree_vector (expr_list); } } else { if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) attr_args = NULL_TREE; else { expr_list = c_parser_expr_list (parser, false, true, NULL, NULL, 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)) c_parser_consume_token (parser); else { parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return attrs; } attrs = chainon (attrs, attr); } if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) c_parser_consume_token (parser); else { parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return attrs; } if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) c_parser_consume_token (parser); else { parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return attrs; } parser->lex_untranslated_string = false; } return attrs; } /* Parse a type name (C90 6.5.5, C99 6.7.6). type-name: specifier-qualifier-list abstract-declarator[opt] */ static struct c_type_name * c_parser_type_name (c_parser *parser) { struct c_declspecs *specs = build_null_declspecs (); struct c_declarator *declarator; struct c_type_name *ret; bool dummy = false; 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; } 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; ret = XOBNEW (&parser_obstack, struct c_type_name); ret->specs = specs; ret->declarator = declarator; return ret; } /* Parse an initializer (C90 6.5.7, C99 6.7.8). initializer: assignment-expression { initializer-list } { initializer-list , } initializer-list: designation[opt] initializer initializer-list , designation[opt] initializer designation: designator-list = designator-list: designator designator-list designator designator: array-designator . identifier array-designator: [ constant-expression ] GNU extensions: initializer: { } designation: array-designator identifier : array-designator: [ constant-expression ... constant-expression ] Any expression without commas is accepted in the syntax for the constant-expressions, with non-constant expressions rejected later. This function is only used for top-level initializers; for nested ones, see c_parser_initval. */ static struct c_expr c_parser_initializer (c_parser *parser) { if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) return c_parser_braced_init (parser, NULL_TREE, false); 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_read_conversion (loc, ret); return ret; } } /* Parse a braced initializer list. TYPE is the type specified for a compound literal, and NULL_TREE for other initializers and for nested braced lists. NESTED_P is true for nested braced lists, false for the list of a compound literal or the list that is the top-level initializer in a declaration. */ 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, &braced_init_obstack); else really_start_incremental_init (type); if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { pedwarn (brace_loc, OPT_Wpedantic, "ISO C forbids empty initializer braces"); } else { /* Parse a non-empty initializer list, possibly with a trailing comma. */ while (true) { c_parser_initelt (parser, &braced_init_obstack); if (parser->error) break; if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); else break; if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) break; } } if (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) { 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); 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, 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 longer list or a structure member designator may not. */ if (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_2nd_token (parser)->type == CPP_COLON) { /* Old-style structure member designator. */ 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_Wpedantic, "obsolete use of designated initializer with %<:%>"); c_parser_consume_token (parser); c_parser_consume_token (parser); } else { /* des_seen is 0 if there have been no designators, 1 if there has been a single array designator and 2 otherwise. */ int des_seen = 0; /* Location of a designator. */ 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)) { int des_prev = des_seen; if (!des_seen) des_loc = c_parser_peek_token (parser)->location; if (des_seen < 2) des_seen++; if (c_parser_next_token_is (parser, CPP_DOT)) { des_seen = 2; c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_NAME)) { set_init_label (c_parser_peek_token (parser)->value, braced_init_obstack); c_parser_consume_token (parser); } else { 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, false, braced_init_obstack); return; } } else { tree first, second; 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 the first assignment expression inside the square brackets, but after a first array designator a subsequent square bracket is for Objective-C taken to start an expression, using the obsolete form of designated initializer without '=', rather than possibly being a second level of designation: in LALR terms, the '[' is shifted rather than reducing designator to designator-list. */ if (des_prev == 1 && c_dialect_objc ()) { des_seen = des_prev; break; } if (des_prev == 0 && c_dialect_objc ()) { /* This might be an array designator or an Objective-C message expression. If the former, continue parsing here; if the latter, parse the remainder of the initializer given the starting primary-expression. ??? It might make sense to distinguish when des_prev == 1 as well; see previous comment. */ tree rec, args; struct c_expr mexpr; c_parser_consume_token (parser); if (c_parser_peek_token (parser)->type == CPP_NAME && ((c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME) || (c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))) { /* Type name receiver. */ tree id = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); rec = objc_get_class_reference (id); 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; /* Expression receiver. So far only one part without commas has been parsed; there might be more of the expression. */ rec = first; 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_read_conversion (exp_loc, next); rec = build_compound_expr (comma_loc, rec, next.value); } parse_message_args: /* Now parse the objc-message-args. */ args = c_parser_objc_message_args (parser); c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); mexpr.value = 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, 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, braced_init_obstack); if (second) pedwarn (ellipsis_loc, OPT_Wpedantic, "ISO C forbids specifying range of elements to initialize"); } else c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); } } if (des_seen >= 1) { if (c_parser_next_token_is (parser, CPP_EQ)) { if (!flag_isoc99) pedwarn (des_loc, OPT_Wpedantic, "ISO C90 forbids specifying subobject to initialize"); c_parser_consume_token (parser); } else { if (des_seen == 1) pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "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, false, braced_init_obstack); return; } } } } c_parser_initval (parser, NULL, braced_init_obstack); } /* Parse a nested initializer; as c_parser_initializer but parses initializers within braced lists, after any designators have been applied. If AFTER is not NULL then it is an Objective-C message expression which is the primary-expression starting the initializer. */ static void 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 ()); if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !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_read_conversion (loc, init); } process_init_element (init, false, braced_init_obstack); } /* Parse a compound statement (possibly a function body) (C90 6.6.2, C99 6.8.2). compound-statement: { block-item-list[opt] } { label-declarations block-item-list } block-item-list: block-item block-item-list block-item block-item: nested-declaration statement nested-declaration: declaration GNU extensions: compound-statement: { label-declarations block-item-list } nested-declaration: __extension__ nested-declaration nested-function-definition label-declarations: label-declaration label-declarations label-declaration label-declaration: __label__ identifier-list ; Allowing the mixing of declarations and code is new in C99. The GNU syntax also permits (not shown above) labels at the end of compound statements, which yield an error. We don't allow labels on declarations; this might seem like a natural extension, but there would be a conflict between attributes on the label and prefix attributes on the declaration. ??? The syntax follows the 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 openmp-directive: barrier-directive flush-directive */ 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 %<{%>")) { /* 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 (brace_loc, stmt, true); } /* Parse a compound statement except for the opening brace. This is used for parsing both compound statements and statement expressions (which follow different paths to handling the opening). */ static void c_parser_compound_statement_nostart (c_parser *parser) { bool last_stmt = false; bool last_label = false; 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)) { /* 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. */ while (true) { tree label; if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); break; } label = declare_label (c_parser_peek_token (parser)->value); C_DECLARED_LABEL_FLAG (label) = 1; 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); else break; } c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } pedwarn (label_loc, OPT_Wpedantic, "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; } while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) { location_t loc = c_parser_peek_token (parser)->location; if (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) && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) { if (c_parser_next_token_is_keyword (parser, RID_CASE)) label_loc = c_parser_peek_2nd_token (parser)->location; else 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_tokens_start_declaration (parser)) { last_label = false; mark_valid_location_for_stdc_pragma (false); c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); if (last_stmt) pedwarn_c90 (loc, (pedantic && !flag_isoc99) ? OPT_Wpedantic : OPT_Wdeclaration_after_statement, "ISO C90 forbids mixed declarations and code"); last_stmt = false; } else if (!last_label && c_parser_next_token_is_keyword (parser, RID_EXTENSION)) { /* __extension__ can start a declaration, but is also an unary operator that can start an expression. Consume all but the last of a possible series of __extension__ to determine which. */ while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD && (c_parser_peek_2nd_token (parser)->keyword == RID_EXTENSION)) c_parser_consume_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; 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) pedwarn_c90 (loc, (pedantic && !flag_isoc99) ? OPT_Wpedantic : OPT_Wdeclaration_after_statement, "ISO C90 forbids mixed declarations and code"); last_stmt = false; } else goto statement; } else if (c_parser_next_token_is (parser, CPP_PRAGMA)) { /* External pragmas, and some omp pragmas, are not associated with regular c code, and so are not to be considered statements syntactically. This ensures that the user doesn't put them places that would turn into syntax errors if the directive were ignored. */ if (c_parser_pragma (parser, pragma_compound)) last_label = false, last_stmt = true; } 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) { mark_valid_location_for_stdc_pragma (save_valid_for_pragma); error_at (loc, """expected %<}%> before %"); return; } else { error_at (loc, "% without a previous %"); c_parser_consume_token (parser); continue; } } else { 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_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). label: identifier : attributes[opt] case constant-expression : default : GNU extensions: label: case constant-expression ... constant-expression : The use of attributes on labels is a GNU extension. The syntax in GNU C accepts any expressions without commas, non-constant expressions being rejected later. */ static void c_parser_label (c_parser *parser) { location_t loc1 = c_parser_peek_token (parser)->location; tree label = NULL_TREE; if (c_parser_next_token_is_keyword (parser, RID_CASE)) { tree exp1, exp2; c_parser_consume_token (parser); exp1 = c_parser_expr_no_commas (parser, NULL).value; if (c_parser_next_token_is (parser, CPP_COLON)) { c_parser_consume_token (parser); 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 (loc1, exp1, exp2); } else c_parser_error (parser, "expected %<:%> or %<...%>"); } else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) { c_parser_consume_token (parser); if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) label = do_case (loc1, NULL_TREE, NULL_TREE); } else { tree name = c_parser_peek_token (parser)->value; tree tlab; tree attrs; location_t loc2 = c_parser_peek_token (parser)->location; gcc_assert (c_parser_next_token_is (parser, CPP_NAME)); c_parser_consume_token (parser); gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); c_parser_consume_token (parser); attrs = c_parser_attributes (parser); tlab = define_label (loc2, name); if (tlab) { decl_attributes (&tlab, attrs, 0); label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab)); } } if (label) { if (c_parser_next_tokens_start_declaration (parser)) { error_at (c_parser_peek_token (parser)->location, "a label can only be part of a statement and " "a declaration is not a statement"); c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false, /*static_assert_ok*/ true, /*empty_ok*/ true, /*nested*/ true, /*start_attr_ok*/ true, NULL); } } } /* Parse a statement (C90 6.6, C99 6.8). statement: labeled-statement compound-statement expression-statement selection-statement iteration-statement jump-statement labeled-statement: label statement expression-statement: expression[opt] ; selection-statement: if-statement switch-statement iteration-statement: while-statement do-statement for-statement jump-statement: goto identifier ; continue ; break ; return expression[opt] ; GNU extensions: statement: asm-statement jump-statement: goto * expression ; Objective-C: statement: objc-throw-statement objc-try-catch-statement objc-synchronized-statement objc-throw-statement: @throw expression ; @throw ; OpenMP: statement: openmp-construct openmp-construct: parallel-construct for-construct sections-construct single-construct parallel-for-construct parallel-sections-construct master-construct critical-construct atomic-construct ordered-construct parallel-construct: parallel-directive structured-block for-construct: for-directive iteration-statement sections-construct: sections-directive section-scope single-construct: single-directive structured-block parallel-for-construct: parallel-for-directive iteration-statement parallel-sections-construct: parallel-sections-directive section-scope master-construct: master-directive structured-block critical-construct: critical-directive structured-block atomic-construct: atomic-directive expression-statement ordered-construct: ordered-directive structured-block Transactional Memory: statement: transaction-statement transaction-cancel-statement */ static void c_parser_statement (c_parser *parser) { 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) && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) c_parser_label (parser); c_parser_statement_after_labels (parser); } /* Parse a statement, other than a labeled statement. */ static void c_parser_statement_after_labels (c_parser *parser) { location_t loc = c_parser_peek_token (parser)->location; tree stmt = NULL_TREE; bool in_if_block = parser->in_if_block; parser->in_if_block = false; switch (c_parser_peek_token (parser)->type) { case CPP_OPEN_BRACE: add_stmt (c_parser_compound_statement (parser)); break; case CPP_KEYWORD: switch (c_parser_peek_token (parser)->keyword) { case RID_IF: c_parser_if_statement (parser); break; case RID_SWITCH: c_parser_switch_statement (parser); break; case RID_WHILE: c_parser_while_statement (parser); break; case RID_DO: c_parser_do_statement (parser); break; case RID_FOR: c_parser_for_statement (parser); break; case RID_GOTO: c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_NAME)) { 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); 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 (loc, &c_cont_label, false); goto expect_semicolon; case RID_BREAK: c_parser_consume_token (parser); 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 (loc, NULL_TREE, NULL_TREE); c_parser_consume_token (parser); } else { 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 (loc, NULL_TREE); c_parser_consume_token (parser); } else { 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_finally_statement (parser); break; case RID_AT_SYNCHRONIZED: gcc_assert (c_dialect_objc ()); c_parser_objc_synchronized_statement (parser); break; default: goto expr_stmt; } break; case CPP_SEMICOLON: c_parser_consume_token (parser); break; case CPP_CLOSE_PAREN: case CPP_CLOSE_SQUARE: /* Avoid infinite loop in error recovery: c_parser_skip_until_found stops at a closing nesting delimiter without consuming it, but here we need to consume it to proceed further. */ c_parser_error (parser, "expected statement"); c_parser_consume_token (parser); break; case CPP_PRAGMA: c_parser_pragma (parser, pragma_stmt); break; default: expr_stmt: stmt = c_finish_expr_stmt (loc, c_parser_expression_conv (parser).value); expect_semicolon: c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); break; } /* Two cases cannot and do not have line numbers associated: If stmt is degenerate, such as "2;", then stmt is an INTEGER_CST, which cannot hold line numbers. But that's OK because the statement will either be changed to a MODIFY_EXPR during gimplification of the statement expr, or discarded. If stmt was compound, but without new variables, we will have skipped the creation of a BIND and will have a bare STATEMENT_LIST. But that's OK because (recursively) all of the component statements should already have line numbers assigned. ??? Can we discard no-op statements earlier? */ 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: ( expression ) */ static tree c_parser_paren_condition (c_parser *parser) { tree cond; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return error_mark_node; cond = c_parser_condition (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return cond; } /* Parse a statement which is a block in C99. */ 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 (loc, block, flag_isoc99); } /* Parse the body of an if statement. This is just parsing a statement but (a) it is a block in C99, (b) we track whether the body is an if statement for the sake of -Wparentheses warnings, (c) we handle an empty body specially for the sake of -Wempty-body warnings, and (d) we call parser_compound_statement directly because c_parser_statement_after_labels resets parser->in_if_block. */ 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) && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) c_parser_label (parser); *if_p = c_parser_next_token_is_keyword (parser, RID_IF); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { 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 (body_loc, block, flag_isoc99); } /* Parse the else body of an if statement. This is just parsing a statement but (a) it is a block in C99, (b) we handle an empty body specially for the sake of -Wempty-body warnings. */ 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) || (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) c_parser_label (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { 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 c_parser_statement_after_labels (parser); return c_end_compound_stmt (else_loc, block, flag_isoc99); } /* Parse an if statement (C90 6.6.4, C99 6.8.4). if-statement: if ( expression ) statement if ( expression ) statement else statement */ static void c_parser_if_statement (c_parser *parser) { tree block; location_t loc; tree cond; bool first_if = false; tree first_body, second_body; bool in_if_block; gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF)); c_parser_consume_token (parser); block = c_begin_compound_stmt (flag_isoc99); loc = c_parser_peek_token (parser)->location; cond = c_parser_paren_condition (parser); in_if_block = parser->in_if_block; parser->in_if_block = true; first_body = c_parser_if_body (parser, &first_if); parser->in_if_block = in_if_block; if (c_parser_next_token_is_keyword (parser, RID_ELSE)) { c_parser_consume_token (parser); second_body = c_parser_else_body (parser); } else second_body = NULL_TREE; c_finish_if_stmt (loc, cond, first_body, second_body, first_if); add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); } /* Parse a switch statement (C90 6.6.4, C99 6.8.4). switch-statement: switch (expression) statement */ 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 { 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) { 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 (switch_loc, block, flag_isoc99)); } /* Parse a while statement (C90 6.6.5, C99 6.8.5). while-statement: while (expression) statement */ static void c_parser_while_statement (c_parser *parser) { tree block, cond, body, save_break, save_cont; location_t loc; gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE)); c_parser_consume_token (parser); block = c_begin_compound_stmt (flag_isoc99); loc = c_parser_peek_token (parser)->location; cond = c_parser_paren_condition (parser); 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, NULL, body, c_break_label, c_cont_label, true); add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); c_break_label = save_break; c_cont_label = save_cont; } /* Parse a do statement (C90 6.6.5, C99 6.8.5). do-statement: do statement while ( expression ) ; */ static void c_parser_do_statement (c_parser *parser) { tree block, cond, body, save_break, save_cont, new_break, new_cont; location_t loc; 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_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; c_break_label = NULL_TREE; save_cont = c_cont_label; c_cont_label = NULL_TREE; body = c_parser_c99_block_statement (parser); c_parser_require_keyword (parser, RID_WHILE, "expected %"); new_break = c_break_label; c_break_label = save_break; new_cont = c_cont_label; c_cont_label = save_cont; cond = c_parser_paren_condition (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 (loc, block, flag_isoc99)); } /* Parse a for statement (C90 6.6.5, C99 6.8.5). for-statement: for ( expression[opt] ; expression[opt] ; expression[opt] ) statement for ( nested-declaration expression[opt] ; expression[opt] ) statement The form with a declaration is new in C99. ??? In accordance with the old parser, the declaration may be a nested function, which is then rejected in check_for_loop_decls, but does it make any sense for this to be included in the grammar? 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? In Objective-C, there are two additional variants: foreach-statement: for ( expression in expresssion ) statement for ( declaration in expression ) statement This is inconsistent with C, because the second variant is allowed even if c99 is not enabled. The rest of the comment documents these Objective-C foreach-statement. Here is the canonical example of the first variant: for (object in array) { do something with object } we call the first expression ("object") the "object_expression" and the second expression ("array") the "collection_expression". object_expression must be an lvalue of type "id" (a generic Objective-C object) because the loop works by assigning to object_expression the various objects from the collection_expression. collection_expression must evaluate to something of type "id" which responds to the method countByEnumeratingWithState:objects:count:. The canonical example of the second variant is: for (id object in array) { do something with object } which is completely equivalent to { id object; for (object in array) { do something with object } } Note that initizializing 'object' in some way (eg, "for ((object = xxx) in array) { do something with object }") is possibly technically valid, but completely pointless as 'object' will be assigned to something else as soon as the loop starts. We should most likely reject it (TODO). The beginning of the Objective-C foreach-statement looks exactly like the beginning of the for-statement, and we can tell it is a foreach-statement only because the initial declaration or expression is terminated by 'in' instead of ';'. */ static void c_parser_for_statement (c_parser *parser) { tree block, cond, incr, save_break, save_cont, body; /* The following are only used when parsing an ObjC foreach statement. */ tree object_expression; /* Silence the bogus uninitialized warning. */ tree collection_expression = NULL; location_t loc = c_parser_peek_token (parser)->location; location_t for_loc = c_parser_peek_token (parser)->location; bool is_foreach_statement = false; gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); c_parser_consume_token (parser); /* Open a compound statement in Objective-C as well, just in case this is as foreach expression. */ block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ()); cond = error_mark_node; incr = error_mark_node; if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { /* Parse the initialization declaration or expression. */ object_expression = error_mark_node; parser->objc_could_be_foreach_context = c_dialect_objc (); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { parser->objc_could_be_foreach_context = false; c_parser_consume_token (parser); c_finish_expr_stmt (loc, NULL_TREE); } else if (c_parser_next_tokens_start_declaration (parser)) { c_parser_declaration_or_fndef (parser, true, true, true, true, true, &object_expression); parser->objc_could_be_foreach_context = false; if (c_parser_next_token_is_keyword (parser, RID_IN)) { c_parser_consume_token (parser); is_foreach_statement = true; if (check_for_loop_decls (for_loc, true) == NULL_TREE) c_parser_error (parser, "multiple iterating variables in fast enumeration"); } else check_for_loop_decls (for_loc, flag_isoc99); } else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) { /* __extension__ can start a declaration, but is also an unary operator that can start an expression. Consume all but the last of a possible series of __extension__ to determine which. */ while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD && (c_parser_peek_2nd_token (parser)->keyword == RID_EXTENSION)) c_parser_consume_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, true, &object_expression); parser->objc_could_be_foreach_context = false; restore_extension_diagnostics (ext); 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; } else { init_expr: { tree init_expression; init_expression = c_parser_expression (parser).value; parser->objc_could_be_foreach_context = false; if (c_parser_next_token_is_keyword (parser, RID_IN)) { c_parser_consume_token (parser); is_foreach_statement = true; if (! lvalue_p (init_expression)) c_parser_error (parser, "invalid iterating variable in fast enumeration"); object_expression = c_fully_fold (init_expression, false, NULL); } else { c_finish_expr_stmt (loc, init_expression); c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } } } /* Parse the loop condition. In the case of a foreach statement, there is no loop condition. */ gcc_assert (!parser->objc_could_be_foreach_context); if (!is_foreach_statement) { if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { c_parser_consume_token (parser); cond = NULL_TREE; } else { cond = c_parser_condition (parser); c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } } /* Parse the increment expression (the third expression in a for-statement). In the case of a foreach-statement, this is the expression that follows the 'in'. */ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { if (is_foreach_statement) { c_parser_error (parser, "missing collection in fast enumeration"); collection_expression = error_mark_node; } else incr = c_process_expr_stmt (loc, NULL_TREE); } else { 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 %<)%>"); } 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); 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; } /* Parse an asm statement, a GNU extension. This is a full-blown asm statement with inputs, outputs, clobbers, and volatile tag allowed. 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[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. */ static tree c_parser_asm_statement (c_parser *parser) { 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)) { quals = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); } else if (c_parser_next_token_is_keyword (parser, RID_CONST) || c_parser_next_token_is_keyword (parser, RID_RESTRICT)) { 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 %<(%>")) goto error; str = c_parser_asm_string_literal (parser); 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); break; case 1: inputs = c_parser_asm_operands (parser); 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; } done_asm: if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); 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 (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. asm-operands: asm-operand asm-operands , asm-operand asm-operand: asm-string-literal ( expression ) [ identifier ] asm-string-literal ( expression ) */ static tree c_parser_asm_operands (c_parser *parser) { tree list = NULL_TREE; while (true) { tree name, str; struct c_expr expr; if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) { c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_NAME)) { tree id = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); name = build_string (IDENTIFIER_LENGTH (id), IDENTIFIER_POINTER (id)); } else { c_parser_error (parser, "expected identifier"); c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL); return NULL_TREE; } c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); } else name = NULL_TREE; str = c_parser_asm_string_literal (parser); if (str == NULL_TREE) return NULL_TREE; parser->lex_untranslated_string = false; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { parser->lex_untranslated_string = true; return NULL_TREE; } expr = c_parser_expression (parser); mark_exp_read (expr.value); parser->lex_untranslated_string = true; if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return NULL_TREE; } list = chainon (list, build_tree_list (build_tree_list (name, str), expr.value)); if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); else break; } return list; } /* Parse asm clobbers, a GNU extension. asm-clobbers: asm-string-literal asm-clobbers , asm-string-literal */ static tree c_parser_asm_clobbers (c_parser *parser) { tree list = NULL_TREE; while (true) { tree str = c_parser_asm_string_literal (parser); if (str) list = tree_cons (NULL_TREE, str, list); else return NULL_TREE; if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); else break; } 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 primary-expression starting the expression as an initializer. assignment-expression: conditional-expression unary-expression assignment-operator assignment-expression assignment-operator: one of = *= /= %= += -= <<= >>= &= ^= |= In GNU C we accept any conditional expression on the LHS and diagnose the invalid lvalue rather than producing a syntax error. */ static struct c_expr 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: code = NOP_EXPR; break; case CPP_MULT_EQ: code = MULT_EXPR; break; case CPP_DIV_EQ: code = TRUNC_DIV_EXPR; break; case CPP_MOD_EQ: code = TRUNC_MOD_EXPR; break; case CPP_PLUS_EQ: code = PLUS_EXPR; break; case CPP_MINUS_EQ: code = MINUS_EXPR; break; case CPP_LSHIFT_EQ: code = LSHIFT_EXPR; break; case CPP_RSHIFT_EQ: code = RSHIFT_EXPR; break; case CPP_AND_EQ: code = BIT_AND_EXPR; break; case CPP_XOR_EQ: code = BIT_XOR_EXPR; break; case CPP_OR_EQ: code = BIT_IOR_EXPR; break; default: 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_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 { TREE_NO_WARNING (ret.value) = 1; ret.original_code = ERROR_MARK; } ret.original_type = NULL; return ret; } /* Parse a conditional expression (C90 6.3.15, C99 6.5.15). If AFTER is not NULL then it is an Objective-C message expression which is the primary-expression starting the expression as an initializer. conditional-expression: logical-OR-expression logical-OR-expression ? expression : conditional-expression GNU extensions: conditional-expression: logical-OR-expression ? : conditional-expression */ 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, PREC_NONE); if (c_parser_next_token_is_not (parser, CPP_QUERY)) return 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)) { tree eptype = NULL_TREE; middle_loc = c_parser_peek_token (parser)->location; pedwarn (middle_loc, OPT_Wpedantic, "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 = 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 (cond_loc, default_conversion (cond.value)); c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node; exp1 = c_parser_expression_conv (parser); 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 %<:%>")) { 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; } { 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. PREC is the starting precedence, usually PREC_NONE. multiplicative-expression: cast-expression multiplicative-expression * cast-expression multiplicative-expression / cast-expression multiplicative-expression % cast-expression additive-expression: multiplicative-expression additive-expression + multiplicative-expression additive-expression - multiplicative-expression shift-expression: additive-expression shift-expression << additive-expression shift-expression >> additive-expression relational-expression: shift-expression relational-expression < shift-expression relational-expression > shift-expression relational-expression <= shift-expression relational-expression >= shift-expression equality-expression: relational-expression equality-expression == relational-expression equality-expression != relational-expression AND-expression: equality-expression AND-expression & equality-expression exclusive-OR-expression: AND-expression exclusive-OR-expression ^ AND-expression inclusive-OR-expression: exclusive-OR-expression inclusive-OR-expression | exclusive-OR-expression logical-AND-expression: inclusive-OR-expression logical-AND-expression && inclusive-OR-expression logical-OR-expression: logical-AND-expression logical-OR-expression || logical-AND-expression */ static struct c_expr 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 operators are left-associative. Thus a binary expression is of form: E0 op1 E1 op2 E2 ... which we represent on a stack. On the stack, the precedence levels are strictly increasing. When a new operator is encountered of higher precedence than that at the top of the stack, it is pushed; its LHS is the top expression, and its RHS is everything parsed until it is popped. When a new operator is encountered with precedence less than or equal to that at the top of the stack, triples E[i-1] op[i] E[i] are popped and replaced by the result of the operation until the operator at the top of 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 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 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: \ c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ == truthvalue_false_node); \ break; \ case TRUTH_ORIF_EXPR: \ c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ == truthvalue_true_node); \ break; \ default: \ break; \ } \ stack[sp - 1].expr \ = default_function_array_read_conversion (stack[sp - 1].loc, \ stack[sp - 1].expr); \ stack[sp].expr \ = 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; sp = 0; while (true) { enum c_parser_prec oprec; enum tree_code ocode; if (parser->error) goto out; switch (c_parser_peek_token (parser)->type) { case CPP_MULT: oprec = PREC_MULT; ocode = MULT_EXPR; break; case CPP_DIV: oprec = PREC_MULT; ocode = TRUNC_DIV_EXPR; break; case CPP_MOD: oprec = PREC_MULT; ocode = TRUNC_MOD_EXPR; break; case CPP_PLUS: oprec = PREC_ADD; ocode = PLUS_EXPR; break; case CPP_MINUS: oprec = PREC_ADD; ocode = MINUS_EXPR; break; case CPP_LSHIFT: oprec = PREC_SHIFT; ocode = LSHIFT_EXPR; break; case CPP_RSHIFT: oprec = PREC_SHIFT; ocode = RSHIFT_EXPR; break; case CPP_LESS: oprec = PREC_REL; ocode = LT_EXPR; break; case CPP_GREATER: oprec = PREC_REL; ocode = GT_EXPR; break; case CPP_LESS_EQ: oprec = PREC_REL; ocode = LE_EXPR; break; case CPP_GREATER_EQ: oprec = PREC_REL; ocode = GE_EXPR; break; case CPP_EQ_EQ: oprec = PREC_EQ; ocode = EQ_EXPR; break; case CPP_NOT_EQ: oprec = PREC_EQ; ocode = NE_EXPR; break; case CPP_AND: oprec = PREC_BITAND; ocode = BIT_AND_EXPR; break; case CPP_XOR: oprec = PREC_BITXOR; ocode = BIT_XOR_EXPR; break; case CPP_OR: oprec = PREC_BITOR; ocode = BIT_IOR_EXPR; break; case CPP_AND_AND: oprec = PREC_LOGAND; ocode = TRUTH_ANDIF_EXPR; break; case CPP_OR_OR: oprec = PREC_LOGOR; ocode = TRUTH_ORIF_EXPR; break; default: /* Not a binary operator, so end of the binary expression. */ goto out; } binary_loc = c_parser_peek_token (parser)->location; while (oprec <= stack[sp].prec) { if (sp == 0) goto out; POP; } c_parser_consume_token (parser); switch (ocode) { case TRUTH_ANDIF_EXPR: stack[sp].expr = default_function_array_read_conversion (stack[sp].loc, stack[sp].expr); stack[sp].expr.value = c_objc_common_truthvalue_conversion (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_read_conversion (stack[sp].loc, stack[sp].expr); stack[sp].expr.value = c_objc_common_truthvalue_conversion (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) POP; return stack[0].expr; #undef POP } /* Parse a cast expression (C90 6.3.4, C99 6.5.4). If AFTER is not NULL then it is an Objective-C message expression which is the primary-expression starting the expression as an initializer. cast-expression: unary-expression ( type-name ) unary-expression */ 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, 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. 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))) { struct c_type_name *type_name; struct c_expr ret; struct c_expr expr; c_parser_consume_token (parser); type_name = c_parser_type_name (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); if (type_name == NULL) { ret.value = error_mark_node; ret.original_code = ERROR_MARK; ret.original_type = NULL; return ret; } /* Save casted types in the function's used types hash table. */ 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, 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 return c_parser_unary_expression (parser); } /* Parse an unary expression (C90 6.3.3, C99 6.5.3). unary-expression: postfix-expression ++ unary-expression -- unary-expression unary-operator cast-expression sizeof unary-expression sizeof ( type-name ) unary-operator: one of & * + - ~ ! GNU extensions: unary-expression: __alignof__ unary-expression __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. */ static struct c_expr 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_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_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); case CPP_AND: c_parser_consume_token (parser); 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_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_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_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_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_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_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, op_loc); c_parser_consume_token (parser); } else { c_parser_error (parser, "expected identifier"); ret.value = error_mark_node; } return ret; case CPP_KEYWORD: switch (c_parser_peek_token (parser)->keyword) { case RID_SIZEOF: return c_parser_sizeof_expression (parser); case RID_ALIGNOF: return c_parser_alignof_expression (parser); case RID_EXTENSION: c_parser_consume_token (parser); ext = disable_extension_diagnostics (); ret = c_parser_cast_expression (parser, NULL); restore_extension_diagnostics (ext); 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 (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 (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); } default: return c_parser_postfix_expression (parser); } } /* Parse a sizeof expression. */ static struct c_expr c_parser_sizeof_expression (c_parser *parser) { struct c_expr expr; location_t expr_loc; gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); c_parser_consume_token (parser); 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))) { /* Either sizeof ( type-name ) or sizeof unary-expression starting with a compound literal. */ struct c_type_name *type_name; c_parser_consume_token (parser); expr_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; 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, expr_loc); goto sizeof_expr; } /* sizeof ( type-name ). */ c_inhibit_evaluation_warnings--; in_sizeof--; 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: 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_at (expr_loc, "% applied to a bit-field"); return c_expr_sizeof_expr (expr_loc, expr); } } /* Parse an alignof expression. */ 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_Wpedantic, "ISO C99 does not support %qE", alignof_spelling); else pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support %qE", alignof_spelling); } c_parser_consume_token (parser); 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; 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, loc); goto alignof_expr; } /* alignof ( type-name ). */ c_inhibit_evaluation_warnings--; in_alignof--; ret.value = c_alignof (loc, groktypename (type_name, NULL, NULL)); ret.original_code = ERROR_MARK; ret.original_type = NULL; return ret; } else { struct c_expr ret; expr = c_parser_unary_expression (parser); alignof_expr: mark_exp_read (expr.value); c_inhibit_evaluation_warnings--; in_alignof--; pedwarn (loc, OPT_Wpedantic, "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 **ret_cexpr_list, bool choose_expr_p) { location_t loc = c_parser_peek_token (parser)->location; vec *cexpr_list; c_expr_t expr; bool saved_force_folding_builtin_constant_p; *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; } saved_force_folding_builtin_constant_p = force_folding_builtin_constant_p; force_folding_builtin_constant_p |= choose_expr_p; expr = c_parser_expr_no_commas (parser, NULL); force_folding_builtin_constant_p = saved_force_folding_builtin_constant_p; vec_alloc (cexpr_list, 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: primary-expression postfix-expression [ expression ] postfix-expression ( argument-expression-list[opt] ) postfix-expression . identifier postfix-expression -> identifier postfix-expression ++ postfix-expression -- ( type-name ) { initializer-list } ( type-name ) { initializer-list , } argument-expression-list: argument-expression argument-expression-list , argument-expression primary-expression: identifier constant string-literal ( expression ) GNU extensions: primary-expression: __func__ (treated as a keyword in GNU C) __FUNCTION__ __PRETTY_FUNCTION__ ( compound-statement ) __builtin_va_arg ( assignment-expression , type-name ) __builtin_offsetof ( type-name , offsetof-member-designator ) __builtin_choose_expr ( assignment-expression , 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 offsetof-member-designator . identifier offsetof-member-designator [ expression ] Objective-C: primary-expression: [ objc-receiver objc-message-args ] @selector ( objc-selector-arg ) @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; struct c_type_name *t1, *t2; 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; 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); break; case CPP_OBJC_STRING: gcc_assert (c_dialect_objc ()); expr.value = objc_build_string_object (c_parser_peek_token (parser)->value); c_parser_consume_token (parser); break; case CPP_NAME: switch (c_parser_peek_token (parser)->id_kind) { case C_ID_ID: { tree id = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); expr.value = build_external_ref (loc, id, (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN), &expr.original_type); break; } case C_ID_CLASSNAME: { /* Here we parse the Objective-C 2.0 Class.name dot syntax. */ tree class_name = c_parser_peek_token (parser)->value; tree component; c_parser_consume_token (parser); gcc_assert (c_dialect_objc ()); if (!c_parser_require (parser, CPP_DOT, "expected %<.%>")) { expr.value = error_mark_node; break; } if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); expr.value = error_mark_node; break; } component = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); expr.value = objc_build_class_component_ref (class_name, component); break; } default: c_parser_error (parser, "expected expression"); expr.value = error_mark_node; break; } break; case CPP_OPEN_PAREN: /* A parenthesized expression, statement expression or compound literal. */ if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE) { /* A statement expression. */ tree stmt; location_t brace_loc; c_parser_consume_token (parser); brace_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); if (!building_stmt_list_p ()) { 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; break; } stmt = c_begin_stmt_expr (); c_parser_compound_statement_nostart (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); pedwarn (loc, OPT_Wpedantic, "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))) { /* A compound literal. ??? Can we actually get here rather 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; } else expr = c_parser_postfix_expression_after_paren_type (parser, type_name, loc); } else { /* A parenthesized expression. */ c_parser_consume_token (parser); expr = c_parser_expression (parser); if (TREE_CODE (expr.value) == MODIFY_EXPR) TREE_NO_WARNING (expr.value) = 1; 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 %<)%>"); } break; case CPP_KEYWORD: switch (c_parser_peek_token (parser)->keyword) { case RID_FUNCTION_NAME: case RID_PRETTY_FUNCTION_NAME: case RID_C99_FUNCTION_NAME: expr.value = fname_decl (loc, c_parser_peek_token (parser)->keyword, c_parser_peek_token (parser)->value); c_parser_consume_token (parser); break; case RID_VA_ARG: c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; 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; 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; } else { 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: c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; break; } t1 = c_parser_type_name (parser); if (t1 == NULL) parser->error = true; if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) gcc_assert (parser->error); if (parser->error) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; break; } { tree type = groktypename (t1, NULL, NULL); tree offsetof_ref; if (type == error_mark_node) offsetof_ref = error_mark_node; else { 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 (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) || c_parser_next_token_is (parser, CPP_DEREF)) { 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)) { c_parser_error (parser, "expected identifier"); break; } offsetof_ref = build_component_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 (loc, offsetof_ref, idx); } } } else c_parser_error (parser, "expected identifier"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); expr.value = fold_offsetof (offsetof_ref); } break; case RID_CHOOSE_EXPR: { vec *cexpr_list; c_expr_t *e1_p, *e2_p, *e3_p; tree c; c_parser_consume_token (parser); if (!c_parser_get_builtin_args (parser, "__builtin_choose_expr", &cexpr_list, true)) { expr.value = error_mark_node; break; } if (vec_safe_length (cexpr_list) != 3) { error_at (loc, "wrong number of arguments to " "%<__builtin_choose_expr%>"); expr.value = error_mark_node; break; } e1_p = &(*cexpr_list)[0]; e2_p = &(*cexpr_list)[1]; e3_p = &(*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; } case RID_TYPES_COMPATIBLE_P: c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; break; } t1 = c_parser_type_name (parser); if (t1 == NULL) { expr.value = error_mark_node; break; } if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; break; } t2 = c_parser_type_name (parser); if (t2 == NULL) { expr.value = error_mark_node; 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 (e1); e2 = TYPE_MAIN_VARIANT (e2); expr.value = comptypes (e1, e2) ? integer_one_node : integer_zero_node; } break; case RID_BUILTIN_COMPLEX: { vec *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, false)) { expr.value = error_mark_node; break; } if (vec_safe_length (cexpr_list) != 2) { error_at (loc, "wrong number of arguments to " "%<__builtin_complex%>"); expr.value = error_mark_node; break; } e1_p = &(*cexpr_list)[0]; e2_p = &(*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_Wpedantic, "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 *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, false)) { expr.value = error_mark_node; break; } FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) mark_exp_read (p->value); if (vec_safe_length (cexpr_list) == 2) expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, NULL_TREE, (*cexpr_list)[1].value); else if (vec_safe_length (cexpr_list) == 3) expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, (*cexpr_list)[1].value, (*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; 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 (loc, sel); } break; case RID_AT_PROTOCOL: gcc_assert (c_dialect_objc ()); c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; break; } 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); expr.value = error_mark_node; break; } { tree id = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); expr.value = objc_build_protocol_expr (id); } break; case RID_AT_ENCODE: /* Extension to support C-structures in the archiver. */ gcc_assert (c_dialect_objc ()); c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; break; } t1 = c_parser_type_name (parser); if (t1 == NULL) { expr.value = error_mark_node; 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, NULL, NULL); expr.value = objc_build_encode_expr (type); } break; default: c_parser_error (parser, "expected expression"); expr.value = error_mark_node; break; } break; case CPP_OPEN_SQUARE: if (c_dialect_objc ()) { tree receiver, args; c_parser_consume_token (parser); receiver = c_parser_objc_receiver (parser); args = c_parser_objc_message_args (parser); c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); 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; break; } return c_parser_postfix_expression_after_primary (parser, loc, expr); } /* Parse a postfix expression after a parenthesized type name: the brace-enclosed initializer of a compound literal, possibly followed by some postfix operators. This is separate because it is not 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. 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, 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_expr, &type_expr_const); start_loc = c_parser_peek_token (parser)->location; if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) { 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 (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_Wpedantic, "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; 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); } /* Callback function for sizeof_pointer_memaccess_warning to compare types. */ static bool sizeof_ptr_memacc_comptypes (tree type1, tree type2) { return comptypes (type1, type2) == 1; } /* Parse a postfix expression after the initial primary or compound 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) { struct c_expr orig_expr; tree ident, idx; location_t sizeof_arg_loc[3]; tree sizeof_arg[3]; unsigned int i; vec *exprlist; vec *origtypes = NULL; while (true) { location_t op_loc = c_parser_peek_token (parser)->location; switch (c_parser_peek_token (parser)->type) { case CPP_OPEN_SQUARE: /* Array reference. */ c_parser_consume_token (parser); idx = c_parser_expression (parser).value; c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); 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); for (i = 0; i < 3; i++) { sizeof_arg[i] = NULL_TREE; sizeof_arg_loc[i] = UNKNOWN_LOCATION; } if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) exprlist = NULL; else exprlist = c_parser_expr_list (parser, true, false, &origtypes, sizeof_arg_loc, sizeof_arg); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); orig_expr = expr; mark_exp_read (expr.value); if (warn_sizeof_pointer_memaccess) sizeof_pointer_memaccess_warning (sizeof_arg_loc, expr.value, exprlist, sizeof_arg, sizeof_ptr_memacc_comptypes); /* 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) { 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_loc, expr); if (c_parser_next_token_is (parser, CPP_NAME)) ident = c_parser_peek_token (parser)->value; else { 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 (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_loc, expr); if (c_parser_next_token_is (parser, CPP_NAME)) ident = c_parser_peek_token (parser)->value; else { 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 (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_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_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; } } } /* Parse an expression (C90 6.3.17, C99 6.5.17). expression: assignment-expression expression , assignment-expression */ static struct c_expr c_parser_expression (c_parser *parser) { struct c_expr expr; expr = c_parser_expr_no_commas (parser, NULL); 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 (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; } /* Parse an expression and convert functions or arrays to pointers. */ 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 (loc, expr); return expr; } /* Parse a non-empty list of expressions. If CONVERT_P, convert functions and arrays to pointers. If FOLD_P, fold the expressions. nonempty-expr-list: assignment-expression nonempty-expr-list , assignment-expression */ static vec * c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, vec **p_orig_types, location_t *sizeof_arg_loc, tree *sizeof_arg) { vec *ret; vec *orig_types; struct c_expr expr; location_t loc = c_parser_peek_token (parser)->location; location_t cur_sizeof_arg_loc = UNKNOWN_LOCATION; unsigned int idx = 0; ret = make_tree_vector (); if (p_orig_types == NULL) orig_types = NULL; else orig_types = make_tree_vector (); if (sizeof_arg != NULL && c_parser_next_token_is_keyword (parser, RID_SIZEOF)) cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location; expr = c_parser_expr_no_commas (parser, NULL); if (convert_p) expr = default_function_array_read_conversion (loc, expr); if (fold_p) expr.value = c_fully_fold (expr.value, false, NULL); ret->quick_push (expr.value); if (orig_types) orig_types->quick_push (expr.original_type); if (sizeof_arg != NULL && cur_sizeof_arg_loc != UNKNOWN_LOCATION && expr.original_code == SIZEOF_EXPR) { sizeof_arg[0] = c_last_sizeof_arg; sizeof_arg_loc[0] = cur_sizeof_arg_loc; } while (c_parser_next_token_is (parser, CPP_COMMA)) { c_parser_consume_token (parser); loc = c_parser_peek_token (parser)->location; if (sizeof_arg != NULL && c_parser_next_token_is_keyword (parser, RID_SIZEOF)) cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location; else cur_sizeof_arg_loc = UNKNOWN_LOCATION; expr = c_parser_expr_no_commas (parser, NULL); if (convert_p) expr = default_function_array_read_conversion (loc, expr); if (fold_p) expr.value = c_fully_fold (expr.value, false, NULL); vec_safe_push (ret, expr.value); if (orig_types) vec_safe_push (orig_types, expr.original_type); if (++idx < 3 && sizeof_arg != NULL && cur_sizeof_arg_loc != UNKNOWN_LOCATION && expr.original_code == SIZEOF_EXPR) { sizeof_arg[idx] = c_last_sizeof_arg; sizeof_arg_loc[idx] = cur_sizeof_arg_loc; } } if (orig_types) *p_orig_types = orig_types; return ret; } /* Parse Objective-C-specific constructs. */ /* Parse an objc-class-definition. objc-class-definition: @interface identifier objc-superclass[opt] objc-protocol-refs[opt] objc-class-instance-variables[opt] objc-methodprotolist @end @implementation identifier objc-superclass[opt] 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: : identifier "@interface identifier (" must start "@interface identifier ( identifier ) ...": objc-methodprotolist in the first production may not start with a parenthesized identifier as a declarator of a data definition with no declaration specifiers if the objc-superclass, objc-protocol-refs and objc-class-instance-variables are omitted. */ static void c_parser_objc_class_definition (c_parser *parser, tree attributes) { bool iface_p; tree id1; tree superclass; if (c_parser_next_token_is_keyword (parser, RID_AT_INTERFACE)) iface_p = true; else if (c_parser_next_token_is_keyword (parser, RID_AT_IMPLEMENTATION)) iface_p = false; else gcc_unreachable (); c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); return; } id1 = c_parser_peek_token (parser)->value; 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)) { if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { /* We have a class extension. */ id2 = NULL_TREE; } else { c_parser_error (parser, "expected identifier or %<)%>"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return; } } else { id2 = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); if (!iface_p) { objc_start_category_implementation (id1, id2); return; } if (c_parser_next_token_is (parser, CPP_LESS)) proto = c_parser_objc_protocol_refs (parser); 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 (); return; } if (c_parser_next_token_is (parser, CPP_COLON)) { c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); return; } superclass = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); } else superclass = NULL_TREE; if (iface_p) { 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, attributes); } else objc_start_class_implementation (id1, superclass); if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) c_parser_objc_class_instance_variables (parser); if (iface_p) { objc_continue_interface (); c_parser_objc_methodprotolist (parser); c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); objc_finish_interface (); } else { objc_continue_implementation (); return; } } /* Parse objc-class-instance-variables. objc-class-instance-variables: { objc-instance-variable-decl-list[opt] } objc-instance-variable-decl-list: objc-visibility-spec objc-instance-variable-decl ; ; objc-instance-variable-decl-list objc-visibility-spec objc-instance-variable-decl-list objc-instance-variable-decl ; objc-instance-variable-decl-list ; objc-visibility-spec: @private @protected @public objc-instance-variable-decl: struct-declaration */ static void c_parser_objc_class_instance_variables (c_parser *parser) { gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); c_parser_consume_token (parser); while (c_parser_next_token_is_not (parser, CPP_EOF)) { tree decls; /* Parse any stray semicolon. */ if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "extra semicolon"); c_parser_consume_token (parser); continue; } /* Stop if at the end of the instance variables. */ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { c_parser_consume_token (parser); break; } /* Parse any objc-visibility-spec. */ if (c_parser_next_token_is_keyword (parser, RID_AT_PRIVATE)) { c_parser_consume_token (parser); objc_set_visibility (OBJC_IVAR_VIS_PRIVATE); continue; } else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED)) { c_parser_consume_token (parser); objc_set_visibility (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 (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)) { c_parser_pragma (parser, pragma_external); continue; } /* Parse some comma-separated declarations. */ decls = c_parser_struct_declaration (parser); 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 %<;%>"); } } /* Parse an objc-class-declaration. objc-class-declaration: @class identifier-list ; */ static void c_parser_objc_class_declaration (c_parser *parser) { gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_CLASS)); c_parser_consume_token (parser); /* Any identifiers, including those declared as type names, are OK here. */ while (true) { tree id; 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; } id = c_parser_peek_token (parser)->value; objc_declare_class (id); 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 %<;%>"); } /* Parse an objc-alias-declaration. objc-alias-declaration: @compatibility_alias identifier identifier ; */ static void c_parser_objc_alias_declaration (c_parser *parser) { tree id1, id2; gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_ALIAS)); 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); return; } id1 = c_parser_peek_token (parser)->value; 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); return; } id2 = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); objc_declare_alias (id1, id2); } /* Parse an objc-protocol-definition. objc-protocol-definition: @protocol identifier objc-protocol-refs[opt] objc-methodprotolist @end @protocol identifier-list ; "@protocol identifier ;" should be resolved as "@protocol identifier-list ;": objc-methodprotolist may not start with a semicolon in the first alternative if objc-protocol-refs are omitted. */ static void 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)) { c_parser_error (parser, "expected identifier"); return; } if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA || c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON) { /* Any identifiers, including those declared as type names, are OK here. */ while (true) { tree id; if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); break; } id = c_parser_peek_token (parser)->value; objc_declare_protocol (id, attributes); 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 %<;%>"); } else { tree id = c_parser_peek_token (parser)->value; tree proto = NULL_TREE; c_parser_consume_token (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, attributes); c_parser_objc_methodprotolist (parser); c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); parser->objc_pq_context = false; objc_finish_interface (); } } /* Parse an objc-method-type. objc-method-type: + - 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 true; case CPP_MINUS: c_parser_consume_token (parser); return false; default: gcc_unreachable (); } } /* Parse an objc-method-definition. objc-method-definition: objc-method-type objc-method-decl ;[opt] compound-statement */ static void c_parser_objc_method_definition (c_parser *parser) { 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, 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); pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "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; 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. objc-methodprotolist: empty 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 other data definitions outside functions, and the stray semicolon is diagnosed the same way as a stray semicolon outside a function. */ static void c_parser_objc_methodprotolist (c_parser *parser) { while (true) { /* The list is terminated by @end. */ switch (c_parser_peek_token (parser)->type) { case CPP_SEMICOLON: pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "ISO C does not allow extra %<;%> outside of a function"); c_parser_consume_token (parser); break; case CPP_PLUS: case CPP_MINUS: c_parser_objc_methodproto (parser); break; case CPP_PRAGMA: c_parser_pragma (parser, pragma_external); break; case CPP_EOF: return; default: if (c_parser_next_token_is_keyword (parser, RID_AT_END)) return; else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)) c_parser_objc_at_property_declaration (parser); else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL)) { objc_set_method_opt (true); 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; } } } /* Parse an objc-methodproto. objc-methodproto: objc-method-type objc-method-decl ; */ static void c_parser_objc_methodproto (c_parser *parser) { 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, is_class_method, &attributes, NULL); /* Forget protocol qualifiers now. */ parser->objc_pq_context = false; /* 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: ( objc-type-name ) objc-selector objc-selector ( objc-type-name ) objc-keyword-selector objc-optparmlist objc-keyword-selector objc-optparmlist attributes objc-keyword-selector: objc-keyword-decl objc-keyword-selector objc-keyword-decl objc-keyword-decl: objc-selector : ( objc-type-name ) identifier objc-selector : identifier : ( objc-type-name ) identifier : identifier objc-optparmlist: objc-optparms objc-optellipsis objc-optparms: empty objc-opt-parms , parameter-declaration objc-optellipsis: empty , ... */ static tree 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); type = c_parser_objc_type_name (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } sel = c_parser_objc_selector (parser); /* If there is no selector, or a colon follows, we have an objc-keyword-selector. If there is a selector, and a colon does not follow, that selector ends the objc-method-decl. */ if (!sel || c_parser_next_token_is (parser, CPP_COLON)) { tree tsel = sel; tree list = NULL_TREE; 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)) { c_parser_consume_token (parser); atype = c_parser_objc_type_name (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"); return error_mark_node; } id = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); 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. */ parms = make_node (TREE_LIST); while (c_parser_next_token_is (parser, CPP_COMMA)) { struct c_parm *parm; c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) { 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, expr))); } sel = list; } 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. objc-type-name: objc-type-qualifiers[opt] type-name objc-type-qualifiers[opt] objc-type-qualifiers: objc-type-qualifier objc-type-qualifiers objc-type-qualifier objc-type-qualifier: one of in out inout bycopy byref oneway */ static tree c_parser_objc_type_name (c_parser *parser) { tree quals = NULL_TREE; struct c_type_name *type_name = NULL; tree type = NULL_TREE; while (true) { c_token *token = c_parser_peek_token (parser); if (token->type == CPP_KEYWORD && (token->keyword == RID_IN || token->keyword == RID_OUT || token->keyword == RID_INOUT || token->keyword == RID_BYCOPY || token->keyword == RID_BYREF || token->keyword == RID_ONEWAY)) { quals = chainon (build_tree_list (NULL_TREE, token->value), quals); c_parser_consume_token (parser); } else break; } 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); } /* Parse objc-protocol-refs. objc-protocol-refs: < identifier-list > */ static tree c_parser_objc_protocol_refs (c_parser *parser) { tree list = NULL_TREE; gcc_assert (c_parser_next_token_is (parser, CPP_LESS)); c_parser_consume_token (parser); /* Any identifiers, including those declared as type names, are OK here. */ while (true) { tree id; if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); break; } id = c_parser_peek_token (parser)->value; list = chainon (list, build_tree_list (NULL_TREE, id)); c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); else break; } c_parser_require (parser, CPP_GREATER, "expected %<>%>"); return list; } /* Parse an objc-try-catch-finally-statement. objc-try-catch-finally-statement: @try compound-statement objc-catch-list[opt] @try compound-statement objc-catch-list[opt] @finally compound-statement objc-catch-list: @catch ( 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_finally_statement (c_parser *parser) { location_t location; tree stmt; gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY)); c_parser_consume_token (parser); location = c_parser_peek_token (parser)->location; objc_maybe_warn_exceptions (location); stmt = c_parser_compound_statement (parser); 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 %<(%>")) seen_open_paren = true; if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) { /* We have "@catch (...)" (where the '...' are literally what is in the code). Skip the '...'. parameter_declaration is set to NULL_TREE, and objc_being_catch_clauses() knows that that means '...'. */ c_parser_consume_token (parser); parameter_declaration = NULL_TREE; } else { /* We have "@catch (NSException *exception)" or something like that. Parse the parameter declaration. */ parm = c_parser_parameter_declaration (parser, NULL_TREE); if (parm == NULL) parameter_declaration = error_mark_node; else parameter_declaration = grokparm (parm, 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)) { c_parser_consume_token (parser); location = c_parser_peek_token (parser)->location; stmt = c_parser_compound_statement (parser); objc_build_finally_clause (location, stmt); } objc_finish_try_stmt (); } /* Parse an objc-synchronized-statement. objc-synchronized-statement: @synchronized ( expression ) compound-statement */ static void c_parser_objc_synchronized_statement (c_parser *parser) { location_t loc; tree expr, stmt; gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED)); c_parser_consume_token (parser); loc = c_parser_peek_token (parser)->location; objc_maybe_warn_exceptions (loc); if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr = c_parser_expression (parser).value; expr = c_fully_fold (expr, false, NULL); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } else expr = error_mark_node; stmt = c_parser_compound_statement (parser); objc_build_synchronized (loc, expr, stmt); } /* Parse an objc-selector; return NULL_TREE without an error if the next token is not an objc-selector. objc-selector: identifier one of enum struct union if else while do for switch case default break continue return goto asm sizeof typeof __alignof unsigned long const short volatile signed restrict _Complex in out inout bycopy byref oneway int char float double void _Bool ??? Why this selection of keywords but not, for example, storage class specifiers? */ static tree c_parser_objc_selector (c_parser *parser) { c_token *token = c_parser_peek_token (parser); tree value = token->value; if (token->type == CPP_NAME) { c_parser_consume_token (parser); return value; } if (token->type != CPP_KEYWORD) return NULL_TREE; switch (token->keyword) { case RID_ENUM: case RID_STRUCT: case RID_UNION: case RID_IF: case RID_ELSE: case RID_WHILE: case RID_DO: case RID_FOR: case RID_SWITCH: case RID_CASE: case RID_DEFAULT: case RID_BREAK: case RID_CONTINUE: case RID_RETURN: case RID_GOTO: case RID_ASM: case RID_SIZEOF: case RID_TYPEOF: case RID_ALIGNOF: case RID_UNSIGNED: case RID_LONG: case RID_INT128: case RID_CONST: case RID_SHORT: case RID_VOLATILE: case RID_SIGNED: case RID_RESTRICT: case RID_COMPLEX: case RID_IN: case RID_OUT: case RID_INOUT: case RID_BYCOPY: case RID_BYREF: case RID_ONEWAY: case RID_INT: case RID_CHAR: case RID_FLOAT: case RID_DOUBLE: case RID_VOID: case RID_BOOL: c_parser_consume_token (parser); return value; default: return NULL_TREE; } } /* Parse an objc-selector-arg. objc-selector-arg: objc-selector objc-keywordname-list objc-keywordname-list: objc-keywordname objc-keywordname-list objc-keywordname objc-keywordname: objc-selector : : */ static tree c_parser_objc_selector_arg (c_parser *parser) { tree sel = c_parser_objc_selector (parser); tree list = NULL_TREE; if (sel && c_parser_next_token_is_not (parser, CPP_COLON)) return sel; while (true) { if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) return list; list = chainon (list, build_tree_list (sel, NULL_TREE)); sel = c_parser_objc_selector (parser); if (!sel && c_parser_next_token_is_not (parser, CPP_COLON)) break; } return list; } /* Parse an objc-receiver. objc-receiver: expression class-name type-name */ static tree c_parser_objc_receiver (c_parser *parser) { if (c_parser_peek_token (parser)->type == CPP_NAME && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) { tree id = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); return objc_get_class_reference (id); } return c_fully_fold (c_parser_expression (parser).value, false, NULL); } /* Parse objc-message-args. objc-message-args: objc-selector objc-keywordarg-list objc-keywordarg-list: objc-keywordarg objc-keywordarg-list objc-keywordarg objc-keywordarg: objc-selector : objc-keywordexpr : objc-keywordexpr */ static tree c_parser_objc_message_args (c_parser *parser) { tree sel = c_parser_objc_selector (parser); tree list = NULL_TREE; if (sel && c_parser_next_token_is_not (parser, CPP_COLON)) return sel; while (true) { tree keywordexpr; if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) return error_mark_node; keywordexpr = c_parser_objc_keywordexpr (parser); list = chainon (list, build_tree_list (sel, keywordexpr)); sel = c_parser_objc_selector (parser); if (!sel && c_parser_next_token_is_not (parser, CPP_COLON)) break; } return list; } /* Parse an objc-keywordexpr. objc-keywordexpr: nonempty-expr-list */ static tree c_parser_objc_keywordexpr (c_parser *parser) { tree ret; vec *expr_list = c_parser_expr_list (parser, true, true, NULL, NULL, NULL); if (vec_safe_length (expr_list) == 1) { /* Just return the expression, remove a level of indirection. */ ret = (*expr_list)[0]; } else { /* We have a comma expression, we will collapse later. */ ret = build_tree_list_vec (expr_list); } release_tree_vector (expr_list); return ret; } /* A check, needed in several places, that ObjC interface, implementation or method definitions are not prefixed by incorrect items. */ static bool c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, struct c_declspecs *specs) { if (!specs->declspecs_seen_p || specs->non_sc_seen_p || specs->typespec_kind != ctsk_none) { c_parser_error (parser, "no type or storage class may be specified here,"); c_parser_skip_to_end_of_block_or_statement (parser); return true; } return false; } /* Parse an Objective-C @property declaration. The syntax is: objc-property-declaration: '@property' objc-property-attributes[opt] struct-declaration ; objc-property-attributes: '(' objc-property-attribute-list ')' objc-property-attribute-list: objc-property-attribute objc-property-attribute-list, objc-property-attribute objc-property-attribute 'getter' = identifier 'setter' = identifier 'readonly' 'readwrite' 'assign' 'retain' 'copy' 'nonatomic' For example: @property NSString *name; @property (readonly) id object; @property (retain, nonatomic, getter=getTheName) id name; @property int a, b, c; PS: This function is identical to cp_parser_objc_at_propery_declaration for C++. Keep them in sync. */ static void c_parser_objc_at_property_declaration (c_parser *parser) { /* The following variables hold the attributes of the properties as parsed. They are 'false' or 'NULL_TREE' if the attribute was not seen. When we see an attribute, we set them to 'true' (if they are boolean properties) or to the identifier (if they have an argument, ie, for getter and setter). Note that here we only parse the list of attributes, check the syntax and accumulate the attributes that we find. objc_add_property_declaration() will then process the information. */ bool property_assign = false; bool property_copy = false; tree property_getter_ident = NULL_TREE; bool property_nonatomic = false; bool property_readonly = false; bool property_readwrite = false; bool property_retain = false; tree property_setter_ident = NULL_TREE; /* 'properties' is the list of properties that we read. Usually a single one, but maybe more (eg, in "@property int a, b, c;" there are three). */ tree properties; location_t loc; loc = c_parser_peek_token (parser)->location; gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)); c_parser_consume_token (parser); /* Eat '@property'. */ /* Parse the optional attribute list... */ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { /* Eat the '(' */ c_parser_consume_token (parser); /* Property attribute keywords are valid now. */ parser->objc_property_attr_context = true; while (true) { bool syntax_error = false; c_token *token = c_parser_peek_token (parser); enum rid keyword; if (token->type != CPP_KEYWORD) { if (token->type == CPP_CLOSE_PAREN) c_parser_error (parser, "expected identifier"); else { c_parser_consume_token (parser); c_parser_error (parser, "unknown property attribute"); } break; } keyword = token->keyword; c_parser_consume_token (parser); switch (keyword) { case RID_ASSIGN: property_assign = true; break; case RID_COPY: property_copy = true; break; case RID_NONATOMIC: property_nonatomic = true; break; case RID_READONLY: property_readonly = true; break; case RID_READWRITE: property_readwrite = true; break; case RID_RETAIN: property_retain = true; break; case RID_GETTER: case RID_SETTER: if (c_parser_next_token_is_not (parser, CPP_EQ)) { if (keyword == RID_GETTER) c_parser_error (parser, "missing %<=%> (after % 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); return false; case PRAGMA_OMP_FLUSH: if (context != pragma_compound) { if (context == pragma_stmt) c_parser_error (parser, "%<#pragma omp flush%> may only be " "used in compound statements"); goto bad_stmt; } 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_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; case PRAGMA_GCC_PCH_PREPROCESS: c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; default: if (id < PRAGMA_FIRST_EXTERNAL) { if (context == pragma_external) { bad_stmt: c_parser_error (parser, "expected declaration specifiers"); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; } c_parser_omp_construct (parser); return true; } break; } c_parser_consume_pragma (parser); c_invoke_pragma_handler (id); /* 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; c_parser_skip_to_pragma_eol (parser); return false; } /* The interface the pragma parsers have to the lexer. */ enum cpp_ttype pragma_lex (tree *value) { c_token *tok = c_parser_peek_token (the_parser); enum cpp_ttype ret = tok->type; *value = tok->value; if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) ret = CPP_EOF; else { if (ret == CPP_KEYWORD) ret = CPP_NAME; c_parser_consume_token (the_parser); } return ret; } static void c_parser_pragma_pch_preprocess (c_parser *parser) { tree name = NULL; c_parser_consume_pragma (parser); if (c_parser_next_token_is (parser, CPP_STRING)) { name = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); } else c_parser_error (parser, "expected string literal"); c_parser_skip_to_pragma_eol (parser); if (name) c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); } /* OpenMP 2.5 parsing routines. */ /* Returns name of the next clause. If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and the token is not consumed. Otherwise appropriate pragma_omp_clause is returned and the token is consumed. */ static pragma_omp_clause c_parser_omp_clause_name (c_parser *parser) { pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; if (c_parser_next_token_is_keyword (parser, RID_IF)) result = PRAGMA_OMP_CLAUSE_IF; else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) result = PRAGMA_OMP_CLAUSE_DEFAULT; else if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); switch (p[0]) { case 'c': 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 ("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; else if (!strcmp ("num_threads", p)) result = PRAGMA_OMP_CLAUSE_NUM_THREADS; break; case 'o': if (!strcmp ("ordered", p)) result = PRAGMA_OMP_CLAUSE_ORDERED; break; case 'p': if (!strcmp ("private", p)) result = PRAGMA_OMP_CLAUSE_PRIVATE; break; case 'r': if (!strcmp ("reduction", p)) result = PRAGMA_OMP_CLAUSE_REDUCTION; break; case 's': if (!strcmp ("schedule", p)) result = PRAGMA_OMP_CLAUSE_SCHEDULE; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; break; case 'u': if (!strcmp ("untied", p)) result = PRAGMA_OMP_CLAUSE_UNTIED; break; } } if (result != PRAGMA_OMP_CLAUSE_NONE) c_parser_consume_token (parser); return result; } /* Validate that a clause of the given type does not already exist. */ static void 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) { location_t loc = OMP_CLAUSE_LOCATION (c); error_at (loc, "too many %qs clauses", name); break; } } /* OpenMP 2.5: variable-list: 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, 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, location_t clause_loc, enum omp_clause_code kind, tree list) { if (c_parser_next_token_is_not (parser, CPP_NAME) || c_parser_peek_token (parser)->id_kind != C_ID_ID) c_parser_error (parser, "expected identifier"); while (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_token (parser)->id_kind == C_ID_ID) { tree t = lookup_name (c_parser_peek_token (parser)->value); if (t == NULL_TREE) 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 (clause_loc, kind); OMP_CLAUSE_DECL (u) = t; OMP_CLAUSE_CHAIN (u) = list; list = u; } else list = tree_cons (t, NULL_TREE, list); c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_COMMA)) break; c_parser_consume_token (parser); } return list; } /* Similarly, but expect leading and trailing parenthesis. This is a very common case for omp clauses. */ static tree 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, 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 ) */ static tree c_parser_omp_clause_copyin (c_parser *parser, tree list) { return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list); } /* OpenMP 2.5: copyprivate ( variable-list ) */ static tree c_parser_omp_clause_copyprivate (c_parser *parser, tree list) { return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list); } /* OpenMP 2.5: default ( shared | none ) */ 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 %<(%>")) return list; if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); switch (p[0]) { case 'n': if (strcmp ("none", p) != 0) goto invalid_kind; kind = OMP_CLAUSE_DEFAULT_NONE; break; case 's': if (strcmp ("shared", p) != 0) goto invalid_kind; kind = OMP_CLAUSE_DEFAULT_SHARED; break; default: goto invalid_kind; } c_parser_consume_token (parser); } else { invalid_kind: c_parser_error (parser, "expected % or %"); } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) return list; check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default"); c = build_omp_clause (loc, OMP_CLAUSE_DEFAULT); OMP_CLAUSE_CHAIN (c) = list; OMP_CLAUSE_DEFAULT_KIND (c) = kind; return c; } /* OpenMP 2.5: firstprivate ( variable-list ) */ static tree 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); tree c; check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if"); c = build_omp_clause (loc, OMP_CLAUSE_IF); OMP_CLAUSE_IF_EXPR (c) = t; OMP_CLAUSE_CHAIN (c) = list; list = c; } else c_parser_error (parser, "expected %<(%>"); return list; } /* OpenMP 2.5: lastprivate ( variable-list ) */ static tree 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 */ 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 (loc, OMP_CLAUSE_NOWAIT); OMP_CLAUSE_CHAIN (c) = list; return c; } /* OpenMP 2.5: num_threads ( expression ) */ 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 %<)%>"); if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { c_parser_error (parser, "expected integer expression"); return list; } /* Attempt to statically determine when the number isn't positive. */ 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_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 (num_threads_loc, OMP_CLAUSE_NUM_THREADS); OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; OMP_CLAUSE_CHAIN (c) = list; list = c; } return list; } /* OpenMP 2.5: ordered */ static tree 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 (c_parser_peek_token (parser)->location, OMP_CLAUSE_ORDERED); OMP_CLAUSE_CHAIN (c) = list; return c; } /* OpenMP 2.5: private ( variable-list ) */ static tree c_parser_omp_clause_private (c_parser *parser, tree list) { return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list); } /* OpenMP 2.5: reduction ( reduction-operator : variable-list ) reduction-operator: 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; switch (c_parser_peek_token (parser)->type) { case CPP_PLUS: code = PLUS_EXPR; break; case CPP_MULT: code = MULT_EXPR; break; case CPP_MINUS: code = MINUS_EXPR; break; case CPP_AND: code = BIT_AND_EXPR; break; case CPP_XOR: code = BIT_XOR_EXPR; break; case CPP_OR: code = BIT_IOR_EXPR; break; case CPP_AND_AND: code = TRUTH_ANDIF_EXPR; break; 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 %"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); return list; } c_parser_consume_token (parser); if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) { tree nl, c; 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; list = nl; } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } return list; } /* OpenMP 2.5: schedule ( schedule-kind ) schedule ( schedule-kind , expression ) schedule-kind: 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 (loc, OMP_CLAUSE_SCHEDULE); if (c_parser_next_token_is (parser, CPP_NAME)) { tree kind = c_parser_peek_token (parser)->value; const char *p = IDENTIFIER_POINTER (kind); switch (p[0]) { case 'd': if (strcmp ("dynamic", p) != 0) goto invalid_kind; OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC; break; case 'g': if (strcmp ("guided", p) != 0) goto invalid_kind; OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED; break; case 'r': if (strcmp ("runtime", p) != 0) goto invalid_kind; OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME; break; default: goto invalid_kind; } } 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; c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_COMMA)) { location_t here; c_parser_consume_token (parser); 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_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 c_parser_error (parser, "expected integer expression"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } else c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<,%> or %<)%>"); check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule"); OMP_CLAUSE_CHAIN (c) = list; return c; invalid_kind: c_parser_error (parser, "invalid schedule kind"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); return list; } /* OpenMP 2.5: shared ( variable-list ) */ static tree 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. */ static tree c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, const char *where) { tree clauses = NULL; bool first = true; while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) { location_t here; pragma_omp_clause c_kind; const char *c_name; tree prev = clauses; if (!first && c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); first = false; here = c_parser_peek_token (parser)->location; c_kind = c_parser_omp_clause_name (parser); 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"; break; case PRAGMA_OMP_CLAUSE_COPYPRIVATE: clauses = c_parser_omp_clause_copyprivate (parser, clauses); c_name = "copyprivate"; break; case PRAGMA_OMP_CLAUSE_DEFAULT: clauses = c_parser_omp_clause_default (parser, clauses); c_name = "default"; break; case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: 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"; break; case PRAGMA_OMP_CLAUSE_LASTPRIVATE: 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"; break; case PRAGMA_OMP_CLAUSE_NUM_THREADS: clauses = c_parser_omp_clause_num_threads (parser, clauses); c_name = "num_threads"; break; case PRAGMA_OMP_CLAUSE_ORDERED: clauses = c_parser_omp_clause_ordered (parser, clauses); c_name = "ordered"; break; case PRAGMA_OMP_CLAUSE_PRIVATE: clauses = c_parser_omp_clause_private (parser, clauses); c_name = "private"; break; case PRAGMA_OMP_CLAUSE_REDUCTION: clauses = c_parser_omp_clause_reduction (parser, clauses); c_name = "reduction"; break; case PRAGMA_OMP_CLAUSE_SCHEDULE: clauses = c_parser_omp_clause_schedule (parser, clauses); c_name = "schedule"; break; case PRAGMA_OMP_CLAUSE_SHARED: 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; } if (((mask >> c_kind) & 1) == 0 && !parser->error) { /* Remove the invalid clause(s) from the list to avoid confusing the rest of the compiler. */ clauses = prev; error_at (here, "%qs is not valid for %qs", c_name, where); } } saw_error: c_parser_skip_to_pragma_eol (parser); return c_finish_omp_clauses (clauses); } /* OpenMP 2.5: structured-block: statement In practice, we're also interested in adding the statement to an outer node. So it is convenient if we work around the fact that c_parser_statement calls add_stmt. */ static tree c_parser_omp_structured_block (c_parser *parser) { tree stmt = push_stmt_list (); c_parser_statement (parser); return pop_stmt_list (stmt); } /* OpenMP 2.5: # pragma omp atomic new-line expression-stmt expression-stmt: x binop= expr | x++ | ++x | x-- | --x binop: +, *, -, /, &, ^, |, <<, >> where x is an lvalue expression with scalar type. OpenMP 3.1: # pragma omp atomic new-line update-stmt # pragma omp atomic read new-line read-stmt # pragma omp atomic write new-line write-stmt # pragma omp atomic update new-line update-stmt # pragma omp atomic capture new-line capture-stmt # pragma omp atomic capture new-line capture-block read-stmt: v = x write-stmt: x = expr update-stmt: expression-stmt | x = x binop expr capture-stmt: v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x capture-block: { v = x; update-stmt; } | { update-stmt; v = x; } where x and v are lvalue expressions with scalar type. LOC is the location of the #pragma token. */ static void c_parser_omp_atomic (location_t loc, c_parser *parser) { tree lhs = 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 POSTINCREMENT_EXPR: if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) code = OMP_ATOMIC_CAPTURE_OLD; /* FALLTHROUGH */ case PREINCREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); opcode = PLUS_EXPR; rhs = integer_one_node; break; 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); 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: opcode = MULT_EXPR; break; case CPP_DIV_EQ: opcode = TRUNC_DIV_EXPR; break; case CPP_PLUS_EQ: opcode = PLUS_EXPR; break; case CPP_MINUS_EQ: opcode = MINUS_EXPR; break; case CPP_LSHIFT_EQ: opcode = LSHIFT_EXPR; break; case CPP_RSHIFT_EQ: opcode = RSHIFT_EXPR; break; case CPP_AND_EQ: opcode = BIT_AND_EXPR; break; case CPP_OR_EQ: opcode = BIT_IOR_EXPR; break; case CPP_XOR_EQ: opcode = BIT_XOR_EXPR; break; case CPP_EQ: if (structured_block || code == OMP_ATOMIC) { location_t aloc = c_parser_peek_token (parser)->location; location_t rhs_loc; enum c_parser_prec oprec = PREC_NONE; c_parser_consume_token (parser); rhs1 = c_parser_unary_expression (parser).value; rhs1 = c_fully_fold (rhs1, false, NULL); if (rhs1 == error_mark_node) goto saw_error; switch (c_parser_peek_token (parser)->type) { case CPP_SEMICOLON: if (code == OMP_ATOMIC_CAPTURE_NEW) { code = OMP_ATOMIC_CAPTURE_OLD; v = lhs; lhs = NULL_TREE; lhs1 = rhs1; rhs1 = NULL_TREE; c_parser_consume_token (parser); goto restart; } c_parser_error (parser, "invalid form of %<#pragma omp atomic%>"); goto saw_error; case CPP_MULT: opcode = MULT_EXPR; oprec = PREC_MULT; break; case CPP_DIV: opcode = TRUNC_DIV_EXPR; oprec = PREC_MULT; break; case CPP_PLUS: opcode = PLUS_EXPR; oprec = PREC_ADD; break; case CPP_MINUS: opcode = MINUS_EXPR; oprec = PREC_ADD; break; case CPP_LSHIFT: opcode = LSHIFT_EXPR; oprec = PREC_SHIFT; break; case CPP_RSHIFT: opcode = RSHIFT_EXPR; oprec = PREC_SHIFT; break; case CPP_AND: opcode = BIT_AND_EXPR; oprec = PREC_BITAND; break; case CPP_OR: opcode = BIT_IOR_EXPR; oprec = PREC_BITOR; break; case CPP_XOR: opcode = BIT_XOR_EXPR; oprec = PREC_BITXOR; break; default: c_parser_error (parser, "invalid operator for %<#pragma omp atomic%>"); goto saw_error; } loc = aloc; c_parser_consume_token (parser); rhs_loc = c_parser_peek_token (parser)->location; if (commutative_tree_code (opcode)) oprec = (enum c_parser_prec) (oprec - 1); rhs_expr = c_parser_binary_expression (parser, NULL, oprec); rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr); rhs = rhs_expr.value; rhs = c_fully_fold (rhs, false, NULL); goto stmt_done; } /* FALLTHROUGH */ default: c_parser_error (parser, "invalid operator for %<#pragma omp atomic%>"); goto saw_error; } /* Arrange to pass the location of the assignment operator to c_finish_omp_atomic. */ loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); { location_t rhs_loc = c_parser_peek_token (parser)->location; 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_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); if (!structured_block) c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } /* OpenMP 2.5: # pragma omp barrier new-line */ 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 (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 (location_t loc, c_parser *parser) { tree stmt, name = NULL; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_NAME)) { name = c_parser_peek_token (parser)->value; c_parser_consume_token (parser); c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } else c_parser_error (parser, "expected identifier"); } 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); stmt = c_parser_omp_structured_block (parser); return c_finish_omp_critical (loc, stmt, name); } /* OpenMP 2.5: # pragma omp flush flush-vars[opt] new-line flush-vars: ( variable-list ) */ 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, 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 (loc); } /* 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. LOC is the location of the OMP in "#pragma omp". */ static tree 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, 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 *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; } for_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); for (i = 0; i < collapse; i++) { 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 (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_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; } /* 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 %<;%>"); /* 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; 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; } 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 (); 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) { 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 (!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 (!for_block->is_empty ()) { /* 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, for_block->pop (), 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 \ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ | (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 (location_t loc, c_parser *parser) { tree block, clauses, ret; clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, "#pragma omp for"); block = c_begin_compound_stmt (true); ret = c_parser_omp_for_loop (loc, parser, clauses, NULL); block = c_end_compound_stmt (loc, block, true); add_stmt (block); return ret; } /* OpenMP 2.5: # pragma omp master new-line structured-block LOC is the location of the #pragma token. */ static tree c_parser_omp_master (location_t loc, c_parser *parser) { c_parser_skip_to_pragma_eol (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 (location_t loc, c_parser *parser) { c_parser_skip_to_pragma_eol (parser); return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser)); } /* OpenMP 2.5: section-scope: { section-sequence } section-sequence: section-directive[opt] 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 (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. */ parser->error = false; return NULL_TREE; } stmt = push_stmt_list (); if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION) { substmt = push_stmt_list (); while (1) { c_parser_statement (parser); if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) break; if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) break; if (c_parser_next_token_is (parser, CPP_EOF)) break; } substmt = pop_stmt_list (substmt); substmt = build1 (OMP_SECTION, void_type_node, substmt); SET_EXPR_LOCATION (substmt, loc); add_stmt (substmt); } while (1) { if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) break; if (c_parser_next_token_is (parser, CPP_EOF)) break; loc = c_parser_peek_token (parser)->location; if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) { c_parser_consume_pragma (parser); c_parser_skip_to_pragma_eol (parser); error_suppress = false; } else if (!error_suppress) { error_at (loc, "expected %<#pragma omp section%> or %<}%>"); error_suppress = true; } substmt = c_parser_omp_structured_block (parser); substmt = build1 (OMP_SECTION, void_type_node, substmt); SET_EXPR_LOCATION (substmt, loc); add_stmt (substmt); } c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<#pragma omp section%> or %<}%>"); 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; return add_stmt (stmt); } /* 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 \ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree c_parser_omp_sections (location_t loc, c_parser *parser) { tree block, clauses, ret; clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, "#pragma omp sections"); block = c_begin_compound_stmt (true); ret = c_parser_omp_sections_scope (loc, parser); if (ret) OMP_SECTIONS_CLAUSES (ret) = clauses; block = c_end_compound_stmt (loc, block, true); add_stmt (block); return ret; } /* OpenMP 2.5: # 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 \ ( (1u << PRAGMA_OMP_CLAUSE_IF) \ | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) static tree 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"; tree stmt, clauses, par_clause, ws_clause, block; unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; if (c_parser_next_token_is_keyword (parser, RID_FOR)) { c_parser_consume_token (parser); p_kind = PRAGMA_OMP_PARALLEL_FOR; p_name = "#pragma omp parallel for"; mask |= OMP_FOR_CLAUSE_MASK; mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); } else if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); if (strcmp (p, "sections") == 0) { c_parser_consume_token (parser); p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; p_name = "#pragma omp parallel sections"; mask |= OMP_SECTIONS_CLAUSE_MASK; mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); } } clauses = c_parser_omp_all_clauses (parser, mask, p_name); switch (p_kind) { case PRAGMA_OMP_PARALLEL: block = c_begin_omp_parallel (); c_parser_statement (parser); stmt = c_finish_omp_parallel (loc, clauses, block); break; case PRAGMA_OMP_PARALLEL_FOR: block = c_begin_omp_parallel (); 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 (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 (loc, par_clause, block); OMP_PARALLEL_COMBINED (stmt) = 1; break; default: gcc_unreachable (); } return stmt; } /* 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 \ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree 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) = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, "#pragma omp single"); OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (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. */ static void c_parser_omp_construct (c_parser *parser) { enum pragma_kind p_kind; location_t loc; tree stmt; loc = c_parser_peek_token (parser)->location; p_kind = c_parser_peek_token (parser)->pragma_kind; c_parser_consume_pragma (parser); switch (p_kind) { case PRAGMA_OMP_ATOMIC: c_parser_omp_atomic (loc, parser); return; case PRAGMA_OMP_CRITICAL: stmt = c_parser_omp_critical (loc, parser); break; case PRAGMA_OMP_FOR: stmt = c_parser_omp_for (loc, parser); break; case PRAGMA_OMP_MASTER: stmt = c_parser_omp_master (loc, parser); break; case PRAGMA_OMP_ORDERED: stmt = c_parser_omp_ordered (loc, parser); break; case PRAGMA_OMP_PARALLEL: stmt = c_parser_omp_parallel (loc, parser); break; case PRAGMA_OMP_SECTIONS: stmt = c_parser_omp_sections (loc, parser); break; case PRAGMA_OMP_SINGLE: 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) gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION); } /* OpenMP 2.5: # pragma omp threadprivate (variable-list) */ static void c_parser_omp_threadprivate (c_parser *parser) { tree vars, t; location_t loc; c_parser_consume_pragma (parser); 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_at (loc, "%qD is not a variable", v); else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v)) error_at (loc, "%qE declared % after first use", v); else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (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_at (loc, "% %qE has incomplete type", v); else { if (! DECL_THREAD_LOCAL_P (v)) { DECL_TLS_MODEL (v) = decl_default_tls_model (v); /* If rtl has been already set for this var, call make_decl_rtl once again, so that encode_section_info has a chance to look at the new decl flags. */ if (DECL_RTL_SET_P (v)) make_decl_rtl (v); } C_DECL_THREADPRIVATE_P (v) = 1; } } 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. */ void c_parse_file (void) { /* Use local storage to begin. If the first token is a pragma, parse it. If it is #pragma GCC pch_preprocess, then this will load a PCH file which will cause garbage collection. */ c_parser tparser; memset (&tparser, 0, sizeof tparser); the_parser = &tparser; if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) c_parser_pragma_pch_preprocess (&tparser); 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; } #include "gt-c-c-parser.h"