| /* 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 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 2, 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 COPYING. If not, write to the Free |
| Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301, USA. */ |
| |
| /* 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" |
| |
| |
| /* Miscellaneous data and functions needed for the parser. */ |
| |
| int yydebug; |
| |
| /* Objective-C specific parser/lexer information. */ |
| |
| static int objc_pq_context = 0; |
| |
| /* 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. */ |
| static int objc_need_raw_identifier = 0; |
| #define OBJC_NEED_RAW_IDENTIFIER(VAL) \ |
| do { \ |
| if (c_dialect_objc ()) \ |
| objc_need_raw_identifier = VAL; \ |
| } while (0) |
| /* APPLE LOCAL begin C* property (Radar 4436866) (in 4.2 d) */ |
| /* For checking property attribute keywords */ |
| static int objc_property_attr_context; |
| /* APPLE LOCAL end C* property (Radar 4436866) (in 4.2 d) */ |
| /* APPLE LOCAL radar 3803157 - objc attribute (in 4.2 e) */ |
| static tree objc_method_attributes; |
| /* APPLE LOCAL begin C* language (in 4.2 f) */ |
| /* For checking for 'foreach' context. */ |
| static int objc_foreach_context; |
| /* APPLE LOCAL end C* language (in 4.2 f) */ |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 g) */ |
| #ifndef IASM_SEE_OPCODE |
| #define IASM_SEE_OPCODE(YYCHAR, T) YYCHAR |
| #endif |
| #define TYPESPEC 1 |
| #define IDENTIFIER 2 |
| /* APPLE LOCAL end CW asm blocks (in 4.2 g) */ |
| |
| /* APPLE LOCAL radar 6185344 */ |
| static int parsing_block_return_type; |
| |
| /* The reserved keyword table. */ |
| struct resword |
| { |
| const char *word; |
| ENUM_BITFIELD(rid) rid : 16; |
| unsigned int disable : 16; |
| }; |
| |
| /* Disable mask. Keywords are disabled if (reswords[i].disable & |
| mask) is _true_. */ |
| #define D_C89 0x01 /* not in C89 */ |
| #define D_EXT 0x02 /* GCC extension */ |
| #define D_EXT89 0x04 /* GCC extension incorporated in C99 */ |
| #define D_OBJC 0x08 /* Objective C only */ |
| |
| static const struct resword reswords[] = |
| { |
| { "_Bool", RID_BOOL, 0 }, |
| { "_Complex", RID_COMPLEX, 0 }, |
| /* APPLE LOCAL CW asm blocks (in 4.2 h) */ |
| { "_asm", RID_ASM, 0 }, |
| { "_Decimal32", RID_DFLOAT32, D_EXT }, |
| { "_Decimal64", RID_DFLOAT64, D_EXT }, |
| { "_Decimal128", RID_DFLOAT128, D_EXT }, |
| { "__FUNCTION__", RID_FUNCTION_NAME, 0 }, |
| { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 }, |
| { "__alignof", RID_ALIGNOF, 0 }, |
| { "__alignof__", RID_ALIGNOF, 0 }, |
| { "__asm", RID_ASM, 0 }, |
| { "__asm__", RID_ASM, 0 }, |
| { "__attribute", RID_ATTRIBUTE, 0 }, |
| { "__attribute__", RID_ATTRIBUTE, 0 }, |
| { "__builtin_choose_expr", RID_CHOOSE_EXPR, 0 }, |
| { "__builtin_offsetof", RID_OFFSETOF, 0 }, |
| { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, 0 }, |
| { "__builtin_va_arg", RID_VA_ARG, 0 }, |
| { "__complex", RID_COMPLEX, 0 }, |
| { "__complex__", RID_COMPLEX, 0 }, |
| { "__const", RID_CONST, 0 }, |
| { "__const__", RID_CONST, 0 }, |
| { "__extension__", RID_EXTENSION, 0 }, |
| { "__func__", RID_C99_FUNCTION_NAME, 0 }, |
| { "__imag", RID_IMAGPART, 0 }, |
| { "__imag__", RID_IMAGPART, 0 }, |
| { "__inline", RID_INLINE, 0 }, |
| { "__inline__", RID_INLINE, 0 }, |
| { "__label__", RID_LABEL, 0 }, |
| /* APPLE LOCAL private extern (in 4.2 i) */ |
| { "__private_extern__", RID_PRIVATE_EXTERN, 0 }, |
| { "__real", RID_REALPART, 0 }, |
| { "__real__", RID_REALPART, 0 }, |
| { "__restrict", RID_RESTRICT, 0 }, |
| { "__restrict__", RID_RESTRICT, 0 }, |
| { "__signed", RID_SIGNED, 0 }, |
| { "__signed__", RID_SIGNED, 0 }, |
| { "__thread", RID_THREAD, 0 }, |
| { "__typeof", RID_TYPEOF, 0 }, |
| { "__typeof__", RID_TYPEOF, 0 }, |
| { "__volatile", RID_VOLATILE, 0 }, |
| { "__volatile__", RID_VOLATILE, 0 }, |
| { "asm", RID_ASM, D_EXT }, |
| { "auto", RID_AUTO, 0 }, |
| { "break", RID_BREAK, 0 }, |
| { "case", RID_CASE, 0 }, |
| { "char", RID_CHAR, 0 }, |
| { "const", RID_CONST, 0 }, |
| { "continue", RID_CONTINUE, 0 }, |
| { "default", RID_DEFAULT, 0 }, |
| { "do", RID_DO, 0 }, |
| { "double", RID_DOUBLE, 0 }, |
| { "else", RID_ELSE, 0 }, |
| { "enum", RID_ENUM, 0 }, |
| { "extern", RID_EXTERN, 0 }, |
| { "float", RID_FLOAT, 0 }, |
| { "for", RID_FOR, 0 }, |
| { "goto", RID_GOTO, 0 }, |
| { "if", RID_IF, 0 }, |
| { "inline", RID_INLINE, D_EXT89 }, |
| { "int", RID_INT, 0 }, |
| { "long", RID_LONG, 0 }, |
| { "register", RID_REGISTER, 0 }, |
| { "restrict", RID_RESTRICT, D_C89 }, |
| { "return", RID_RETURN, 0 }, |
| { "short", RID_SHORT, 0 }, |
| { "signed", RID_SIGNED, 0 }, |
| { "sizeof", RID_SIZEOF, 0 }, |
| { "static", RID_STATIC, 0 }, |
| { "struct", RID_STRUCT, 0 }, |
| { "switch", RID_SWITCH, 0 }, |
| { "typedef", RID_TYPEDEF, 0 }, |
| { "typeof", RID_TYPEOF, D_EXT }, |
| { "union", RID_UNION, 0 }, |
| { "unsigned", RID_UNSIGNED, 0 }, |
| { "void", RID_VOID, 0 }, |
| { "volatile", RID_VOLATILE, 0 }, |
| { "while", RID_WHILE, 0 }, |
| /* These Objective-C keywords are recognized only immediately after |
| an '@'. */ |
| { "class", RID_AT_CLASS, D_OBJC }, |
| { "compatibility_alias", RID_AT_ALIAS, D_OBJC }, |
| { "defs", RID_AT_DEFS, D_OBJC }, |
| { "encode", RID_AT_ENCODE, D_OBJC }, |
| { "end", RID_AT_END, D_OBJC }, |
| { "implementation", RID_AT_IMPLEMENTATION, D_OBJC }, |
| { "interface", RID_AT_INTERFACE, D_OBJC }, |
| /* APPLE LOCAL begin C* language (in 4.2 j) */ |
| { "optional", RID_AT_OPTIONAL, D_OBJC }, |
| { "required", RID_AT_REQUIRED, D_OBJC }, |
| /* APPLE LOCAL end C* language (in 4.2 j) */ |
| /* APPLE LOCAL C* property (Radar 4436866) (in 4.2 k) */ |
| { "property", RID_AT_PROPERTY, D_OBJC }, |
| /* APPLE LOCAL radar 4564694 */ |
| { "package", RID_AT_PACKAGE, D_OBJC }, |
| { "private", RID_AT_PRIVATE, D_OBJC }, |
| { "protected", RID_AT_PROTECTED, D_OBJC }, |
| { "protocol", RID_AT_PROTOCOL, D_OBJC }, |
| { "public", RID_AT_PUBLIC, D_OBJC }, |
| { "selector", RID_AT_SELECTOR, D_OBJC }, |
| { "throw", RID_AT_THROW, D_OBJC }, |
| { "try", RID_AT_TRY, D_OBJC }, |
| { "catch", RID_AT_CATCH, D_OBJC }, |
| { "finally", RID_AT_FINALLY, D_OBJC }, |
| { "synchronized", RID_AT_SYNCHRONIZED, D_OBJC }, |
| /* These are recognized only in protocol-qualifier context |
| (see above) */ |
| { "bycopy", RID_BYCOPY, D_OBJC }, |
| { "byref", RID_BYREF, D_OBJC }, |
| { "in", RID_IN, D_OBJC }, |
| { "inout", RID_INOUT, D_OBJC }, |
| { "oneway", RID_ONEWAY, D_OBJC }, |
| { "out", RID_OUT, D_OBJC }, |
| /* APPLE LOCAL begin C* property (Radar 4436866) (in 4.2 l) */ |
| /* These are recognized inside a property attribute list */ |
| { "readonly", RID_READONLY, D_OBJC }, |
| { "getter", RID_GETTER, D_OBJC }, |
| { "setter", RID_SETTER, D_OBJC }, |
| /* APPLE LOCAL end C* property (Radar 4436866) (in 4.2 l) */ |
| /* APPLE LOCAL begin objc new property */ |
| { "synthesize", RID_AT_SYNTHESIZE, D_OBJC }, |
| { "dynamic", RID_AT_DYNAMIC, D_OBJC }, |
| { "readwrite", RID_READWRITE, D_OBJC }, |
| { "assign", RID_ASSIGN, D_OBJC }, |
| { "retain", RID_RETAIN, D_OBJC }, |
| { "copy", RID_COPY, D_OBJC }, |
| /* APPLE LOCAL end objc new property */ |
| /* APPLE LOCAL radar 4947014 - objc atomic property */ |
| { "nonatomic", RID_NONATOMIC, D_OBJC }, |
| }; |
| #define N_reswords (sizeof reswords / sizeof (struct resword)) |
| |
| /* All OpenMP clauses. OpenMP 2.5. */ |
| typedef enum pragma_omp_clause { |
| PRAGMA_OMP_CLAUSE_NONE = 0, |
| |
| PRAGMA_OMP_CLAUSE_COPYIN, |
| PRAGMA_OMP_CLAUSE_COPYPRIVATE, |
| PRAGMA_OMP_CLAUSE_DEFAULT, |
| PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, |
| PRAGMA_OMP_CLAUSE_IF, |
| PRAGMA_OMP_CLAUSE_LASTPRIVATE, |
| PRAGMA_OMP_CLAUSE_NOWAIT, |
| PRAGMA_OMP_CLAUSE_NUM_THREADS, |
| PRAGMA_OMP_CLAUSE_ORDERED, |
| PRAGMA_OMP_CLAUSE_PRIVATE, |
| PRAGMA_OMP_CLAUSE_REDUCTION, |
| PRAGMA_OMP_CLAUSE_SCHEDULE, |
| PRAGMA_OMP_CLAUSE_SHARED |
| } pragma_omp_clause; |
| |
| |
| /* 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 = (flag_isoc99 ? 0 : D_C89) |
| | (flag_no_asm ? (flag_isoc99 ? D_EXT : D_EXT|D_EXT89) : 0); |
| |
| if (!c_dialect_objc ()) |
| mask |= D_OBJC; |
| |
| ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX); |
| for (i = 0; i < N_reswords; i++) |
| { |
| /* If a keyword is disabled, do not enter it into the table |
| and so create a canonical spelling that isn't a keyword. */ |
| if (reswords[i].disable & mask) |
| continue; |
| |
| id = get_identifier (reswords[i].word); |
| C_RID_CODE (id) = reswords[i].rid; |
| C_IS_RESERVED_WORD (id) = 1; |
| ridpointers [(int) 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; |
| /* APPLE LOCAL begin CW asm blocks */ |
| /* Token flags. */ |
| unsigned char flags; |
| /* APPLE LOCAL end CW asm blocks */ |
| /* If this token is a CPP_PRAGMA, this indicates the pragma that |
| was seen. Otherwise it is PRAGMA_NONE. */ |
| ENUM_BITFIELD (pragma_kind) pragma_kind : 7; |
| /* True if this token is from a system header. */ |
| BOOL_BITFIELD in_system_header : 1; |
| /* The value associated with this token, if any. */ |
| tree value; |
| /* 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; |
| } c_parser; |
| |
| |
| /* The actual parser and external interface. ??? Does this need to be |
| garbage-collected? */ |
| |
| static GTY (()) c_parser *the_parser; |
| |
| /* APPLE LOCAL C* language (in 4.2 ae) */ |
| static c_token * c_parser_peek_2nd_token (c_parser *); |
| |
| /* Read in and lex a single token, storing it in *TOKEN. */ |
| |
| static void |
| /* APPLE LOCAL C* language (in 4.2 ae) */ |
| c_lex_one_token (c_token *token, c_parser *parser) |
| { |
| timevar_push (TV_LEX); |
| |
| /* APPLE LOCAL CW asm blocks */ |
| token->type = c_lex_with_flags (&token->value, &token->location, &token->flags); |
| token->id_kind = C_ID_NONE; |
| token->keyword = RID_MAX; |
| token->pragma_kind = PRAGMA_NONE; |
| token->in_system_header = in_system_header; |
| |
| switch (token->type) |
| { |
| case CPP_NAME: |
| { |
| tree decl; |
| |
| int objc_force_identifier = objc_need_raw_identifier; |
| OBJC_NEED_RAW_IDENTIFIER (0); |
| |
| if (C_IS_RESERVED_WORD (token->value)) |
| { |
| enum rid rid_code = C_RID_CODE (token->value); |
| |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 ad) */ |
| if (IASM_SEE_OPCODE (TYPESPEC, token->value) == IDENTIFIER |
| && iasm_state >= iasm_decls |
| && iasm_in_operands == false) |
| { |
| /* If this was an opcode, prefer it. */ |
| token->id_kind = C_ID_ID; |
| break; |
| } |
| /* APPLE LOCAL end CW asm blocks (in 4.2 ad) */ |
| |
| if (c_dialect_objc ()) |
| { |
| if (!OBJC_IS_AT_KEYWORD (rid_code) |
| /* APPLE LOCAL objc new property */ |
| && !OBJC_IS_NEW_PATTR_KEYWORD (rid_code) |
| && (!OBJC_IS_PQ_KEYWORD (rid_code) || 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; |
| } |
| /* APPLE LOCAL begin radar 4708210 (for_objc_collection in 4.2) */ |
| else if (objc_foreach_context && rid_code == RID_IN) |
| { |
| /* This is dangerous, we assume we don't need 3 input tokens look ahead. */ |
| c_token *tk = c_parser_peek_2nd_token (parser); |
| if (tk->type == CPP_NAME |
| || tk->type == CPP_OPEN_PAREN |
| || tk->type == CPP_MULT |
| || tk->type == CPP_PLUS |
| || tk->type == CPP_PLUS_PLUS |
| || tk->type == CPP_MINUS |
| || tk->type == CPP_MINUS_MINUS |
| /* APPLE LOCAL radar 4529200 (in 4.2 af) */ |
| || tk->type == CPP_OPEN_SQUARE) |
| { |
| token->type = CPP_KEYWORD; |
| token->keyword = rid_code; |
| break; |
| } |
| } |
| /* APPLE LOCAL end radar 4708210 (for_objc_collection in 4.2) */ |
| /* APPLE LOCAL begin objc new property */ |
| else if (objc_property_attr_context && OBJC_IS_NEW_PATTR_KEYWORD (rid_code)) |
| { |
| token->type = CPP_KEYWORD; |
| token->keyword = rid_code; |
| break; |
| } |
| /* APPLE LOCAL end objc new property */ |
| } |
| else |
| { |
| /* Return the canonical spelling for this keyword. */ |
| token->value = ridpointers[(int) rid_code]; |
| 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. */ |
| OBJC_NEED_RAW_IDENTIFIER (0); |
| break; |
| case CPP_PRAGMA: |
| /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */ |
| token->pragma_kind = TREE_INT_CST_LOW (token->value); |
| token->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) |
| { |
| /* APPLE LOCAL begin switch these two */ |
| parser->tokens_avail = 1; |
| /* APPLE LOCAL C* language (in 4.2 ae) */ |
| c_lex_one_token (&parser->tokens[0], parser); |
| /* APPLE LOCAL end switch these two */ |
| } |
| 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) |
| { |
| c_token *token; |
| |
| /* Peek at the next token. */ |
| token = c_parser_peek_token (parser); |
| /* Check to see if it is the indicated keyword. */ |
| return token->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: |
| 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: |
| /* APPLE LOCAL private extern 5487726 */ |
| case RID_PRIVATE_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: |
| 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); |
| /* APPLE LOCAL begin radar 5277239 */ |
| /* Yes, we can have CLASS.method to mean property-style dot-syntax |
| notation to call a class method (equiv to [CLASS meth]). */ |
| return c_token_starts_declspecs (token) |
| && (token->id_kind != C_ID_CLASSNAME |
| || c_parser_peek_2nd_token (parser)->type != CPP_DOT); |
| /* APPLE LOCAL end radar 5277239 */ |
| } |
| |
| /* 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); |
| /* APPLE LOCAL begin switch these two */ |
| parser->tokens_avail = 2; |
| /* APPLE LOCAL C* language (in 4.2 ae) */ |
| c_lex_one_token (&parser->tokens[1], parser); |
| /* APPLE LOCAL end switch these two */ |
| 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; |
| in_system_header = token->in_system_header; |
| } |
| } |
| |
| /* 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; |
| } |
| |
| /* 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)); |
| pedantic = 0; |
| warn_pointer_arith = 0; |
| warn_traditional = 0; |
| flag_iso = 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) |
| { |
| pedantic = flags & 1; |
| warn_pointer_arith = (flags >> 1) & 1; |
| warn_traditional = (flags >> 2) & 1; |
| flag_iso = (flags >> 3) & 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; |
| |
| /* APPLE LOCAL begin CW asm blocks */ |
| static void c_parser_iasm_top_statement (c_parser *); |
| static void c_parser_iasm_compound_statement (c_parser *); |
| static bool c_parser_iasm_bol (c_parser *); |
| static void c_parser_iasm_line_seq_opt (c_parser*); |
| /* APPLE LOCAL end CW asm blocks */ |
| static void c_parser_external_declaration (c_parser *); |
| static void c_parser_asm_definition (c_parser *); |
| /* APPLE LOCAL radar 4708210 (for_objc_collection in 4.2) */ |
| static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, bool, tree*); |
| 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 *); |
| /* APPLE LOCAL begin radar 5732232 - blocks (C++ ca) */ |
| static tree c_parser_block_literal_expr (c_parser *); |
| static bool c_parser_block_byref_declarations (c_parser *); |
| /* APPLE LOCAL end radar 5732232 - blocks (C++ ca) */ |
| 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 *); |
| |
| 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. */ |
| /* APPLE LOCAL radar 4548636 - class attributes. */ |
| static void c_parser_objc_class_definition (c_parser *, tree); |
| static void c_parser_objc_class_instance_variables (c_parser *); |
| static void c_parser_objc_class_declaration (c_parser *); |
| static void c_parser_objc_alias_declaration (c_parser *); |
| /* APPLE LOCAL radar 4947311 - protocol attributes */ |
| static void c_parser_objc_protocol_definition (c_parser *, tree); |
| static enum tree_code c_parser_objc_method_type (c_parser *); |
| static void c_parser_objc_method_definition (c_parser *); |
| /* APPLE LOCAL C* property (Radar 4436866) (in 4.2 b) */ |
| static void c_parser_objc_interfacedecllist (c_parser *); |
| /* APPLE LOCAL C* property (Radar 4436866) (in 4.2 x) */ |
| static void c_parser_objc_property_declaration (c_parser *); |
| /* APPLE LOCAL begin objc new property */ |
| static void c_parser_objc_atsynthesize_declaration (c_parser *); |
| static void c_parser_objc_atdynamic_declaration (c_parser *); |
| /* APPLE LOCAL end objc new property */ |
| 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)) |
| { |
| if (pedantic) |
| pedwarn ("ISO C forbids an empty source file"); |
| } |
| 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 ()); |
| /* APPLE LOCAL radar 4548636 - class attributes. */ |
| c_parser_objc_class_definition (parser, NULL_TREE); |
| break; |
| case RID_AT_CLASS: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_class_declaration (parser); |
| break; |
| case RID_AT_ALIAS: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_alias_declaration (parser); |
| break; |
| case RID_AT_PROTOCOL: |
| gcc_assert (c_dialect_objc ()); |
| /* APPLE LOCAL begin radar 4947311 - protocol attributes */ |
| c_parser_objc_protocol_definition (parser, NULL_TREE); |
| break; |
| /* APPLE LOCAL end radar 4947311 - protocol attributes */ |
| /* APPLE LOCAL begin C* property (Radar 4436866) (in 4.2 x) */ |
| case RID_AT_PROPERTY: |
| c_parser_objc_property_declaration (parser); |
| break; |
| /* APPLE LOCAL end C* property (Radar 4436866) (in 4.2 x) */ |
| /* APPLE LOCAL begin objc new property */ |
| case RID_AT_SYNTHESIZE: |
| c_parser_objc_atsynthesize_declaration (parser); |
| break; |
| case RID_AT_DYNAMIC: |
| c_parser_objc_atdynamic_declaration (parser); |
| break; |
| /* APPLE LOCAL end objc new property */ |
| 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: |
| if (pedantic) |
| pedwarn ("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. */ |
| /* APPLE LOCAL radar 4708210 (for_objc_collection in 4.2) */ |
| c_parser_declaration_or_fndef (parser, true, true, false, true, NULL); |
| break; |
| } |
| } |
| |
| |
| /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 |
| 6.7, 6.9.1). If FNDEF_OK is true, a function definition is |
| accepted; otherwise (old-style parameter declarations) only other |
| declarations are accepted. If NESTED is true, we are inside a |
| function or parsing old-style parameter declarations; any functions |
| encountered are nested functions and declaration specifiers are |
| required; otherwise we are at top level and functions are normal |
| functions and declaration specifiers may be optional. If EMPTY_OK |
| is true, empty declarations are OK (subject to all other |
| constraints); otherwise (old-style parameter declarations) they are |
| diagnosed. If START_ATTR_OK is true, the declaration specifiers |
| may start with attributes; otherwise they may not. |
| |
| 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, |
| /* APPLE LOCAL radar 4708210 (for_objc_collection in 4.2) */ |
| bool nested, bool start_attr_ok, tree *foreach_elem) |
| { |
| struct c_declspecs *specs; |
| tree prefix_attrs; |
| tree all_prefix_attrs; |
| bool diagnosed_no_specs = false; |
| |
| 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 ("empty declaration"); |
| } |
| c_parser_consume_token (parser); |
| return; |
| } |
| /* APPLE LOCAL begin radar 4548636 - class attributes. */ |
| else if (c_parser_next_token_is_keyword (parser, RID_AT_INTERFACE) |
| || c_parser_next_token_is_keyword (parser, RID_AT_IMPLEMENTATION)) |
| { |
| gcc_assert (c_dialect_objc ()); |
| if (!specs->declspecs_seen_p || specs->attrs == NULL_TREE |
| || specs->type_seen_p || specs->non_sc_seen_p) |
| c_parser_error (parser, "no type or storage class may be specified here"); |
| c_parser_objc_class_definition (parser, specs->attrs); |
| return; |
| } |
| /* APPLE LOCAL end radar 4548636 - class attributes. */ |
| /* APPLE LOCAL begin radar 4947311 - protocol attributes */ |
| else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL)) |
| { |
| gcc_assert (c_dialect_objc ()); |
| if (!specs->declspecs_seen_p || specs->attrs == NULL_TREE |
| || specs->type_seen_p || specs->non_sc_seen_p) |
| c_parser_error (parser, "no type or storage class may be specified here"); |
| c_parser_objc_protocol_definition (parser, specs->attrs); |
| return; |
| } |
| /* APPLE LOCAL end radar 4947311 - protocol attributes */ |
| 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) |
| /* APPLE LOCAL radar 4708210 (for_objc_collection in 4.2) */ |
| || c_parser_next_token_is_keyword (parser, RID_IN) |
| || 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 ("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); |
| /* APPLE LOCAL begin radar 4708210 (for_objc_collection in 4.2) */ |
| if (c_parser_next_token_is_keyword (parser, RID_IN)) |
| { |
| gcc_assert (foreach_elem); |
| *foreach_elem = start_decl (declarator, specs, true, |
| chainon (postfix_attrs, all_prefix_attrs)); |
| if (!*foreach_elem) |
| *foreach_elem = error_mark_node; |
| start_init (*foreach_elem, asm_name, global_bindings_p ()); |
| return; |
| } |
| /* APPLE LOCAL end radar 4708210 (for_objc_collection in 4.2) */ |
| 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) |
| { |
| /* APPLE LOCAL begin radar 5985368 */ |
| if (declarator->declarator && declarator->declarator->kind == cdk_block_pointer) |
| error ("bad definition of a block"); |
| else if (pedantic) |
| /* APPLE LOCAL end radar 5985368 */ |
| pedwarn ("ISO C forbids nested functions"); |
| /* APPLE LOCAL begin nested functions 4258406 4357979 (in 4.2 m) */ |
| else if (flag_nested_functions == 0) |
| error ("nested functions are disabled, use -fnested-functions to re-enable"); |
| /* APPLE LOCAL end nested functions 4258406 4357979 (in 4.2 m) */ |
| |
| 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) |
| 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)) |
| /* APPLE LOCAL radar 4708210 (for_objc_collection in 4.2) */ |
| c_parser_declaration_or_fndef (parser, false, false, true, false, NULL); |
| DECL_SOURCE_LOCATION (current_function_decl) |
| = c_parser_peek_token (parser)->location; |
| store_parm_decls (); |
| fnbody = c_parser_compound_statement (parser); |
| if (nested) |
| { |
| tree decl = current_function_decl; |
| add_stmt (fnbody); |
| finish_function (); |
| pop_function_context (); |
| add_stmt (build_stmt (DECL_EXPR, decl)); |
| } |
| else |
| { |
| add_stmt (fnbody); |
| finish_function (); |
| } |
| break; |
| } |
| } |
| |
| /* APPLE LOCAL begin radar 4708210 (for_objc_collection in 4.2) */ |
| /* This routine finishes up parsing of objc's foreach loop header. */ |
| |
| static tree |
| finish_parse_foreach_header (c_parser *parser, tree foreach_elem_selector) |
| { |
| tree res; |
| int save_flag_isoc99 = flag_isoc99; |
| gcc_assert (foreach_elem_selector); |
| /* Consume 'in' keyword */ |
| c_parser_consume_token (parser); |
| res = build_tree_list (foreach_elem_selector, c_parser_initializer (parser).value); |
| finish_init (); |
| flag_isoc99 = 1; |
| check_for_loop_decls (); |
| flag_isoc99 = save_flag_isoc99; |
| return res; |
| } |
| /* APPLE LOCAL end radar 4708210 (for_objc_collection in 4.2) */ |
| |
| /* 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) |
| { |
| /* APPLE LOCAL begin CW asm blocks */ |
| tree asm_str; |
| if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN) |
| { |
| /* This asm is a decl-specifier */ |
| c_parser_declaration_or_fndef (parser, true, true, false, true, NULL); |
| return; |
| } |
| asm_str = c_parser_simple_asm_expr (parser); |
| /* APPLE LOCAL end CW asm blocks */ |
| 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 |
| |
| 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) |
| { |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 ac) */ |
| case RID_ASM: |
| /* A rough estimate is that the storage class asm requiers |
| that '(' not immediately follow the asm. */ |
| if (current_function_decl == NULL_TREE |
| && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) |
| goto out; |
| /* APPLE LOCAL end CW asm blocks (in 4.2 ac) */ |
| case RID_STATIC: |
| case RID_EXTERN: |
| case RID_REGISTER: |
| case RID_TYPEDEF: |
| case RID_INLINE: |
| case RID_AUTO: |
| case RID_THREAD: |
| /* APPLE LOCAL private extern (in 4.2 aa) */ |
| case RID_PRIVATE_EXTERN: |
| 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: |
| if (!typespec_ok) |
| goto out; |
| attrs_ok = true; |
| seen_type = true; |
| OBJC_NEED_RAW_IDENTIFIER (1); |
| 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; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); |
| c_parser_consume_token (parser); |
| attrs = c_parser_attributes (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 an enum definition. */ |
| tree type = start_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; |
| 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; |
| } |
| enum_id = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_EQ)) |
| { |
| c_parser_consume_token (parser); |
| enum_value = c_parser_expr_no_commas (parser, NULL).value; |
| } |
| else |
| enum_value = NULL_TREE; |
| enum_decl = build_enumerator (enum_id, enum_value); |
| TREE_CHAIN (enum_decl) = values; |
| values = enum_decl; |
| seen_comma = false; |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| { |
| seen_comma = true; |
| c_parser_consume_token (parser); |
| } |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) |
| { |
| if (seen_comma && pedantic && !flag_isoc99) |
| pedwarn ("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)) |
| pedwarn ("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); |
| 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)); |
| /* APPLE LOCAL begin radar 4441551 */ |
| if (flag_objc2_check && flag_objc_abi == 1) |
| warning (0, "@defs will not be supported in future"); |
| /* APPLE LOCAL radar 4705250 */ |
| else if (flag_objc_abi == 2 && flag_objc_atdefs != 1) |
| error ("@defs is not supported in new abi"); |
| /* APPLE LOCAL end radar 4441551 */ |
| } |
| 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)) |
| { |
| if (pedantic) |
| pedwarn ("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 ("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; |
| 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 (); |
| 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) |
| { |
| if (pedantic) |
| pedwarn ("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). */ |
| ret = grokfield (build_id_declarator (NULL_TREE), specs, NULL_TREE); |
| } |
| 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 (declarator, specs, width); |
| 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; |
| 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 ("%<typeof%> applied to a bit-field"); |
| ret.spec = TREE_TYPE (expr.value); |
| /* APPLE LOCAL begin radar 4204796 (in 4.2 n) */ |
| if (c_dialect_objc() |
| && ret.spec != error_mark_node |
| && lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (ret.spec))) |
| ret.spec = build_qualified_type |
| (ret.spec, (TYPE_QUALS (ret.spec) & ~TYPE_QUAL_VOLATILE)); |
| /* APPLE LOCAL end radar 4204796 (in 4.2 n) */ |
| 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); |
| |
| if (EXPR_P (e)) |
| SET_EXPR_LOCATION (e, input_location); |
| |
| 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); |
| } |
| /* APPLE LOCAL begin radar 5732232 - blocks (C++ cc) */ |
| else if (flag_blocks && c_parser_next_token_is (parser, CPP_XOR)) { |
| 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 |
| /* APPLE LOCAL radar 5814025 (C++ cc) */ |
| return make_block_pointer_declarator (quals_attrs, inner); |
| } |
| /* APPLE LOCAL end radar 5732232 - blocks (C++ cc) */ |
| /* 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 |
| /* APPLE LOCAL begin radar 4281748 */ |
| && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME |
| || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) |
| /* APPLE LOCAL end radar 4281748 */ |
| || 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. */ |
| |
| /* APPLE LOCAL radar 6185344 */ |
| if (!parsing_block_return_type && 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, !id_present); |
| 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 ("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); |
| 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 %<)%>"); |
| 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 c_lex_string_translate to 0. It would be better to follow the |
| C++ parser rather than using the c_lex_string_translate 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 ("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 |
| c_lex_string_translate kludge. */ |
| c_lex_string_translate = 0; |
| c_parser_consume_token (parser); |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| c_lex_string_translate = 1; |
| return NULL_TREE; |
| } |
| str = c_parser_asm_string_literal (parser); |
| c_lex_string_translate = 1; |
| 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 |
| c_lex_string_translate kludge. */ |
| c_lex_string_translate = 0; |
| c_parser_consume_token (parser); |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| c_lex_string_translate = 1; |
| return attrs; |
| } |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| c_lex_string_translate = 1; |
| 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: |
| /* APPLE LOCAL private extern 5487726 */ |
| case RID_PRIVATE_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: |
| ok = true; |
| break; |
| default: |
| ok = false; |
| break; |
| } |
| if (!ok) |
| break; |
| } |
| 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 |
| { |
| c_lex_string_translate = 1; |
| 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 |
| { |
| c_lex_string_translate = 1; |
| 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 |
| { |
| c_lex_string_translate = 1; |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| return attrs; |
| } |
| c_lex_string_translate = 1; |
| } |
| 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) |
| { |
| 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)) |
| { |
| if (pedantic) |
| pedwarn ("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 %<}%>"); |
| 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); |
| if (pedantic) |
| pedwarn ("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; |
| 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 < 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); |
| return; |
| } |
| } |
| else |
| { |
| tree first, second; |
| /* ??? 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)) |
| { |
| 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 (pedantic && second) |
| pedwarn ("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 (pedantic && !flag_isoc99) |
| pedwarn ("ISO C90 forbids specifying subobject to initialize"); |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| if (des_seen == 1) |
| { |
| if (pedantic) |
| pedwarn ("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); |
| 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); |
| } |
| |
| /* 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 %<{%>")) |
| 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; |
| /* APPLE LOCAL radar 5732232 - blocks (not in C++) */ |
| bool first_stmt = true; |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) |
| { |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 am) */ |
| if (flag_iasm_blocks) |
| iasm_end_block (); |
| /* APPLE LOCAL end CW asm blocks */ |
| return; |
| } |
| if (c_parser_next_token_is_keyword (parser, RID_LABEL)) |
| { |
| /* 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) = 1; |
| add_stmt (build_stmt (DECL_EXPR, label)); |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| c_parser_consume_token (parser); |
| else |
| break; |
| } |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| } |
| /* ??? Locating this diagnostic on the token after the |
| declarations end follows the old parser, but it might be |
| better to locate it where the declarations start instead. */ |
| if (pedantic) |
| pedwarn ("ISO C forbids label declarations"); |
| } |
| /* We must now have at least one statement, label or declaration. */ |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) |
| { |
| c_parser_error (parser, "expected declaration or statement"); |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 am) */ |
| if (flag_iasm_blocks) |
| iasm_end_block (); |
| /* APPLE LOCAL end CW asm blocks */ |
| return; |
| } |
| while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) |
| { |
| location_t loc = c_parser_peek_token (parser)->location; |
| if (c_parser_next_token_is_keyword (parser, RID_CASE) |
| || c_parser_next_token_is_keyword (parser, RID_DEFAULT) |
| || (c_parser_next_token_is (parser, CPP_NAME) |
| /* APPLE LOCAL CW asm blocks */ |
| && iasm_state < iasm_decls |
| && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) |
| { |
| last_label = true; |
| last_stmt = false; |
| c_parser_label (parser); |
| } |
| else if (!last_label |
| && c_parser_next_token_starts_declspecs (parser)) |
| { |
| last_label = false; |
| /* APPLE LOCAL radar 4708210 (for_objc_collection in 4.2) */ |
| c_parser_declaration_or_fndef (parser, true, true, true, true, NULL); |
| if (last_stmt |
| && ((pedantic && !flag_isoc99) |
| || warn_declaration_after_statement)) |
| pedwarn_c90 ("%HISO C90 forbids mixed declarations and code", |
| &loc); |
| last_stmt = false; |
| } |
| else if (!last_label |
| && c_parser_next_token_is_keyword (parser, RID_EXTENSION)) |
| { |
| /* __extension__ can start a declaration, but is also an |
| unary operator that can start an expression. Consume all |
| but the last of a possible series of __extension__ to |
| determine which. */ |
| while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD |
| && (c_parser_peek_2nd_token (parser)->keyword |
| == RID_EXTENSION)) |
| c_parser_consume_token (parser); |
| if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser))) |
| { |
| int ext; |
| ext = disable_extension_diagnostics (); |
| c_parser_consume_token (parser); |
| last_label = false; |
| /* APPLE LOCAL radar 4708210 (for_objc_collection in 4.2) */ |
| c_parser_declaration_or_fndef (parser, true, true, true, true, NULL); |
| /* Following the old parser, __extension__ does not |
| disable this diagnostic. */ |
| restore_extension_diagnostics (ext); |
| if (last_stmt |
| && ((pedantic && !flag_isoc99) |
| || warn_declaration_after_statement)) |
| pedwarn_c90 ("%HISO C90 forbids mixed declarations and code", |
| &loc); |
| last_stmt = false; |
| } |
| else |
| goto statement; |
| } |
| /* APPLE LOCAL begin radar 5732232 - blocks (not in C++) */ |
| else if (flag_blocks && first_stmt && |
| c_parser_next_token_is (parser, CPP_OR) && |
| c_parser_block_byref_declarations (parser)) |
| { |
| ; |
| } |
| /* APPLE LOCAL end radar 5732232 - blocks (not in C++) */ |
| else if (c_parser_next_token_is (parser, CPP_PRAGMA)) |
| { |
| /* External pragmas, and some omp pragmas, are not associated |
| with regular c code, and so are not to be considered statements |
| syntactically. This ensures that the user doesn't put them |
| places that would turn into syntax errors if the directive |
| were ignored. */ |
| if (c_parser_pragma (parser, pragma_compound)) |
| last_label = false, last_stmt = true; |
| } |
| else if (c_parser_next_token_is (parser, CPP_EOF)) |
| { |
| c_parser_error (parser, "expected declaration or statement"); |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 am) */ |
| if (flag_iasm_blocks) |
| iasm_end_block (); |
| /* APPLE LOCAL end CW asm blocks */ |
| return; |
| } |
| else |
| { |
| statement: |
| last_label = false; |
| last_stmt = true; |
| c_parser_statement_after_labels (parser); |
| } |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 al) */ |
| /* MAYBE NOT NEEDED HERE. */ |
| if (flag_iasm_blocks) iasm_in_decl = false; |
| /* APPLE LOCAL end CW asm blocks (in 4.2 al) */ |
| parser->error = false; |
| /* APPLE LOCAL radar 5732232 - blocks (not in C++) */ |
| first_stmt = false; |
| } |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 am) */ |
| if (flag_iasm_blocks) |
| iasm_end_block (); |
| /* APPLE LOCAL end CW asm blocks */ |
| if (last_label) |
| error ("label at end of compound statement"); |
| c_parser_consume_token (parser); |
| } |
| |
| /* Parse a label (C90 6.6.1, C99 6.8.1). |
| |
| label: |
| identifier : attributes[opt] |
| case constant-expression : |
| default : |
| |
| GNU extensions: |
| |
| label: |
| case constant-expression ... constant-expression : |
| |
| The use of attributes on labels is a GNU extension. The syntax in |
| GNU C accepts any expressions without commas, non-constant |
| expressions being rejected later. */ |
| |
| static void |
| c_parser_label (c_parser *parser) |
| { |
| location_t loc1 = c_parser_peek_token (parser)->location; |
| tree label = NULL_TREE; |
| if (c_parser_next_token_is_keyword (parser, RID_CASE)) |
| { |
| tree exp1, exp2; |
| c_parser_consume_token (parser); |
| exp1 = c_parser_expr_no_commas (parser, NULL).value; |
| if (c_parser_next_token_is (parser, CPP_COLON)) |
| { |
| c_parser_consume_token (parser); |
| label = do_case (exp1, NULL_TREE); |
| } |
| else if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) |
| { |
| c_parser_consume_token (parser); |
| exp2 = c_parser_expr_no_commas (parser, NULL).value; |
| if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) |
| label = do_case (exp1, exp2); |
| } |
| else |
| c_parser_error (parser, "expected %<:%> or %<...%>"); |
| } |
| else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) |
| { |
| c_parser_consume_token (parser); |
| if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) |
| label = do_case (NULL_TREE, NULL_TREE); |
| } |
| else |
| { |
| tree name = c_parser_peek_token (parser)->value; |
| tree tlab; |
| location_t loc2; |
| tree attrs; |
| gcc_assert (c_parser_next_token_is (parser, CPP_NAME)); |
| c_parser_consume_token (parser); |
| gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); |
| loc2 = c_parser_peek_token (parser)->location; |
| c_parser_consume_token (parser); |
| attrs = c_parser_attributes (parser); |
| tlab = define_label (loc2, name); |
| if (tlab) |
| { |
| decl_attributes (&tlab, attrs, 0); |
| label = add_stmt (build_stmt (LABEL_EXPR, tlab)); |
| } |
| } |
| if (label) |
| SET_EXPR_LOCATION (label, loc1); |
| } |
| |
| /* Parse a statement (C90 6.6, C99 6.8). |
| |
| statement: |
| labeled-statement |
| compound-statement |
| expression-statement |
| selection-statement |
| iteration-statement |
| jump-statement |
| |
| labeled-statement: |
| label statement |
| |
| expression-statement: |
| expression[opt] ; |
| |
| selection-statement: |
| if-statement |
| switch-statement |
| |
| iteration-statement: |
| while-statement |
| do-statement |
| for-statement |
| |
| jump-statement: |
| goto identifier ; |
| continue ; |
| break ; |
| return expression[opt] ; |
| |
| GNU extensions: |
| |
| statement: |
| asm-statement |
| |
| jump-statement: |
| goto * expression ; |
| |
| Objective-C: |
| |
| statement: |
| objc-throw-statement |
| objc-try-catch-statement |
| objc-synchronized-statement |
| |
| objc-throw-statement: |
| @throw expression ; |
| @throw ; |
| |
| OpenMP: |
| |
| statement: |
| openmp-construct |
| |
| openmp-construct: |
| parallel-construct |
| for-construct |
| sections-construct |
| single-construct |
| parallel-for-construct |
| parallel-sections-construct |
| master-construct |
| critical-construct |
| atomic-construct |
| ordered-construct |
| |
| parallel-construct: |
| parallel-directive structured-block |
| |
| for-construct: |
| for-directive iteration-statement |
| |
| sections-construct: |
| sections-directive section-scope |
| |
| single-construct: |
| single-directive structured-block |
| |
| parallel-for-construct: |
| parallel-for-directive iteration-statement |
| |
| parallel-sections-construct: |
| parallel-sections-directive section-scope |
| |
| master-construct: |
| master-directive structured-block |
| |
| critical-construct: |
| critical-directive structured-block |
| |
| atomic-construct: |
| atomic-directive expression-statement |
| |
| ordered-construct: |
| ordered-directive structured-block */ |
| |
| static void |
| c_parser_statement (c_parser *parser) |
| { |
| while (c_parser_next_token_is_keyword (parser, RID_CASE) |
| || c_parser_next_token_is_keyword (parser, RID_DEFAULT) |
| || (c_parser_next_token_is (parser, CPP_NAME) |
| && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) |
| c_parser_label (parser); |
| c_parser_statement_after_labels (parser); |
| } |
| |
| /* Parse a statement, other than a labeled statement. */ |
| |
| static void |
| c_parser_statement_after_labels (c_parser *parser) |
| { |
| location_t loc = c_parser_peek_token (parser)->location; |
| tree stmt = NULL_TREE; |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_OPEN_BRACE: |
| add_stmt (c_parser_compound_statement (parser)); |
| break; |
| case CPP_KEYWORD: |
| switch (c_parser_peek_token (parser)->keyword) |
| { |
| case RID_IF: |
| c_parser_if_statement (parser); |
| break; |
| case RID_SWITCH: |
| c_parser_switch_statement (parser); |
| break; |
| case RID_WHILE: |
| c_parser_while_statement (parser); |
| break; |
| case RID_DO: |
| c_parser_do_statement (parser); |
| break; |
| case RID_FOR: |
| c_parser_for_statement (parser); |
| break; |
| case RID_GOTO: |
| /* APPLE LOCAL begin radar 5732232 - blocks (C++ cb) */ |
| if (cur_block) |
| error ("goto not allowed in block literal"); |
| /* APPLE LOCAL end radar 5732232 - blocks (C++ cb) */ |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| stmt = c_finish_goto_label (c_parser_peek_token (parser)->value); |
| c_parser_consume_token (parser); |
| } |
| else if (c_parser_next_token_is (parser, CPP_MULT)) |
| { |
| c_parser_consume_token (parser); |
| stmt = c_finish_goto_ptr (c_parser_expression (parser).value); |
| } |
| else |
| c_parser_error (parser, "expected identifier or %<*%>"); |
| goto expect_semicolon; |
| case RID_CONTINUE: |
| c_parser_consume_token (parser); |
| stmt = c_finish_bc_stmt (&c_cont_label, false); |
| goto expect_semicolon; |
| case RID_BREAK: |
| c_parser_consume_token (parser); |
| stmt = c_finish_bc_stmt (&c_break_label, true); |
| goto expect_semicolon; |
| case RID_RETURN: |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| { |
| stmt = c_finish_return (NULL_TREE); |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| stmt = c_finish_return (c_parser_expression_conv (parser).value); |
| goto expect_semicolon; |
| } |
| break; |
| case RID_ASM: |
| stmt = c_parser_asm_statement (parser); |
| break; |
| case RID_AT_THROW: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| { |
| stmt = objc_build_throw_stmt (NULL_TREE); |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| stmt |
| = objc_build_throw_stmt (c_parser_expression (parser).value); |
| goto expect_semicolon; |
| } |
| break; |
| case RID_AT_TRY: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_try_catch_statement (parser); |
| break; |
| case RID_AT_SYNCHRONIZED: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_objc_synchronized_statement (parser); |
| break; |
| default: |
| goto expr_stmt; |
| } |
| break; |
| case CPP_SEMICOLON: |
| c_parser_consume_token (parser); |
| break; |
| case CPP_CLOSE_PAREN: |
| case CPP_CLOSE_SQUARE: |
| /* Avoid infinite loop in error recovery: |
| c_parser_skip_until_found stops at a closing nesting |
| delimiter without consuming it, but here we need to consume |
| it to proceed further. */ |
| c_parser_error (parser, "expected statement"); |
| c_parser_consume_token (parser); |
| break; |
| case CPP_PRAGMA: |
| c_parser_pragma (parser, pragma_stmt); |
| break; |
| default: |
| expr_stmt: |
| /* APPLE LOCAL begin CW asm blocks */ |
| /* (in 4.2 al) */ |
| if (iasm_state >= iasm_decls) |
| { |
| iasm_state = iasm_asm; |
| inside_iasm_block = true; |
| iasm_kill_regs = true; |
| iasm_in_decl = false; |
| c_parser_iasm_line_seq_opt (parser); |
| stmt = NULL_TREE; |
| break; |
| } |
| /* APPLE LOCAL end CW asm blocks */ |
| stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value); |
| expect_semicolon: |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| break; |
| } |
| /* Two cases cannot and do not have line numbers associated: If stmt |
| is degenerate, such as "2;", then stmt is an INTEGER_CST, which |
| cannot hold line numbers. But that's OK because the statement |
| will either be changed to a MODIFY_EXPR during gimplification of |
| the statement expr, or discarded. If stmt was compound, but |
| without new variables, we will have skipped the creation of a |
| BIND and will have a bare STATEMENT_LIST. But that's OK because |
| (recursively) all of the component statements should already have |
| line numbers assigned. ??? Can we discard no-op statements |
| earlier? */ |
| if (stmt && EXPR_P (stmt)) |
| SET_EXPR_LOCATION (stmt, loc); |
| } |
| |
| /* Parse a parenthesized condition from an if, do or while statement. |
| |
| condition: |
| ( expression ) |
| */ |
| static tree |
| c_parser_paren_condition (c_parser *parser) |
| { |
| location_t loc; |
| tree cond; |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| return error_mark_node; |
| loc = c_parser_peek_token (parser)->location; |
| cond = c_objc_common_truthvalue_conversion |
| (c_parser_expression_conv (parser).value); |
| if (EXPR_P (cond)) |
| SET_EXPR_LOCATION (cond, loc); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| return cond; |
| } |
| |
| /* Parse a statement which is a block in C99. */ |
| |
| static tree |
| c_parser_c99_block_statement (c_parser *parser) |
| { |
| tree block = c_begin_compound_stmt (flag_isoc99); |
| c_parser_statement (parser); |
| return c_end_compound_stmt (block, flag_isoc99); |
| } |
| |
| /* Parse the body of an if statement or the else half thereof. This |
| is just parsing a statement but (a) it is a block in C99, (b) we |
| track whether the body is an if statement for the sake of |
| -Wparentheses warnings, (c) we handle an empty body specially for |
| the sake of -Wextra warnings. */ |
| |
| static tree |
| c_parser_if_body (c_parser *parser, bool *if_p) |
| { |
| tree block = c_begin_compound_stmt (flag_isoc99); |
| while (c_parser_next_token_is_keyword (parser, RID_CASE) |
| || c_parser_next_token_is_keyword (parser, RID_DEFAULT) |
| || (c_parser_next_token_is (parser, CPP_NAME) |
| && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) |
| c_parser_label (parser); |
| *if_p = c_parser_next_token_is_keyword (parser, RID_IF); |
| /* APPLE LOCAL mainline */ |
| if (c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| add_stmt (build_empty_stmt ()); |
| c_parser_statement_after_labels (parser); |
| return c_end_compound_stmt (block, flag_isoc99); |
| } |
| |
| /* Parse an if statement (C90 6.6.4, C99 6.8.4). |
| |
| if-statement: |
| if ( expression ) statement |
| if ( expression ) statement else statement |
| */ |
| |
| static void |
| c_parser_if_statement (c_parser *parser) |
| { |
| tree block; |
| location_t loc; |
| tree cond; |
| bool first_if = false, second_if = false; |
| tree first_body, second_body; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF)); |
| c_parser_consume_token (parser); |
| block = c_begin_compound_stmt (flag_isoc99); |
| loc = c_parser_peek_token (parser)->location; |
| cond = c_parser_paren_condition (parser); |
| first_body = c_parser_if_body (parser, &first_if); |
| if (c_parser_next_token_is_keyword (parser, RID_ELSE)) |
| { |
| c_parser_consume_token (parser); |
| second_body = c_parser_if_body (parser, &second_if); |
| } |
| else |
| second_body = NULL_TREE; |
| c_finish_if_stmt (loc, cond, first_body, second_body, first_if); |
| add_stmt (c_end_compound_stmt (block, flag_isoc99)); |
| } |
| |
| /* Parse a switch statement (C90 6.6.4, C99 6.8.4). |
| |
| switch-statement: |
| switch (expression) statement |
| */ |
| |
| static void |
| c_parser_switch_statement (c_parser *parser) |
| { |
| tree block, expr, body, save_break; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH)); |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL radar 6083129 - byref escapes (C++ cp) */ |
| in_bc_stmt_block (); |
| block = c_begin_compound_stmt (flag_isoc99); |
| if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| expr = c_parser_expression (parser).value; |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| } |
| else |
| expr = error_mark_node; |
| c_start_case (expr); |
| save_break = c_break_label; |
| c_break_label = NULL_TREE; |
| body = c_parser_c99_block_statement (parser); |
| c_finish_case (body); |
| if (c_break_label) |
| add_stmt (build1 (LABEL_EXPR, void_type_node, c_break_label)); |
| c_break_label = save_break; |
| add_stmt (c_end_compound_stmt (block, flag_isoc99)); |
| /* APPLE LOCAL radar 6083129 - byref escapes (C++ cp) */ |
| outof_bc_stmt_block (); |
| } |
| |
| /* Parse a while statement (C90 6.6.5, C99 6.8.5). |
| |
| while-statement: |
| APPLE LOCAL begin for-fsf-4_4 3274130 5295549 |
| while attributes (expression) statement |
| |
| The use of attributes is a GNU extension. |
| APPLE LOCAL end for-fsf-4_4 3274130 5295549 |
| */ |
| |
| static void |
| c_parser_while_statement (c_parser *parser) |
| { |
| /* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ |
| tree block, cond, body, save_break, save_cont, attrs; |
| /* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ |
| location_t loc; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE)); |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ |
| attrs = c_parser_attributes (parser); |
| /* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ |
| /* APPLE LOCAL radar 6083129 - byref escapes (C++ cp) */ |
| in_bc_stmt_block (); |
| block = c_begin_compound_stmt (flag_isoc99); |
| loc = c_parser_peek_token (parser)->location; |
| cond = c_parser_paren_condition (parser); |
| save_break = c_break_label; |
| c_break_label = NULL_TREE; |
| save_cont = c_cont_label; |
| c_cont_label = NULL_TREE; |
| body = c_parser_c99_block_statement (parser); |
| /* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ |
| c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, attrs, |
| true); |
| /* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ |
| add_stmt (c_end_compound_stmt (block, flag_isoc99)); |
| /* APPLE LOCAL radar 6083129 - byref escapes (C++ cp) */ |
| outof_bc_stmt_block (); |
| c_break_label = save_break; |
| c_cont_label = save_cont; |
| } |
| |
| /* Parse a do statement (C90 6.6.5, C99 6.8.5). |
| |
| do-statement: |
| APPLE LOCAL begin for-fsf-4_4 3274130 5295549 |
| do attributes statement while ( expression ) ; |
| |
| The use of attributes is a GNU extension. |
| APPLE LOCAL end for-fsf-4_4 3274130 5295549 |
| */ |
| |
| static void |
| c_parser_do_statement (c_parser *parser) |
| { |
| /* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ |
| tree block, cond, body, save_break, save_cont, new_break, new_cont, attrs; |
| /* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ |
| location_t loc; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO)); |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ |
| attrs = c_parser_attributes (parser); |
| /* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ |
| /* APPLE LOCAL radar 6083129 - byref escapes (C++ cp) */ |
| in_bc_stmt_block (); |
| block = c_begin_compound_stmt (flag_isoc99); |
| loc = c_parser_peek_token (parser)->location; |
| save_break = c_break_label; |
| c_break_label = NULL_TREE; |
| save_cont = c_cont_label; |
| c_cont_label = NULL_TREE; |
| body = c_parser_c99_block_statement (parser); |
| c_parser_require_keyword (parser, RID_WHILE, "expected %<while%>"); |
| new_break = c_break_label; |
| c_break_label = save_break; |
| new_cont = c_cont_label; |
| c_cont_label = save_cont; |
| cond = c_parser_paren_condition (parser); |
| if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| /* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ |
| c_finish_loop (loc, cond, NULL, body, new_break, new_cont, attrs, false); |
| /* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ |
| add_stmt (c_end_compound_stmt (block, flag_isoc99)); |
| /* APPLE LOCAL radar 6083129 - byref escapes (C++ cp) */ |
| outof_bc_stmt_block (); |
| } |
| |
| /* Parse a for statement (C90 6.6.5, C99 6.8.5). |
| |
| for-statement: |
| APPLE LOCAL begin for-fsf-4_4 3274130 5295549 |
| for attributes ( expression[opt] ; expression[opt] ; expression[opt] ) \ |
| statement |
| for attributes ( nested-declaration expression[opt] ; expression[opt] ) \ |
| statement |
| |
| The form with a declaration is new in C99. |
| |
| The use of attributes is a GNU extension. |
| |
| APPLE LOCAL end for-fsf-4_4 3274130 5295549 |
| ??? In accordance with the old parser, the declaration may be a |
| nested function, which is then rejected in check_for_loop_decls, |
| but does it make any sense for this to be included in the grammar? |
| Note in particular that the nested function does not include a |
| trailing ';', whereas the "declaration" production includes one. |
| Also, can we reject bad declarations earlier and cheaper than |
| check_for_loop_decls? */ |
| |
| static void |
| c_parser_for_statement (c_parser *parser) |
| { |
| /* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ |
| tree block, cond, incr, save_break, save_cont, body, attrs; |
| /* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ |
| location_t loc; |
| /* APPLE LOCAL radar 4708210 (for_objc_collection in 4.2) */ |
| bool foreach_p = false; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); |
| loc = c_parser_peek_token (parser)->location; |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ |
| attrs = c_parser_attributes (parser); |
| /* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ |
| /* APPLE LOCAL radar 6083129 - byref escapes (C++ cp) */ |
| in_bc_stmt_block (); |
| /* APPLE LOCAL radar 4472881 (in 4.2 ah) */ |
| block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ()); |
| if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| /* APPLE LOCAL radar 4472881 (in 4.2 u) */ |
| objc_foreach_context = 1; |
| /* Parse the initialization declaration or expression. */ |
| if (c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| { |
| c_parser_consume_token (parser); |
| c_finish_expr_stmt (NULL_TREE); |
| } |
| else if (c_parser_next_token_starts_declspecs (parser)) |
| { |
| /* APPLE LOCAL begin radar 4708210 (for_objc_collection in 4.2) */ |
| cond = NULL_TREE; |
| c_parser_declaration_or_fndef (parser, true, true, true, true, &cond); |
| /* APPLE LOCAL radar 5925639 */ |
| if (c_parser_next_token_is_keyword (parser, RID_IN) && cond) |
| { |
| cond = finish_parse_foreach_header (parser, cond); |
| foreach_p = true; |
| } |
| else |
| check_for_loop_decls (); |
| /* APPLE LOCAL end radar 4708210 (for_objc_collection in 4.2) */ |
| } |
| else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) |
| { |
| /* __extension__ can start a declaration, but is also an |
| unary operator that can start an expression. Consume all |
| but the last of a possible series of __extension__ to |
| determine which. */ |
| while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD |
| && (c_parser_peek_2nd_token (parser)->keyword |
| == RID_EXTENSION)) |
| c_parser_consume_token (parser); |
| if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser))) |
| { |
| int ext; |
| ext = disable_extension_diagnostics (); |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL begin radar 4708210 (for_objc_collection in 4.2) */ |
| cond = NULL_TREE; |
| c_parser_declaration_or_fndef (parser, true, true, true, true, &cond); |
| restore_extension_diagnostics (ext); |
| /* APPLE LOCAL radar 5925639 */ |
| if (c_parser_next_token_is_keyword (parser, RID_IN) && cond) |
| { |
| cond = finish_parse_foreach_header (parser, cond); |
| foreach_p = true; |
| } |
| else |
| check_for_loop_decls (); |
| /* APPLE LOCAL end radar 4708210 (for_objc_collection in 4.2) */ |
| } |
| else |
| goto init_expr; |
| } |
| else |
| { |
| init_expr: |
| /* APPLE LOCAL begin radar 4708210 (for_objc_collection in 4.2) */ |
| cond = c_parser_expression (parser).value; |
| if (c_parser_next_token_is_keyword (parser, RID_IN)) |
| { |
| c_parser_consume_token (parser); /* IN */ |
| cond = build_tree_list (cond, c_parser_initializer (parser).value); |
| foreach_p = true; |
| } |
| else |
| { |
| c_finish_expr_stmt (cond); |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| } |
| } |
| objc_foreach_context = 0; |
| /* APPLE LOCAL end radar 4708210 (for_objc_collection in 4.2) */ |
| /* Parse the loop condition. */ |
| loc = c_parser_peek_token (parser)->location; |
| if (c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| { |
| c_parser_consume_token (parser); |
| cond = NULL_TREE; |
| } |
| /* APPLE LOCAL begin radar 4708210 (for_objc_collection in 4.2) */ |
| else if (foreach_p) |
| ; |
| /* APPLE LOCAL end radar 4708210 (for_objc_collection in 4.2) */ |
| else |
| { |
| tree ocond = c_parser_expression_conv (parser).value; |
| cond = c_objc_common_truthvalue_conversion (ocond); |
| if (EXPR_P (cond)) |
| SET_EXPR_LOCATION (cond, loc); |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| } |
| /* Parse the increment expression. */ |
| if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) |
| incr = c_process_expr_stmt (NULL_TREE); |
| else |
| incr = c_process_expr_stmt (c_parser_expression (parser).value); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| } |
| else |
| { |
| cond = error_mark_node; |
| incr = error_mark_node; |
| } |
| save_break = c_break_label; |
| c_break_label = NULL_TREE; |
| save_cont = c_cont_label; |
| c_cont_label = NULL_TREE; |
| body = c_parser_c99_block_statement (parser); |
| /* APPLE LOCAL begin radar 4708210 (for_objc_collection in 4.2) */ |
| if (foreach_p) |
| objc_finish_foreach_loop (loc, cond, body, c_break_label, c_cont_label); |
| else |
| /* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ |
| c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, attrs, |
| true); |
| /* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ |
| /* APPLE LOCAL end radar 4708210 (for_objc_collection in 4.2) */ |
| /* APPLE LOCAL radar 4472881 (in 4.2 ai) */ |
| add_stmt (c_end_compound_stmt (block, flag_isoc99 || c_dialect_objc ())); |
| /* APPLE LOCAL radar 6083129 - byref escapes (C++ cp) */ |
| outof_bc_stmt_block (); |
| c_break_label = save_break; |
| c_cont_label = save_cont; |
| } |
| |
| /* Parse an asm statement, a GNU extension. This is a full-blown asm |
| statement with inputs, outputs, clobbers, and volatile tag |
| allowed. |
| |
| asm-statement: |
| asm type-qualifier[opt] ( asm-argument ) ; |
| |
| asm-argument: |
| asm-string-literal |
| asm-string-literal : asm-operands[opt] |
| asm-string-literal : asm-operands[opt] : asm-operands[opt] |
| asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers |
| |
| Qualifiers other than volatile are accepted in the syntax but |
| warned for. */ |
| |
| static tree |
| c_parser_asm_statement (c_parser *parser) |
| { |
| tree quals, str, outputs, inputs, clobbers, ret; |
| bool simple; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL CW asm blocks */ |
| iasm_state = iasm_decls; |
| if (c_parser_next_token_is_keyword (parser, RID_VOLATILE)) |
| { |
| quals = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| } |
| else if (c_parser_next_token_is_keyword (parser, RID_CONST) |
| || c_parser_next_token_is_keyword (parser, RID_RESTRICT)) |
| { |
| warning (0, "%E qualifier ignored on asm", |
| c_parser_peek_token (parser)->value); |
| quals = NULL_TREE; |
| c_parser_consume_token (parser); |
| } |
| else |
| quals = NULL_TREE; |
| /* APPLE LOCAL begin CW asm blocks */ |
| /* A CW-style asm block is introduced by an open brace. */ |
| /* (in 4.2 as) */ |
| if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| { |
| if (quals) |
| warning (0, "%E qualifier ignored on asm", quals); |
| c_parser_consume_token (parser); |
| if (flag_iasm_blocks) |
| c_parser_iasm_compound_statement (parser); |
| else |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); |
| c_parser_error (parser, "asm blocks not enabled, use `-fasm-blocks'"); |
| iasm_state = iasm_none; |
| } |
| return NULL_TREE; |
| } |
| if (quals == NULL_TREE |
| && (c_parser_next_token_is (parser, CPP_DOT) |
| || c_parser_next_token_is (parser, CPP_ATSIGN) |
| || c_parser_next_token_is (parser, CPP_NAME) |
| || c_parser_next_token_is_keyword (parser, RID_ASM) |
| || c_parser_next_token_is (parser, CPP_SEMICOLON) |
| || (c_parser_iasm_bol (parser) |
| && ! c_parser_next_token_is (parser, CPP_OPEN_PAREN)))) |
| { |
| if (flag_iasm_blocks) |
| c_parser_iasm_top_statement (parser); |
| else |
| error ("asm blocks not enabled, use `-fasm-blocks'"); |
| return NULL_TREE; |
| } |
| iasm_state = iasm_none; |
| /* APPLE LOCAL end CW asm blocks */ |
| /* ??? Follow the C++ parser rather than using the |
| c_lex_string_translate kludge. */ |
| c_lex_string_translate = 0; |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| c_lex_string_translate = 1; |
| return NULL_TREE; |
| } |
| str = c_parser_asm_string_literal (parser); |
| if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) |
| { |
| simple = true; |
| outputs = NULL_TREE; |
| inputs = NULL_TREE; |
| clobbers = NULL_TREE; |
| goto done_asm; |
| } |
| if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")) |
| { |
| c_lex_string_translate = 1; |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| return NULL_TREE; |
| } |
| simple = false; |
| /* Parse outputs. */ |
| if (c_parser_next_token_is (parser, CPP_COLON) |
| || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) |
| outputs = NULL_TREE; |
| else |
| outputs = c_parser_asm_operands (parser, false); |
| if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) |
| { |
| inputs = NULL_TREE; |
| clobbers = NULL_TREE; |
| goto done_asm; |
| } |
| if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")) |
| { |
| c_lex_string_translate = 1; |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| return NULL_TREE; |
| } |
| /* Parse inputs. */ |
| if (c_parser_next_token_is (parser, CPP_COLON) |
| || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) |
| inputs = NULL_TREE; |
| else |
| inputs = c_parser_asm_operands (parser, true); |
| if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) |
| { |
| clobbers = NULL_TREE; |
| goto done_asm; |
| } |
| if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")) |
| { |
| c_lex_string_translate = 1; |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| return NULL_TREE; |
| } |
| /* Parse clobbers. */ |
| clobbers = c_parser_asm_clobbers (parser); |
| done_asm: |
| c_lex_string_translate = 1; |
| if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| return NULL_TREE; |
| } |
| if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| ret = build_asm_stmt (quals, build_asm_expr (str, outputs, inputs, |
| clobbers, simple)); |
| return ret; |
| } |
| |
| /* Parse asm operands, a GNU extension. If CONVERT_P (for inputs but |
| not outputs), apply the default conversion of functions and arrays |
| to pointers. |
| |
| asm-operands: |
| asm-operand |
| asm-operands , asm-operand |
| |
| asm-operand: |
| asm-string-literal ( expression ) |
| [ identifier ] asm-string-literal ( expression ) |
| */ |
| |
| static tree |
| c_parser_asm_operands (c_parser *parser, bool convert_p) |
| { |
| tree list = NULL_TREE; |
| while (true) |
| { |
| tree name, str; |
| struct c_expr expr; |
| if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) |
| { |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| tree id = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| name = build_string (IDENTIFIER_LENGTH (id), |
| IDENTIFIER_POINTER (id)); |
| } |
| else |
| { |
| c_parser_error (parser, "expected identifier"); |
| c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL); |
| return NULL_TREE; |
| } |
| c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, |
| "expected %<]%>"); |
| } |
| else |
| name = NULL_TREE; |
| str = c_parser_asm_string_literal (parser); |
| if (str == NULL_TREE) |
| return NULL_TREE; |
| c_lex_string_translate = 1; |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| c_lex_string_translate = 0; |
| return NULL_TREE; |
| } |
| expr = c_parser_expression (parser); |
| if (convert_p) |
| expr = default_function_array_conversion (expr); |
| c_lex_string_translate = 0; |
| if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| return NULL_TREE; |
| } |
| list = chainon (list, build_tree_list (build_tree_list (name, str), |
| expr.value)); |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| c_parser_consume_token (parser); |
| else |
| break; |
| } |
| return list; |
| } |
| |
| /* Parse asm clobbers, a GNU extension. |
| |
| asm-clobbers: |
| asm-string-literal |
| asm-clobbers , asm-string-literal |
| */ |
| |
| static tree |
| c_parser_asm_clobbers (c_parser *parser) |
| { |
| tree list = NULL_TREE; |
| while (true) |
| { |
| tree str = c_parser_asm_string_literal (parser); |
| if (str) |
| list = tree_cons (NULL_TREE, str, list); |
| else |
| return NULL_TREE; |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| c_parser_consume_token (parser); |
| else |
| break; |
| } |
| return list; |
| } |
| |
| /* Parse an expression other than a compound expression; that is, an |
| assignment expression (C90 6.3.16, C99 6.5.16). If AFTER is not |
| NULL then it is an Objective-C message expression which is the |
| primary-expression starting the expression as an initializer. |
| |
| assignment-expression: |
| conditional-expression |
| unary-expression assignment-operator assignment-expression |
| |
| assignment-operator: one of |
| = *= /= %= += -= <<= >>= &= ^= |= |
| |
| In GNU C we accept any conditional expression on the LHS and |
| diagnose the invalid lvalue rather than producing a syntax |
| error. */ |
| |
| static struct c_expr |
| c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) |
| { |
| struct c_expr lhs, rhs, ret; |
| enum tree_code code; |
| gcc_assert (!after || c_dialect_objc ()); |
| lhs = c_parser_conditional_expression (parser, after); |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_EQ: |
| code = NOP_EXPR; |
| break; |
| case CPP_MULT_EQ: |
| code = MULT_EXPR; |
| break; |
| case CPP_DIV_EQ: |
| code = TRUNC_DIV_EXPR; |
| break; |
| case CPP_MOD_EQ: |
| code = TRUNC_MOD_EXPR; |
| break; |
| case CPP_PLUS_EQ: |
| code = PLUS_EXPR; |
| break; |
| case CPP_MINUS_EQ: |
| code = MINUS_EXPR; |
| break; |
| case CPP_LSHIFT_EQ: |
| code = LSHIFT_EXPR; |
| break; |
| case CPP_RSHIFT_EQ: |
| code = RSHIFT_EXPR; |
| break; |
| case CPP_AND_EQ: |
| code = BIT_AND_EXPR; |
| break; |
| case CPP_XOR_EQ: |
| code = BIT_XOR_EXPR; |
| break; |
| case CPP_OR_EQ: |
| code = BIT_IOR_EXPR; |
| break; |
| default: |
| return lhs; |
| } |
| c_parser_consume_token (parser); |
| rhs = c_parser_expr_no_commas (parser, NULL); |
| rhs = default_function_array_conversion (rhs); |
| ret.value = build_modify_expr (lhs.value, code, rhs.value); |
| if (code == NOP_EXPR) |
| ret.original_code = MODIFY_EXPR; |
| else |
| { |
| TREE_NO_WARNING (ret.value) = 1; |
| ret.original_code = ERROR_MARK; |
| } |
| return ret; |
| } |
| |
| /* Parse a conditional expression (C90 6.3.15, C99 6.5.15). If AFTER |
| is not NULL then it is an Objective-C message expression which is |
| the primary-expression starting the expression as an initializer. |
| |
| conditional-expression: |
| logical-OR-expression |
| logical-OR-expression ? expression : conditional-expression |
| |
| GNU extensions: |
| |
| conditional-expression: |
| logical-OR-expression ? : conditional-expression |
| */ |
| |
| static struct c_expr |
| c_parser_conditional_expression (c_parser *parser, struct c_expr *after) |
| { |
| struct c_expr cond, exp1, exp2, ret; |
| gcc_assert (!after || c_dialect_objc ()); |
| cond = c_parser_binary_expression (parser, after); |
| if (c_parser_next_token_is_not (parser, CPP_QUERY)) |
| return cond; |
| cond = default_function_array_conversion (cond); |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_COLON)) |
| { |
| if (pedantic) |
| pedwarn ("ISO C forbids omitting the middle term of a ?: expression"); |
| /* Make sure first operand is calculated only once. */ |
| exp1.value = save_expr (default_conversion (cond.value)); |
| cond.value = c_objc_common_truthvalue_conversion (exp1.value); |
| skip_evaluation += cond.value == truthvalue_true_node; |
| } |
| else |
| { |
| cond.value |
| = c_objc_common_truthvalue_conversion |
| (default_conversion (cond.value)); |
| skip_evaluation += cond.value == truthvalue_false_node; |
| exp1 = c_parser_expression_conv (parser); |
| skip_evaluation += ((cond.value == truthvalue_true_node) |
| - (cond.value == truthvalue_false_node)); |
| } |
| if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) |
| { |
| skip_evaluation -= cond.value == truthvalue_true_node; |
| ret.value = error_mark_node; |
| ret.original_code = ERROR_MARK; |
| return ret; |
| } |
| exp2 = c_parser_conditional_expression (parser, NULL); |
| exp2 = default_function_array_conversion (exp2); |
| skip_evaluation -= cond.value == truthvalue_true_node; |
| ret.value = build_conditional_expr (cond.value, exp1.value, exp2.value); |
| ret.original_code = ERROR_MARK; |
| return ret; |
| } |
| |
| /* Parse a binary expression; that is, a logical-OR-expression (C90 |
| 6.3.5-6.3.14, C99 6.5.5-6.5.14). If AFTER is not NULL then it is |
| an Objective-C message expression which is the primary-expression |
| starting the expression as an initializer. |
| |
| multiplicative-expression: |
| cast-expression |
| multiplicative-expression * cast-expression |
| multiplicative-expression / cast-expression |
| multiplicative-expression % cast-expression |
| |
| additive-expression: |
| multiplicative-expression |
| additive-expression + multiplicative-expression |
| additive-expression - multiplicative-expression |
| |
| shift-expression: |
| additive-expression |
| shift-expression << additive-expression |
| shift-expression >> additive-expression |
| |
| relational-expression: |
| shift-expression |
| relational-expression < shift-expression |
| relational-expression > shift-expression |
| relational-expression <= shift-expression |
| relational-expression >= shift-expression |
| |
| equality-expression: |
| relational-expression |
| equality-expression == relational-expression |
| equality-expression != relational-expression |
| |
| AND-expression: |
| equality-expression |
| AND-expression & equality-expression |
| |
| exclusive-OR-expression: |
| AND-expression |
| exclusive-OR-expression ^ AND-expression |
| |
| inclusive-OR-expression: |
| exclusive-OR-expression |
| inclusive-OR-expression | exclusive-OR-expression |
| |
| logical-AND-expression: |
| inclusive-OR-expression |
| logical-AND-expression && inclusive-OR-expression |
| |
| logical-OR-expression: |
| logical-AND-expression |
| logical-OR-expression || logical-AND-expression |
| */ |
| |
| static struct c_expr |
| c_parser_binary_expression (c_parser *parser, struct c_expr *after) |
| { |
| /* A binary expression is parsed using operator-precedence parsing, |
| with the operands being cast expressions. All the binary |
| operators are left-associative. Thus a binary expression is of |
| form: |
| |
| E0 op1 E1 op2 E2 ... |
| |
| which we represent on a stack. On the stack, the precedence |
| levels are strictly increasing. When a new operator is |
| encountered of higher precedence than that at the top of the |
| stack, it is pushed; its LHS is the top expression, and its RHS |
| is everything parsed until it is popped. When a new operator is |
| encountered with precedence less than or equal to that at the top |
| of the stack, triples E[i-1] op[i] E[i] are popped and replaced |
| by the result of the operation until the operator at the top of |
| the stack has lower precedence than the new operator or there is |
| only one element on the stack; then the top expression is the LHS |
| of the new operator. In the case of logical AND and OR |
| expressions, we also need to adjust skip_evaluation as |
| appropriate when the operators are pushed and popped. */ |
| |
| /* The precedence levels, where 0 is a dummy lowest level used for |
| the bottom of the stack. */ |
| enum prec { |
| PREC_NONE, |
| PREC_LOGOR, |
| PREC_LOGAND, |
| PREC_BITOR, |
| PREC_BITXOR, |
| PREC_BITAND, |
| PREC_EQ, |
| PREC_REL, |
| PREC_SHIFT, |
| PREC_ADD, |
| PREC_MULT, |
| NUM_PRECS |
| }; |
| struct { |
| /* The expression at this stack level. */ |
| struct c_expr expr; |
| /* The precedence of the operator on its left, PREC_NONE at the |
| bottom of the stack. */ |
| enum prec prec; |
| /* The operation on its left. */ |
| enum tree_code op; |
| } stack[NUM_PRECS]; |
| int sp; |
| #define POP \ |
| do { \ |
| switch (stack[sp].op) \ |
| { \ |
| case TRUTH_ANDIF_EXPR: \ |
| skip_evaluation -= stack[sp - 1].expr.value == truthvalue_false_node; \ |
| break; \ |
| case TRUTH_ORIF_EXPR: \ |
| skip_evaluation -= stack[sp - 1].expr.value == truthvalue_true_node; \ |
| break; \ |
| default: \ |
| break; \ |
| } \ |
| stack[sp - 1].expr \ |
| = default_function_array_conversion (stack[sp - 1].expr); \ |
| stack[sp].expr \ |
| = default_function_array_conversion (stack[sp].expr); \ |
| stack[sp - 1].expr = parser_build_binary_op (stack[sp].op, \ |
| stack[sp - 1].expr, \ |
| stack[sp].expr); \ |
| sp--; \ |
| } while (0) |
| gcc_assert (!after || c_dialect_objc ()); |
| stack[0].expr = c_parser_cast_expression (parser, after); |
| /* APPLE LOCAL begin radar 4426814 */ |
| if (c_dialect_objc() && flag_objc_gc) |
| /* APPLE LOCAL radar 5276085 */ |
| stack[0].expr.value = objc_build_weak_reference_tree (stack[0].expr.value); |
| /* APPLE LOCAL end radar 4426814 */ |
| stack[0].prec = PREC_NONE; |
| sp = 0; |
| while (true) |
| { |
| enum prec oprec; |
| enum tree_code ocode; |
| if (parser->error) |
| goto out; |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_MULT: |
| oprec = PREC_MULT; |
| ocode = MULT_EXPR; |
| break; |
| case CPP_DIV: |
| oprec = PREC_MULT; |
| ocode = TRUNC_DIV_EXPR; |
| break; |
| case CPP_MOD: |
| oprec = PREC_MULT; |
| ocode = TRUNC_MOD_EXPR; |
| break; |
| case CPP_PLUS: |
| oprec = PREC_ADD; |
| ocode = PLUS_EXPR; |
| break; |
| case CPP_MINUS: |
| oprec = PREC_ADD; |
| ocode = MINUS_EXPR; |
| break; |
| case CPP_LSHIFT: |
| oprec = PREC_SHIFT; |
| ocode = LSHIFT_EXPR; |
| break; |
| case CPP_RSHIFT: |
| oprec = PREC_SHIFT; |
| ocode = RSHIFT_EXPR; |
| break; |
| case CPP_LESS: |
| oprec = PREC_REL; |
| ocode = LT_EXPR; |
| break; |
| case CPP_GREATER: |
| oprec = PREC_REL; |
| ocode = GT_EXPR; |
| break; |
| case CPP_LESS_EQ: |
| oprec = PREC_REL; |
| ocode = LE_EXPR; |
| break; |
| case CPP_GREATER_EQ: |
| oprec = PREC_REL; |
| ocode = GE_EXPR; |
| break; |
| case CPP_EQ_EQ: |
| oprec = PREC_EQ; |
| ocode = EQ_EXPR; |
| break; |
| case CPP_NOT_EQ: |
| oprec = PREC_EQ; |
| ocode = NE_EXPR; |
| break; |
| case CPP_AND: |
| oprec = PREC_BITAND; |
| ocode = BIT_AND_EXPR; |
| break; |
| case CPP_XOR: |
| oprec = PREC_BITXOR; |
| ocode = BIT_XOR_EXPR; |
| break; |
| case CPP_OR: |
| oprec = PREC_BITOR; |
| ocode = BIT_IOR_EXPR; |
| break; |
| case CPP_AND_AND: |
| oprec = PREC_LOGAND; |
| ocode = TRUTH_ANDIF_EXPR; |
| break; |
| case CPP_OR_OR: |
| oprec = PREC_LOGOR; |
| ocode = TRUTH_ORIF_EXPR; |
| break; |
| default: |
| /* Not a binary operator, so end of the binary |
| expression. */ |
| goto out; |
| } |
| c_parser_consume_token (parser); |
| while (oprec <= stack[sp].prec) |
| POP; |
| switch (ocode) |
| { |
| case TRUTH_ANDIF_EXPR: |
| stack[sp].expr |
| = default_function_array_conversion (stack[sp].expr); |
| stack[sp].expr.value = c_objc_common_truthvalue_conversion |
| (default_conversion (stack[sp].expr.value)); |
| skip_evaluation += stack[sp].expr.value == truthvalue_false_node; |
| break; |
| case TRUTH_ORIF_EXPR: |
| stack[sp].expr |
| = default_function_array_conversion (stack[sp].expr); |
| stack[sp].expr.value = c_objc_common_truthvalue_conversion |
| (default_conversion (stack[sp].expr.value)); |
| skip_evaluation += stack[sp].expr.value == truthvalue_true_node; |
| break; |
| default: |
| break; |
| } |
| sp++; |
| stack[sp].expr = c_parser_cast_expression (parser, NULL); |
| /* APPLE LOCAL begin radar 4426814 */ |
| if (c_dialect_objc() && flag_objc_gc) |
| /* APPLE LOCAL radar 5276085 */ |
| stack[sp].expr.value = objc_build_weak_reference_tree (stack[sp].expr.value); |
| /* APPLE LOCAL end radar 4426814 */ |
| stack[sp].prec = oprec; |
| stack[sp].op = ocode; |
| } |
| out: |
| while (sp > 0) |
| POP; |
| return stack[0].expr; |
| #undef POP |
| } |
| |
| /* Parse a cast expression (C90 6.3.4, C99 6.5.4). If AFTER is not |
| NULL then it is an Objective-C message expression which is the |
| primary-expression starting the expression as an initializer. |
| |
| cast-expression: |
| unary-expression |
| ( type-name ) unary-expression |
| */ |
| |
| static struct c_expr |
| c_parser_cast_expression (c_parser *parser, struct c_expr *after) |
| { |
| gcc_assert (!after || c_dialect_objc ()); |
| if (after) |
| return c_parser_postfix_expression_after_primary (parser, *after); |
| /* If the expression begins with a parenthesized type name, it may |
| be either a cast or a compound literal; we need to see whether |
| the next character is '{' to tell the difference. If not, it is |
| an unary expression. */ |
| if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) |
| && c_token_starts_typename (c_parser_peek_2nd_token (parser))) |
| { |
| struct c_type_name *type_name; |
| struct c_expr ret; |
| struct c_expr expr; |
| c_parser_consume_token (parser); |
| type_name = c_parser_type_name (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| if (type_name == NULL) |
| { |
| ret.value = error_mark_node; |
| ret.original_code = ERROR_MARK; |
| return ret; |
| } |
| |
| /* Save casted types in the function's used types hash table. */ |
| used_types_insert (type_name->specs->type); |
| |
| if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| return c_parser_postfix_expression_after_paren_type (parser, |
| type_name); |
| expr = c_parser_cast_expression (parser, NULL); |
| expr = default_function_array_conversion (expr); |
| ret.value = c_cast_expr (type_name, expr.value); |
| ret.original_code = ERROR_MARK; |
| return ret; |
| } |
| else |
| return c_parser_unary_expression (parser); |
| } |
| |
| /* Parse an unary expression (C90 6.3.3, C99 6.5.3). |
| |
| unary-expression: |
| postfix-expression |
| ++ unary-expression |
| -- unary-expression |
| unary-operator cast-expression |
| sizeof unary-expression |
| sizeof ( type-name ) |
| |
| unary-operator: one of |
| & * + - ~ ! |
| |
| GNU extensions: |
| |
| unary-expression: |
| __alignof__ unary-expression |
| __alignof__ ( type-name ) |
| && identifier |
| |
| unary-operator: one of |
| __extension__ __real__ __imag__ |
| |
| In addition, the GNU syntax treats ++ and -- as unary operators, so |
| they may be applied to cast expressions with errors for non-lvalues |
| given later. */ |
| |
| static struct c_expr |
| c_parser_unary_expression (c_parser *parser) |
| { |
| int ext; |
| struct c_expr ret, op; |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_PLUS_PLUS: |
| c_parser_consume_token (parser); |
| op = c_parser_cast_expression (parser, NULL); |
| op = default_function_array_conversion (op); |
| return parser_build_unary_op (PREINCREMENT_EXPR, op); |
| case CPP_MINUS_MINUS: |
| c_parser_consume_token (parser); |
| op = c_parser_cast_expression (parser, NULL); |
| op = default_function_array_conversion (op); |
| return parser_build_unary_op (PREDECREMENT_EXPR, op); |
| case CPP_AND: |
| c_parser_consume_token (parser); |
| return parser_build_unary_op (ADDR_EXPR, |
| c_parser_cast_expression (parser, NULL)); |
| case CPP_MULT: |
| c_parser_consume_token (parser); |
| op = c_parser_cast_expression (parser, NULL); |
| op = default_function_array_conversion (op); |
| ret.value = build_indirect_ref (op.value, "unary *"); |
| ret.original_code = ERROR_MARK; |
| return ret; |
| case CPP_PLUS: |
| c_parser_consume_token (parser); |
| if (!c_dialect_objc () && !in_system_header) |
| warning (OPT_Wtraditional, |
| "traditional C rejects the unary plus operator"); |
| op = c_parser_cast_expression (parser, NULL); |
| op = default_function_array_conversion (op); |
| return parser_build_unary_op (CONVERT_EXPR, op); |
| case CPP_MINUS: |
| c_parser_consume_token (parser); |
| op = c_parser_cast_expression (parser, NULL); |
| op = default_function_array_conversion (op); |
| return parser_build_unary_op (NEGATE_EXPR, op); |
| case CPP_COMPL: |
| c_parser_consume_token (parser); |
| op = c_parser_cast_expression (parser, NULL); |
| op = default_function_array_conversion (op); |
| return parser_build_unary_op (BIT_NOT_EXPR, op); |
| case CPP_NOT: |
| c_parser_consume_token (parser); |
| op = c_parser_cast_expression (parser, NULL); |
| op = default_function_array_conversion (op); |
| return parser_build_unary_op (TRUTH_NOT_EXPR, op); |
| case CPP_AND_AND: |
| /* Refer to the address of a label as a pointer. */ |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| ret.value = finish_label_address_expr |
| (c_parser_peek_token (parser)->value); |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| c_parser_error (parser, "expected identifier"); |
| ret.value = error_mark_node; |
| } |
| ret.original_code = ERROR_MARK; |
| return ret; |
| case CPP_KEYWORD: |
| switch (c_parser_peek_token (parser)->keyword) |
| { |
| case RID_SIZEOF: |
| return c_parser_sizeof_expression (parser); |
| case RID_ALIGNOF: |
| return c_parser_alignof_expression (parser); |
| case RID_EXTENSION: |
| c_parser_consume_token (parser); |
| ext = disable_extension_diagnostics (); |
| ret = c_parser_cast_expression (parser, NULL); |
| restore_extension_diagnostics (ext); |
| return ret; |
| case RID_REALPART: |
| c_parser_consume_token (parser); |
| op = c_parser_cast_expression (parser, NULL); |
| op = default_function_array_conversion (op); |
| return parser_build_unary_op (REALPART_EXPR, op); |
| case RID_IMAGPART: |
| c_parser_consume_token (parser); |
| op = c_parser_cast_expression (parser, NULL); |
| op = default_function_array_conversion (op); |
| return parser_build_unary_op (IMAGPART_EXPR, op); |
| default: |
| return c_parser_postfix_expression (parser); |
| } |
| default: |
| return c_parser_postfix_expression (parser); |
| } |
| } |
| |
| /* Parse a sizeof expression. */ |
| |
| static struct c_expr |
| c_parser_sizeof_expression (c_parser *parser) |
| { |
| struct c_expr expr; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); |
| c_parser_consume_token (parser); |
| skip_evaluation++; |
| in_sizeof++; |
| if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) |
| && c_token_starts_typename (c_parser_peek_2nd_token (parser))) |
| { |
| /* Either sizeof ( type-name ) or sizeof unary-expression |
| starting with a compound literal. */ |
| struct c_type_name *type_name; |
| c_parser_consume_token (parser); |
| type_name = c_parser_type_name (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| if (type_name == NULL) |
| { |
| struct c_expr ret; |
| skip_evaluation--; |
| in_sizeof--; |
| ret.value = error_mark_node; |
| ret.original_code = ERROR_MARK; |
| return ret; |
| } |
| if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| { |
| expr = c_parser_postfix_expression_after_paren_type (parser, |
| type_name); |
| goto sizeof_expr; |
| } |
| /* sizeof ( type-name ). */ |
| skip_evaluation--; |
| in_sizeof--; |
| if (type_name->declarator->kind == cdk_array |
| && type_name->declarator->u.array.vla_unspec_p) |
| { |
| /* C99 6.7.5.2p4 */ |
| error ("%<[*]%> not allowed in other than a declaration"); |
| } |
| return c_expr_sizeof_type (type_name); |
| } |
| else |
| { |
| expr = c_parser_unary_expression (parser); |
| sizeof_expr: |
| skip_evaluation--; |
| in_sizeof--; |
| if (TREE_CODE (expr.value) == COMPONENT_REF |
| && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) |
| error ("%<sizeof%> applied to a bit-field"); |
| return c_expr_sizeof_expr (expr); |
| } |
| } |
| |
| /* Parse an alignof expression. */ |
| |
| static struct c_expr |
| c_parser_alignof_expression (c_parser *parser) |
| { |
| struct c_expr expr; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF)); |
| c_parser_consume_token (parser); |
| skip_evaluation++; |
| in_alignof++; |
| if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) |
| && c_token_starts_typename (c_parser_peek_2nd_token (parser))) |
| { |
| /* Either __alignof__ ( type-name ) or __alignof__ |
| unary-expression starting with a compound literal. */ |
| struct c_type_name *type_name; |
| struct c_expr ret; |
| c_parser_consume_token (parser); |
| type_name = c_parser_type_name (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| if (type_name == NULL) |
| { |
| struct c_expr ret; |
| skip_evaluation--; |
| in_alignof--; |
| ret.value = error_mark_node; |
| ret.original_code = ERROR_MARK; |
| return ret; |
| } |
| if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| { |
| expr = c_parser_postfix_expression_after_paren_type (parser, |
| type_name); |
| goto alignof_expr; |
| } |
| /* alignof ( type-name ). */ |
| skip_evaluation--; |
| in_alignof--; |
| ret.value = c_alignof (groktypename (type_name)); |
| ret.original_code = ERROR_MARK; |
| return ret; |
| } |
| else |
| { |
| struct c_expr ret; |
| expr = c_parser_unary_expression (parser); |
| alignof_expr: |
| skip_evaluation--; |
| in_alignof--; |
| ret.value = c_alignof_expr (expr.value); |
| ret.original_code = ERROR_MARK; |
| return ret; |
| } |
| } |
| |
| /* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2). |
| |
| postfix-expression: |
| primary-expression |
| postfix-expression [ expression ] |
| postfix-expression ( argument-expression-list[opt] ) |
| postfix-expression . identifier |
| APPLE LOCAL CW asm blocks |
| typedef-name . identifier |
| postfix-expression -> identifier |
| postfix-expression ++ |
| postfix-expression -- |
| ( type-name ) { initializer-list } |
| ( type-name ) { initializer-list , } |
| APPLE LOCAL CW asm blocks |
| primary-expression PTR postfix-expression |
| |
| argument-expression-list: |
| argument-expression |
| argument-expression-list , argument-expression |
| |
| primary-expression: |
| APPLE LOCAL CW asm blocks |
| . |
| identifier |
| APPLE LOCAL CW asm blocks |
| @identifier |
| constant |
| string-literal |
| ( expression ) |
| APPLE LOCAL CW asm blocks |
| [ expression ] |
| |
| GNU extensions: |
| |
| primary-expression: |
| __func__ |
| (treated as a keyword in GNU C) |
| __FUNCTION__ |
| __PRETTY_FUNCTION__ |
| ( compound-statement ) |
| __builtin_va_arg ( assignment-expression , type-name ) |
| __builtin_offsetof ( type-name , offsetof-member-designator ) |
| __builtin_choose_expr ( assignment-expression , |
| assignment-expression , |
| assignment-expression ) |
| __builtin_types_compatible_p ( type-name , type-name ) |
| APPLE LOCAL blocks (C++ cf) |
| ^ block-literal-expr |
| |
| offsetof-member-designator: |
| identifier |
| offsetof-member-designator . identifier |
| offsetof-member-designator [ expression ] |
| |
| Objective-C: |
| |
| primary-expression: |
| [ objc-receiver objc-message-args ] |
| @selector ( objc-selector-arg ) |
| @protocol ( identifier ) |
| @encode ( type-name ) |
| objc-string-literal |
| */ |
| |
| static struct c_expr |
| c_parser_postfix_expression (c_parser *parser) |
| { |
| struct c_expr expr, e1, e2, e3; |
| struct c_type_name *t1, *t2; |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_NUMBER: |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 ak) */ |
| if (cpp_get_options (parse_in)->h_suffix |
| && c_parser_peek_token (parser)->value == error_mark_node) |
| { |
| /* This was previously deferred. */ |
| cpp_error (parse_in, CPP_DL_ERROR, "invalid suffix on integer constant"); |
| c_parser_consume_token (parser); |
| } |
| /* APPLE LOCAL end CW asm blocks (in 4.2 ak) */ |
| case CPP_CHAR: |
| case CPP_WCHAR: |
| expr.value = c_parser_peek_token (parser)->value; |
| expr.original_code = ERROR_MARK; |
| c_parser_consume_token (parser); |
| break; |
| case CPP_STRING: |
| case CPP_WSTRING: |
| expr.value = c_parser_peek_token (parser)->value; |
| expr.original_code = STRING_CST; |
| c_parser_consume_token (parser); |
| break; |
| case CPP_OBJC_STRING: |
| gcc_assert (c_dialect_objc ()); |
| expr.value |
| = objc_build_string_object (c_parser_peek_token (parser)->value); |
| expr.original_code = ERROR_MARK; |
| c_parser_consume_token (parser); |
| break; |
| case CPP_NAME: |
| /* APPLE LOCAL begin radar 5277239 */ |
| if (c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME |
| && c_parser_peek_2nd_token (parser)->type == CPP_DOT) |
| { |
| /* CLASS.class_method expression. */ |
| tree receiver, component; |
| receiver = c_parser_objc_receiver (parser); |
| /* consume '.' operator */ |
| c_parser_consume_token (parser); |
| component = c_parser_objc_message_args (parser); |
| expr.value = objc_build_property_reference_expr (receiver, component); |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| /* APPLE LOCAL end radar 5277239 */ |
| if (c_parser_peek_token (parser)->id_kind != C_ID_ID) |
| { |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 bf) */ |
| if (inside_iasm_block |
| && c_parser_peek_2nd_token (parser)->type == CPP_DOT) |
| { |
| expr.value = c_parser_peek_token (parser)->value; |
| expr.original_code = ERROR_MARK; |
| c_parser_consume_token (parser); |
| break; |
| } |
| /* APPLE LOCAL end CW asm blocks (in 4.2 bf) */ |
| c_parser_error (parser, "expected expression"); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| { |
| tree id = c_parser_peek_token (parser)->value; |
| location_t loc = c_parser_peek_token (parser)->location; |
| c_parser_consume_token (parser); |
| expr.value = build_external_ref (id, |
| (c_parser_peek_token (parser)->type |
| == CPP_OPEN_PAREN), loc); |
| /* APPLE LOCAL begin radar 5732232 - blocks (C++ cd) */ |
| /* If a variabled declared as referenced variable, using |...| syntax, |
| is used in the block, it has to be derefrenced because this |
| variable holds address of the outside variable referenced in. */ |
| |
| /* APPLE LOCAL begin radar 5932809 - copyable byref blocks (C++ cd) */ |
| if (TREE_CODE (expr.value) == VAR_DECL |
| && !building_block_byref_decl) |
| { |
| if (BLOCK_DECL_BYREF (expr.value)) |
| { |
| tree orig_decl = expr.value; |
| expr.value = build_indirect_ref (expr.value, "unary *"); |
| if (COPYABLE_BYREF_LOCAL_VAR (orig_decl)) { |
| /* What we have is an expression which is of type |
| struct __Block_byref_X. Must get to the value of the variable |
| embedded in this structure. It is at: |
| __Block_byref_X.forwarding->x */ |
| expr.value = build_byref_local_var_access (expr.value, |
| DECL_NAME (orig_decl)); |
| } |
| } |
| else if (COPYABLE_BYREF_LOCAL_VAR (expr.value)) |
| expr.value = build_byref_local_var_access (expr.value, |
| DECL_NAME (expr.value)); |
| } |
| /* APPLE LOCAL end radar 5932809 - copyable byref blocks */ |
| |
| /* APPLE LOCAL end radar 5732232 - blocks (C++ cd) */ |
| expr.original_code = ERROR_MARK; |
| } |
| break; |
| case CPP_OPEN_PAREN: |
| /* A parenthesized expression, statement expression or compound |
| literal. */ |
| if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE) |
| { |
| /* A statement expression. */ |
| tree stmt; |
| c_parser_consume_token (parser); |
| c_parser_consume_token (parser); |
| if (cur_stmt_list == NULL) |
| { |
| error ("braced-group within expression allowed " |
| "only inside a function"); |
| parser->error = true; |
| c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| stmt = c_begin_stmt_expr (); |
| c_parser_compound_statement_nostart (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| if (pedantic) |
| pedwarn ("ISO C forbids braced-groups within expressions"); |
| expr.value = c_finish_stmt_expr (stmt); |
| expr.original_code = ERROR_MARK; |
| } |
| else if (c_token_starts_typename (c_parser_peek_2nd_token (parser))) |
| { |
| /* A compound literal. ??? Can we actually get here rather |
| than going directly to |
| c_parser_postfix_expression_after_paren_type from |
| elsewhere? */ |
| struct c_type_name *type_name; |
| c_parser_consume_token (parser); |
| type_name = c_parser_type_name (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| if (type_name == NULL) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| } |
| else |
| expr = c_parser_postfix_expression_after_paren_type (parser, |
| type_name); |
| } |
| else |
| { |
| /* A parenthesized expression. */ |
| c_parser_consume_token (parser); |
| expr = c_parser_expression (parser); |
| if (TREE_CODE (expr.value) == MODIFY_EXPR) |
| TREE_NO_WARNING (expr.value) = 1; |
| expr.original_code = ERROR_MARK; |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| } |
| break; |
| case CPP_KEYWORD: |
| switch (c_parser_peek_token (parser)->keyword) |
| { |
| case RID_FUNCTION_NAME: |
| case RID_PRETTY_FUNCTION_NAME: |
| case RID_C99_FUNCTION_NAME: |
| expr.value = fname_decl (c_parser_peek_token (parser)->keyword, |
| c_parser_peek_token (parser)->value); |
| expr.original_code = ERROR_MARK; |
| c_parser_consume_token (parser); |
| break; |
| case RID_VA_ARG: |
| c_parser_consume_token (parser); |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| e1 = c_parser_expr_no_commas (parser, NULL); |
| if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| t1 = c_parser_type_name (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| if (t1 == NULL) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| } |
| else |
| { |
| expr.value = build_va_arg (e1.value, groktypename (t1)); |
| expr.original_code = ERROR_MARK; |
| } |
| break; |
| case RID_OFFSETOF: |
| c_parser_consume_token (parser); |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| t1 = c_parser_type_name (parser); |
| if (t1 == NULL) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| { |
| tree type = groktypename (t1); |
| tree offsetof_ref; |
| if (type == error_mark_node) |
| offsetof_ref = error_mark_node; |
| else |
| offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node); |
| /* Parse the second argument to __builtin_offsetof. We |
| must have one identifier, and beyond that we want to |
| accept sub structure and sub array references. */ |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| offsetof_ref = build_component_ref |
| (offsetof_ref, c_parser_peek_token (parser)->value); |
| c_parser_consume_token (parser); |
| while (c_parser_next_token_is (parser, CPP_DOT) |
| || c_parser_next_token_is (parser, |
| CPP_OPEN_SQUARE)) |
| { |
| if (c_parser_next_token_is (parser, CPP_DOT)) |
| { |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is_not (parser, |
| CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| break; |
| } |
| offsetof_ref = build_component_ref |
| (offsetof_ref, |
| c_parser_peek_token (parser)->value); |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| tree idx; |
| c_parser_consume_token (parser); |
| idx = c_parser_expression (parser).value; |
| c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, |
| "expected %<]%>"); |
| offsetof_ref = build_array_ref (offsetof_ref, idx); |
| } |
| } |
| } |
| else |
| c_parser_error (parser, "expected identifier"); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| expr.value = fold_offsetof (offsetof_ref, NULL_TREE); |
| expr.original_code = ERROR_MARK; |
| } |
| break; |
| case RID_CHOOSE_EXPR: |
| c_parser_consume_token (parser); |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| e1 = c_parser_expr_no_commas (parser, NULL); |
| if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| e2 = c_parser_expr_no_commas (parser, NULL); |
| if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| e3 = c_parser_expr_no_commas (parser, NULL); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| { |
| tree c; |
| |
| c = fold (e1.value); |
| if (TREE_CODE (c) != INTEGER_CST) |
| error ("first argument to %<__builtin_choose_expr%> not" |
| " a constant"); |
| expr = integer_zerop (c) ? e3 : e2; |
| } |
| break; |
| case RID_TYPES_COMPATIBLE_P: |
| c_parser_consume_token (parser); |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| t1 = c_parser_type_name (parser); |
| if (t1 == NULL) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| t2 = c_parser_type_name (parser); |
| if (t2 == NULL) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| { |
| tree e1, e2; |
| |
| e1 = TYPE_MAIN_VARIANT (groktypename (t1)); |
| e2 = TYPE_MAIN_VARIANT (groktypename (t2)); |
| |
| expr.value = comptypes (e1, e2) |
| ? build_int_cst (NULL_TREE, 1) |
| : build_int_cst (NULL_TREE, 0); |
| expr.original_code = ERROR_MARK; |
| } |
| break; |
| case RID_AT_SELECTOR: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_consume_token (parser); |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| { |
| tree sel = c_parser_objc_selector_arg (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| expr.value = objc_build_selector_expr (sel); |
| expr.original_code = ERROR_MARK; |
| } |
| break; |
| case RID_AT_PROTOCOL: |
| gcc_assert (c_dialect_objc ()); |
| c_parser_consume_token (parser); |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| { |
| tree id = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| expr.value = objc_build_protocol_expr (id); |
| expr.original_code = ERROR_MARK; |
| } |
| break; |
| case RID_AT_ENCODE: |
| /* Extension to support C-structures in the archiver. */ |
| gcc_assert (c_dialect_objc ()); |
| c_parser_consume_token (parser); |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| t1 = c_parser_type_name (parser); |
| if (t1 == NULL) |
| { |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| break; |
| } |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| { |
| tree type = groktypename (t1); |
| expr.value = objc_build_encode_expr (type); |
| expr.original_code = ERROR_MARK; |
| } |
| break; |
| default: |
| c_parser_error (parser, "expected expression"); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| break; |
| /* APPLE LOCAL begin radar 5732232 - blocks (C++ cf) */ |
| case CPP_XOR: |
| if (flag_blocks) { |
| expr.value = c_parser_block_literal_expr (parser); |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| c_parser_error (parser, "expected expression"); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| /* APPLE LOCAL end radar 5732232 - blocks (C++ cf) */ |
| case CPP_OPEN_SQUARE: |
| /* APPLE LOCAL begin CW asm blocks */ |
| if (inside_iasm_block) |
| { |
| c_parser_consume_token (parser); |
| expr = c_parser_expression (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, |
| "expected %<]%>"); |
| expr.value = iasm_build_bracket (expr.value, NULL_TREE); |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| /* APPLE LOCAL end CW asm blocks */ |
| if (c_dialect_objc ()) |
| { |
| tree receiver, args; |
| c_parser_consume_token (parser); |
| receiver = c_parser_objc_receiver (parser); |
| args = c_parser_objc_message_args (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, |
| "expected %<]%>"); |
| expr.value = objc_build_message_expr (build_tree_list (receiver, |
| args)); |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| /* Else fall through to report error. */ |
| default: |
| /* APPLE LOCAL begin CW asm blocks */ |
| if (inside_iasm_block) |
| { |
| if (c_parser_next_token_is (parser, CPP_DOT)) |
| { |
| /* (in 4.2 ba) */ |
| c_parser_consume_token (parser); |
| expr.value = get_identifier ("."); |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| /* (in 4.2 be) */ |
| if (c_parser_next_token_is (parser, CPP_ATSIGN)) |
| { |
| tree id; |
| location_t loc = c_parser_peek_token (parser)->location; |
| c_parser_consume_token (parser); |
| if (c_parser_peek_token (parser)->id_kind != C_ID_ID) |
| { |
| c_parser_error (parser, "expected identifier"); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| |
| id = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| id = prepend_char_identifier (id, '@'); |
| expr.value = build_external_ref (id, |
| (c_parser_peek_token (parser)->type |
| == CPP_OPEN_PAREN), loc); |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| } |
| /* APPLE LOCAL end CW asm blocks */ |
| c_parser_error (parser, "expected expression"); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| return c_parser_postfix_expression_after_primary (parser, expr); |
| } |
| |
| /* Parse a postfix expression after a parenthesized type name: the |
| brace-enclosed initializer of a compound literal, possibly followed |
| by some postfix operators. This is separate because it is not |
| possible to tell until after the type name whether a cast |
| expression has a cast or a compound literal, or whether the operand |
| of sizeof is a parenthesized type name or starts with a compound |
| literal. */ |
| |
| static struct c_expr |
| c_parser_postfix_expression_after_paren_type (c_parser *parser, |
| struct c_type_name *type_name) |
| { |
| tree type; |
| struct c_expr init; |
| struct c_expr expr; |
| start_init (NULL_TREE, NULL, 0); |
| type = groktypename (type_name); |
| if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) |
| { |
| error ("compound literal has variable size"); |
| type = error_mark_node; |
| } |
| init = c_parser_braced_init (parser, type, false); |
| finish_init (); |
| maybe_warn_string_init (type, init); |
| |
| /* APPLE LOCAL AltiVec (in 4.2 o) */ |
| if (pedantic && TREE_CODE (type) != VECTOR_TYPE && !flag_isoc99) |
| pedwarn ("ISO C90 forbids compound literals"); |
| expr.value = build_compound_literal (type, init.value); |
| expr.original_code = ERROR_MARK; |
| return c_parser_postfix_expression_after_primary (parser, expr); |
| } |
| |
| /* Parse a postfix expression after the initial primary or compound |
| literal; that is, parse a series of postfix operators. */ |
| |
| static struct c_expr |
| c_parser_postfix_expression_after_primary (c_parser *parser, |
| struct c_expr expr) |
| { |
| tree ident, idx, exprlist; |
| while (true) |
| { |
| /* APPLE LOCAL begin CW asm blocks */ |
| if (inside_iasm_block |
| && c_parser_iasm_bol (parser)) |
| return expr; |
| /* APPLE LOCAL end CW asm blocks */ |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_OPEN_SQUARE: |
| /* Array reference. */ |
| c_parser_consume_token (parser); |
| idx = c_parser_expression (parser).value; |
| c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, |
| "expected %<]%>"); |
| expr.value = build_array_ref (expr.value, idx); |
| expr.original_code = ERROR_MARK; |
| break; |
| case CPP_OPEN_PAREN: |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 bd) */ |
| if (inside_iasm_block) |
| return expr; |
| /* APPLE LOCAL end CW asm blocks (in 4.2 bd) */ |
| /* Function call. */ |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) |
| exprlist = NULL_TREE; |
| else |
| exprlist = c_parser_expr_list (parser, true); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| expr.value = build_function_call (expr.value, exprlist); |
| expr.original_code = ERROR_MARK; |
| break; |
| case CPP_DOT: |
| /* Structure element reference. */ |
| c_parser_consume_token (parser); |
| expr = default_function_array_conversion (expr); |
| /* APPLE LOCAL begin CW asm blocks */ |
| if (inside_iasm_block) |
| { |
| /* (in 4.2 bf) */ |
| if (c_parser_next_token_is (parser, CPP_NAME) |
| /* (in 4.2 bc) */ |
| || c_parser_next_token_is (parser, CPP_NUMBER)) |
| { |
| tree c = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| expr.value = iasm_c_build_component_ref (expr.value, c); |
| expr.original_code = ERROR_MARK; |
| break; |
| } |
| } |
| /* APPLE LOCAL end CW asm blocks */ |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| ident = c_parser_peek_token (parser)->value; |
| else |
| { |
| c_parser_error (parser, "expected identifier"); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| return expr; |
| } |
| c_parser_consume_token (parser); |
| expr.value = build_component_ref (expr.value, ident); |
| expr.original_code = ERROR_MARK; |
| break; |
| case CPP_DEREF: |
| /* Structure element reference. */ |
| c_parser_consume_token (parser); |
| expr = default_function_array_conversion (expr); |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| ident = c_parser_peek_token (parser)->value; |
| else |
| { |
| c_parser_error (parser, "expected identifier"); |
| expr.value = error_mark_node; |
| expr.original_code = ERROR_MARK; |
| return expr; |
| } |
| c_parser_consume_token (parser); |
| expr.value = build_component_ref (build_indirect_ref (expr.value, |
| "->"), ident); |
| expr.original_code = ERROR_MARK; |
| break; |
| case CPP_PLUS_PLUS: |
| /* Postincrement. */ |
| c_parser_consume_token (parser); |
| expr = default_function_array_conversion (expr); |
| expr.value = build_unary_op (POSTINCREMENT_EXPR, expr.value, 0); |
| expr.original_code = ERROR_MARK; |
| break; |
| case CPP_MINUS_MINUS: |
| /* Postdecrement. */ |
| c_parser_consume_token (parser); |
| expr = default_function_array_conversion (expr); |
| expr.value = build_unary_op (POSTDECREMENT_EXPR, expr.value, 0); |
| expr.original_code = ERROR_MARK; |
| break; |
| /* APPLE LOCAL begin CW asm blocks (in 4.2 bb) */ |
| case CPP_NAME: |
| if (inside_iasm_block) |
| { |
| tree id = c_parser_peek_token (parser)->value; |
| struct c_expr e2; |
| if (strcasecmp (IDENTIFIER_POINTER (id), "ptr") == 0) |
| { |
| c_parser_consume_token (parser); |
| e2 = c_parser_postfix_expression (parser); |
| expr.value = iasm_ptr_conv (expr.value, e2.value); |
| expr.original_code = ERROR_MARK; |
| } |
| } |
| return expr; |
| /* APPLE LOCAL end CW asm blocks */ |
| default: |
| return expr; |
| } |
| } |
| } |
| |
| /* Parse an expression (C90 6.3.17, C99 6.5.17). |
| |
| expression: |
| assignment-expression |
| expression , assignment-expression |
| */ |
| |
| static struct c_expr |
| c_parser_expression (c_parser *parser) |
| { |
| struct c_expr expr; |
| expr = c_parser_expr_no_commas (parser, NULL); |
| while (c_parser_next_token_is (parser, CPP_COMMA)) |
| { |
| struct c_expr next; |
| c_parser_consume_token (parser); |
| next = c_parser_expr_no_commas (parser, NULL); |
| next = default_function_array_conversion (next); |
| expr.value = build_compound_expr (expr.value, next.value); |
| expr.original_code = COMPOUND_EXPR; |
| } |
| return expr; |
| } |
| |
| /* Parse an expression and convert functions or arrays to |
| pointers. */ |
| |
| static struct c_expr |
| c_parser_expression_conv (c_parser *parser) |
| { |
| struct c_expr expr; |
| expr = c_parser_expression (parser); |
| expr = default_function_array_conversion (expr); |
| return expr; |
| } |
| |
| /* Parse a non-empty list of expressions. If CONVERT_P, convert |
| functions and arrays to pointers. |
| |
| nonempty-expr-list: |
| assignment-expression |
| nonempty-expr-list , assignment-expression |
| */ |
| |
| static tree |
| c_parser_expr_list (c_parser *parser, bool convert_p) |
| { |
| struct c_expr expr; |
| tree ret, cur; |
| expr = c_parser_expr_no_commas (parser, NULL); |
| if (convert_p) |
| expr = default_function_array_conversion (expr); |
| ret = cur = build_tree_list (NULL_TREE, expr.value); |
| while (c_parser_next_token_is (parser, CPP_COMMA)) |
| { |
| c_parser_consume_token (parser); |
| expr = c_parser_expr_no_commas (parser, NULL); |
| if (convert_p) |
| expr = default_function_array_conversion (expr); |
| cur = TREE_CHAIN (cur) = build_tree_list (NULL_TREE, expr.value); |
| } |
| return ret; |
| } |
| |
| |
| /* Parse Objective-C-specific constructs. */ |
| |
| /* Parse an objc-class-definition. |
| |
| objc-class-definition: |
| @interface identifier objc-superclass[opt] objc-protocol-refs[opt] |
| objc-class-instance-variables[opt] objc-methodprotolist @end |
| @implementation identifier objc-superclass[opt] |
| objc-class-instance-variables[opt] |
| @interface identifier ( identifier ) objc-protocol-refs[opt] |
| objc-methodprotolist @end |
| @implementation identifier ( identifier ) |
| |
| objc-superclass: |
| : identifier |
| |
| "@interface identifier (" must start "@interface identifier ( |
| identifier ) ...": objc-methodprotolist in the first production may |
| not start with a parenthesized identifier as a declarator of a data |
| definition with no declaration specifiers if the objc-superclass, |
| objc-protocol-refs and objc-class-instance-variables are omitted. */ |
| |
| static void |
| /* APPLE LOCAL radar 4548636 - class attributes. */ |
| c_parser_objc_class_definition (c_parser *parser, tree prefix_attrs) |
| { |
| bool iface_p; |
| tree id1; |
| tree superclass; |
| if (c_parser_next_token_is_keyword (parser, RID_AT_INTERFACE)) |
| iface_p = true; |
| else if (c_parser_next_token_is_keyword (parser, RID_AT_IMPLEMENTATION)) |
| /* APPLE LOCAL begin radar 4548636 - class attributes. */ |
| { |
| if (prefix_attrs) |
| { |
| error ("attributes may not be specified on an implementation"); |
| prefix_attrs = NULL_TREE; |
| } |
| iface_p = false; |
| } |
| /* APPLE LOCAL end radar 4548636 - class attributes. */ |
| else |
| gcc_unreachable (); |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| /* APPLE LOCAL radar 4533974 - ObjC new protocol (in 4.2 v) */ |
| c_parser_error (parser, "expected identifier or protocol references"); |
| return; |
| } |
| id1 = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) |
| { |
| /* APPLE LOCAL radar 4965989 */ |
| tree id2 = NULL_TREE; |
| tree proto = NULL_TREE; |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL begin radar 4965989 */ |
| if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) |
| { |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| return; |
| } |
| id2 = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| } |
| /* APPLE LOCAL end radar 4965989 */ |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| if (!iface_p) |
| { |
| /* APPLE LOCAL begin radar 4965989 */ |
| if (id2 == NULL_TREE) |
| { |
| error ("cannot implement anonymous category"); |
| return; |
| } |
| /* APPLE LOCAL end radar 4965989 */ |
| objc_start_category_implementation (id1, id2); |
| return; |
| } |
| if (c_parser_next_token_is (parser, CPP_LESS)) |
| proto = c_parser_objc_protocol_refs (parser); |
| /* APPLE LOCAL begin radar 4548636 - class attributes. */ |
| if (prefix_attrs) |
| error ("attributes may not be specified on a category"); |
| /* APPLE LOCAL end radar 4548636 - class attributes. */ |
| objc_start_category_interface (id1, id2, proto); |
| /* APPLE LOCAL C* property (Radar 4436866) (in 4.2 q) */ |
| c_parser_objc_interfacedecllist (parser); |
| c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); |
| objc_finish_interface (); |
| return; |
| } |
| if (c_parser_next_token_is (parser, CPP_COLON)) |
| { |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| return; |
| } |
| superclass = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| } |
| else |
| superclass = NULL_TREE; |
| if (iface_p) |
| { |
| tree proto = NULL_TREE; |
| if (c_parser_next_token_is (parser, CPP_LESS)) |
| proto = c_parser_objc_protocol_refs (parser); |
| /* APPLE LOCAL radar 4548636 - class attributes. */ |
| objc_start_class_interface (id1, superclass, proto, prefix_attrs); |
| } |
| else |
| objc_start_class_implementation (id1, superclass); |
| if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| c_parser_objc_class_instance_variables (parser); |
| if (iface_p) |
| { |
| objc_continue_interface (); |
| /* APPLE LOCAL C* property (Radar 4436866) (in 4.2 q) */ |
| c_parser_objc_interfacedecllist (parser); |
| c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); |
| objc_finish_interface (); |
| } |
| else |
| { |
| objc_continue_implementation (); |
| return; |
| } |
| } |
| |
| /* APPLE LOCAL begin C* property (Radar 4436866) (in 4.2 s) */ |
| static tree |
| c_parser_objc_eq_identifier (c_parser *parser) |
| { |
| tree id; |
| if (c_parser_next_token_is_not (parser, CPP_EQ)) |
| { |
| c_parser_error (parser, "expected %<=%>"); |
| return NULL_TREE; |
| } |
| /* Consume '=' */ |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| return NULL_TREE; |
| } |
| id = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| return id; |
| } |
| |
| /* Parse obj-property-attribute. |
| */ |
| static void |
| c_parser_objc_property_attribute (c_parser *parser) |
| { |
| tree id; |
| if (c_parser_peek_token (parser)->type != CPP_KEYWORD) |
| { |
| c_parser_error (parser, "expected a property attribute"); |
| c_parser_consume_token (parser); |
| return; |
| } |
| switch (c_parser_peek_token (parser)->keyword) |
| { |
| case RID_READONLY: |
| c_parser_consume_token (parser); |
| objc_set_property_attr (1, NULL_TREE); |
| break; |
| case RID_GETTER: |
| c_parser_consume_token (parser); |
| id = c_parser_objc_eq_identifier (parser); |
| if (id) |
| objc_set_property_attr (2, id); |
| break; |
| case RID_SETTER: |
| c_parser_consume_token (parser); |
| id = c_parser_objc_eq_identifier (parser); |
| if (id) |
| objc_set_property_attr (3, id); |
| /* Consume the ':' which must always follow the setter name. */ |
| if (c_parser_next_token_is (parser, CPP_COLON)) |
| c_parser_consume_token (parser); |
| break; |
| /* APPLE LOCAL begin objc new property */ |
| case RID_READWRITE: |
| c_parser_consume_token (parser); |
| objc_set_property_attr (9, NULL_TREE); |
| break; |
| case RID_ASSIGN: |
| c_parser_consume_token (parser); |
| objc_set_property_attr (10, NULL_TREE); |
| break; |
| case RID_RETAIN: |
| c_parser_consume_token (parser); |
| objc_set_property_attr (11, NULL_TREE); |
| break; |
| case RID_COPY: |
| c_parser_consume_token (parser); |
| objc_set_property_attr (12, NULL_TREE); |
| break; |
| /* APPLE LOCAL end objc new property */ |
| /* APPLE LOCAL begin radar 4947014 - objc atomic property */ |
| case RID_NONATOMIC: |
| c_parser_consume_token (parser); |
| objc_set_property_attr (13, NULL_TREE); |
| break; |
| /* APPLE LOCAL end radar 4947014 - objc atomic property */ |
| default: |
| c_parser_error (parser, "expected a property attribute"); |
| c_parser_consume_token (parser); |
| } |
| } |
| |
| static void |
| c_parser_objc_property_attrlist (c_parser *parser) |
| { |
| while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN) |
| && c_parser_next_token_is_not (parser, CPP_EOF)) |
| { |
| c_parser_objc_property_attribute (parser); |
| if (c_parser_next_token_is (parser, CPP_COMMA) |
| || c_parser_next_token_is (parser, CPP_NAME) /* error */) |
| c_parser_consume_token (parser); |
| } |
| } |
| |
| static void |
| c_parser_objc_property_attr_decl (c_parser *parser) |
| { |
| if (!c_parser_next_token_is (parser, CPP_OPEN_PAREN)) |
| return; |
| c_parser_consume_token (parser); |
| c_parser_objc_property_attrlist (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| } |
| |
| static tree |
| c_parser_component_decl (c_parser *parser) |
| { |
| tree decl = c_parser_struct_declaration (parser); |
| return decl; |
| } |
| |
| static void |
| c_parser_objc_property_declaration (c_parser *parser) |
| { |
| tree prop; |
| c_parser_require_keyword (parser, RID_AT_PROPERTY, "expected %<@property%>"); |
| objc_property_attr_context = 1; |
| objc_set_property_attr (0, NULL_TREE); |
| c_parser_objc_property_attr_decl (parser); |
| objc_property_attr_context = 0; |
| prop = c_parser_component_decl (parser); |
| /* Comma-separated properties are chained together in |
| reverse order; add them one by one. */ |
| prop = nreverse (prop); |
| |
| for (; prop; prop = TREE_CHAIN (prop)) |
| objc_add_property_variable (copy_node (prop)); |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| } |
| /* APPLE LOCAL end C* property (Radar 4436866) (in 4.2 s) */ |
| |
| /* APPLE LOCAL begin objc new property */ |
| static void |
| c_parser_objc_atsynthesize_declaration (c_parser *parser) |
| { |
| tree list = NULL_TREE; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNTHESIZE)); |
| c_parser_consume_token (parser); |
| while (true) |
| { |
| tree prop_id, ivar_id; |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| break; |
| } |
| prop_id = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| ivar_id = c_parser_next_token_is (parser, CPP_EQ) |
| ? c_parser_objc_eq_identifier (parser) |
| : NULL_TREE; |
| list = chainon (list, build_tree_list (ivar_id, prop_id)); |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| c_parser_consume_token (parser); |
| else |
| break; |
| } |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| objc_declare_property_impl (1, list); |
| return; |
| } |
| |
| static void |
| c_parser_objc_atdynamic_declaration (c_parser *parser) |
| { |
| tree list = NULL_TREE; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_DYNAMIC)); |
| c_parser_consume_token (parser); |
| while (true) |
| { |
| tree id; |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| break; |
| } |
| id = c_parser_peek_token (parser)->value; |
| list = chainon (list, build_tree_list (NULL_TREE, id)); |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| c_parser_consume_token (parser); |
| else |
| break; |
| } |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| objc_declare_property_impl (2, list); |
| return; |
| } |
| /* APPLE LOCAL end objc new property */ |
| |
| /* Parse objc-class-instance-variables. |
| |
| objc-class-instance-variables: |
| { objc-instance-variable-decl-list[opt] } |
| |
| objc-instance-variable-decl-list: |
| objc-visibility-spec |
| objc-instance-variable-decl ; |
| ; |
| objc-instance-variable-decl-list objc-visibility-spec |
| objc-instance-variable-decl-list objc-instance-variable-decl ; |
| objc-instance-variable-decl-list ; |
| |
| objc-visibility-spec: |
| @private |
| @protected |
| @public |
| |
| objc-instance-variable-decl: |
| struct-declaration |
| */ |
| |
| static void |
| c_parser_objc_class_instance_variables (c_parser *parser) |
| { |
| gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); |
| c_parser_consume_token (parser); |
| while (c_parser_next_token_is_not (parser, CPP_EOF)) |
| { |
| tree decls; |
| /* Parse any stray semicolon. */ |
| if (c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| { |
| if (pedantic) |
| pedwarn ("extra semicolon in struct or union specified"); |
| c_parser_consume_token (parser); |
| continue; |
| } |
| /* Stop if at the end of the instance variables. */ |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) |
| { |
| c_parser_consume_token (parser); |
| break; |
| } |
| /* Parse any objc-visibility-spec. */ |
| if (c_parser_next_token_is_keyword (parser, RID_AT_PRIVATE)) |
| { |
| c_parser_consume_token (parser); |
| objc_set_visibility (2); |
| continue; |
| } |
| else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED)) |
| { |
| c_parser_consume_token (parser); |
| objc_set_visibility (0); |
| continue; |
| } |
| else if (c_parser_next_token_is_keyword (parser, RID_AT_PUBLIC)) |
| { |
| c_parser_consume_token (parser); |
| objc_set_visibility (1); |
| continue; |
| } |
| /* APPLE LOCAL begin radar 4564694 */ |
| else if (c_parser_next_token_is_keyword (parser, RID_AT_PACKAGE)) |
| { |
| c_parser_consume_token (parser); |
| objc_set_visibility (3); |
| continue; |
| } |
| /* APPLE LOCAL end radar 4564694 */ |
| else if (c_parser_next_token_is (parser, CPP_PRAGMA)) |
| { |
| c_parser_pragma (parser, pragma_external); |
| continue; |
| } |
| |
| /* Parse some comma-separated declarations. */ |
| decls = c_parser_struct_declaration (parser); |
| { |
| /* Comma-separated instance variables are chained together in |
| reverse order; add them one by one. */ |
| tree ivar = nreverse (decls); |
| for (; ivar; ivar = TREE_CHAIN (ivar)) |
| objc_add_instance_variable (copy_node (ivar)); |
| } |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| } |
| } |
| |
| /* Parse an objc-class-declaration. |
| |
| objc-class-declaration: |
| @class identifier-list ; |
| */ |
| |
| static void |
| c_parser_objc_class_declaration (c_parser *parser) |
| { |
| tree list = NULL_TREE; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_CLASS)); |
| c_parser_consume_token (parser); |
| /* Any identifiers, including those declared as type names, are OK |
| here. */ |
| while (true) |
| { |
| tree id; |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| break; |
| } |
| id = c_parser_peek_token (parser)->value; |
| list = chainon (list, build_tree_list (NULL_TREE, id)); |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| c_parser_consume_token (parser); |
| else |
| break; |
| } |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| objc_declare_class (list); |
| } |
| |
| /* Parse an objc-alias-declaration. |
| |
| objc-alias-declaration: |
| @compatibility_alias identifier identifier ; |
| */ |
| |
| static void |
| c_parser_objc_alias_declaration (c_parser *parser) |
| { |
| tree id1, id2; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_ALIAS)); |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); |
| return; |
| } |
| id1 = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); |
| return; |
| } |
| id2 = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| objc_declare_alias (id1, id2); |
| } |
| |
| /* Parse an objc-protocol-definition. |
| |
| objc-protocol-definition: |
| @protocol identifier objc-protocol-refs[opt] objc-methodprotolist @end |
| @protocol identifier-list ; |
| |
| "@protocol identifier ;" should be resolved as "@protocol |
| identifier-list ;": objc-methodprotolist may not start with a |
| semicolon in the first alternative if objc-protocol-refs are |
| omitted. */ |
| |
| static void |
| /* APPLE LOCAL radar 4947311 - protocol attributes */ |
| c_parser_objc_protocol_definition (c_parser *parser, tree attributes) |
| { |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL)); |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| return; |
| } |
| if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
| || c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON) |
| { |
| tree list = NULL_TREE; |
| /* Any identifiers, including those declared as type names, are |
| OK here. */ |
| while (true) |
| { |
| tree id; |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| break; |
| } |
| id = c_parser_peek_token (parser)->value; |
| list = chainon (list, build_tree_list (NULL_TREE, id)); |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| c_parser_consume_token (parser); |
| else |
| break; |
| } |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| /* APPLE LOCAL radar 4947311 - protocol attributes */ |
| objc_declare_protocols (list, attributes); |
| } |
| else |
| { |
| tree id = c_parser_peek_token (parser)->value; |
| tree proto = NULL_TREE; |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_LESS)) |
| proto = c_parser_objc_protocol_refs (parser); |
| objc_pq_context = 1; |
| /* APPLE LOCAL radar 4947311 - protocol attributes */ |
| objc_start_protocol (id, proto, attributes); |
| /* APPLE LOCAL C* property (Radar 4436866) (in 4.2 r) */ |
| c_parser_objc_interfacedecllist (parser); |
| c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); |
| objc_pq_context = 0; |
| objc_finish_interface (); |
| } |
| } |
| |
| /* Parse an objc-method-type. |
| |
| objc-method-type: |
| + |
| - |
| */ |
| |
| static enum tree_code |
| c_parser_objc_method_type (c_parser *parser) |
| { |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_PLUS: |
| c_parser_consume_token (parser); |
| return PLUS_EXPR; |
| case CPP_MINUS: |
| c_parser_consume_token (parser); |
| return MINUS_EXPR; |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| /* Parse an objc-method-definition. |
| |
| objc-method-definition: |
| objc-method-type objc-method-decl ;[opt] compound-statement |
| */ |
| |
| static void |
| c_parser_objc_method_definition (c_parser *parser) |
| { |
| enum tree_code type = c_parser_objc_method_type (parser); |
| tree decl; |
| objc_set_method_type (type); |
| objc_pq_context = 1; |
| decl = c_parser_objc_method_decl (parser); |
| if (c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| { |
| c_parser_consume_token (parser); |
| if (pedantic) |
| pedwarn ("extra semicolon in method definition specified"); |
| } |
| if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| { |
| c_parser_error (parser, "expected %<{%>"); |
| return; |
| } |
| /* APPLE LOCAL begin fix -fnon-lvalue-assign (in 4.2) */ |
| /* in_gimple_form is set at beginning of last pass of previous function build. |
| Must reset it here since we are building the parse tree here. */ |
| in_gimple_form = 0; |
| /* APPLE LOCAL end -fnon-lvalue-assign (in 4.2) */ |
| objc_pq_context = 0; |
| /* APPLE LOCAL begin radar 3803157 - objc attribute (in 4.2 a) */ |
| objc_start_method_definition (decl, objc_method_attributes); |
| objc_method_attributes = NULL_TREE; |
| /* APPLE LOCAL end radar 3803157 - objc attribute (in 4.2 a) */ |
| add_stmt (c_parser_compound_statement (parser)); |
| objc_finish_method_definition (current_function_decl); |
| } |
| |
| /* APPLE LOCAL begin C* language (in 4.2 w) */ |
| /* True iff the gioven TOKEN starts a methodproto. */ |
| |
| static bool |
| c_token_starts_methodproto (c_token *token) |
| { |
| return token->type == CPP_PLUS |
| || token->type == CPP_MINUS |
| || (token->type == CPP_KEYWORD |
| && (token->keyword == RID_AT_REQUIRED |
| || token->keyword == RID_AT_OPTIONAL)); |
| } |
| /* APPLE LOCAL end C* language (in 4.2 w) */ |
| |
| /* Parse an objc-methodprotolist. |
| |
| objc-methodprotolist: |
| empty |
| objc-methodprotolist objc-methodproto |
| objc-methodprotolist declaration |
| objc-methodprotolist ; |
| |
| The declaration is a data definition, which may be missing |
| declaration specifiers under the same rules and diagnostics as |
| other data definitions outside functions, and the stray semicolon |
| is diagnosed the same way as a stray semicolon outside a |
| function. */ |
| |
| static void |
| /* APPLE LOCAL C* property (Radar 4436866) (in 4.2 b) */ |
| c_parser_objc_interfacedecllist (c_parser *parser) |
| { |
| while (true) |
| { |
| /* APPLE LOCAL begin C* property (Radar 4436866) (in 4.2 b) */ |
| c_token *token; |
| token = c_parser_peek_token (parser); |
| if (token->type == CPP_KEYWORD |
| && token->keyword == RID_AT_PROPERTY) |
| { |
| c_parser_objc_property_declaration (parser); |
| continue; |
| } |
| /* APPLE LOCAL end C* property (Radar 4436866) (in 4.2 b) */ |
| /* APPLE LOCAL begin C* language (in 4.2 w) */ |
| if (c_token_starts_methodproto (token)) |
| { |
| c_parser_objc_methodproto (parser); |
| continue; |
| } |
| /* APPLE LOCAL end C* language (in 4.2 w) */ |
| |
| /* The list is terminated by @end. */ |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_SEMICOLON: |
| if (pedantic) |
| pedwarn ("ISO C does not allow extra %<;%> outside of a function"); |
| c_parser_consume_token (parser); |
| break; |
| /* APPLE LOCAL begin C* language (in 4.2 w) */ |
| /* CPP_PLUS and CPP_MINUS deleted */ |
| /* APPLE LOCAL end C* language (in 4.2 w) */ |
| case CPP_PRAGMA: |
| c_parser_pragma (parser, pragma_external); |
| break; |
| case CPP_EOF: |
| return; |
| default: |
| if (c_parser_next_token_is_keyword (parser, RID_AT_END)) |
| return; |
| /* APPLE LOCAL radar 4708210 (for_objc_collection in 4.2) */ |
| c_parser_declaration_or_fndef (parser, false, true, false, true, NULL); |
| break; |
| } |
| } |
| } |
| |
| /* Parse an objc-methodproto. |
| |
| objc-methodproto: |
| objc-method-type objc-method-decl ; |
| */ |
| |
| static void |
| c_parser_objc_methodproto (c_parser *parser) |
| { |
| /* APPLE LOCAL C* language */ |
| enum tree_code type; |
| tree decl; |
| /* APPLE LOCAL begin C* language */ |
| if (c_parser_next_token_is_keyword (parser, RID_AT_REQUIRED)) |
| { |
| objc_set_method_opt (0); |
| c_parser_consume_token (parser); |
| return; |
| } |
| if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL)) |
| { |
| objc_set_method_opt (1); |
| c_parser_consume_token (parser); |
| return; |
| } |
| /* APPLE LOCAL begin C* language */ |
| /* APPLE LOCAL C* language */ |
| type = c_parser_objc_method_type (parser); |
| objc_set_method_type (type); |
| /* Remember protocol qualifiers in prototypes. */ |
| objc_pq_context = 1; |
| decl = c_parser_objc_method_decl (parser); |
| /* Forget protocol qualifiers here. */ |
| objc_pq_context = 0; |
| /* APPLE LOCAL begin radar 3803157 - objc attribute (in 4.2 c) */ |
| objc_add_method_declaration (decl, objc_method_attributes); |
| objc_method_attributes = NULL_TREE; |
| /* APPLE LOCAL end radar 3803157 - objc attribute (in 4.2 c) */ |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| } |
| |
| /* Parse an objc-method-decl. |
| |
| objc-method-decl: |
| ( objc-type-name ) objc-selector |
| objc-selector |
| ( objc-type-name ) objc-keyword-selector objc-optparmlist |
| objc-keyword-selector objc-optparmlist |
| |
| objc-keyword-selector: |
| objc-keyword-decl |
| objc-keyword-selector objc-keyword-decl |
| |
| objc-keyword-decl: |
| objc-selector : ( objc-type-name ) identifier |
| objc-selector : identifier |
| : ( objc-type-name ) identifier |
| : identifier |
| |
| objc-optparmlist: |
| objc-optparms objc-optellipsis |
| |
| objc-optparms: |
| empty |
| objc-opt-parms , parameter-declaration |
| |
| objc-optellipsis: |
| empty |
| , ... |
| */ |
| |
| static tree |
| c_parser_objc_method_decl (c_parser *parser) |
| { |
| tree type = NULL_TREE; |
| tree sel; |
| tree parms = NULL_TREE; |
| bool ellipsis = false; |
| |
| if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) |
| { |
| c_parser_consume_token (parser); |
| type = c_parser_objc_type_name (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| } |
| sel = c_parser_objc_selector (parser); |
| /* If there is no selector, or a colon follows, we have an |
| objc-keyword-selector. If there is a selector, and a colon does |
| not follow, that selector ends the objc-method-decl. */ |
| if (!sel || c_parser_next_token_is (parser, CPP_COLON)) |
| { |
| tree tsel = sel; |
| tree list = NULL_TREE; |
| while (true) |
| { |
| /* APPLE LOCAL radar 4157812 */ |
| tree attr = NULL_TREE; |
| tree atype = NULL_TREE, id, keyworddecl; |
| if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) |
| break; |
| if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) |
| { |
| c_parser_consume_token (parser); |
| atype = c_parser_objc_type_name (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| } |
| /* APPLE LOCAL begin radar 4157812 */ |
| if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) |
| attr = c_parser_attributes (parser); |
| /* APPLE LOCAL end radar 4157812 */ |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| return error_mark_node; |
| } |
| id = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL radar 4157812 */ |
| keyworddecl = objc_build_keyword_decl (tsel, atype, id, attr); |
| list = chainon (list, keyworddecl); |
| tsel = c_parser_objc_selector (parser); |
| if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON)) |
| break; |
| } |
| /* APPLE LOCAL begin radar 3803157 - objc attribute (in 4.2 y) */ |
| if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) |
| objc_method_attributes = c_parser_attributes (parser); |
| /* APPLE LOCAL end radar 3803157 - objc attribute (in 4.2 y) */ |
| /* Parse the optional parameter list. Optional Objective-C |
| method parameters follow the C syntax, and may include '...' |
| to denote a variable number of arguments. */ |
| parms = make_node (TREE_LIST); |
| while (c_parser_next_token_is (parser, CPP_COMMA)) |
| { |
| struct c_parm *parm; |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) |
| { |
| ellipsis = true; |
| c_parser_consume_token (parser); |
| /* APPLE LOCAL end radar 3803157 - objc attribute (in 4.2 y) */ |
| if (objc_method_attributes) |
| error ("method attributes must be specified at the end only"); |
| if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) |
| objc_method_attributes = c_parser_attributes (parser); |
| /* APPLE LOCAL end radar 3803157 - objc attribute (in 4.2 y) */ |
| break; |
| } |
| parm = c_parser_parameter_declaration (parser, NULL_TREE); |
| if (parm == NULL) |
| break; |
| parms = chainon (parms, |
| build_tree_list (NULL_TREE, grokparm (parm))); |
| } |
| sel = list; |
| } |
| /* APPLE LOCAL begin radar 3803157 - objc attribute (in 4.2 y) */ |
| else |
| { |
| gcc_assert (objc_method_attributes == NULL_TREE); |
| if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) |
| objc_method_attributes = c_parser_attributes (parser); |
| } |
| /* APPLE LOCAL end radar 3803157 - objc attribute (in 4.2 y) */ |
| /* APPLE LOCAL begin radar 4157812 */ |
| if (sel == NULL) |
| { |
| c_parser_error (parser, "objective-c method declaration is expected"); |
| return error_mark_node; |
| } |
| /* APPLE LOCAL end radar 4157812 */ |
| return objc_build_method_signature (type, sel, parms, ellipsis); |
| } |
| |
| /* Parse an objc-type-name. |
| |
| objc-type-name: |
| objc-type-qualifiers[opt] type-name |
| objc-type-qualifiers[opt] |
| |
| objc-type-qualifiers: |
| objc-type-qualifier |
| objc-type-qualifiers objc-type-qualifier |
| |
| objc-type-qualifier: one of |
| in out inout bycopy byref oneway |
| */ |
| |
| static tree |
| c_parser_objc_type_name (c_parser *parser) |
| { |
| tree quals = NULL_TREE; |
| struct c_type_name *typename = NULL; |
| tree type = NULL_TREE; |
| while (true) |
| { |
| c_token *token = c_parser_peek_token (parser); |
| if (token->type == CPP_KEYWORD |
| && (token->keyword == RID_IN |
| || token->keyword == RID_OUT |
| || token->keyword == RID_INOUT |
| || token->keyword == RID_BYCOPY |
| || token->keyword == RID_BYREF |
| || token->keyword == RID_ONEWAY)) |
| { |
| /* APPLE LOCAL radar 4301047 (in 4.2 z) */ |
| quals = chainon (build_tree_list (NULL_TREE, token->value), quals); |
| c_parser_consume_token (parser); |
| } |
| else |
| break; |
| } |
| if (c_parser_next_token_starts_typename (parser)) |
| typename = c_parser_type_name (parser); |
| if (typename) |
| type = groktypename (typename); |
| return build_tree_list (quals, type); |
| } |
| |
| /* Parse objc-protocol-refs. |
| |
| objc-protocol-refs: |
| < identifier-list > |
| */ |
| |
| static tree |
| c_parser_objc_protocol_refs (c_parser *parser) |
| { |
| tree list = NULL_TREE; |
| gcc_assert (c_parser_next_token_is (parser, CPP_LESS)); |
| c_parser_consume_token (parser); |
| /* Any identifiers, including those declared as type names, are OK |
| here. */ |
| while (true) |
| { |
| tree id; |
| if (c_parser_next_token_is_not (parser, CPP_NAME)) |
| { |
| c_parser_error (parser, "expected identifier"); |
| break; |
| } |
| id = c_parser_peek_token (parser)->value; |
| list = chainon (list, build_tree_list (NULL_TREE, id)); |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| c_parser_consume_token (parser); |
| else |
| break; |
| } |
| c_parser_require (parser, CPP_GREATER, "expected %<>%>"); |
| return list; |
| } |
| |
| /* Parse an objc-try-catch-statement. |
| |
| objc-try-catch-statement: |
| @try compound-statement objc-catch-list[opt] |
| @try compound-statement objc-catch-list[opt] @finally compound-statement |
| |
| objc-catch-list: |
| @catch ( parameter-declaration ) compound-statement |
| objc-catch-list @catch ( parameter-declaration ) compound-statement |
| */ |
| |
| static void |
| c_parser_objc_try_catch_statement (c_parser *parser) |
| { |
| location_t loc; |
| tree stmt; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY)); |
| c_parser_consume_token (parser); |
| loc = c_parser_peek_token (parser)->location; |
| stmt = c_parser_compound_statement (parser); |
| objc_begin_try_stmt (loc, stmt); |
| while (c_parser_next_token_is_keyword (parser, RID_AT_CATCH)) |
| { |
| struct c_parm *parm; |
| c_parser_consume_token (parser); |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| break; |
| /* APPLE LOCAL begin radar 2848255 */ |
| if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) |
| { |
| /* @catch (...) */ |
| c_parser_consume_token (parser); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| objc_begin_catch_clause (NULL_TREE); |
| } |
| else |
| { |
| parm = c_parser_parameter_declaration (parser, NULL_TREE); |
| if (parm == NULL) |
| { |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); |
| break; |
| } |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| objc_begin_catch_clause (grokparm (parm)); |
| } |
| /* APPLE LOCAL end radar 2848255 */ |
| if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) |
| c_parser_compound_statement_nostart (parser); |
| objc_finish_catch_clause (); |
| } |
| if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY)) |
| { |
| location_t finloc; |
| tree finstmt; |
| c_parser_consume_token (parser); |
| finloc = c_parser_peek_token (parser)->location; |
| finstmt = c_parser_compound_statement (parser); |
| objc_build_finally_clause (finloc, finstmt); |
| } |
| objc_finish_try_stmt (); |
| } |
| |
| /* APPLE LOCAL begin radar 5982990 */ |
| /* This routine is called from c_parser_objc_synchronized_statement |
| and is identical to c_parser_compound_statement with |
| the addition of volatizing local variables seen in the scope |
| of @synchroniz block. |
| */ |
| static tree |
| c_parser_objc_synch_compound_statement (c_parser *parser) |
| { |
| tree stmt; |
| if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) |
| return error_mark_node; |
| stmt = c_begin_compound_stmt (true); |
| c_parser_compound_statement_nostart (parser); |
| if (flag_objc_sjlj_exceptions) |
| objc_mark_locals_volatile (NULL); |
| return c_end_compound_stmt (stmt, true); |
| } |
| /* APPLE LOCAL end radar 5982990 */ |
| |
| /* Parse an objc-synchronized-statement. |
| |
| objc-synchronized-statement: |
| @synchronized ( expression ) compound-statement |
| */ |
| |
| static void |
| c_parser_objc_synchronized_statement (c_parser *parser) |
| { |
| location_t loc; |
| tree expr, stmt; |
| gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED)); |
| c_parser_consume_token (parser); |
| loc = c_parser_peek_token (parser)->location; |
| if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| expr = c_parser_expression (parser).value; |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| } |
| else |
| expr = error_mark_node; |
| /* APPLE LOCAL radar 5982990 */ |
| stmt = c_parser_objc_synch_compound_statement (parser); |
| objc_build_synchronized (loc, expr, stmt); |
| } |
| |
| /* Parse an objc-selector; return NULL_TREE without an error if the |
| next token is not an objc-selector. |
| |
| objc-selector: |
| identifier |
| one of |
| enum struct union if else while do for switch case default |
| break continue return goto asm sizeof typeof __alignof |
| unsigned long const short volatile signed restrict _Complex |
| in out inout bycopy byref oneway int char float double void _Bool |
| |
| ??? Why this selection of keywords but not, for example, storage |
| class specifiers? */ |
| |
| static tree |
| c_parser_objc_selector (c_parser *parser) |
| { |
| c_token *token = c_parser_peek_token (parser); |
| tree value = token->value; |
| if (token->type == CPP_NAME) |
| { |
| c_parser_consume_token (parser); |
| return value; |
| } |
| if (token->type != CPP_KEYWORD) |
| return NULL_TREE; |
| switch (token->keyword) |
| { |
| case RID_ENUM: |
| case RID_STRUCT: |
| case RID_UNION: |
| case RID_IF: |
| case RID_ELSE: |
| case RID_WHILE: |
| case RID_DO: |
| case RID_FOR: |
| case RID_SWITCH: |
| case RID_CASE: |
| case RID_DEFAULT: |
| case RID_BREAK: |
| case RID_CONTINUE: |
| case RID_RETURN: |
| case RID_GOTO: |
| case RID_ASM: |
| case RID_SIZEOF: |
| case RID_TYPEOF: |
| case RID_ALIGNOF: |
| case RID_UNSIGNED: |
| case RID_LONG: |
| case RID_CONST: |
| case RID_SHORT: |
| case RID_VOLATILE: |
| case RID_SIGNED: |
| case RID_RESTRICT: |
| case RID_COMPLEX: |
| case RID_IN: |
| case RID_OUT: |
| case RID_INOUT: |
| case RID_BYCOPY: |
| case RID_BYREF: |
| case RID_ONEWAY: |
| case RID_INT: |
| case RID_CHAR: |
| case RID_FLOAT: |
| case RID_DOUBLE: |
| case RID_VOID: |
| case RID_BOOL: |
| c_parser_consume_token (parser); |
| return value; |
| default: |
| return NULL_TREE; |
| } |
| } |
| |
| /* Parse an objc-selector-arg. |
| |
| objc-selector-arg: |
| objc-selector |
| objc-keywordname-list |
| |
| objc-keywordname-list: |
| objc-keywordname |
| objc-keywordname-list objc-keywordname |
| |
| objc-keywordname: |
| objc-selector : |
| : |
| */ |
| |
| static tree |
| c_parser_objc_selector_arg (c_parser *parser) |
| { |
| tree sel = c_parser_objc_selector (parser); |
| tree list = NULL_TREE; |
| if (sel && c_parser_next_token_is_not (parser, CPP_COLON)) |
| return sel; |
| while (true) |
| { |
| if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) |
| return list; |
| list = chainon (list, build_tree_list (sel, NULL_TREE)); |
| sel = c_parser_objc_selector (parser); |
| if (!sel && c_parser_next_token_is_not (parser, CPP_COLON)) |
| break; |
| } |
| return list; |
| } |
| |
| /* Parse an objc-receiver. |
| |
| objc-receiver: |
| expression |
| class-name |
| type-name |
| */ |
| |
| static tree |
| c_parser_objc_receiver (c_parser *parser) |
| { |
| if (c_parser_peek_token (parser)->type == CPP_NAME |
| && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME |
| || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) |
| { |
| tree id = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| return objc_get_class_reference (id); |
| } |
| return c_parser_expression (parser).value; |
| } |
| |
| /* Parse objc-message-args. |
| |
| objc-message-args: |
| objc-selector |
| objc-keywordarg-list |
| |
| objc-keywordarg-list: |
| objc-keywordarg |
| objc-keywordarg-list objc-keywordarg |
| |
| objc-keywordarg: |
| objc-selector : objc-keywordexpr |
| : objc-keywordexpr |
| */ |
| |
| static tree |
| c_parser_objc_message_args (c_parser *parser) |
| { |
| tree sel = c_parser_objc_selector (parser); |
| tree list = NULL_TREE; |
| if (sel && c_parser_next_token_is_not (parser, CPP_COLON)) |
| return sel; |
| while (true) |
| { |
| tree keywordexpr; |
| if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) |
| return list; |
| keywordexpr = c_parser_objc_keywordexpr (parser); |
| list = chainon (list, build_tree_list (sel, keywordexpr)); |
| sel = c_parser_objc_selector (parser); |
| if (!sel && c_parser_next_token_is_not (parser, CPP_COLON)) |
| break; |
| } |
| return list; |
| } |
| |
| /* Parse an objc-keywordexpr. |
| |
| objc-keywordexpr: |
| nonempty-expr-list |
| */ |
| |
| static tree |
| c_parser_objc_keywordexpr (c_parser *parser) |
| { |
| tree list = c_parser_expr_list (parser, true); |
| if (TREE_CHAIN (list) == NULL_TREE) |
| { |
| /* Just return the expression, remove a level of |
| indirection. */ |
| return TREE_VALUE (list); |
| } |
| else |
| { |
| /* We have a comma expression, we will collapse later. */ |
| return list; |
| } |
| } |
| |
| |
| /* Handle pragmas. Some OpenMP pragmas are associated with, and therefore |
| should be considered, statements. ALLOW_STMT is true if we're within |
| the context of a function and such pragmas are to be allowed. Returns |
| true if we actually parsed such a pragma. */ |
| |
| static bool |
| c_parser_pragma (c_parser *parser, enum pragma_context context) |
| { |
| unsigned int id; |
| |
| id = c_parser_peek_token (parser)->pragma_kind; |
| gcc_assert (id != PRAGMA_NONE); |
| |
| switch (id) |
| { |
| case PRAGMA_OMP_BARRIER: |
| if (context != pragma_compound) |
| { |
| if (context == pragma_stmt) |
| c_parser_error (parser, "%<#pragma omp barrier%> may only be " |
| "used in compound statements"); |
| goto bad_stmt; |
| } |
| c_parser_omp_barrier (parser); |
| return false; |
| |
| case PRAGMA_OMP_FLUSH: |
| if (context != pragma_compound) |
| { |
| if (context == pragma_stmt) |
| c_parser_error (parser, "%<#pragma omp flush%> may only be " |
| "used in compound statements"); |
| goto bad_stmt; |
| } |
| c_parser_omp_flush (parser); |
| return false; |
| |
| case PRAGMA_OMP_THREADPRIVATE: |
| c_parser_omp_threadprivate (parser); |
| return false; |
| |
| case PRAGMA_OMP_SECTION: |
| error ("%<#pragma omp section%> may only be used in " |
| "%<#pragma omp sections%> construct"); |
| c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); |
| return false; |
| |
| case PRAGMA_GCC_PCH_PREPROCESS: |
| c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); |
| c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); |
| return false; |
| |
| default: |
| if (id < PRAGMA_FIRST_EXTERNAL) |
| { |
| if (context == pragma_external) |
| { |
| bad_stmt: |
| c_parser_error (parser, "expected declaration specifiers"); |
| c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); |
| return false; |
| } |
| c_parser_omp_construct (parser); |
| return true; |
| } |
| break; |
| } |
| |
| c_parser_consume_pragma (parser); |
| c_invoke_pragma_handler (id); |
| |
| /* Skip to EOL, but suppress any error message. Those will have been |
| generated by the handler routine through calling error, as opposed |
| to calling c_parser_error. */ |
| parser->error = true; |
| c_parser_skip_to_pragma_eol (parser); |
| |
| return false; |
| } |
| |
| /* The interface the pragma parsers have to the lexer. */ |
| |
| enum cpp_ttype |
| pragma_lex (tree *value) |
| { |
| c_token *tok = c_parser_peek_token (the_parser); |
| enum cpp_ttype ret = tok->type; |
| |
| *value = tok->value; |
| if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) |
| ret = CPP_EOF; |
| else |
| { |
| if (ret == CPP_KEYWORD) |
| ret = CPP_NAME; |
| c_parser_consume_token (the_parser); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| c_parser_pragma_pch_preprocess (c_parser *parser) |
| { |
| tree name = NULL; |
| |
| c_parser_consume_pragma (parser); |
| if (c_parser_next_token_is (parser, CPP_STRING)) |
| { |
| name = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| } |
| else |
| c_parser_error (parser, "expected string literal"); |
| c_parser_skip_to_pragma_eol (parser); |
| |
| if (name) |
| c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); |
| } |
| |
| /* OpenMP 2.5 parsing routines. */ |
| |
| /* Returns name of the next clause. |
| If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and |
| the token is not consumed. Otherwise appropriate pragma_omp_clause is |
| returned and the token is consumed. */ |
| |
| static pragma_omp_clause |
| c_parser_omp_clause_name (c_parser *parser) |
| { |
| pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; |
| |
| if (c_parser_next_token_is_keyword (parser, RID_IF)) |
| result = PRAGMA_OMP_CLAUSE_IF; |
| else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) |
| result = PRAGMA_OMP_CLAUSE_DEFAULT; |
| else if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
| |
| switch (p[0]) |
| { |
| case 'c': |
| if (!strcmp ("copyin", p)) |
| result = PRAGMA_OMP_CLAUSE_COPYIN; |
| else if (!strcmp ("copyprivate", p)) |
| result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; |
| break; |
| case 'f': |
| if (!strcmp ("firstprivate", p)) |
| result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; |
| break; |
| case 'l': |
| if (!strcmp ("lastprivate", p)) |
| result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; |
| break; |
| case 'n': |
| if (!strcmp ("nowait", p)) |
| result = PRAGMA_OMP_CLAUSE_NOWAIT; |
| else if (!strcmp ("num_threads", p)) |
| result = PRAGMA_OMP_CLAUSE_NUM_THREADS; |
| break; |
| case 'o': |
| if (!strcmp ("ordered", p)) |
| result = PRAGMA_OMP_CLAUSE_ORDERED; |
| break; |
| case 'p': |
| if (!strcmp ("private", p)) |
| result = PRAGMA_OMP_CLAUSE_PRIVATE; |
| break; |
| case 'r': |
| if (!strcmp ("reduction", p)) |
| result = PRAGMA_OMP_CLAUSE_REDUCTION; |
| break; |
| case 's': |
| if (!strcmp ("schedule", p)) |
| result = PRAGMA_OMP_CLAUSE_SCHEDULE; |
| else if (!strcmp ("shared", p)) |
| result = PRAGMA_OMP_CLAUSE_SHARED; |
| break; |
| } |
| } |
| |
| if (result != PRAGMA_OMP_CLAUSE_NONE) |
| c_parser_consume_token (parser); |
| |
| return result; |
| } |
| |
| /* Validate that a clause of the given type does not already exist. */ |
| |
| static void |
| check_no_duplicate_clause (tree clauses, enum tree_code code, const char *name) |
| { |
| tree c; |
| |
| for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) |
| if (OMP_CLAUSE_CODE (c) == code) |
| { |
| error ("too many %qs clauses", name); |
| break; |
| } |
| } |
| |
| /* OpenMP 2.5: |
| variable-list: |
| identifier |
| variable-list , identifier |
| |
| If KIND is nonzero, create the appropriate node and install the decl |
| in OMP_CLAUSE_DECL and add the node to the head of the list. |
| |
| If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; |
| return the list created. */ |
| |
| static tree |
| c_parser_omp_variable_list (c_parser *parser, enum omp_clause_code kind, |
| tree list) |
| { |
| if (c_parser_next_token_is_not (parser, CPP_NAME) |
| || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
| c_parser_error (parser, "expected identifier"); |
| |
| while (c_parser_next_token_is (parser, CPP_NAME) |
| && c_parser_peek_token (parser)->id_kind == C_ID_ID) |
| { |
| tree t = lookup_name (c_parser_peek_token (parser)->value); |
| |
| if (t == NULL_TREE) |
| undeclared_variable (c_parser_peek_token (parser)->value, |
| c_parser_peek_token (parser)->location); |
| else if (t == error_mark_node) |
| ; |
| else if (kind != 0) |
| { |
| tree u = build_omp_clause (kind); |
| OMP_CLAUSE_DECL (u) = t; |
| OMP_CLAUSE_CHAIN (u) = list; |
| list = u; |
| } |
| else |
| list = tree_cons (t, NULL_TREE, list); |
| |
| c_parser_consume_token (parser); |
| |
| if (c_parser_next_token_is_not (parser, CPP_COMMA)) |
| break; |
| |
| c_parser_consume_token (parser); |
| } |
| |
| return list; |
| } |
| |
| /* Similarly, but expect leading and trailing parenthesis. This is a very |
| common case for omp clauses. */ |
| |
| static tree |
| c_parser_omp_var_list_parens (c_parser *parser, enum tree_code kind, tree list) |
| { |
| if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| list = c_parser_omp_variable_list (parser, kind, list); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| } |
| return list; |
| } |
| |
| /* OpenMP 2.5: |
| copyin ( variable-list ) */ |
| |
| static tree |
| c_parser_omp_clause_copyin (c_parser *parser, tree list) |
| { |
| return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list); |
| } |
| |
| /* OpenMP 2.5: |
| copyprivate ( variable-list ) */ |
| |
| static tree |
| c_parser_omp_clause_copyprivate (c_parser *parser, tree list) |
| { |
| return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list); |
| } |
| |
| /* OpenMP 2.5: |
| default ( shared | none ) */ |
| |
| static tree |
| c_parser_omp_clause_default (c_parser *parser, tree list) |
| { |
| enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; |
| tree c; |
| |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| return list; |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
| |
| switch (p[0]) |
| { |
| case 'n': |
| if (strcmp ("none", p) != 0) |
| goto invalid_kind; |
| kind = OMP_CLAUSE_DEFAULT_NONE; |
| break; |
| |
| case 's': |
| if (strcmp ("shared", p) != 0) |
| goto invalid_kind; |
| kind = OMP_CLAUSE_DEFAULT_SHARED; |
| break; |
| |
| default: |
| goto invalid_kind; |
| } |
| |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| invalid_kind: |
| c_parser_error (parser, "expected %<none%> or %<shared%>"); |
| } |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| |
| if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) |
| return list; |
| |
| check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default"); |
| c = build_omp_clause (OMP_CLAUSE_DEFAULT); |
| OMP_CLAUSE_CHAIN (c) = list; |
| OMP_CLAUSE_DEFAULT_KIND (c) = kind; |
| |
| return c; |
| } |
| |
| /* OpenMP 2.5: |
| firstprivate ( variable-list ) */ |
| |
| static tree |
| c_parser_omp_clause_firstprivate (c_parser *parser, tree list) |
| { |
| return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list); |
| } |
| |
| /* OpenMP 2.5: |
| if ( expression ) */ |
| |
| static tree |
| c_parser_omp_clause_if (c_parser *parser, tree list) |
| { |
| if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) |
| { |
| tree t = c_parser_paren_condition (parser); |
| tree c; |
| |
| check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if"); |
| |
| c = build_omp_clause (OMP_CLAUSE_IF); |
| OMP_CLAUSE_IF_EXPR (c) = t; |
| OMP_CLAUSE_CHAIN (c) = list; |
| list = c; |
| } |
| else |
| c_parser_error (parser, "expected %<(%>"); |
| |
| return list; |
| } |
| |
| /* OpenMP 2.5: |
| lastprivate ( variable-list ) */ |
| |
| static tree |
| c_parser_omp_clause_lastprivate (c_parser *parser, tree list) |
| { |
| return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list); |
| } |
| |
| /* OpenMP 2.5: |
| nowait */ |
| |
| static tree |
| c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) |
| { |
| tree c; |
| |
| check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait"); |
| |
| c = build_omp_clause (OMP_CLAUSE_NOWAIT); |
| OMP_CLAUSE_CHAIN (c) = list; |
| return c; |
| } |
| |
| /* OpenMP 2.5: |
| num_threads ( expression ) */ |
| |
| static tree |
| c_parser_omp_clause_num_threads (c_parser *parser, tree list) |
| { |
| if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| tree c, t = c_parser_expression (parser).value; |
| |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| |
| if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
| { |
| c_parser_error (parser, "expected integer expression"); |
| return list; |
| } |
| |
| /* Attempt to statically determine when the number isn't positive. */ |
| c = fold_build2 (LE_EXPR, boolean_type_node, t, |
| build_int_cst (TREE_TYPE (t), 0)); |
| if (c == boolean_true_node) |
| { |
| warning (0, "%<num_threads%> value must be positive"); |
| t = integer_one_node; |
| } |
| |
| check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads"); |
| |
| c = build_omp_clause (OMP_CLAUSE_NUM_THREADS); |
| OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; |
| OMP_CLAUSE_CHAIN (c) = list; |
| list = c; |
| } |
| |
| return list; |
| } |
| |
| /* OpenMP 2.5: |
| ordered */ |
| |
| static tree |
| c_parser_omp_clause_ordered (c_parser *parser ATTRIBUTE_UNUSED, tree list) |
| { |
| tree c; |
| |
| check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered"); |
| |
| c = build_omp_clause (OMP_CLAUSE_ORDERED); |
| OMP_CLAUSE_CHAIN (c) = list; |
| return c; |
| } |
| |
| /* OpenMP 2.5: |
| private ( variable-list ) */ |
| |
| static tree |
| c_parser_omp_clause_private (c_parser *parser, tree list) |
| { |
| return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list); |
| } |
| |
| /* OpenMP 2.5: |
| reduction ( reduction-operator : variable-list ) |
| |
| reduction-operator: |
| One of: + * - & ^ | && || */ |
| |
| static tree |
| c_parser_omp_clause_reduction (c_parser *parser, tree list) |
| { |
| if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| { |
| enum tree_code code; |
| |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_PLUS: |
| code = PLUS_EXPR; |
| break; |
| case CPP_MULT: |
| code = MULT_EXPR; |
| break; |
| case CPP_MINUS: |
| code = MINUS_EXPR; |
| break; |
| case CPP_AND: |
| code = BIT_AND_EXPR; |
| break; |
| case CPP_XOR: |
| code = BIT_XOR_EXPR; |
| break; |
| case CPP_OR: |
| code = BIT_IOR_EXPR; |
| break; |
| case CPP_AND_AND: |
| code = TRUTH_ANDIF_EXPR; |
| break; |
| case CPP_OR_OR: |
| code = TRUTH_ORIF_EXPR; |
| break; |
| default: |
| c_parser_error (parser, |
| "expected %<+%>, %<*%>, %<-%>, %<&%>, " |
| "%<^%>, %<|%>, %<&&%>, or %<||%>"); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); |
| return list; |
| } |
| c_parser_consume_token (parser); |
| if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) |
| { |
| tree nl, c; |
| |
| nl = c_parser_omp_variable_list (parser, OMP_CLAUSE_REDUCTION, list); |
| for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
| OMP_CLAUSE_REDUCTION_CODE (c) = code; |
| |
| list = nl; |
| } |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| } |
| return list; |
| } |
| |
| /* OpenMP 2.5: |
| schedule ( schedule-kind ) |
| schedule ( schedule-kind , expression ) |
| |
| schedule-kind: |
| static | dynamic | guided | runtime |
| */ |
| |
| static tree |
| c_parser_omp_clause_schedule (c_parser *parser, tree list) |
| { |
| tree c, t; |
| |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| return list; |
| |
| c = build_omp_clause (OMP_CLAUSE_SCHEDULE); |
| |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| tree kind = c_parser_peek_token (parser)->value; |
| const char *p = IDENTIFIER_POINTER (kind); |
| |
| switch (p[0]) |
| { |
| case 'd': |
| if (strcmp ("dynamic", p) != 0) |
| goto invalid_kind; |
| OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC; |
| break; |
| |
| case 'g': |
| if (strcmp ("guided", p) != 0) |
| goto invalid_kind; |
| OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED; |
| break; |
| |
| case 'r': |
| if (strcmp ("runtime", p) != 0) |
| goto invalid_kind; |
| OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME; |
| break; |
| |
| default: |
| goto invalid_kind; |
| } |
| } |
| else if (c_parser_next_token_is_keyword (parser, RID_STATIC)) |
| OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; |
| else |
| goto invalid_kind; |
| |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| { |
| c_parser_consume_token (parser); |
| |
| t = c_parser_expr_no_commas (parser, NULL).value; |
| |
| if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) |
| error ("schedule %<runtime%> does not take " |
| "a %<chunk_size%> parameter"); |
| else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE) |
| OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; |
| else |
| c_parser_error (parser, "expected integer expression"); |
| |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| } |
| else |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<,%> or %<)%>"); |
| |
| check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule"); |
| OMP_CLAUSE_CHAIN (c) = list; |
| return c; |
| |
| invalid_kind: |
| c_parser_error (parser, "invalid schedule kind"); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); |
| return list; |
| } |
| |
| /* OpenMP 2.5: |
| shared ( variable-list ) */ |
| |
| static tree |
| c_parser_omp_clause_shared (c_parser *parser, tree list) |
| { |
| return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list); |
| } |
| |
| /* Parse all OpenMP clauses. The set clauses allowed by the directive |
| is a bitmask in MASK. Return the list of clauses found; the result |
| of clause default goes in *pdefault. */ |
| |
| static tree |
| c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, |
| const char *where) |
| { |
| tree clauses = NULL; |
| |
| while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) |
| { |
| const pragma_omp_clause c_kind = c_parser_omp_clause_name (parser); |
| const char *c_name; |
| tree prev = clauses; |
| |
| switch (c_kind) |
| { |
| case PRAGMA_OMP_CLAUSE_COPYIN: |
| clauses = c_parser_omp_clause_copyin (parser, clauses); |
| c_name = "copyin"; |
| break; |
| case PRAGMA_OMP_CLAUSE_COPYPRIVATE: |
| clauses = c_parser_omp_clause_copyprivate (parser, clauses); |
| c_name = "copyprivate"; |
| break; |
| case PRAGMA_OMP_CLAUSE_DEFAULT: |
| clauses = c_parser_omp_clause_default (parser, clauses); |
| c_name = "default"; |
| break; |
| case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: |
| clauses = c_parser_omp_clause_firstprivate (parser, clauses); |
| c_name = "firstprivate"; |
| break; |
| case PRAGMA_OMP_CLAUSE_IF: |
| clauses = c_parser_omp_clause_if (parser, clauses); |
| c_name = "if"; |
| break; |
| case PRAGMA_OMP_CLAUSE_LASTPRIVATE: |
| clauses = c_parser_omp_clause_lastprivate (parser, clauses); |
| c_name = "lastprivate"; |
| break; |
| case PRAGMA_OMP_CLAUSE_NOWAIT: |
| clauses = c_parser_omp_clause_nowait (parser, clauses); |
| c_name = "nowait"; |
| break; |
| case PRAGMA_OMP_CLAUSE_NUM_THREADS: |
| clauses = c_parser_omp_clause_num_threads (parser, clauses); |
| c_name = "num_threads"; |
| break; |
| case PRAGMA_OMP_CLAUSE_ORDERED: |
| clauses = c_parser_omp_clause_ordered (parser, clauses); |
| c_name = "ordered"; |
| break; |
| case PRAGMA_OMP_CLAUSE_PRIVATE: |
| clauses = c_parser_omp_clause_private (parser, clauses); |
| c_name = "private"; |
| break; |
| case PRAGMA_OMP_CLAUSE_REDUCTION: |
| clauses = c_parser_omp_clause_reduction (parser, clauses); |
| c_name = "reduction"; |
| break; |
| case PRAGMA_OMP_CLAUSE_SCHEDULE: |
| clauses = c_parser_omp_clause_schedule (parser, clauses); |
| c_name = "schedule"; |
| break; |
| case PRAGMA_OMP_CLAUSE_SHARED: |
| clauses = c_parser_omp_clause_shared (parser, clauses); |
| c_name = "shared"; |
| break; |
| default: |
| c_parser_error (parser, "expected %<#pragma omp%> clause"); |
| goto saw_error; |
| } |
| |
| if (((mask >> c_kind) & 1) == 0 && !parser->error) |
| { |
| /* Remove the invalid clause(s) from the list to avoid |
| confusing the rest of the compiler. */ |
| clauses = prev; |
| error ("%qs is not valid for %qs", c_name, where); |
| } |
| } |
| |
| saw_error: |
| c_parser_skip_to_pragma_eol (parser); |
| |
| return c_finish_omp_clauses (clauses); |
| } |
| |
| /* OpenMP 2.5: |
| structured-block: |
| statement |
| |
| In practice, we're also interested in adding the statement to an |
| outer node. So it is convenient if we work around the fact that |
| c_parser_statement calls add_stmt. */ |
| |
| static tree |
| c_parser_omp_structured_block (c_parser *parser) |
| { |
| tree stmt = push_stmt_list (); |
| c_parser_statement (parser); |
| return pop_stmt_list (stmt); |
| } |
| |
| /* OpenMP 2.5: |
| # pragma omp atomic new-line |
| expression-stmt |
| |
| expression-stmt: |
| x binop= expr | x++ | ++x | x-- | --x |
| binop: |
| +, *, -, /, &, ^, |, <<, >> |
| |
| where x is an lvalue expression with scalar type. */ |
| |
| static void |
| c_parser_omp_atomic (c_parser *parser) |
| { |
| tree lhs, rhs; |
| tree stmt; |
| enum tree_code code; |
| |
| c_parser_skip_to_pragma_eol (parser); |
| |
| lhs = c_parser_unary_expression (parser).value; |
| switch (TREE_CODE (lhs)) |
| { |
| case ERROR_MARK: |
| saw_error: |
| c_parser_skip_to_end_of_block_or_statement (parser); |
| return; |
| |
| case PREINCREMENT_EXPR: |
| case POSTINCREMENT_EXPR: |
| lhs = TREE_OPERAND (lhs, 0); |
| code = PLUS_EXPR; |
| rhs = integer_one_node; |
| break; |
| |
| case PREDECREMENT_EXPR: |
| case POSTDECREMENT_EXPR: |
| lhs = TREE_OPERAND (lhs, 0); |
| code = MINUS_EXPR; |
| rhs = integer_one_node; |
| break; |
| |
| default: |
| switch (c_parser_peek_token (parser)->type) |
| { |
| case CPP_MULT_EQ: |
| code = MULT_EXPR; |
| break; |
| case CPP_DIV_EQ: |
| code = TRUNC_DIV_EXPR; |
| break; |
| case CPP_PLUS_EQ: |
| code = PLUS_EXPR; |
| break; |
| case CPP_MINUS_EQ: |
| code = MINUS_EXPR; |
| break; |
| case CPP_LSHIFT_EQ: |
| code = LSHIFT_EXPR; |
| break; |
| case CPP_RSHIFT_EQ: |
| code = RSHIFT_EXPR; |
| break; |
| case CPP_AND_EQ: |
| code = BIT_AND_EXPR; |
| break; |
| case CPP_OR_EQ: |
| code = BIT_IOR_EXPR; |
| break; |
| case CPP_XOR_EQ: |
| code = BIT_XOR_EXPR; |
| break; |
| default: |
| c_parser_error (parser, |
| "invalid operator for %<#pragma omp atomic%>"); |
| goto saw_error; |
| } |
| |
| c_parser_consume_token (parser); |
| rhs = c_parser_expression (parser).value; |
| break; |
| } |
| stmt = c_finish_omp_atomic (code, lhs, rhs); |
| if (stmt != error_mark_node) |
| add_stmt (stmt); |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| } |
| |
| |
| /* OpenMP 2.5: |
| # pragma omp barrier new-line |
| */ |
| |
| static void |
| c_parser_omp_barrier (c_parser *parser) |
| { |
| c_parser_consume_pragma (parser); |
| c_parser_skip_to_pragma_eol (parser); |
| |
| c_finish_omp_barrier (); |
| } |
| |
| /* OpenMP 2.5: |
| # pragma omp critical [(name)] new-line |
| structured-block |
| */ |
| |
| static tree |
| c_parser_omp_critical (c_parser *parser) |
| { |
| tree stmt, name = NULL; |
| |
| if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) |
| { |
| c_parser_consume_token (parser); |
| if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| name = c_parser_peek_token (parser)->value; |
| c_parser_consume_token (parser); |
| c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| } |
| else |
| c_parser_error (parser, "expected identifier"); |
| } |
| else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) |
| c_parser_error (parser, "expected %<(%> or end of line"); |
| c_parser_skip_to_pragma_eol (parser); |
| |
| stmt = c_parser_omp_structured_block (parser); |
| return c_finish_omp_critical (stmt, name); |
| } |
| |
| /* OpenMP 2.5: |
| # pragma omp flush flush-vars[opt] new-line |
| |
| flush-vars: |
| ( variable-list ) */ |
| |
| static void |
| c_parser_omp_flush (c_parser *parser) |
| { |
| c_parser_consume_pragma (parser); |
| if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) |
| c_parser_omp_var_list_parens (parser, 0, NULL); |
| else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) |
| c_parser_error (parser, "expected %<(%> or end of line"); |
| c_parser_skip_to_pragma_eol (parser); |
| |
| c_finish_omp_flush (); |
| } |
| |
| /* Parse the restricted form of the for statment allowed by OpenMP. |
| The real trick here is to determine the loop control variable early |
| so that we can push a new decl if necessary to make it private. */ |
| |
| static tree |
| c_parser_omp_for_loop (c_parser *parser) |
| { |
| tree decl, cond, incr, save_break, save_cont, body, init; |
| location_t loc; |
| |
| if (!c_parser_next_token_is_keyword (parser, RID_FOR)) |
| { |
| c_parser_error (parser, "for statement expected"); |
| return NULL; |
| } |
| loc = c_parser_peek_token (parser)->location; |
| c_parser_consume_token (parser); |
| |
| if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) |
| return NULL; |
| |
| /* Parse the initialization declaration or expression. */ |
| if (c_parser_next_token_starts_declspecs (parser)) |
| { |
| /* APPLE LOCAL radar 4708210 (for_objc_collection in 4.2) */ |
| c_parser_declaration_or_fndef (parser, true, true, true, true, NULL); |
| decl = check_for_loop_decls (); |
| if (decl == NULL) |
| goto error_init; |
| init = decl; |
| } |
| else if (c_parser_next_token_is (parser, CPP_NAME) |
| && c_parser_peek_2nd_token (parser)->type == CPP_EQ) |
| { |
| decl = c_parser_postfix_expression (parser).value; |
| |
| c_parser_require (parser, CPP_EQ, "expected %<=%>"); |
| |
| init = c_parser_expr_no_commas (parser, NULL).value; |
| init = build_modify_expr (decl, NOP_EXPR, init); |
| init = c_process_expr_stmt (init); |
| |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| } |
| else |
| goto error_init; |
| |
| /* Parse the loop condition. */ |
| cond = NULL_TREE; |
| if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) |
| { |
| cond = c_parser_expression_conv (parser).value; |
| cond = c_objc_common_truthvalue_conversion (cond); |
| if (EXPR_P (cond)) |
| SET_EXPR_LOCATION (cond, input_location); |
| } |
| c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); |
| |
| /* Parse the increment expression. */ |
| incr = NULL_TREE; |
| if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) |
| incr = c_process_expr_stmt (c_parser_expression (parser).value); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| |
| parse_body: |
| save_break = c_break_label; |
| c_break_label = size_one_node; |
| save_cont = c_cont_label; |
| c_cont_label = NULL_TREE; |
| body = push_stmt_list (); |
| |
| add_stmt (c_parser_c99_block_statement (parser)); |
| if (c_cont_label) |
| add_stmt (build1 (LABEL_EXPR, void_type_node, c_cont_label)); |
| |
| body = pop_stmt_list (body); |
| c_break_label = save_break; |
| c_cont_label = save_cont; |
| |
| /* Only bother calling c_finish_omp_for if we havn't already generated |
| an error from the initialization parsing. */ |
| if (decl != NULL && decl != error_mark_node && init != error_mark_node) |
| return c_finish_omp_for (loc, decl, init, cond, incr, body, NULL); |
| return NULL; |
| |
| error_init: |
| c_parser_error (parser, "expected iteration declaration or initialization"); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); |
| decl = init = cond = incr = NULL_TREE; |
| goto parse_body; |
| } |
| |
| /* OpenMP 2.5: |
| #pragma omp for for-clause[optseq] new-line |
| for-loop |
| */ |
| |
| #define OMP_FOR_CLAUSE_MASK \ |
| ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
| | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ |
| | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) |
| |
| static tree |
| c_parser_omp_for (c_parser *parser) |
| { |
| tree block, clauses, ret; |
| |
| clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, |
| "#pragma omp for"); |
| |
| block = c_begin_compound_stmt (true); |
| ret = c_parser_omp_for_loop (parser); |
| if (ret) |
| OMP_FOR_CLAUSES (ret) = clauses; |
| block = c_end_compound_stmt (block, true); |
| add_stmt (block); |
| |
| return ret; |
| } |
| |
| /* OpenMP 2.5: |
| # pragma omp master new-line |
| structured-block |
| */ |
| |
| static tree |
| c_parser_omp_master (c_parser *parser) |
| { |
| c_parser_skip_to_pragma_eol (parser); |
| return c_finish_omp_master (c_parser_omp_structured_block (parser)); |
| } |
| |
| /* OpenMP 2.5: |
| # pragma omp ordered new-line |
| structured-block |
| */ |
| |
| static tree |
| c_parser_omp_ordered (c_parser *parser) |
| { |
| c_parser_skip_to_pragma_eol (parser); |
| return c_finish_omp_ordered (c_parser_omp_structured_block (parser)); |
| } |
| |
| /* OpenMP 2.5: |
| |
| section-scope: |
| { section-sequence } |
| |
| section-sequence: |
| section-directive[opt] structured-block |
| section-sequence section-directive structured-block */ |
| |
| static tree |
| c_parser_omp_sections_scope (c_parser *parser) |
| { |
| tree stmt, substmt; |
| bool error_suppress = false; |
| location_t loc; |
| |
| if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) |
| { |
| /* Avoid skipping until the end of the block. */ |
| parser->error = false; |
| return NULL_TREE; |
| } |
| |
| stmt = push_stmt_list (); |
| |
| loc = c_parser_peek_token (parser)->location; |
| if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION) |
| { |
| substmt = push_stmt_list (); |
| |
| while (1) |
| { |
| c_parser_statement (parser); |
| |
| if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) |
| break; |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) |
| break; |
| if (c_parser_next_token_is (parser, CPP_EOF)) |
| break; |
| } |
| |
| substmt = pop_stmt_list (substmt); |
| substmt = build1 (OMP_SECTION, void_type_node, substmt); |
| SET_EXPR_LOCATION (substmt, loc); |
| add_stmt (substmt); |
| } |
| |
| while (1) |
| { |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) |
| break; |
| if (c_parser_next_token_is (parser, CPP_EOF)) |
| break; |
| |
| loc = c_parser_peek_token (parser)->location; |
| if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) |
| { |
| c_parser_consume_pragma (parser); |
| c_parser_skip_to_pragma_eol (parser); |
| error_suppress = false; |
| } |
| else if (!error_suppress) |
| { |
| error ("expected %<#pragma omp section%> or %<}%>"); |
| error_suppress = true; |
| } |
| |
| substmt = c_parser_omp_structured_block (parser); |
| substmt = build1 (OMP_SECTION, void_type_node, substmt); |
| SET_EXPR_LOCATION (substmt, loc); |
| add_stmt (substmt); |
| } |
| c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, |
| "expected %<#pragma omp section%> or %<}%>"); |
| |
| substmt = pop_stmt_list (stmt); |
| |
| stmt = make_node (OMP_SECTIONS); |
| TREE_TYPE (stmt) = void_type_node; |
| OMP_SECTIONS_BODY (stmt) = substmt; |
| |
| return add_stmt (stmt); |
| } |
| |
| /* OpenMP 2.5: |
| # pragma omp sections sections-clause[optseq] newline |
| sections-scope |
| */ |
| |
| #define OMP_SECTIONS_CLAUSE_MASK \ |
| ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
| | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) |
| |
| static tree |
| c_parser_omp_sections (c_parser *parser) |
| { |
| tree block, clauses, ret; |
| |
| clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, |
| "#pragma omp sections"); |
| |
| block = c_begin_compound_stmt (true); |
| ret = c_parser_omp_sections_scope (parser); |
| if (ret) |
| OMP_SECTIONS_CLAUSES (ret) = clauses; |
| block = c_end_compound_stmt (block, true); |
| add_stmt (block); |
| |
| return ret; |
| } |
| |
| /* OpenMP 2.5: |
| # pragma parallel parallel-clause new-line |
| # pragma parallel for parallel-for-clause new-line |
| # pragma parallel sections parallel-sections-clause new-line |
| */ |
| |
| #define OMP_PARALLEL_CLAUSE_MASK \ |
| ( (1u << PRAGMA_OMP_CLAUSE_IF) \ |
| | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ |
| | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ |
| | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ |
| | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
| | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) |
| |
| static tree |
| c_parser_omp_parallel (c_parser *parser) |
| { |
| enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; |
| const char *p_name = "#pragma omp parallel"; |
| tree stmt, clauses, par_clause, ws_clause, block; |
| unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; |
| |
| if (c_parser_next_token_is_keyword (parser, RID_FOR)) |
| { |
| c_parser_consume_token (parser); |
| p_kind = PRAGMA_OMP_PARALLEL_FOR; |
| p_name = "#pragma omp parallel for"; |
| mask |= OMP_FOR_CLAUSE_MASK; |
| mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); |
| } |
| else if (c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
| if (strcmp (p, "sections") == 0) |
| { |
| c_parser_consume_token (parser); |
| p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; |
| p_name = "#pragma omp parallel sections"; |
| mask |= OMP_SECTIONS_CLAUSE_MASK; |
| mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); |
| } |
| } |
| |
| clauses = c_parser_omp_all_clauses (parser, mask, p_name); |
| |
| switch (p_kind) |
| { |
| case PRAGMA_OMP_PARALLEL: |
| block = c_begin_omp_parallel (); |
| c_parser_statement (parser); |
| stmt = c_finish_omp_parallel (clauses, block); |
| break; |
| |
| case PRAGMA_OMP_PARALLEL_FOR: |
| block = c_begin_omp_parallel (); |
| c_split_parallel_clauses (clauses, &par_clause, &ws_clause); |
| stmt = c_parser_omp_for_loop (parser); |
| if (stmt) |
| OMP_FOR_CLAUSES (stmt) = ws_clause; |
| stmt = c_finish_omp_parallel (par_clause, block); |
| OMP_PARALLEL_COMBINED (stmt) = 1; |
| break; |
| |
| case PRAGMA_OMP_PARALLEL_SECTIONS: |
| block = c_begin_omp_parallel (); |
| c_split_parallel_clauses (clauses, &par_clause, &ws_clause); |
| stmt = c_parser_omp_sections_scope (parser); |
| if (stmt) |
| OMP_SECTIONS_CLAUSES (stmt) = ws_clause; |
| stmt = c_finish_omp_parallel (par_clause, block); |
| OMP_PARALLEL_COMBINED (stmt) = 1; |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| return stmt; |
| } |
| |
| /* OpenMP 2.5: |
| # pragma omp single single-clause[optseq] new-line |
| structured-block |
| */ |
| |
| #define OMP_SINGLE_CLAUSE_MASK \ |
| ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ |
| | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) |
| |
| static tree |
| c_parser_omp_single (c_parser *parser) |
| { |
| tree stmt = make_node (OMP_SINGLE); |
| TREE_TYPE (stmt) = void_type_node; |
| |
| OMP_SINGLE_CLAUSES (stmt) |
| = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, |
| "#pragma omp single"); |
| OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser); |
| |
| return add_stmt (stmt); |
| } |
| |
| |
| /* Main entry point to parsing most OpenMP pragmas. */ |
| |
| static void |
| c_parser_omp_construct (c_parser *parser) |
| { |
| enum pragma_kind p_kind; |
| location_t loc; |
| tree stmt; |
| |
| loc = c_parser_peek_token (parser)->location; |
| p_kind = c_parser_peek_token (parser)->pragma_kind; |
| c_parser_consume_pragma (parser); |
| |
| /* For all constructs below except #pragma omp atomic |
| MUST_NOT_THROW catch handlers are needed when exceptions |
| are enabled. */ |
| if (p_kind != PRAGMA_OMP_ATOMIC) |
| c_maybe_initialize_eh (); |
| |
| switch (p_kind) |
| { |
| case PRAGMA_OMP_ATOMIC: |
| c_parser_omp_atomic (parser); |
| return; |
| case PRAGMA_OMP_CRITICAL: |
| stmt = c_parser_omp_critical (parser); |
| break; |
| case PRAGMA_OMP_FOR: |
| stmt = c_parser_omp_for (parser); |
| break; |
| case PRAGMA_OMP_MASTER: |
| stmt = c_parser_omp_master (parser); |
| break; |
| case PRAGMA_OMP_ORDERED: |
| stmt = c_parser_omp_ordered (parser); |
| break; |
| case PRAGMA_OMP_PARALLEL: |
| stmt = c_parser_omp_parallel (parser); |
| break; |
| case PRAGMA_OMP_SECTIONS: |
| stmt = c_parser_omp_sections (parser); |
| break; |
| case PRAGMA_OMP_SINGLE: |
| stmt = c_parser_omp_single (parser); |
| break; |
| default: |
| gcc_unreachable (); |
| } |
| |
| if (stmt) |
| SET_EXPR_LOCATION (stmt, loc); |
| } |
| |
| |
| /* OpenMP 2.5: |
| # pragma omp threadprivate (variable-list) */ |
| |
| static void |
| c_parser_omp_threadprivate (c_parser *parser) |
| { |
| tree vars, t; |
| |
| c_parser_consume_pragma (parser); |
| vars = c_parser_omp_var_list_parens (parser, 0, NULL); |
| |
| if (!targetm.have_tls) |
| sorry ("threadprivate variables not supported in this target"); |
| |
| /* Mark every variable in VARS to be assigned thread local storage. */ |
| for (t = vars; t; t = TREE_CHAIN (t)) |
| { |
| tree v = TREE_PURPOSE (t); |
| |
| /* If V had already been marked threadprivate, it doesn't matter |
| whether it had been used prior to this point. */ |
| if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v)) |
| error ("%qE declared %<threadprivate%> after first use", v); |
| else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v)) |
| error ("automatic variable %qE cannot be %<threadprivate%>", v); |
| else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) |
| error ("%<threadprivate%> %qE has incomplete type", v); |
| else |
| { |
| if (! DECL_THREAD_LOCAL_P (v)) |
| { |
| DECL_TLS_MODEL (v) = decl_default_tls_model (v); |
| /* If rtl has been already set for this var, call |
| make_decl_rtl once again, so that encode_section_info |
| has a chance to look at the new decl flags. */ |
| /* LLVM LOCAL begin */ |
| #ifndef ENABLE_LLVM |
| if (DECL_RTL_SET_P (v)) |
| make_decl_rtl (v); |
| #else |
| if (DECL_LLVM_SET_P (v)) |
| make_decl_llvm (v); |
| #endif |
| /* LLVM LOCAL end */ |
| } |
| C_DECL_THREADPRIVATE_P (v) = 1; |
| } |
| } |
| |
| c_parser_skip_to_pragma_eol (parser); |
| } |
| |
| |
| /* Parse a single source file. */ |
| |
| void |
| c_parse_file (void) |
| { |
| /* Use local storage to begin. If the first token is a pragma, parse it. |
| If it is #pragma GCC pch_preprocess, then this will load a PCH file |
| which will cause garbage collection. */ |
| c_parser tparser; |
| |
| memset (&tparser, 0, sizeof tparser); |
| the_parser = &tparser; |
| |
| if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) |
| c_parser_pragma_pch_preprocess (&tparser); |
| |
| the_parser = GGC_NEW (c_parser); |
| *the_parser = tparser; |
| |
| c_parser_translation_unit (the_parser); |
| the_parser = NULL; |
| } |
| |
| /* APPLE LOCAL begin CW asm blocks */ |
| static void c_parser_iasm_statement (c_parser*); |
| static tree c_parser_iasm_identifier_or_number (c_parser*); |
| |
| static bool |
| c_parser_iasm_bol (c_parser *parser) |
| { |
| location_t loc; |
| c_token *token; |
| /* We can't use c_parser_peek_token here, as it will give errors for things like |
| 1st in MS-stype asm. */ |
| if (parser->tokens_avail == 0) |
| { |
| loc = input_location; |
| parser->tokens_avail = 1; |
| c_lex_one_token (&parser->tokens[0], parser); |
| input_location = loc; |
| } |
| token = &parser->tokens[0]; |
| |
| return (token->flags & BOL) != 0; |
| } |
| |
| /* (in 4.2 ao) */ |
| static void |
| c_parser_iasm_maybe_skip_comments (c_parser *parser) |
| { |
| if (flag_ms_asms |
| && c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| { |
| /* Eat the ';', then skip rest of characters on this line. */ |
| c_parser_consume_token (parser); |
| gcc_assert (parser->tokens_avail == 0); |
| iasm_skip_to_eol (); |
| } |
| } |
| |
| /* (in 4.2 ap) */ |
| /* (in 4.2 ax) */ |
| /* Parse an asm line. The first token cannot be at the beginning of |
| the line. */ |
| |
| static void |
| c_parser_iasm_statement_seq_opt (c_parser* parser) |
| { |
| int check; |
| /* Scan statements until there aren't any more. */ |
| while (true) |
| { |
| check = 0; |
| /* Semicolons divide up individual statements. */ |
| if (c_parser_next_token_is (parser, CPP_SEMICOLON)) |
| { |
| /* ; denotes comments in MS-style asms. */ |
| if (flag_ms_asms) |
| { |
| c_parser_iasm_maybe_skip_comments (parser); |
| return; |
| } |
| c_parser_consume_token (parser); |
| } |
| else if (c_parser_next_token_is_keyword (parser, RID_ASM)) |
| { |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| /* Parse a single statement. */ |
| c_parser_iasm_statement (parser); |
| /* Resynchronize from c_parser_iasm_bol. */ |
| input_location = c_parser_peek_token (parser)->location; |
| check = 1; |
| } |
| |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE) |
| || c_parser_next_token_is (parser, CPP_EOF) |
| /* We parse at most, one line. */ |
| || c_parser_iasm_bol (parser)) |
| return; |
| |
| if (check |
| && !(c_parser_next_token_is (parser, CPP_CLOSE_BRACE) |
| || c_parser_next_token_is (parser, CPP_SEMICOLON) |
| || c_parser_next_token_is_keyword (parser, RID_ASM) |
| || c_parser_iasm_bol (parser))) |
| { |
| c_parser_error (parser, "expected %<;%> or %<}%> %<asm%> or end-of-line"); |
| } |
| } |
| if (!c_parser_iasm_bol (parser)) |
| c_parser_iasm_maybe_skip_comments (parser); |
| } |
| |
| /* (in 4.2 au) */ |
| static void |
| c_parser_iasm_line (c_parser* parser) |
| { |
| c_parser_iasm_statement_seq_opt (parser); |
| } |
| |
| /* (in 4.2 au) */ |
| /* Parse an (optional) line-seq. |
| |
| line-seq: |
| line |
| line-seq [opt] line */ |
| |
| static void |
| c_parser_iasm_line_seq_opt (c_parser* parser) |
| { |
| /* Scan lines of asm until there aren't any more. */ |
| while (true) |
| { |
| /* If we're looking at a `}', then we've run out of lines. */ |
| if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE) |
| || c_parser_next_token_is (parser, CPP_EOF)) |
| break; |
| |
| /* Parse the line. */ |
| c_parser_iasm_line (parser); |
| } |
| } |
| |
| /* (in 4.2 at) */ |
| /* (in 4.2 av) */ |
| /* (in 4.2 aw) */ |
| /* This is the section of CW-asm-specific parsing functions. */ |
| |
| static void |
| c_parser_iasm_compound_statement (c_parser *parser) |
| { |
| tree stmt; |
| |
| iasm_state = iasm_asm; |
| inside_iasm_block = true; |
| iasm_kill_regs = true; |
| stmt = c_begin_compound_stmt (true); |
| /* Parse an (optional) statement-seq. */ |
| c_parser_iasm_line_seq_opt (parser); |
| add_stmt (c_end_compound_stmt (stmt, true)); |
| /* Consume the `}'. */ |
| c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); |
| /* We're done with the block of asm. */ |
| /* (in 4.2 ay) */ |
| iasm_end_block (); |
| iasm_state = iasm_none; |
| } |
| |
| static void |
| c_parser_iasm_top_statement (c_parser *parser) |
| { |
| tree stmt; |
| |
| iasm_state = iasm_asm; |
| inside_iasm_block = true; |
| iasm_kill_regs = true; |
| stmt = c_begin_compound_stmt (true); |
| if (!c_parser_iasm_bol (parser)) |
| { |
| /* Parse a line. */ |
| c_parser_iasm_line (parser); |
| } |
| add_stmt (c_end_compound_stmt (stmt, true)); |
| /* We're done with the block of asm. */ |
| iasm_end_block (); |
| iasm_state = iasm_none; |
| } |
| |
| /* Build an identifier comprising the string passed and the |
| next token. */ |
| |
| static tree |
| iasm_build_identifier_string (c_parser* parser, const char* str) |
| { |
| char *buf; |
| int len; |
| tree id; |
| |
| if (strcmp (str, ".") == 0 |
| && (c_parser_peek_token (parser)->flags & PREV_WHITE) == 0) |
| { |
| if (c_parser_next_token_is_keyword (parser, RID_SHORT)) |
| { |
| c_parser_consume_token (parser); |
| return get_identifier (".short"); |
| } |
| if (c_parser_next_token_is_keyword (parser, RID_LONG)) |
| { |
| c_parser_consume_token (parser); |
| return get_identifier (".long"); |
| } |
| } |
| |
| id = c_parser_iasm_identifier_or_number (parser); |
| len = strlen (str); |
| buf = (char *) alloca (IDENTIFIER_LENGTH (id) + len + 1); |
| memcpy (buf, str, len); |
| memcpy (buf+len, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id)); |
| buf[IDENTIFIER_LENGTH (id) + len] = 0; |
| return get_identifier (buf); |
| } |
| |
| static tree |
| c_parser_identifier (c_parser* parser) |
| { |
| c_token *token; |
| tree t; |
| |
| /* Look for the identifier. */ |
| token = c_parser_peek_token (parser); |
| t = token->value; |
| if (!c_parser_require (parser, CPP_NAME, "expected identifier")) |
| return error_mark_node; |
| |
| /* Return the value. */ |
| return t; |
| } |
| |
| /* (in 4.2 aq) */ |
| /* Parse a CW asm identifier. Returns an IDENTIFIER_NODE representing |
| the identifier. The CW asm identifieriers include [.+-] as part of |
| the identifier. */ |
| |
| static tree |
| c_parser_iasm_identifier (c_parser* parser) |
| { |
| c_token *token; |
| tree t; |
| const char *str = ""; |
| |
| /* We have to accept certain keywords. */ |
| token = c_parser_peek_token (parser); |
| if (token->flags & NAMED_OP) |
| { |
| const char *s = 0; |
| switch (token->type) { |
| case CPP_AND_AND: s="and"; break; |
| case CPP_AND_EQ: s="and_eq"; break; |
| case CPP_AND: s="bitand"; break; |
| case CPP_OR: s="bitor"; break; |
| case CPP_COMPL: s="compl"; break; |
| case CPP_NOT: s="not"; break; |
| case CPP_NOT_EQ: s="not_eq"; break; |
| case CPP_OR_OR: s="or"; break; |
| case CPP_OR_EQ: s="or_eq"; break; |
| case CPP_XOR: s="xor"; break; |
| case CPP_XOR_EQ: s="xor_eq"; break; |
| default: break; |
| } |
| |
| /* The above list is the entire list of named operators. We |
| can't fail to translate the name. See operator_array in |
| libcpp/init.c. */ |
| gcc_assert (s != 0); |
| c_parser_consume_token (parser); |
| t = get_identifier (s); |
| } |
| else if (token->type == CPP_DOT) |
| { |
| /* .align */ |
| c_parser_consume_token (parser); |
| t = iasm_build_identifier_string (parser, "."); |
| } |
| else if (token->value |
| && IASM_SEE_OPCODE (TYPESPEC, token->value) == IDENTIFIER) |
| { |
| t = token->value; |
| c_parser_consume_token (parser); |
| } |
| else |
| t = c_parser_identifier (parser); |
| |
| if (t == error_mark_node) |
| return t; |
| |
| token = c_parser_peek_token (parser); |
| |
| switch (token->type) |
| { |
| case CPP_DOT: |
| str = "."; |
| break; |
| case CPP_PLUS: |
| str = "+"; |
| break; |
| case CPP_MINUS: |
| str = "-"; |
| break; |
| case CPP_PLUS_PLUS: |
| str = "++"; |
| break; |
| case CPP_MINUS_MINUS: |
| str = "--"; |
| break; |
| default: |
| return t; |
| } |
| |
| /* If there was whitespace between the identifier and the [.+-] |
| character, then that character can't be part of the |
| identifier. */ |
| if (token->flags & PREV_WHITE) |
| return t; |
| |
| c_parser_consume_token (parser); |
| |
| return iasm_get_identifier (t, str); |
| } |
| |
| static tree |
| c_parser_iasm_identifier_or_number (c_parser* parser) |
| { |
| c_token *token; |
| |
| token = c_parser_peek_token (parser); |
| if (token->type == CPP_NUMBER |
| && TREE_CODE (token->value) == INTEGER_CST) |
| { |
| char buf[60]; |
| |
| sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, tree_low_cst (token->value, 0)); |
| c_parser_consume_token (parser); |
| return get_identifier (buf); |
| } |
| |
| return c_parser_identifier (parser); |
| } |
| |
| /* (in 4.2 an) */ |
| static tree |
| c_parser_iasm_maybe_prefix (c_parser *parser, tree id) |
| { |
| tree prefix_list = NULL_TREE; |
| |
| while (iasm_is_prefix (id)) |
| { |
| if (c_parser_iasm_bol (parser)) |
| break; |
| prefix_list = tree_cons (NULL_TREE, id, prefix_list); |
| id = c_parser_iasm_identifier (parser); |
| } |
| |
| if (prefix_list) |
| id = tree_cons (NULL_TREE, id, prefix_list); |
| return id; |
| } |
| |
| static tree |
| c_parser_iasm_operand (c_parser *parser) |
| { |
| tree operand; |
| |
| /* Jump into the usual operand precedence stack. */ |
| operand = c_parser_binary_expression (parser, false).value; |
| |
| /* (in 4.2 bd) */ |
| while (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) |
| { |
| struct c_expr op2; |
| c_parser_consume_token (parser); |
| op2 = c_parser_expr_no_commas (parser, NULL); |
| c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, |
| "expected %<)%>"); |
| operand = iasm_build_register_offset (operand, op2.value); |
| } |
| |
| return operand; |
| } |
| |
| /* Eat tokens until we get back to something we recognize. */ |
| |
| static void |
| c_parser_iasm_skip_to_next_asm (c_parser *parser) |
| { |
| c_token *token = c_parser_peek_token (parser); |
| do |
| { |
| if (c_parser_iasm_bol (parser) |
| || token->type == CPP_SEMICOLON |
| || token->type == CPP_CLOSE_BRACE |
| || token->type == CPP_EOF |
| || token->keyword == RID_ASM) |
| return; |
| c_parser_consume_token (parser); |
| } |
| while (1); |
| } |
| |
| /* (in 4.2 az) */ |
| static tree |
| c_parser_iasm_operands (c_parser *parser) |
| { |
| tree operands = NULL_TREE, operand; |
| |
| while (true) |
| { |
| /* If we're looking at the end of the line, then we've run out of operands. */ |
| if (c_parser_iasm_bol (parser) |
| || c_parser_next_token_is (parser, CPP_SEMICOLON) |
| || c_parser_next_token_is (parser, CPP_CLOSE_BRACE) |
| || c_parser_next_token_is (parser, CPP_EOF) |
| || c_parser_next_token_is_keyword (parser, RID_ASM)) |
| break; |
| |
| operand = c_parser_iasm_operand (parser); |
| |
| if (operand && operand != error_mark_node) |
| { |
| operands = chainon (operands, build_tree_list (NULL_TREE, operand)); |
| if (c_parser_next_token_is (parser, CPP_COMMA)) |
| c_parser_consume_token (parser); |
| } |
| else |
| { |
| c_parser_iasm_skip_to_next_asm (parser); |
| return NULL_TREE; |
| } |
| } |
| |
| return operands; |
| } |
| |
| /* (in 4.2 ar) */ |
| /* A single statement consists of one or more labels (identified by a |
| leading '@' and/or a trailing ':'), optionally followed by opcode |
| and operands. */ |
| |
| static void |
| c_parser_iasm_statement (c_parser* parser) |
| { |
| tree aname, anothername, operands; |
| |
| /* (in 4.2 ax) */ |
| int iasm_lineno = input_line; |
| |
| /* Keep sucking labels from the front of the statement until a |
| non-label is seen. */ |
| while (true) |
| { |
| if (c_parser_next_token_is (parser, CPP_SEMICOLON) |
| || c_parser_next_token_is (parser, CPP_CLOSE_BRACE) |
| || c_parser_next_token_is (parser, CPP_EOF)) |
| break; |
| |
| if (c_parser_next_token_is (parser, CPP_PRAGMA)) |
| { |
| c_parser_pragma (parser, pragma_compound); |
| } |
| else if (c_parser_next_token_is (parser, CPP_ATSIGN)) |
| { |
| c_parser_consume_token (parser); |
| aname = c_parser_iasm_identifier_or_number (parser); |
| /* Optional ':' after a label. */ |
| if (c_parser_next_token_is (parser, CPP_COLON)) |
| c_parser_consume_token (parser); |
| iasm_label (aname, true); |
| } |
| else |
| { |
| /* (in 4.2 an) */ |
| aname = c_parser_iasm_identifier (parser); |
| if (c_parser_next_token_is (parser, CPP_COLON)) |
| { |
| c_parser_consume_token (parser); |
| iasm_label (aname, false); |
| } |
| else |
| { |
| enum rid scspec = RID_EXTERN; |
| |
| if (strcmp (IDENTIFIER_POINTER (aname), "entry") == 0) |
| { |
| if (c_parser_next_token_is_keyword (parser, RID_STATIC) |
| || c_parser_next_token_is_keyword (parser, RID_EXTERN)) |
| { |
| scspec = c_parser_peek_token (parser)->keyword; |
| c_parser_consume_token (parser); |
| } |
| anothername = c_parser_iasm_operand (parser); |
| iasm_entry (scspec, anothername); |
| } |
| else |
| { |
| aname = c_parser_iasm_maybe_prefix (parser, aname); |
| iasm_in_operands = true; |
| operands = c_parser_iasm_operands (parser); |
| iasm_stmt (aname, operands, iasm_lineno); |
| } |
| if (c_parser_iasm_bol (parser)) |
| return; |
| break; |
| } |
| } |
| |
| if (c_parser_iasm_bol (parser)) |
| return; |
| } |
| c_parser_iasm_maybe_skip_comments (parser); |
| } |
| /* APPLE LOCAL end CW asm blocks */ |
| /* APPLE LOCAL begin radar 5732232 - blocks (C++ ce) */ |
| static tree block_copy_assign_decl; |
| static tree block_destroy_decl; |
| |
| void |
| gen_block_byref_release_exp (tree var_decl) |
| { |
| tree cleanup = build_block_byref_release_exp (var_decl); |
| if (cleanup) |
| add_stmt (cleanup); |
| } |
| |
| bool building_block_byref_decl = false; |
| static bool |
| c_parser_block_byref_declarations (c_parser* parser) |
| { |
| if (!in_imm_block ()) |
| return false; |
| warning (0, "| x | has been deprecated in blocks"); |
| do { |
| struct c_expr byref_decl_expr; |
| c_parser_consume_token (parser); /* consume '|' or ',' */ |
| if (!c_parser_next_token_is (parser, CPP_NAME)) |
| { |
| error ("expected identifier in block by-reference variable list"); |
| return false; |
| } |
| building_block_byref_decl = true; |
| byref_decl_expr = c_parser_cast_expression (parser, NULL); |
| building_block_byref_decl = false; |
| if (byref_decl_expr.value != error_mark_node && |
| !(TREE_CODE (byref_decl_expr.value) == VAR_DECL && |
| (BLOCK_DECL_BYREF (byref_decl_expr.value) || |
| in_block_global_byref_list (byref_decl_expr.value)))) |
| error ( |
| "only a visible variable may be used in a block byref declaration"); |
| } while (c_parser_next_token_is (parser, CPP_COMMA)); |
| |
| if (!c_parser_next_token_is (parser, CPP_OR)) |
| { |
| error ("expected identifier or '|' at end of block by-reference variable list"); |
| return false; |
| } |
| c_parser_consume_token (parser); /* consume '|' */ |
| return true; |
| } |
| |
| /** build_block_struct_type - |
| struct block_1 { |
| struct invok_impl impl; |
| void *CopyFuncPtr; // only if BLOCK_HAS_COPY_DISPOSE is set |
| void *DestroyFuncPtr; // only if BLOCK_HAS_COPY_DISPOSE is set |
| int x; // ref variable list ... |
| int *y; // byref variable list |
| }; |
| */ |
| static tree |
| build_block_struct_type (struct block_sema_info * block_impl) |
| { |
| tree field_decl_chain, field_decl, chain; |
| char buffer[32]; |
| static int unique_count; |
| tree block_struct_type; |
| /* build struct invok_impl */ |
| if (!invoke_impl_ptr_type) |
| build_block_internal_types (); |
| |
| /* Check and see if this block is required to have a Copy/Dispose |
| helper function. If yes, set BlockHasCopyDispose to TRUE. */ |
| for (chain = block_impl->block_ref_decl_list; chain; |
| chain = TREE_CHAIN (chain)) |
| if (block_requires_copying (TREE_VALUE (chain))) |
| { |
| block_impl->BlockHasCopyDispose = TRUE; |
| break; |
| } |
| |
| /* Further check to see that we have __byref variables which require |
| Copy/Dispose helpers. */ |
| for (chain = block_impl->block_byref_decl_list; chain; |
| chain = TREE_CHAIN (chain)) |
| if (COPYABLE_BYREF_LOCAL_VAR (TREE_VALUE (chain))) |
| { |
| block_impl->BlockHasCopyDispose = TRUE; |
| break; |
| } |
| |
| sprintf(buffer, "__block_%d", ++unique_count); |
| push_to_top_level (); |
| block_struct_type = start_struct (RECORD_TYPE, get_identifier (buffer)); |
| /* struct invok_impl impl; */ |
| field_decl = build_decl (FIELD_DECL, get_identifier ("impl"), |
| TREE_TYPE (invoke_impl_ptr_type)); |
| field_decl_chain = field_decl; |
| if (block_impl->BlockHasCopyDispose) |
| { |
| /* void *CopyFuncPtr; */ |
| field_decl = build_decl (FIELD_DECL, get_identifier ("CopyFuncPtr"), |
| ptr_type_node); |
| chainon (field_decl_chain, field_decl); |
| /* void *DestroyFuncPtr; */ |
| field_decl = build_decl (FIELD_DECL, get_identifier ("DestroyFuncPtr"), |
| ptr_type_node); |
| chainon (field_decl_chain, field_decl); |
| /* If inner block of a nested block has BlockHasCopyDispose, so |
| does its outer block. */ |
| if (block_impl->prev_block_info) |
| block_impl->prev_block_info->BlockHasCopyDispose = TRUE; |
| } |
| |
| /* int x; // ref variable list ... */ |
| for (chain = block_impl->block_ref_decl_list; chain; chain = TREE_CHAIN (chain)) |
| { |
| tree p = TREE_VALUE (chain); |
| /* Note! const-ness of copied in variable must not be carried over to the |
| type of the synthesized struct field. It prevents to assign to this |
| field when copy constructor is synthesized. */ |
| field_decl = build_decl (FIELD_DECL, DECL_NAME (p), |
| c_build_qualified_type (TREE_TYPE (p), |
| TYPE_UNQUALIFIED)); |
| chainon (field_decl_chain, field_decl); |
| } |
| |
| /* int *y; // byref variable list */ |
| for (chain = block_impl->block_byref_decl_list; chain; chain = TREE_CHAIN (chain)) |
| { |
| tree p = TREE_VALUE (chain); |
| field_decl = build_decl (FIELD_DECL, DECL_NAME (p), |
| TREE_TYPE (p)); |
| chainon (field_decl_chain, field_decl); |
| } |
| pop_from_top_level (); |
| finish_struct (block_struct_type, field_decl_chain, NULL_TREE); |
| return block_struct_type; |
| } |
| |
| /** |
| build_block_struct_initlist - builds the initializer list: |
| { &_NSConcreteStackBlock or &_NSConcreteGlobalBlock // isa, |
| BLOCK_HAS_COPY_DISPOSE | BLOCK_IS_GLOBAL // flags, |
| sizeof(struct block_1), |
| helper_1 }, |
| copy_helper_block_1, // only if block BLOCK_HAS_COPY_DISPOSE |
| destroy_helper_block_1, // only if block BLOCK_HAS_COPY_DISPOSE |
| x, |
| &y |
| } |
| */ |
| static tree |
| build_block_struct_initlist (tree block_struct_type, |
| struct block_sema_info *block_impl) |
| { |
| tree initlist; |
| int size; |
| tree helper_addr, chain, fields; |
| unsigned flags = 0; |
| static tree NSConcreteStackBlock_decl = NULL_TREE; |
| static tree NSConcreteGlobalBlock_decl = NULL_TREE; |
| |
| if (block_impl->BlockHasCopyDispose) |
| /* Note! setting of this flag merely indicates to the runtime that |
| we have destroy_helper_block/copy_helper_block helper |
| routines. */ |
| flags |= BLOCK_HAS_COPY_DISPOSE; |
| |
| fields = TYPE_FIELDS (TREE_TYPE (invoke_impl_ptr_type)); |
| |
| if (!current_function_decl) |
| { |
| /* This is a global block. */ |
| /* Find an existing declaration for _NSConcreteGlobalBlock or declare |
| extern void *_NSConcreteGlobalBlock; */ |
| if (NSConcreteGlobalBlock_decl == NULL_TREE) |
| { |
| tree name_id = get_identifier("_NSConcreteGlobalBlock"); |
| NSConcreteGlobalBlock_decl = lookup_name (name_id); |
| if (!NSConcreteGlobalBlock_decl) |
| { |
| NSConcreteGlobalBlock_decl = build_decl (VAR_DECL, name_id, ptr_type_node); |
| DECL_EXTERNAL (NSConcreteGlobalBlock_decl) = 1; |
| TREE_PUBLIC (NSConcreteGlobalBlock_decl) = 1; |
| pushdecl_top_level (NSConcreteGlobalBlock_decl); |
| rest_of_decl_compilation (NSConcreteGlobalBlock_decl, 0, 0); |
| } |
| } |
| initlist = build_tree_list (fields, |
| build_fold_addr_expr (NSConcreteGlobalBlock_decl)); |
| flags |= BLOCK_IS_GLOBAL; |
| } |
| else |
| { |
| /* Find an existing declaration for _NSConcreteStackBlock or declare |
| extern void *_NSConcreteStackBlock; */ |
| if (NSConcreteStackBlock_decl == NULL_TREE) |
| { |
| tree name_id = get_identifier("_NSConcreteStackBlock"); |
| NSConcreteStackBlock_decl = lookup_name (name_id); |
| if (!NSConcreteStackBlock_decl) |
| { |
| NSConcreteStackBlock_decl = build_decl (VAR_DECL, name_id, ptr_type_node); |
| DECL_EXTERNAL (NSConcreteStackBlock_decl) = 1; |
| TREE_PUBLIC (NSConcreteStackBlock_decl) = 1; |
| pushdecl_top_level (NSConcreteStackBlock_decl); |
| rest_of_decl_compilation (NSConcreteStackBlock_decl, 0, 0); |
| } |
| } |
| initlist = build_tree_list (fields, |
| build_fold_addr_expr (NSConcreteStackBlock_decl)); |
| } |
| fields = TREE_CHAIN (fields); |
| |
| initlist = tree_cons (fields, |
| build_int_cst (unsigned_type_node, flags), |
| initlist); |
| fields = TREE_CHAIN (fields); |
| size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (block_struct_type)); |
| initlist = tree_cons (fields, |
| build_int_cst (unsigned_type_node, size), |
| initlist); |
| fields = TREE_CHAIN (fields); |
| helper_addr = build_fold_addr_expr (block_impl->helper_func_decl); |
| helper_addr = convert (ptr_type_node, helper_addr); |
| initlist = tree_cons (fields, helper_addr, initlist); |
| gcc_assert (invoke_impl_ptr_type); |
| initlist = build_constructor_from_list (TREE_TYPE (invoke_impl_ptr_type), |
| nreverse (initlist)); |
| fields = TYPE_FIELDS (block_struct_type); |
| initlist = build_tree_list (fields, initlist); |
| if (block_impl->BlockHasCopyDispose) |
| { |
| fields = TREE_CHAIN (fields); |
| helper_addr = build_fold_addr_expr (block_impl->copy_helper_func_decl); |
| helper_addr = convert (ptr_type_node, helper_addr); |
| initlist = tree_cons (fields, helper_addr, initlist); |
| fields = TREE_CHAIN (fields); |
| helper_addr = build_fold_addr_expr (block_impl->destroy_helper_func_decl); |
| helper_addr = convert (ptr_type_node, helper_addr); |
| initlist = tree_cons (fields, helper_addr, initlist); |
| } |
| for (chain = block_impl->block_original_ref_decl_list; chain; |
| chain = TREE_CHAIN (chain)) |
| { |
| tree y = TREE_VALUE (chain); |
| TREE_USED (y) = 1; |
| fields = TREE_CHAIN (fields); |
| initlist = tree_cons (fields, copy_in_object (y), initlist); |
| } |
| for (chain = block_impl->block_original_byref_decl_list; chain; |
| chain = TREE_CHAIN (chain)) |
| { |
| tree y = TREE_VALUE (chain); |
| TREE_USED (y) = 1; |
| fields = TREE_CHAIN (fields); |
| y = build_fold_addr_expr (y); |
| initlist = tree_cons (fields, y, initlist); |
| } |
| return initlist; |
| } |
| |
| /** |
| build_block_literal_tmp - This routine: |
| |
| 1) builds block type: |
| struct block_1 { |
| struct invok_impl impl; |
| void *CopyFuncPtr; // only if block BLOCK_HAS_COPY_DISPOSE |
| void *DestroyFuncPtr; // only if block BLOCK_HAS_COPY_DISPOSE |
| int x; // ref variable list ... |
| int *y; // byref variable list |
| }; |
| |
| 2) build function prototype: |
| double helper_1(struct block_1 *ii, int z); |
| |
| 3) build the temporary initialization: |
| struct block_1 I = { |
| { &_NSConcreteStackBlock or &_NSConcreteGlobalBlock // isa, |
| BLOCK_HAS_COPY_DISPOSE | BLOCK_IS_GLOBAL // flags, |
| sizeof(struct block_1), |
| helper_1 }, |
| copy_helper_block_1, // only if block BLOCK_HAS_COPY_DISPOSE |
| destroy_helper_block_1, // only if block BLOCK_HAS_COPY_DISPOSE |
| x, |
| &y |
| }; |
| |
| It return the temporary. |
| */ |
| |
| static tree |
| build_block_literal_tmp (const char *name, |
| struct block_sema_info * block_impl) |
| { |
| extern tree create_tmp_var_raw (tree, const char *); |
| tree block_holder_tmp_decl; |
| tree constructor, initlist; |
| tree exp, bind; |
| tree block_struct_type = TREE_TYPE (block_impl->block_arg_ptr_type); |
| |
| |
| block_holder_tmp_decl = create_tmp_var_raw (block_struct_type, name); |
| /* Context will not be known until when the literal is synthesized. |
| This is more so in the case of nested block literal blocks. */ |
| DECL_CONTEXT (block_holder_tmp_decl) = current_function_decl; |
| DECL_ARTIFICIAL (block_holder_tmp_decl) = 1; |
| |
| initlist = build_block_struct_initlist (block_struct_type, |
| block_impl); |
| initlist = nreverse (initlist); |
| constructor = build_constructor_from_list (block_struct_type, |
| initlist); |
| TREE_CONSTANT (constructor) = 1; |
| TREE_STATIC (constructor) = 1; |
| TREE_READONLY (constructor) = 1; |
| DECL_INITIAL (block_holder_tmp_decl) = constructor; |
| exp = build_stmt (DECL_EXPR, block_holder_tmp_decl); |
| bind = build3 (BIND_EXPR, void_type_node, block_holder_tmp_decl, exp, NULL); |
| TREE_SIDE_EFFECTS (bind) = 1; |
| add_stmt (bind); |
| /* Temporary representing a global block is made global static. */ |
| if (global_bindings_p ()) { |
| TREE_PUBLIC (block_holder_tmp_decl) = 0; |
| TREE_STATIC (block_holder_tmp_decl) = 1; |
| finish_decl (block_holder_tmp_decl, constructor, NULL_TREE); |
| } |
| return block_holder_tmp_decl; |
| } |
| |
| static tree |
| clean_and_exit (tree block) |
| { |
| pop_function_context (); |
| free (finish_block (block)); |
| return error_mark_node; |
| } |
| |
| /** synth_copy_helper_block_func - This function synthesizes |
| void copy_helper_block (struct block* _dest, struct block *_src) function. |
| */ |
| |
| static void |
| synth_copy_helper_block_func (struct block_sema_info * block_impl) |
| { |
| tree stmt, chain, fnbody; |
| tree dst_arg, src_arg; |
| struct c_arg_info * arg_info; |
| /* Set up: (struct block* _dest, struct block *_src) parameters. */ |
| dst_arg = build_decl (PARM_DECL, get_identifier ("_dst"), |
| block_impl->block_arg_ptr_type); |
| DECL_CONTEXT (dst_arg) = cur_block->copy_helper_func_decl; |
| TREE_USED (dst_arg) = 1; |
| DECL_ARG_TYPE (dst_arg) = block_impl->block_arg_ptr_type; |
| src_arg = build_decl (PARM_DECL, get_identifier ("_src"), |
| block_impl->block_arg_ptr_type); |
| DECL_CONTEXT (dst_arg) = cur_block->copy_helper_func_decl; |
| TREE_USED (src_arg) = 1; |
| DECL_ARG_TYPE (src_arg) = block_impl->block_arg_ptr_type; |
| arg_info = xcalloc (1, sizeof (struct c_arg_info)); |
| TREE_CHAIN (dst_arg) = src_arg; |
| arg_info->parms = dst_arg; |
| arg_info->types = tree_cons (NULL_TREE, block_impl->block_arg_ptr_type, |
| tree_cons (NULL_TREE, |
| block_impl->block_arg_ptr_type, |
| NULL_TREE)); |
| /* function header synthesis. */ |
| push_function_context (); |
| start_block_helper_function (cur_block->copy_helper_func_decl); |
| store_parm_decls_from (arg_info); |
| |
| /* Body of the function. */ |
| stmt = c_begin_compound_stmt (true); |
| for (chain = block_impl->block_ref_decl_list; chain; |
| chain = TREE_CHAIN (chain)) |
| if (block_requires_copying (TREE_VALUE (chain))) |
| { |
| tree p = TREE_VALUE (chain); |
| tree dst_block_component, src_block_component; |
| dst_block_component = build_component_ref (build_indirect_ref (dst_arg, "->"), |
| DECL_NAME (p)); |
| src_block_component = build_component_ref (build_indirect_ref (src_arg, "->"), |
| DECL_NAME (p)); |
| |
| if (TREE_CODE (TREE_TYPE (p)) == BLOCK_POINTER_TYPE) |
| { |
| tree func_params, call_exp; |
| /* _Block_copy_assign(&_dest->myImportedBlock, _src->myImportedClosure) */ |
| /* Build a: void _Block_copy_assign (void *, void *) if not done |
| already. */ |
| if (!block_copy_assign_decl) |
| { |
| tree func_type = |
| build_function_type (void_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, void_list_node))); |
| |
| block_copy_assign_decl = builtin_function ("_Block_copy_assign", func_type, |
| 0, NOT_BUILT_IN, 0, NULL_TREE); |
| TREE_NOTHROW (block_copy_assign_decl) = 0; |
| } |
| dst_block_component = build_fold_addr_expr (dst_block_component); |
| func_params = tree_cons (NULL_TREE, dst_block_component, |
| tree_cons (NULL_TREE, src_block_component, |
| NULL_TREE)); |
| call_exp = build_function_call (block_copy_assign_decl, func_params); |
| add_stmt (call_exp); |
| } |
| else |
| { |
| /* _dest-> imported_object_x = [_src->imported_object_x retain] */ |
| tree rhs, store; |
| /* [_src->imported_object_x retain] */ |
| rhs = retain_block_component (src_block_component); |
| store = build_modify_expr (dst_block_component, NOP_EXPR, rhs); |
| add_stmt (store); |
| } |
| } |
| |
| /* For each __byref declared variable used in |...| Must generate call to: |
| _Block_byref_assign_copy(&_dest->myImportedBlock, _src->myImportedBlock) |
| */ |
| for (chain = block_impl->block_byref_decl_list; chain; |
| chain = TREE_CHAIN (chain)) |
| if (COPYABLE_BYREF_LOCAL_VAR (TREE_VALUE (chain))) |
| { |
| tree func_params, call_exp; |
| tree p = TREE_VALUE (chain); |
| tree dst_block_component, src_block_component; |
| dst_block_component = build_component_ref (build_indirect_ref (dst_arg, "->"), |
| DECL_NAME (p)); |
| src_block_component = build_component_ref (build_indirect_ref (src_arg, "->"), |
| DECL_NAME (p)); |
| |
| /* _Block_byref_assign_copy(&_dest->myImportedClosure, _src->myImportedClosure) */ |
| dst_block_component = build_fold_addr_expr (dst_block_component); |
| func_params = tree_cons (NULL_TREE, dst_block_component, |
| tree_cons (NULL_TREE, src_block_component, |
| NULL_TREE)); |
| call_exp = build_function_call (build_block_byref_assign_copy_decl (), func_params); |
| add_stmt (call_exp); |
| } |
| |
| fnbody = c_end_compound_stmt (stmt, true); |
| add_stmt (fnbody); |
| finish_function (); |
| pop_function_context (); |
| free (arg_info); |
| } |
| |
| static void |
| synth_destroy_helper_block_func (struct block_sema_info * block_impl) |
| { |
| tree stmt, chain, fnbody; |
| tree src_arg; |
| struct c_arg_info * arg_info; |
| /* Set up: (struct block *_src) parameter. */ |
| src_arg = build_decl (PARM_DECL, get_identifier ("_src"), |
| block_impl->block_arg_ptr_type); |
| TREE_USED (src_arg) = 1; |
| DECL_ARG_TYPE (src_arg) = block_impl->block_arg_ptr_type; |
| arg_info = xcalloc (1, sizeof (struct c_arg_info)); |
| arg_info->parms = src_arg; |
| arg_info->types = tree_cons (NULL_TREE, block_impl->block_arg_ptr_type, |
| NULL_TREE); |
| |
| /* function header synthesis. */ |
| push_function_context (); |
| start_block_helper_function (cur_block->destroy_helper_func_decl); |
| store_parm_decls_from (arg_info); |
| |
| /* Body of the function. */ |
| stmt = c_begin_compound_stmt (true); |
| for (chain = block_impl->block_ref_decl_list; chain; |
| chain = TREE_CHAIN (chain)) |
| if (block_requires_copying (TREE_VALUE (chain))) |
| { |
| tree p = TREE_VALUE (chain); |
| tree src_block_component; |
| src_block_component = build_component_ref (build_indirect_ref (src_arg, "->"), |
| DECL_NAME (p)); |
| |
| if (TREE_CODE (TREE_TYPE (p)) == BLOCK_POINTER_TYPE) |
| { |
| tree func_params, call_exp; |
| /* _Block_destroy(_src->myImportedClosure); */ |
| /* _Block_destroy (void *); */ |
| /* Build a: void _Block_destroy (void *) if not done already. */ |
| if (!block_destroy_decl && |
| !(block_destroy_decl = lookup_name (get_identifier ("_Block_destroy")))) |
| { |
| tree func_type = |
| build_function_type (void_type_node, |
| tree_cons (NULL_TREE, ptr_type_node, void_list_node)); |
| |
| block_destroy_decl = builtin_function ("_Block_destroy", func_type, |
| 0, NOT_BUILT_IN, 0, NULL_TREE); |
| TREE_NOTHROW (block_destroy_decl) = 0; |
| } |
| func_params = tree_cons (NULL_TREE, src_block_component, NULL_TREE); |
| call_exp = build_function_call (block_destroy_decl, func_params); |
| add_stmt (call_exp); |
| } |
| else |
| { |
| tree rel_exp; |
| /* [_src->imported_object_0 release]; */ |
| rel_exp = release_block_component (src_block_component); |
| add_stmt (rel_exp); |
| } |
| } |
| |
| /* For each __byref declared variable used in |...| Must generate call to: |
| _Block_byref_release(_src->myImportedClosure) |
| */ |
| for (chain = block_impl->block_byref_decl_list; chain; |
| chain = TREE_CHAIN (chain)) |
| if (COPYABLE_BYREF_LOCAL_VAR (TREE_VALUE (chain))) |
| { |
| tree func_params, call_exp; |
| tree p = TREE_VALUE (chain); |
| tree src_block_component; |
| |
| src_block_component = build_component_ref (build_indirect_ref (src_arg, "->"), |
| DECL_NAME (p)); |
| /* _Block_byref_release(_src->myImportedClosure) */ |
| /* Build a: void _Block_byref_release (void *) if not done |
| already. */ |
| func_params = tree_cons (NULL_TREE, src_block_component, NULL_TREE); |
| call_exp = build_function_call (build_block_byref_release_decl (), func_params); |
| add_stmt (call_exp); |
| } |
| |
| fnbody = c_end_compound_stmt (stmt, true); |
| add_stmt (fnbody); |
| finish_function (); |
| pop_function_context (); |
| free (arg_info); |
| } |
| |
| /** c_parser_block_literal_expr - Main routine to process a block literal |
| with the syntax of ^arg-list[OPT] block or ^()expression. It synthesizes |
| the helper function for later generation and builds the necessary data to |
| represent the block literal where it is declared. |
| */ |
| static tree |
| c_parser_block_literal_expr (c_parser* parser) |
| { |
| char name [32]; |
| static int global_unique_count; |
| int unique_count = ++global_unique_count; |
| tree block_helper_function_decl; |
| tree expr, body, type, arglist, ftype; |
| tree self_arg, stmt; |
| struct c_arg_info *args = NULL; |
| tree arg_type = void_list_node; |
| struct block_sema_info *block_impl; |
| tree tmp; |
| bool open_paren_seen = false; |
| tree restype; |
| tree fnbody, typelist; |
| tree helper_function_type; |
| tree block; |
| /* APPLE LOCAL radar 6185344 */ |
| tree declared_block_return_type = NULL_TREE; |
| /* APPLE LOCAL radar 6237713 */ |
| tree attributes = NULL_TREE; |
| |
| c_parser_consume_token (parser); /* eat '^' */ |
| |
| /* APPLE LOCAL begin radar 6237713 */ |
| if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) |
| attributes = c_parser_attributes (parser); |
| /* APPLE LOCAL end radar 6237713 */ |
| |
| /* APPLE LOCAL begin radar 6185344 */ |
| /* Parse user declared return type. */ |
| if (!c_parser_next_token_is (parser, CPP_OPEN_PAREN) && |
| !c_parser_next_token_is (parser, CPP_OPEN_BRACE)) |
| { |
| struct c_type_name *type; |
| /* APPLE LOCAL begin radar 6237713 */ |
| if (attributes) |
| { |
| warning (0, "attribute before block type is ignored"); |
| attributes = NULL_TREE; |
| } |
| /* APPLE LOCAL end radar 6237713 */ |
| parsing_block_return_type = 1; |
| type = c_parser_type_name (parser); |
| parsing_block_return_type = 0; |
| if (type) { |
| declared_block_return_type = groktypename (type); |
| } |
| } |
| /* APPLE LOCAL end radar 6185344 */ |
| |
| /* Parse the optional argument list */ |
| if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) |
| { |
| c_parser_consume_token (parser); |
| /* Open the scope to collect parameter decls */ |
| push_scope (); |
| args = c_parser_parms_declarator (parser, true, NULL_TREE); |
| /* Check for args as it might be NULL due to error. */ |
| if (args) { |
| arglist = args->parms; |
| arg_type = args->types; |
| } |
| else |
| { |
| pop_scope (); |
| return error_mark_node; |
| } |
| open_paren_seen = true; |
| pop_scope (); |
| } |
| else |
| arglist = build_tree_list (NULL_TREE, void_type_node); |
| |
| block = begin_block (); |
| |
| cur_block->arg_info = NULL; |
| if (declared_block_return_type) |
| { |
| cur_block->return_type = TYPE_MAIN_VARIANT (declared_block_return_type); |
| cur_block->block_has_return_type = true; |
| } |
| else |
| cur_block->return_type = NULL_TREE; |
| |
| if (args) |
| { |
| tree list = NULL_TREE; |
| cur_block->arg_info = args; |
| if (arg_type) |
| { |
| cur_block->hasPrototype = true; |
| /* This is the only way in gcc to know if argument list ends with ... */ |
| for (list = arg_type; TREE_CHAIN (list); list = TREE_CHAIN (list)) |
| ; |
| cur_block->isVariadic = (list != void_list_node); |
| } |
| else |
| { |
| /* K&R syle () argument list. */ |
| cur_block->hasPrototype = false; |
| cur_block->isVariadic = true; |
| } |
| } |
| else |
| { |
| cur_block->hasPrototype = false; |
| cur_block->isVariadic = false; |
| cur_block->arg_info = xcalloc (1, sizeof (struct c_arg_info)); |
| } |
| |
| /* Must also build hidden parameter _self added to the helper |
| function, even though we do not know its type yet. */ |
| self_arg = build_decl (PARM_DECL, get_identifier ("_self"), |
| ptr_type_node); |
| TREE_USED (self_arg) = 1; /* Prevent unused parameter '_self' warning. */ |
| TREE_CHAIN (self_arg) = cur_block->arg_info->parms; |
| cur_block->arg_info->types = tree_cons (NULL_TREE, ptr_type_node, arg_type); |
| cur_block->arg_info->parms = self_arg; |
| |
| /* APPLE LOCAL begin radar 6185344 */ |
| /* Build the declaration of the helper function (if we do not know its result |
| type yet, assume it is 'void'. If user provided it, use it). |
| Treat this as a nested function and use nested function infrastructure for |
| its generation. */ |
| |
| ftype = build_function_type ((!cur_block->block_has_return_type |
| ? void_type_node : cur_block->return_type), |
| cur_block->arg_info->types); |
| /* APPLE LOCAL end radar 6185344 */ |
| /* APPLE LOCAL radar 6160536 */ |
| block_helper_function_decl = build_helper_func_decl (build_block_helper_name (unique_count), |
| ftype); |
| DECL_CONTEXT (block_helper_function_decl) = current_function_decl; |
| cur_block->helper_func_decl = block_helper_function_decl; |
| |
| push_function_context (); |
| start_block_helper_function (cur_block->helper_func_decl); |
| /* Set block's scope to the scope of the helper function's main body. |
| This is primarily used when nested blocks are declared. */ |
| /* FIXME: Name of objc_get_current_scope needs to get changed. */ |
| cur_block->the_scope = (struct c_scope*)objc_get_current_scope (); |
| |
| /* Enter parameter list to the scope of the helper function. */ |
| store_parm_decls_from (cur_block->arg_info); |
| |
| /* APPLE LOCAL begin radar 6237713 */ |
| if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) |
| attributes = c_parser_attributes (parser); |
| decl_attributes (&cur_block->helper_func_decl, attributes, 0); |
| /* APPLE LOCAL end radar 6237713 */ |
| |
| /* Start parsing body or expression part of the block literal. */ |
| if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { |
| tree save_c_break_label = c_break_label; |
| tree save_c_cont_label = c_cont_label; |
| /* Indicate no valid break/continue context by setting these variables |
| to some non-null, non-label value. We'll notice and emit the proper |
| error message in c_finish_bc_stmt. */ |
| c_break_label = c_cont_label = size_zero_node; |
| c_parser_consume_token (parser); /* Consure '{'. */ |
| stmt = c_begin_compound_stmt (true); |
| c_parser_compound_statement_nostart (parser); |
| c_cont_label = save_c_cont_label; |
| c_break_label = save_c_break_label; |
| } |
| else |
| { |
| struct c_expr expr; |
| stmt = c_begin_compound_stmt (true); |
| error ("blocks require { }"); |
| expr = c_parser_cast_expression (parser, NULL); |
| body = expr.value; |
| if (body == error_mark_node) |
| return clean_and_exit (block); |
| |
| if (cur_block->return_type) |
| { |
| error ("return not allowed in block expression literal"); |
| return clean_and_exit (block); |
| } |
| else if (!open_paren_seen) |
| { |
| error ("argument list is required for block expression literals"); |
| return clean_and_exit (block); |
| } |
| else |
| { |
| tree restype = TYPE_MAIN_VARIANT (TREE_TYPE (body)); |
| |
| add_stmt (body); |
| TREE_TYPE (current_function_decl) |
| = build_function_type (restype, |
| TYPE_ARG_TYPES (TREE_TYPE (current_function_decl))); |
| TREE_TYPE (DECL_RESULT (current_function_decl)) = restype; |
| relayout_decl (DECL_RESULT (current_function_decl)); |
| cur_block->return_type = restype; |
| } |
| } |
| |
| cur_block->block_arg_ptr_type = |
| build_pointer_type (build_block_struct_type (cur_block)); |
| |
| restype = !cur_block->return_type ? void_type_node |
| : cur_block->return_type; |
| if (restype == error_mark_node) |
| return clean_and_exit (block); |
| |
| /* Now that we know type of the hidden _self argument, fix its type. */ |
| TREE_TYPE (self_arg) = cur_block->block_arg_ptr_type; |
| DECL_ARG_TYPE (self_arg) = cur_block->block_arg_ptr_type; |
| |
| /* The DECL_RESULT should already have the correct type by now. */ |
| gcc_assert (TREE_TYPE (DECL_RESULT (current_function_decl)) |
| == restype); |
| |
| cur_block->block_body = stmt; |
| block_build_prologue (cur_block); |
| |
| fnbody = c_end_compound_stmt (stmt, true); |
| add_stmt (fnbody); |
| |
| /* We are done parsing of the block body. Return type of block is now known. |
| We also know all we need to know about the helper function. So, fix its |
| type here. */ |
| /* We moved this here because for global blocks, helper function body is |
| not nested and is gimplified in call to finish_function() and return type |
| of the function must be correct. */ |
| ftype = build_function_type (restype, arg_type); |
| /* Declare helper function; as in: |
| double helper_1(struct block_1 *ii, int z); */ |
| typelist = TYPE_ARG_TYPES (ftype); |
| /* (struct block_1 *ii, int z, ...) */ |
| typelist = tree_cons (NULL_TREE, cur_block->block_arg_ptr_type, |
| typelist); |
| helper_function_type = build_function_type (TREE_TYPE (ftype), typelist); |
| TREE_TYPE (cur_block->helper_func_decl) = helper_function_type; |
| finish_function (); |
| pop_function_context (); |
| |
| /* Build the declaration for copy_helper_block and destroy_helper_block |
| helper functions for later use. */ |
| |
| if (cur_block->BlockHasCopyDispose) |
| { |
| /* void copy_helper_block (struct block*, struct block *); */ |
| tree s_ftype = build_function_type (void_type_node, |
| tree_cons (NULL_TREE, cur_block->block_arg_ptr_type, |
| tree_cons (NULL_TREE, |
| cur_block->block_arg_ptr_type, |
| void_list_node))); |
| sprintf (name, "__copy_helper_block_%d", unique_count); |
| cur_block->copy_helper_func_decl = |
| build_helper_func_decl (get_identifier (name), s_ftype); |
| synth_copy_helper_block_func (cur_block); |
| |
| /* void destroy_helper_block (struct block*); */ |
| s_ftype = build_function_type (void_type_node, |
| tree_cons (NULL_TREE, |
| cur_block->block_arg_ptr_type, void_list_node)); |
| sprintf (name, "__destroy_helper_block_%d", unique_count); |
| cur_block->destroy_helper_func_decl = |
| build_helper_func_decl (get_identifier (name), s_ftype); |
| synth_destroy_helper_block_func (cur_block); |
| } |
| |
| block_impl = finish_block (block); |
| |
| /* Build unqiue name of the temporary used in code gen. */ |
| sprintf (name, "__block_holder_tmp_%d", unique_count); |
| tmp = build_block_literal_tmp (name, block_impl); |
| tmp = build_fold_addr_expr (tmp); |
| type = build_block_pointer_type (ftype); |
| expr = convert (type, convert (ptr_type_node, tmp)); |
| free (block_impl); |
| return expr; |
| } |
| /* APPLE LOCAL end radar 5732232 - blocks (C++ ce) */ |
| |
| #include "gt-c-parser.h" |