| /* Parser for C and Objective-C. |
| Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, |
| 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 |
| 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 |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* 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" |
| #include "tree.h" |
| #include "rtl.h" |
| #include "langhooks.h" |
| #include "input.h" |
| #include "cpplib.h" |
| #include "timevar.h" |
| #include "c-pragma.h" |
| #include "c-tree.h" |
| #include "flags.h" |
| #include "output.h" |
| #include "toplev.h" |
| #include "ggc.h" |
| #include "c-common.h" |
| #include "vec.h" |
| #include "target.h" |
| #include "cgraph.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; |
| |
| 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_CNEWVEC (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, |
| /* Not an identifier. */ |
| C_ID_NONE |
| } c_id_kind; |
| |
| /* A single C token after string literal concatenation and conversion |
| of preprocessing tokens to tokens. */ |
| typedef struct c_token GTY (()) |
| { |
| /* 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 value associated with this token, if any. */ |
| tree value; |
| /* The location at which this token was found. */ |
| location_t location; |
| } c_token; |
| |
| /* A parser structure recording information about the state and |
| context of parsing. Includes lexer information with up to two |
| tokens of look-ahead; more are not needed for C. */ |
| typedef struct c_parser GTY(()) |
| { |
| /* 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. */ |
| BOOL_BITFIELD objc_pq_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; |
| } 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 %qs conflicts with C++ keyword", |
| IDENTIFIER_POINTER (token->value)); |
| } |
| else if (c_dialect_objc ()) |
| { |
| if (!objc_is_reserved_word (token->value) |
| && (!OBJC_IS_PQ_KEYWORD (rid_code) |
| || parser->objc_pq_context)) |
| { |
| /* Return the canonical spelling for this keyword. */ |
| token->value = ridpointers[(int) rid_code]; |
| token->type = CPP_KEYWORD; |
| token->keyword = rid_code; |
| break; |
| } |
| } |
| 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 |
| && (global_bindings_p () |
| || (!objc_force_identifier && !decl))) |
| { |
| 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; |
| 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 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_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_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; |
| } |
| } |
| |
| /* Return true if the next token from PARSER can start a type name, |
| false otherwise. */ |
| static inline bool |
| c_parser_next_token_starts_typename (c_parser *parser) |
| { |
| c_token *token = c_parser_peek_token (parser); |
| return c_token_starts_typename (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_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_AUTO: |
| case RID_THREAD: |
| case RID_UNSIGNED: |
| case RID_LONG: |
| 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; |
| } |
| } |
| |
| /* 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); |
| return c_token_starts_declspecs (token); |
| } |
| |
| /* Return a pointer to the next-but-one token from PARSER, reading it |
| in if necessary. The next token is already read in. */ |
| |
| static c_token * |
| c_parser_peek_2nd_token (c_parser *parser) |
| { |
| if (parser->tokens_avail >= 2) |
| return &parser->tokens[1]; |
| gcc_assert (parser->tokens_avail == 1); |
| gcc_assert (parser->tokens[0].type != CPP_EOF); |
| gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL); |
| c_lex_one_token (parser, &parser->tokens[1]); |
| parser->tokens_avail = 2; |
| return &parser->tokens[1]; |
| } |
| |
| /* Consume the next token from PARSER. */ |
| |
| static void |
| 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), |
| token->value); |
| } |
| |
| /* 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) |
| | (cpp_opts->warn_long_long << 5)); |
| cpp_opts->pedantic = pedantic = 0; |
| warn_pointer_arith = 0; |
| cpp_opts->warn_traditional = warn_traditional = 0; |
| flag_iso = 0; |
| warn_long_long = 0; |
| cpp_opts->warn_long_long = 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->pedantic = pedantic = flags & 1; |
| warn_pointer_arith = (flags >> 1) & 1; |
| cpp_opts->warn_traditional = warn_traditional = (flags >> 2) & 1; |
| flag_iso = (flags >> 3) & 1; |
| warn_long_long = (flags >> 4) & 1; |
| cpp_opts->warn_long_long = (flags >> 5) & 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; |
| |
| static void c_parser_external_declaration (c_parser *); |
| static void c_parser_asm_definition (c_parser *); |
| static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, bool); |
| static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool, |
| bool); |
| 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 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); |
| static struct c_parm *c_parser_parameter_declaration (c_parser *, tree); |
| static tree c_parser_simple_asm_expr (c_parser *); |
| static tree c_parser_attributes (c_parser *); |
| static struct c_type_name *c_parser_type_name (c_parser *); |
| static struct c_expr c_parser_initializer (c_parser *); |
| static struct c_expr c_parser_braced_init (c_parser *, tree, bool); |
| static void c_parser_initelt (c_parser *); |
| static void c_parser_initval (c_parser *, struct c_expr *); |
| static 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 *, bool); |
| static tree c_parser_asm_clobbers (c_parser *); |
| static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *); |
| static struct c_expr c_parser_conditional_expression (c_parser *, |
| struct c_expr *); |
| static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *); |
| static struct c_expr c_parser_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 *); |
| static struct c_expr c_parser_postfix_expression_after_primary (c_parser *, |
| struct c_expr); |
| static struct c_expr c_parser_expression (c_parser *); |
| static struct c_expr c_parser_expression_conv (c_parser *); |
| static tree c_parser_expr_list (c_parser *, bool); |
| static 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 *); |
| |
| enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; |
| static bool c_parser_pragma (c_parser *, enum pragma_context); |
| |
| /* These Objective-C parser functions are only ever called when |
| compiling Objective-C. */ |
| static void c_parser_objc_class_definition (c_parser *); |
| static void c_parser_objc_class_instance_variables (c_parser *); |
| static void c_parser_objc_class_declaration (c_parser *); |
| static void c_parser_objc_alias_declaration (c_parser *); |
| static void c_parser_objc_protocol_definition (c_parser *); |
| static enum tree_code c_parser_objc_method_type (c_parser *); |
| static void c_parser_objc_method_definition (c_parser *); |
| static void c_parser_objc_methodprotolist (c_parser *); |
| static void c_parser_objc_methodproto (c_parser *); |
| static tree c_parser_objc_method_decl (c_parser *); |
| static tree c_parser_objc_type_name (c_parser *); |
| static tree c_parser_objc_protocol_refs (c_parser *); |
| static void c_parser_objc_try_catch_statement (c_parser *); |
| static void c_parser_objc_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 *); |
| |
| /* 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_pedantic, |
| "ISO C forbids an empty translation unit"); |
| } |
| else |
| { |
| void *obstack_position = obstack_alloc (&parser_obstack, 0); |
| 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); |
| break; |
| case RID_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); |
| 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_pedantic, |
| "ISO C does not allow extra %<;%> outside of a function"); |
| c_parser_consume_token (parser); |
| break; |
| case CPP_PRAGMA: |
| c_parser_pragma (parser, pragma_external); |
| 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. We can only tell |
| which after parsing the declaration specifiers, if any, and |
| the first declarator. */ |
| c_parser_declaration_or_fndef (parser, true, true, false, true); |
| break; |
| } |
| } |
| |
| |
| /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 |
| 6.7, 6.9.1). If FNDEF_OK is true, a function definition is |
| accepted; otherwise (old-style parameter declarations) only other |
| declarations are accepted. If NESTED is true, we are inside a |
| function or parsing old-style parameter declarations; any functions |
| encountered are nested functions and declaration specifiers are |
| required; otherwise we are at top level and functions are normal |
| functions and declaration specifiers may be optional. If EMPTY_OK |
| is true, empty declarations are OK (subject to all other |
| constraints); otherwise (old-style parameter declarations) they are |
| diagnosed. If START_ATTR_OK is true, the declaration specifiers |
| may start with attributes; otherwise they may not. |
| |
| declaration: |
| declaration-specifiers init-declarator-list[opt] ; |
| |
| 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 |
| |
| 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). |
| |
| OpenMP: |
| |
| declaration: |
| threadprivate-directive */ |
| |
| static void |
| c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, |
| bool nested, bool start_attr_ok) |
| { |
| 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; |
| |
| specs = build_null_declspecs (); |
| c_parser_declspecs (parser, specs, true, true, start_attr_ok); |
| 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; |
| } |
| 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; |
| tree fnbody; |
| /* Declaring either one or more declarators (in which case we |
| should diagnose if there were no declaration specifiers) or a |
| function definition (in which case the diagnostic for |
| implicit int suffices). */ |
| declarator = c_parser_declarator (parser, specs->type_seen_p, |
| 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)) |
| { |
| 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; |
| 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 = c_parser_initializer (parser); |
| finish_init (); |
| if (d != error_mark_node) |
| { |
| maybe_warn_string_init (TREE_TYPE (d), init); |
| finish_decl (d, init.value, asm_name); |
| } |
| } |
| else |
| { |
| tree d = start_decl (declarator, specs, false, |
| chainon (postfix_attrs, |
| all_prefix_attrs)); |
| if (d) |
| finish_decl (d, NULL_TREE, asm_name); |
| } |
| 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 |
| { |
| 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 %<=%>, %<,%>, %<;%>, " |
| "%<asm%> or %<__attribute__%>"); |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| } |
| /* Function definition (nested or otherwise). */ |
| if (nested) |
| { |
| pedwarn (here, OPT_pedantic, "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 %<=%>, %<,%>, %<;%>, %<asm%> " |
| "or %<__attribute__%>"); |
| if (nested) |
| c_pop_function_context (); |
| break; |
| } |
| /* 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, true, false); |
| 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; |
| add_stmt (fnbody); |
| finish_function (); |
| c_pop_function_context (); |
| add_stmt (build_stmt (DECL_EXPR, decl)); |
| } |
| else |
| { |
| add_stmt (fnbody); |
| finish_function (); |
| } |
| 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) |
| cgraph_add_asm_node (asm_str); |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| } |
| |
| /* Parse some declaration specifiers (possibly none) (C90 6.5, C99 |
| 6.7), adding them to SPECS (which may already include some). |
| Storage class specifiers are accepted iff SCSPEC_OK; type |
| specifiers are accepted iff TYPESPEC_OK; attributes are accepted at |
| the start iff START_ATTR_OK. |
| |
| declaration-specifiers: |
| storage-class-specifier declaration-specifiers[opt] |
| type-specifier declaration-specifiers[opt] |
| type-qualifier declaration-specifiers[opt] |
| function-specifier declaration-specifiers[opt] |
| |
| Function specifiers (inline) are from C99, and are currently |
| handled as storage class specifiers, as is __thread. |
| |
| C90 6.5.1, C99 6.7.1: |
| storage-class-specifier: |
| typedef |
| extern |
| static |
| auto |
| register |
| |
| C99 6.7.4: |
| function-specifier: |
| inline |
| |
| 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 |
| |
| (restrict is new in C99.) |
| |
| GNU extensions: |
| |
| declaration-specifiers: |
| attributes declaration-specifiers[opt] |
| |
| storage-class-specifier: |
| __thread |
| |
| type-specifier: |
| typeof-specifier |
| _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) |
| { |
| bool attrs_ok = start_attr_ok; |
| bool seen_type = specs->type_seen_p; |
| 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; |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| tree value = c_parser_peek_token (parser)->value; |
| c_id_kind kind = c_parser_peek_token (parser)->id_kind; |
| /* This finishes the specifiers unless a type name is OK, it |
| is declared as a type name and a type name hasn't yet |
| been seen. */ |
| if (!typespec_ok || seen_type |
| || (kind != C_ID_TYPENAME && kind != C_ID_CLASSNAME)) |
| break; |
| c_parser_consume_token (parser); |
| seen_type = true; |
| attrs_ok = true; |
| if (kind == C_ID_TYPENAME |
| && (!c_dialect_objc () |
| || c_parser_next_token_is_not (parser, CPP_LESS))) |
| { |
| 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); |
| } |
| declspecs_add_type (specs, t); |
| continue; |
| } |
| if (c_parser_next_token_is (parser, CPP_LESS)) |
| { |
| /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>" - |
| 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); |
| declspecs_add_type (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_AUTO: |
| case RID_THREAD: |
| if (!scspec_ok) |
| goto out; |
| attrs_ok = true; |
| /* TODO: Distinguish between function specifiers (inline) |
| and storage class specifiers, either here or in |
| declspecs_add_scspec. */ |
| declspecs_add_scspec (specs, c_parser_peek_token (parser)->value); |
| c_parser_consume_token (parser); |
| break; |
| case RID_UNSIGNED: |
| case RID_LONG: |
| 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; |
| declspecs_add_type (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 (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); |
| declspecs_add_type (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 (specs, t); |
| break; |
| case RID_CONST: |
| case RID_VOLATILE: |
| case RID_RESTRICT: |
| attrs_ok = true; |
| declspecs_add_qual (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 (specs, attrs); |
| 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 ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); |
| 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; |
| c_parser_consume_token (parser); |
| } |
| if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| { |
| /* Parse an enum definition. */ |
| struct c_enum_contents the_enum; |
| tree type = start_enum (&the_enum, ident); |
| tree postfix_attrs; |
| /* We chain the enumerators in reverse order, then put them in |
| forward order at the end. */ |
| tree 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 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); |
| value_loc = token->location; |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_EQ)) |
| { |
| c_parser_consume_token (parser); |
| value_loc = c_parser_peek_token (parser)->location; |
| enum_value = c_parser_expr_no_commas (parser, NULL).value; |
| } |
| else |
| enum_value = NULL_TREE; |
| enum_decl = build_enumerator (&the_enum, enum_id, enum_value, |
| value_loc); |
| 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_pedantic, "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; |
| return ret; |
| } |
| else if (!ident) |
| { |
| c_parser_error (parser, "expected %<{%>"); |
| ret.spec = error_mark_node; |
| ret.kind = ctsk_tagref; |
| return ret; |
| } |
| ret = parser_xref_tag (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 (ident_loc, OPT_pedantic, |
| "ISO C forbids forward references to %<enum%> 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; |
| 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 (); |
| } |
| 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; |
| c_parser_consume_token (parser); |
| } |
| if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| { |
| /* Parse a struct or union definition. Start the scope of the |
| tag before parsing components. */ |
| tree type = start_struct (code, ident); |
| 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 = 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_pedantic, |
| "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 |
| { |
| c_parser_error (parser, "expected %<;%>"); |
| c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); |
| break; |
| } |
| } |
| } |
| postfix_attrs = c_parser_attributes (parser); |
| ret.spec = finish_struct (type, nreverse (contents), |
| chainon (attrs, postfix_attrs)); |
| ret.kind = ctsk_tagdef; |
| return ret; |
| } |
| else if (!ident) |
| { |
| c_parser_error (parser, "expected %<{%>"); |
| ret.spec = error_mark_node; |
| ret.kind = ctsk_tagref; |
| return ret; |
| } |
| ret = parser_xref_tag (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 |
| |
| 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; |
| } |
| specs = build_null_declspecs (); |
| decl_loc = c_parser_peek_token (parser)->location; |
| c_parser_declspecs (parser, specs, false, true, true); |
| 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)) |
| { |
| tree ret; |
| if (!specs->type_seen_p) |
| { |
| pedwarn (decl_loc, OPT_pedantic, |
| "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; |
| } |
| 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->type_seen_p, |
| 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); |
| TREE_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; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF)); |
| c_parser_consume_token (parser); |
| skip_evaluation++; |
| in_typeof++; |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| skip_evaluation--; |
| in_typeof--; |
| return ret; |
| } |
| if (c_parser_next_token_starts_typename (parser)) |
| { |
| struct c_type_name *type = c_parser_type_name (parser); |
| skip_evaluation--; |
| in_typeof--; |
| if (type != NULL) |
| { |
| ret.spec = groktypename (type); |
| 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); |
| skip_evaluation--; |
| in_typeof--; |
| if (TREE_CODE (expr.value) == COMPONENT_REF |
| && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) |
| error_at (here, "%<typeof%> applied to a bit-field"); |
| ret.spec = TREE_TYPE (expr.value); |
| was_vm = variably_modified_type_p (ret.spec, NULL_TREE); |
| /* This should be returned with the type so that when the type |
| is evaluated, this can be evaluated. For now, we avoid |
| evaluation when the context might. */ |
| if (!skip_evaluation && was_vm) |
| { |
| tree e = expr.value; |
| |
| /* If the expression is not of a type to which we cannot assign a line |
| number, wrap the thing in a no-op NOP_EXPR. */ |
| if (DECL_P (e) || CONSTANT_CLASS_P (e)) |
| e = build1 (NOP_EXPR, void_type_node, e); |
| |
| protected_set_expr_location (e, here); |
| |
| add_stmt (e); |
| } |
| pop_maybe_used (was_vm); |
| } |
| 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); |
| 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_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)) |
| { |
| 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); |
| 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); |
| 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; |
| } |
| declarator = build_array_declarator (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) |
| { |
| 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 = XOBNEW (&parser_obstack, struct c_arg_info); |
| ret->parms = 0; |
| ret->tags = 0; |
| ret->types = list; |
| ret->others = 0; |
| ret->pending_sizes = 0; |
| ret->had_vla_unspec = 0; |
| 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); |
| 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. */ |
| |
| static struct c_arg_info * |
| c_parser_parms_list_declarator (c_parser *parser, tree attrs) |
| { |
| bool good_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 = XOBNEW (&parser_obstack, struct c_arg_info); |
| ret->parms = 0; |
| ret->tags = 0; |
| ret->types = 0; |
| ret->others = 0; |
| ret->pending_sizes = 0; |
| ret->had_vla_unspec = 0; |
| c_parser_consume_token (parser); |
| return ret; |
| } |
| if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) |
| { |
| struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info); |
| ret->parms = 0; |
| ret->tags = 0; |
| ret->others = 0; |
| ret->pending_sizes = 0; |
| ret->had_vla_unspec = 0; |
| /* Suppress -Wold-style-definition for this case. */ |
| ret->types = error_mark_node; |
| error_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) |
| { |
| good_parm = true; |
| push_parm_decl (parm); |
| } |
| 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); |
| } |
| if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) |
| { |
| c_parser_consume_token (parser); |
| if (good_parm) |
| return get_parm_info (false); |
| else |
| { |
| struct c_arg_info *ret |
| = XOBNEW (&parser_obstack, struct c_arg_info); |
| ret->parms = 0; |
| ret->tags = 0; |
| ret->types = 0; |
| ret->others = 0; |
| ret->pending_sizes = 0; |
| ret->had_vla_unspec = 0; |
| return ret; |
| } |
| } |
| if (!c_parser_require (parser, CPP_COMMA, |
| "expected %<;%>, %<,%> or %<)%>")) |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| get_pending_sizes (); |
| return NULL; |
| } |
| if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) |
| { |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) |
| { |
| c_parser_consume_token (parser); |
| if (good_parm) |
| return get_parm_info (true); |
| else |
| { |
| struct c_arg_info *ret |
| = XOBNEW (&parser_obstack, struct c_arg_info); |
| ret->parms = 0; |
| ret->tags = 0; |
| ret->types = 0; |
| ret->others = 0; |
| ret->pending_sizes = 0; |
| ret->had_vla_unspec = 0; |
| return ret; |
| } |
| } |
| else |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| get_pending_sizes (); |
| 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; |
| if (!c_parser_next_token_starts_declspecs (parser)) |
| { |
| /* ??? In some Objective-C cases '...' isn't applicable so there |
| should be a different message. */ |
| 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 (specs, attrs); |
| attrs = NULL_TREE; |
| } |
| c_parser_declspecs (parser, specs, true, true, true); |
| finish_declspecs (specs); |
| pending_xref_error (); |
| prefix_attrs = specs->attrs; |
| specs->attrs = NULL_TREE; |
| declarator = c_parser_declarator (parser, specs->type_seen_p, |
| 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; |
| 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 %<asm%>"); |
| str = build_string (1, ""); |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| c_parser_error (parser, "expected string literal"); |
| str = NULL_TREE; |
| } |
| 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; |
| } |
| |
| /* 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; |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| { |
| c_parser_consume_token (parser); |
| continue; |
| } |
| if (c_parser_next_token_is (parser, CPP_KEYWORD)) |
| { |
| /* ??? See comment above about what keywords are |
| accepted here. */ |
| bool ok; |
| switch (c_parser_peek_token (parser)->keyword) |
| { |
| case RID_STATIC: |
| case RID_UNSIGNED: |
| case RID_LONG: |
| case RID_CONST: |
| case RID_EXTERN: |
| case RID_REGISTER: |
| case RID_TYPEDEF: |
| case RID_SHORT: |
| case RID_INLINE: |
| case RID_VOLATILE: |
| case RID_SIGNED: |
| case RID_AUTO: |
| case RID_RESTRICT: |
| case RID_COMPLEX: |
| case RID_THREAD: |
| case RID_INT: |
| case RID_CHAR: |
| case RID_FLOAT: |
| case RID_DOUBLE: |
| case RID_VOID: |
| case RID_DFLOAT32: |
| case RID_DFLOAT64: |
| case RID_DFLOAT128: |
| case RID_BOOL: |
| case RID_FRACT: |
| case RID_ACCUM: |
| case RID_SAT: |
| ok = true; |
| break; |
| default: |
| ok = false; |
| break; |
| } |
| if (!ok) |
| break; |
| /* Accept __attribute__((__const)) as __attribute__((const)) |
| etc. */ |
| attr_name |
| = ridpointers[(int) c_parser_peek_token (parser)->keyword]; |
| } |
| else |
| attr_name = c_parser_peek_token (parser)->value; |
| 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. */ |
| if (c_parser_next_token_is (parser, CPP_NAME) |
| && c_parser_peek_token (parser)->id_kind == C_ID_ID |
| && ((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 |
| { |
| c_parser_consume_token (parser); |
| attr_args = tree_cons (NULL_TREE, arg1, |
| c_parser_expr_list (parser, false)); |
| } |
| } |
| else |
| { |
| if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) |
| attr_args = NULL_TREE; |
| else |
| attr_args = c_parser_expr_list (parser, false); |
| } |
| 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); |
| if (!specs->declspecs_seen_p) |
| { |
| c_parser_error (parser, "expected specifier-qualifier-list"); |
| return NULL; |
| } |
| pending_xref_error (); |
| finish_declspecs (specs); |
| declarator = c_parser_declarator (parser, specs->type_seen_p, |
| 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; |
| ret = c_parser_expr_no_commas (parser, NULL); |
| if (TREE_CODE (ret.value) != STRING_CST |
| && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR) |
| ret = default_function_array_conversion (ret); |
| 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) |
| { |
| location_t brace_loc = c_parser_peek_token (parser)->location; |
| gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); |
| c_parser_consume_token (parser); |
| if (nested_p) |
| push_init_level (0); |
| else |
| really_start_incremental_init (type); |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) |
| { |
| pedwarn (brace_loc, OPT_pedantic, "ISO C forbids empty initializer braces"); |
| } |
| else |
| { |
| /* Parse a non-empty initializer list, possibly with a trailing |
| comma. */ |
| while (true) |
| { |
| c_parser_initelt (parser); |
| 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)) |
| { |
| struct c_expr ret; |
| ret.value = error_mark_node; |
| ret.original_code = ERROR_MARK; |
| c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>"); |
| pop_init_level (0); |
| return ret; |
| } |
| c_parser_consume_token (parser); |
| return pop_init_level (0); |
| } |
| |
| /* Parse a nested initializer, including designators. */ |
| |
| static void |
| c_parser_initelt (c_parser *parser) |
| { |
| /* 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); |
| /* Use the colon as the error location. */ |
| pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_pedantic, |
| "obsolete use of designated initializer with %<:%>"); |
| c_parser_consume_token (parser); |
| c_parser_consume_token (parser); |
| } |
| 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); |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| struct c_expr init; |
| init.value = error_mark_node; |
| init.original_code = ERROR_MARK; |
| c_parser_error (parser, "expected identifier"); |
| c_parser_skip_until_found (parser, CPP_COMMA, NULL); |
| process_init_element (init, false); |
| 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; |
| 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; |
| c_parser_consume_token (parser); |
| next = c_parser_expr_no_commas (parser, NULL); |
| next = default_function_array_conversion (next); |
| rec = build_compound_expr (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 (build_tree_list (rec, args)); |
| mexpr.original_code = ERROR_MARK; |
| /* Now parse and process the remainder of the |
| initializer, starting with this message |
| expression as a primary-expression. */ |
| c_parser_initval (parser, &mexpr); |
| return; |
| } |
| c_parser_consume_token (parser); |
| first = c_parser_expr_no_commas (parser, NULL).value; |
| 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; |
| } |
| else |
| second = NULL_TREE; |
| if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) |
| { |
| c_parser_consume_token (parser); |
| set_init_index (first, second); |
| if (second) |
| pedwarn (ellipsis_loc, OPT_pedantic, |
| "ISO C forbids specifying range of elements to initialize"); |
| } |
| else |
| c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, |
| "expected %<]%>"); |
| } |
| } |
| if (des_seen >= 1) |
| { |
| if (c_parser_next_token_is (parser, CPP_EQ)) |
| { |
| if (!flag_isoc99) |
| pedwarn (des_loc, OPT_pedantic, |
| "ISO C90 forbids specifying subobject to initialize"); |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| if (des_seen == 1) |
| pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, |
| "obsolete use of designated initializer without %<=%>"); |
| else |
| { |
| struct c_expr init; |
| init.value = error_mark_node; |
| init.original_code = ERROR_MARK; |
| c_parser_error (parser, "expected %<=%>"); |
| c_parser_skip_until_found (parser, CPP_COMMA, NULL); |
| process_init_element (init, false); |
| return; |
| } |
| } |
| } |
| } |
| c_parser_initval (parser, NULL); |
| } |
| |
| /* 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 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 |
| { |
| init = c_parser_expr_no_commas (parser, after); |
| if (init.value != NULL_TREE |
| && TREE_CODE (init.value) != STRING_CST |
| && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR) |
| init = default_function_array_conversion (init); |
| } |
| process_init_element (init, false); |
| } |
| |
| /* 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; |
| 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 (stmt, true); |
| return error_mark_node; |
| } |
| stmt = c_begin_compound_stmt (true); |
| c_parser_compound_statement_nostart (parser); |
| return c_end_compound_stmt (stmt, true); |
| } |
| |
| /* 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; |
| location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) |
| { |
| c_parser_consume_token (parser); |
| return; |
| } |
| if (c_parser_next_token_is_keyword (parser, RID_LABEL)) |
| { |
| location_t err_loc = c_parser_peek_token (parser)->location; |
| /* Read zero or more forward-declarations for labels that nested |
| functions can jump to. */ |
| while (c_parser_next_token_is_keyword (parser, RID_LABEL)) |
| { |
| 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) =
|