aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/c-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/c-parser.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/c-parser.c10359
1 files changed, 10359 insertions, 0 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/c-parser.c b/gcc-4.2.1-5666.3/gcc/c-parser.c
new file mode 100644
index 000000000..dc4717df4
--- /dev/null
+++ b/gcc-4.2.1-5666.3/gcc/c-parser.c
@@ -0,0 +1,10359 @@
+/* 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) */
+
+/* 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, 0);
+ 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,
+ /* APPLE LOCAL begin blocks 6339747 */
+ /* A block declarator (maybe empty). */
+ C_DTR_BLOCK,
+ /* APPLE LOCAL end blocks 6339747 */
+ /* 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 *);
+/* 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 ;
+
+ APPLE LOCAL begin blocks 6339747
+ block-declarator:
+ pointer
+ pointer[opt] direct-block-declarator
+
+ direct-block-declarator:
+ ( attributes[opt] block-declarator )
+ direct-block-declarator[opt] array-declarator
+ direct-block-declarator[opt]
+ ( parameter-type-list[opt] ) [opt]
+ APPLE LOCAL end blocks 6339747
+
+ 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. */
+
+ /* APPLE LOCAL blocks 6339747 */
+ if ((kind != C_DTR_ABSTRACT && kind != C_DTR_BLOCK)
+ && 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. */
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree attrs;
+ struct c_declarator *inner;
+ c_parser_consume_token (parser);
+ attrs = c_parser_attributes (parser);
+ if (kind != C_DTR_NORMAL
+ && (c_parser_next_token_starts_declspecs (parser)
+ || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
+ {
+ struct c_arg_info *args
+ = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL,
+ attrs);
+ if (args == NULL)
+ return NULL;
+ else
+ {
+ inner
+ = build_function_declarator (args,
+ build_id_declarator (NULL_TREE));
+ return c_parser_direct_declarator_inner (parser, *seen_id,
+ inner);
+ }
+ }
+ /* A parenthesized declarator. */
+ inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
+ if (inner != NULL && attrs != NULL)
+ inner = build_attrs_declarator (attrs, inner);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ c_parser_consume_token (parser);
+ if (inner == NULL)
+ return NULL;
+ else
+ return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+ }
+ else
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return NULL;
+ }
+ }
+ else
+ {
+ if (kind == C_DTR_NORMAL)
+ {
+ c_parser_error (parser, "expected identifier or %<(%>");
+ return NULL;
+ }
+ else
+ return build_id_declarator (NULL_TREE);
+ }
+}
+
+/* Parse part of a direct declarator or direct abstract declarator,
+ given that some (in INNER) has already been parsed; ID_PRESENT is
+ true if an identifier is present, false for an abstract
+ declarator. */
+
+static struct c_declarator *
+c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
+ struct c_declarator *inner)
+{
+ /* Parse a sequence of array declarators and parameter lists. */
+ if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ struct c_declarator *declarator;
+ struct c_declspecs *quals_attrs = build_null_declspecs ();
+ bool static_seen;
+ bool star_seen;
+ tree dimen;
+ c_parser_consume_token (parser);
+ c_parser_declspecs (parser, quals_attrs, false, false, true);
+ static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
+ if (static_seen)
+ c_parser_consume_token (parser);
+ if (static_seen && !quals_attrs->declspecs_seen_p)
+ c_parser_declspecs (parser, quals_attrs, false, false, true);
+ if (!quals_attrs->declspecs_seen_p)
+ quals_attrs = NULL;
+ /* If "static" is present, there must be an array dimension.
+ Otherwise, there may be a dimension, "*", or no
+ dimension. */
+ if (static_seen)
+ {
+ star_seen = false;
+ dimen = c_parser_expr_no_commas (parser, NULL).value;
+ }
+ else
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ {
+ dimen = NULL_TREE;
+ star_seen = false;
+ }
+ else if (c_parser_next_token_is (parser, CPP_MULT))
+ {
+ if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE)
+ {
+ dimen = NULL_TREE;
+ star_seen = true;
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ star_seen = false;
+ dimen = c_parser_expr_no_commas (parser, NULL).value;
+ }
+ }
+ else
+ {
+ star_seen = false;
+ dimen = c_parser_expr_no_commas (parser, NULL).value;
+ }
+ }
+ if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ return NULL;
+ }
+ declarator = build_array_declarator (dimen, quals_attrs, static_seen,
+ star_seen);
+ if (declarator == NULL)
+ return NULL;
+ inner = set_array_declarator_inner (declarator, inner, !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;
+ }
+ 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? */
+ /* APPLE LOCAL begin Radar 6144634 */
+ /* Normal expr stmts, including modify exprs, get the location where
+ the statement began, i.e. 'loc'. Assignments of Blocks to Block
+ pointer variables get the location of the end of the Block definition,
+ i.e. 'input_location', which should already be set by this point. */
+ if (stmt && EXPR_P (stmt))
+ {
+ if (TREE_CODE (stmt) == MODIFY_EXPR
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (stmt, 0))) == BLOCK_POINTER_TYPE)
+ SET_EXPR_LOCATION (stmt, input_location);
+ else
+ SET_EXPR_LOCATION (stmt, loc);
+ }
+ /* APPLE LOCAL end Radar 6144634 */
+}
+
+/* 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);
+ 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));
+}
+
+/* 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 */ \
+ 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));
+ 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 */ \
+ 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));
+}
+
+/* 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 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 ()));
+ 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:
+ 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)
+ {
+ 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);
+ /* APPLE LOCAL begin radar 6302949 */
+ if (c_parser_next_token_is_not (parser, CPP_COMMA)
+ && c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)
+ && c_parser_next_token_is_not (parser, CPP_EOF))
+ warning (0, "property attributes must be separated by a comma");
+ /* APPLE LOCAL end radar 6302949 */
+ 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;
+ /* APPLE LOCAL weak_import on property 6676828 */
+ note_objc_property_decl_context ();
+ prop = c_parser_component_decl (parser);
+ /* APPLE LOCAL weak_import on property 6676828 */
+ note_end_objc_property_decl_context ();
+ /* 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. */
+ if (DECL_RTL_SET_P (v))
+ make_decl_rtl (v);
+ }
+ C_DECL_THREADPRIVATE_P (v) = 1;
+ }
+ }
+
+ c_parser_skip_to_pragma_eol (parser);
+}
+
+
+/* Parse a 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 (aname == error_mark_node)
+ c_parser_consume_token (parser);
+ else 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) */
+
+/* APPLE LOCAL begin radar 6300081 */
+
+/* This function builds a "generic" block struct type, to be passed
+ into the debug information for blocks pointers, to allow gdb to
+ find the actual function pointer for the block. Any time the Blocks
+ structure layout changes, this may also need to change.
+
+ Currently a block pointer is a pointer to a __block_literal_n struct,
+ the third field of which is a pointer to a __block_descriptor struct,
+ whose third field is the function pointer. There are other fields as
+ well, but these are the ones gdb needs to know about to find the
+ function pointer. Therefore a generic block struct currently looks
+ like this:
+
+ struct __block_literal_generic
+ {
+ void * __isa;
+ int __flags;
+ int __reserved;
+ void (*__FuncPtr)(void *);
+ struct __block_descriptor
+ {
+ unsigned long int reserved;
+ unsigned long int Size;
+ } *__descriptor;
+ };
+
+ IF AT ANY TIME THE STRUCTURE OF A __BLOCK_LITERAL_N CHANGES, THIS
+ MUST BE CHANGED ALSO!!
+
+*/
+
+tree
+/* APPLE LOCAL radar 6353006 */
+c_build_generic_block_struct_type (void)
+{
+ tree field_decl_chain;
+ tree field_decl;
+ tree block_struct_type;
+
+ push_to_top_level ();
+ block_struct_type = start_struct (RECORD_TYPE,
+ get_identifier ("__block_literal_generic"));
+
+ field_decl = build_decl (FIELD_DECL, get_identifier ("__isa"), ptr_type_node);
+ field_decl_chain = field_decl;
+
+ field_decl = build_decl (FIELD_DECL, get_identifier ("__flags"),
+ integer_type_node);
+ chainon (field_decl_chain, field_decl);
+
+ field_decl = build_decl (FIELD_DECL, get_identifier ("__reserved"),
+ integer_type_node);
+ chainon (field_decl_chain, field_decl);
+
+ /* void *__FuncPtr; */
+ field_decl = build_decl (FIELD_DECL, get_identifier ("__FuncPtr"), ptr_type_node);
+ chainon (field_decl_chain, field_decl);
+
+ field_decl = build_decl (FIELD_DECL, get_identifier ("__descriptor"),
+ build_block_descriptor_type (false));
+ chainon (field_decl_chain, field_decl);
+
+ TYPE_BLOCK_IMPL_STRUCT (block_struct_type) = 1;
+ finish_struct (block_struct_type, field_decl_chain, NULL_TREE);
+ pop_from_top_level ();
+ return block_struct_type;
+}
+/* APPLE LOCAL end radar 6300081 */
+
+/* APPLE LOCAL begin radar 5847213 - radar 6329245 */
+/** build_block_struct_type -
+ struct __block_literal_n {
+ void *__isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
+ int __flags;
+ int __reserved;
+ void *__FuncPtr;
+ struct __block_descriptor {
+ unsigned long int reserved; // NULL
+ unsigned long int Size; // sizeof(struct __block_literal_n)
+
+ // optional helper functions
+ void *CopyFuncPtr; // When BLOCK_HAS_COPY_DISPOSE
+ void *DestroyFuncPtr; // When BLOCK_HAS_COPY_DISPOSE
+ } *__descriptor;
+
+ // imported variables
+ 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;
+
+ /* 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 __block 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_literal_%d", ++unique_count);
+ push_to_top_level ();
+ block_struct_type = start_struct (RECORD_TYPE, get_identifier (buffer));
+
+ /* void *__isa; */
+ field_decl = build_decl (FIELD_DECL, get_identifier ("__isa"), ptr_type_node);
+ field_decl_chain = field_decl;
+
+ /* int __flags */
+ field_decl = build_decl (FIELD_DECL, get_identifier ("__flags"),
+ integer_type_node);
+ chainon (field_decl_chain, field_decl);
+
+ /* int __reserved */
+ field_decl = build_decl (FIELD_DECL, get_identifier ("__reserved"),
+ integer_type_node);
+ chainon (field_decl_chain, field_decl);
+
+ /* void *__FuncPtr; */
+ field_decl = build_decl (FIELD_DECL, get_identifier ("__FuncPtr"), ptr_type_node);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct __block_descriptor *__descriptor */
+ field_decl = build_decl (FIELD_DECL, get_identifier ("__descriptor"),
+ build_block_descriptor_type (block_impl->BlockHasCopyDispose));
+ chainon (field_decl_chain, field_decl);
+
+ if (block_impl->BlockHasCopyDispose)
+ {
+ /* 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_descriptor_block_decl -
+ This routine builds a static block_descriptior variable of type:
+ struct __block_descriptor; and initializes it to:
+ {0, sizeof(struct literal_block_n),
+ copy_helper_block_1, // only if block BLOCK_HAS_COPY_DISPOSE
+ destroy_helper_block_1, // only if block BLOCK_HAS_COPY_DISPOSE
+ }
+*/
+static tree
+build_descriptor_block_decl (tree block_struct_type, struct block_sema_info *block_impl)
+{
+ extern tree create_tmp_var_raw (tree, const char *);
+ static int desc_unique_count;
+ int size;
+ tree helper_addr, fields;
+ tree decl, constructor, initlist;
+ tree exp, bind;
+ char name [32];
+ tree descriptor_type =
+ TREE_TYPE (build_block_descriptor_type (block_impl->BlockHasCopyDispose));
+
+ sprintf (name, "__block_descriptor_tmp_%d", ++desc_unique_count);
+ decl = create_tmp_var_raw (descriptor_type, name);
+ DECL_CONTEXT (decl) = NULL_TREE;
+ DECL_ARTIFICIAL (decl) = 1;
+
+ /* Initialize "reserved" field to 0 for now. */
+ fields = TYPE_FIELDS (descriptor_type);
+ initlist = build_tree_list (fields, build_int_cst (long_unsigned_type_node, 0));
+ fields = TREE_CHAIN (fields);
+
+ /* Initialize "Size" field. */
+ size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (block_struct_type));
+ initlist = tree_cons (fields,
+ build_int_cst (long_unsigned_type_node, size),
+ initlist);
+
+ if (block_impl->BlockHasCopyDispose)
+ {
+ /* Initialize "CopyFuncPtr" and "DestroyFuncPtr" fields. */
+ /* Helpers were previously generated completeley as a nested
+ function (and context was required for code gen.) But they are not,
+ so context must be set to NULL so initialization logic does not complain. */
+ DECL_CONTEXT (block_impl->copy_helper_func_decl) = NULL_TREE;
+ 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);
+ DECL_CONTEXT (block_impl->destroy_helper_func_decl) = NULL_TREE;
+ 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);
+ }
+ constructor = build_constructor_from_list (descriptor_type,
+ nreverse (initlist));
+ TREE_CONSTANT (constructor) = 1;
+ TREE_STATIC (constructor) = 1;
+ TREE_READONLY (constructor) = 1;
+ DECL_INITIAL (decl) = constructor;
+ exp = build_stmt (DECL_EXPR, decl);
+ bind = build3 (BIND_EXPR, void_type_node, decl, exp, NULL);
+ TREE_SIDE_EFFECTS (bind) = 1;
+ add_stmt (bind);
+ TREE_PUBLIC (decl) = 0;
+ TREE_STATIC (decl) = 1;
+ finish_decl (decl, constructor, NULL_TREE);
+ return decl;
+}
+
+/**
+ build_block_struct_initlist - builds the initializer list:
+ { &_NSConcreteStackBlock or &_NSConcreteGlobalBlock // __isa,
+ BLOCK_USE_STRET | BLOCK_HAS_COPY_DISPOSE | BLOCK_IS_GLOBAL // __flags,
+ 0, // __reserved
+ &helper_1, // __FuncPtr,
+ &static_descriptor_variable // __descriptor,
+ x, // user variables.
+ &y
+ ...
+ }
+*/
+static tree
+build_block_struct_initlist (tree block_struct_type,
+ struct block_sema_info *block_impl)
+{
+ tree initlist, helper_addr;
+ tree chain, fields;
+ /* APPLE LOCAL radar 7735196 */
+ unsigned int flags = 0;
+ static tree NSConcreteStackBlock_decl = NULL_TREE;
+ static tree NSConcreteGlobalBlock_decl = NULL_TREE;
+ tree descriptor_block_decl = build_descriptor_block_decl (block_struct_type, block_impl);
+
+ 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;
+ /* APPLE LOCAL begin radar 7735196 */
+ if (block_impl->return_type && aggregate_value_p(block_impl->return_type, 0))
+ flags |= BLOCK_USE_STRET;
+ /* APPLE LOCAL end 7735196 */
+
+ fields = TYPE_FIELDS (block_struct_type);
+ /* APPLE LOCAL begin radar 6230297 */
+ if (!current_function_decl ||
+ (block_impl->block_ref_decl_list == NULL_TREE &&
+ block_impl->block_byref_decl_list == NULL_TREE))
+ /* APPLE LOCAL end radar 6230297 */
+ {
+ /* 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);
+ }
+ }
+ /* APPLE LOCAL begin radar 6457359 */
+ initlist = build_tree_list (fields,
+ convert (ptr_type_node,
+ build_fold_addr_expr (NSConcreteGlobalBlock_decl)));
+ /* APPLE LOCAL end radar 6457359 */
+ 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);
+ }
+ }
+ /* APPLE LOCAL begin radar 6457359 */
+ initlist = build_tree_list (fields,
+ convert (ptr_type_node,
+ build_fold_addr_expr (NSConcreteStackBlock_decl)));
+ /* APPLE LOCAL end radar 6457359 */
+ }
+ fields = TREE_CHAIN (fields);
+
+ /* __flags */
+ initlist = tree_cons (fields,
+ build_int_cst (integer_type_node, flags),
+ initlist);
+ fields = TREE_CHAIN (fields);
+
+ /* __reserved */
+ initlist = tree_cons (fields,
+ build_int_cst (integer_type_node, 0),
+ initlist);
+ fields = TREE_CHAIN (fields);
+
+ /* __FuncPtr */
+ 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);
+ fields = TREE_CHAIN (fields);
+
+ /* __descriptor */
+ /* APPLE LOCAL begin radar 6457359 */
+ initlist = tree_cons (fields,
+ build_fold_addr_expr (descriptor_block_decl),
+ initlist);
+ /* APPLE LOCAL end radar 6457359 */
+ 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, y, initlist);
+ }
+ for (chain = block_impl->block_byref_decl_list; chain;
+ chain = TREE_CHAIN (chain))
+ {
+ tree y = lookup_name (DECL_NAME (TREE_VALUE (chain)));
+ tree forwarding_expr;
+ gcc_assert (y);
+ TREE_USED (y) = 1;
+ if (COPYABLE_BYREF_LOCAL_VAR (y))
+ {
+ /* For variables declared __block, either the original one
+ at the point of declaration or the imported version (which is
+ initialized in the helper function's prologue) is used to
+ initilize the byref variable field in the temporary. */
+ if (TREE_CODE (TREE_TYPE (y)) != RECORD_TYPE)
+ y = build_indirect_ref (y, "unary *");
+ /* We will be using the __block_struct_variable.__forwarding as the
+ initializer. */
+ forwarding_expr = build_component_ref (y, get_identifier ("__forwarding"));
+ }
+ else
+ /* Global variable is always assumed passed by its address. */
+ forwarding_expr = build_fold_addr_expr (y);
+ fields = TREE_CHAIN (fields);
+ initlist = tree_cons (fields, forwarding_expr, initlist);
+ }
+ return initlist;
+}
+
+/**
+ build_block_literal_tmp - This routine:
+
+ 1) builds block type:
+ struct __block_literal_n {
+ void *__isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
+ int __flags;
+ int __reserved;
+ void *__FuncPtr
+ struct __block_descriptor {
+ unsigned long int reserved; // NULL
+ unsigned long int Size; // sizeof(struct Block_literal_1)
+
+ // optional helper functions
+ void *CopyFuncPtr; // When BLOCK_HAS_COPY_DISPOSE
+ void *DestroyFuncPtr; // When BLOCK_HAS_COPY_DISPOSE
+ } *__descriptor;
+
+ // imported variables
+ int x; // ref variable list ...
+ int *y; // byref variable list
+ };
+
+ 2) build function prototype:
+ double helper_1(struct __block_literal_n *ii, int z);
+
+ 3) build the temporary initialization:
+ struct __block_literal_n I = {
+ &_NSConcreteStackBlock or &_NSConcreteGlobalBlock // __isa,
+ BLOCK_USE_STRET | BLOCK_HAS_COPY_DISPOSE | BLOCK_IS_GLOBAL // __flags,
+ 0, // __reserved
+ &helper_1, // __FuncPtr
+ &static_descriptor_variable // __descriptor,
+ x, // user variables.
+ &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);
+ /* APPLE LOCAL begin radar 6230297 */
+ bool staticBlockTmp = (block_impl->block_ref_decl_list == NULL_TREE &&
+ block_impl->block_byref_decl_list == NULL_TREE);
+
+
+ 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) = staticBlockTmp ? NULL_TREE
+ : current_function_decl;
+ /* In the new ABI, helper function decl. is the initializer for the
+ descriptor variable which is always declared static. So, it must
+ have no context; otherwise, gcc thinks that it requires trampoline! when
+ address of this function is used as initializer. */
+ DECL_CONTEXT (block_impl->helper_func_decl) = NULL_TREE;
+ /* APPLE LOCAL end radar 6230297 */
+ 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. */
+ /* APPLE LOCAL radar 6230297 */
+ if (staticBlockTmp || 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;
+}
+/* APPLE LOCAL end radar 5847213 - radar 6329245 */
+
+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);
+ /* APPLE LOCAL radar 5847213 */
+ DECL_CONTEXT (src_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)))
+ {
+ /* APPLE LOCAL begin radar 6175959 */
+ int flag;
+ tree 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));
+
+ if (TREE_CODE (TREE_TYPE (p)) == BLOCK_POINTER_TYPE)
+ /* _Block_object_assign(&_dest->myImportedBlock, _src->myImportedClosure, BLOCK_FIELD_IS_BLOCK) */
+ flag = BLOCK_FIELD_IS_BLOCK;
+ else
+ /* _Block_object_assign(&_dest->myImportedBlock, _src->myImportedClosure, BLOCK_FIELD_IS_OBJECT) */
+ flag = BLOCK_FIELD_IS_OBJECT;
+ dst_block_component = build_fold_addr_expr (dst_block_component);
+ call_exp = build_block_object_assign_call_exp (dst_block_component, src_block_component, flag);
+ add_stmt (call_exp);
+ /* APPLE LOCAL end radar 6175959 */
+ }
+
+ /* For each __block declared variable must generate call to:
+ _Block_object_assign(&_dest->myImportedBlock, _src->myImportedBlock, BLOCK_FIELD_IS_BYREF [|BLOCK_FIELD_IS_WEAK])
+ */
+ for (chain = block_impl->block_byref_decl_list; chain;
+ chain = TREE_CHAIN (chain))
+ if (COPYABLE_BYREF_LOCAL_VAR (TREE_VALUE (chain)))
+ {
+ int flag = BLOCK_FIELD_IS_BYREF;
+ tree 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_object_assign(&_dest->myImportedClosure, _src->myImportedClosure, BLOCK_FIELD_IS_BYREF [|BLOCK_FIELD_IS_WEAK]) */
+ if (COPYABLE_WEAK_BLOCK (p))
+ flag |= BLOCK_FIELD_IS_WEAK;
+
+ dst_block_component = build_fold_addr_expr (dst_block_component);
+ call_exp = build_block_object_assign_call_exp (dst_block_component, src_block_component, flag);
+ 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)))
+ {
+ int flag;
+ tree rel_exp;
+ 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)
+ /* _Block_object_dispose(_src->imported_object_0, BLOCK_FIELD_IS_BLOCK); */
+ flag = BLOCK_FIELD_IS_BLOCK;
+ else
+ /* _Block_object_dispose(_src->imported_object_0, BLOCK_FIELD_IS_OBJECT); */
+ flag = BLOCK_FIELD_IS_OBJECT;
+ rel_exp = build_block_object_dispose_call_exp (src_block_component, flag);
+ add_stmt (rel_exp);
+ }
+
+ /* For each __block declared variable must generate call to:
+ _Block_object_dispose(_src->myImportedClosure, BLOCK_FIELD_IS_BYREF[|BLOCK_FIELD_IS_WEAK])
+ */
+ for (chain = block_impl->block_byref_decl_list; chain;
+ chain = TREE_CHAIN (chain))
+ if (COPYABLE_BYREF_LOCAL_VAR (TREE_VALUE (chain)))
+ {
+ tree call_exp;
+ int flag = BLOCK_FIELD_IS_BYREF;
+ tree p = TREE_VALUE (chain);
+ tree src_block_component;
+
+ src_block_component = build_component_ref (build_indirect_ref (src_arg, "->"),
+ DECL_NAME (p));
+ if (COPYABLE_WEAK_BLOCK (p))
+ flag |= BLOCK_FIELD_IS_WEAK;
+ /* _Block_object_dispose(_src->myImportedClosure, BLOCK_FIELD_IS_BYREF[|BLOCK_FIELD_IS_WEAK]) */
+ call_exp = build_block_object_dispose_call_exp (src_block_component, flag);
+ add_stmt (call_exp);
+ }
+
+ fnbody = c_end_compound_stmt (stmt, true);
+ add_stmt (fnbody);
+ finish_function ();
+ pop_function_context ();
+ free (arg_info);
+}
+
+/* Parse a block-id.
+
+ GNU Extension:
+
+ block-id:
+ specifier-qualifier-list block-declarator
+
+ Returns the DECL specified or implied. */
+
+static tree
+c_parser_block_id (c_parser* parser)
+{
+ struct c_declspecs *specs = build_null_declspecs ();
+ struct c_declarator *declarator;
+ 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_BLOCK, &dummy);
+ if (declarator == NULL)
+ return NULL;
+
+ return grokblockdecl (specs, declarator);
+}
+
+/* Parse a block-literal-expr.
+
+ GNU Extension:
+
+ block-literal-expr:
+ ^ parameter-declation-clause exception-specification [opt] compound-statement
+ ^ block-id compound-statement
+
+ 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 = void_list_node, 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 */
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ /* Parse the optional argument list */
+ 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 if (c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
+ {
+ /* Parse user declared return type. */
+ tree decl;
+
+ /* APPLE LOCAL begin radar 6237713 */
+ if (attributes)
+ {
+ warning (0, "attributes before block type are ignored");
+ attributes = NULL_TREE;
+ }
+ /* APPLE LOCAL end radar 6237713 */
+
+ decl = c_parser_block_id (parser);
+
+ if (decl && decl != error_mark_node)
+ {
+ arg_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ arglist = DECL_ARGUMENTS (decl);
+ declared_block_return_type = TREE_TYPE (TREE_TYPE (decl));
+ }
+ }
+
+ 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)
+ cur_block->arg_info = args;
+ else
+ cur_block->arg_info = xcalloc (1, sizeof (struct c_arg_info));
+
+ if (declared_block_return_type)
+ {
+ cur_block->arg_info->parms = arglist;
+ cur_block->arg_info->types = arg_type;
+ }
+
+ /* Must also build hidden parameter .block_descriptor added to the helper
+ function, even though we do not know its type yet. */
+ /* APPLE LOCAL radar 6404979 */
+ self_arg = build_decl (PARM_DECL, get_identifier (".block_descriptor"),
+ ptr_type_node);
+ TREE_USED (self_arg) = 1; /* Prevent unused parameter '.block_descriptor' 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 - radar 6411649 */
+ block_helper_function_decl = build_helper_func_decl (build_block_helper_name (0),
+ 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);
+ /* APPLE LOCAL radar 6246527 */
+ any_recognized_block_attribute (attributes);
+ 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 .block_descriptor 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"