#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"
int yydebug;
static int objc_pq_context = 0;
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)
static int objc_property_attr_context;
static tree objc_method_attributes;
static int objc_foreach_context;
#ifndef IASM_SEE_OPCODE
#define IASM_SEE_OPCODE(YYCHAR, T) YYCHAR
#endif
#define TYPESPEC 1
#define IDENTIFIER 2
struct resword
{
const char *word;
ENUM_BITFIELD(rid) rid : 16;
unsigned int disable : 16;
};
#define D_C89 0x01
#define D_EXT 0x02
#define D_EXT89 0x04
#define D_OBJC 0x08
static const struct resword reswords[] =
{
{ "_Bool", RID_BOOL, 0 },
{ "_Complex", RID_COMPLEX, 0 },
{ "_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 },
{ "__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 },
{ "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 },
{ "optional", RID_AT_OPTIONAL, D_OBJC },
{ "required", RID_AT_REQUIRED, D_OBJC },
{ "property", RID_AT_PROPERTY, D_OBJC },
{ "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 },
{ "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 },
{ "readonly", RID_READONLY, D_OBJC },
{ "getter", RID_GETTER, D_OBJC },
{ "setter", RID_SETTER, D_OBJC },
{ "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 },
{ "nonatomic", RID_NONATOMIC, D_OBJC },
};
#define N_reswords (sizeof reswords / sizeof (struct resword))
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;
void
c_parse_init (void)
{
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 (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;
}
}
#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
typedef enum c_id_kind {
C_ID_ID,
C_ID_TYPENAME,
C_ID_CLASSNAME,
C_ID_NONE
} c_id_kind;
typedef struct c_token GTY (())
{
ENUM_BITFIELD (cpp_ttype) type : 8;
ENUM_BITFIELD (c_id_kind) id_kind : 8;
ENUM_BITFIELD (rid) keyword : 8;
unsigned char flags;
ENUM_BITFIELD (pragma_kind) pragma_kind : 7;
BOOL_BITFIELD in_system_header : 1;
tree value;
location_t location;
} c_token;
typedef struct c_parser GTY(())
{
c_token tokens[2];
short tokens_avail;
BOOL_BITFIELD error : 1;
BOOL_BITFIELD in_pragma : 1;
} c_parser;
static GTY (()) c_parser *the_parser;
static c_token * c_parser_peek_2nd_token (c_parser *);
static void
c_lex_one_token (c_token *token, c_parser *parser)
{
timevar_push (TV_LEX);
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);
if (IASM_SEE_OPCODE (TYPESPEC, token->value) == IDENTIFIER
&& iasm_state >= iasm_decls
&& iasm_in_operands == false)
{
token->id_kind = C_ID_ID;
break;
}
if (c_dialect_objc ())
{
if (!OBJC_IS_AT_KEYWORD (rid_code)
&& !OBJC_IS_NEW_PATTR_KEYWORD (rid_code)
&& (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context))
{
token->value = ridpointers[(int) rid_code];
token->type = CPP_KEYWORD;
token->keyword = rid_code;
break;
}
else if (objc_foreach_context && rid_code == RID_IN)
{
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
|| tk->type == CPP_OPEN_SQUARE)
{
token->type = CPP_KEYWORD;
token->keyword = rid_code;
break;
}
}
else if (objc_property_attr_context && OBJC_IS_NEW_PATTR_KEYWORD (rid_code))
{
token->type = CPP_KEYWORD;
token->keyword = rid_code;
break;
}
}
else
{
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);
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:
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:
OBJC_NEED_RAW_IDENTIFIER (0);
break;
case CPP_PRAGMA:
token->pragma_kind = TREE_INT_CST_LOW (token->value);
token->value = NULL;
break;
default:
break;
}
timevar_pop (TV_LEX);
}
static inline c_token *
c_parser_peek_token (c_parser *parser)
{
if (parser->tokens_avail == 0)
{
parser->tokens_avail = 1;
c_lex_one_token (&parser->tokens[0], parser);
}
return &parser->tokens[0];
}
static inline bool
c_parser_next_token_is (c_parser *parser, enum cpp_ttype type)
{
return c_parser_peek_token (parser)->type == 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);
}
static inline bool
c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword)
{
c_token *token;
token = c_parser_peek_token (parser);
return token->keyword == keyword;
}
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;
}
}
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);
}
static bool
c_token_starts_declspecs (c_token *token)
{
switch (token->type)
{
case CPP_NAME:
switch (token->id_kind)
{
case C_ID_ID:
return false;
case C_ID_TYPENAME:
return true;
case C_ID_CLASSNAME:
gcc_assert (c_dialect_objc ());
return true;
default:
gcc_unreachable ();
}
case CPP_KEYWORD:
switch (token->keyword)
{
case RID_STATIC:
case RID_EXTERN:
case RID_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;
}
}
static inline bool
c_parser_next_token_starts_declspecs (c_parser *parser)
{
c_token *token = c_parser_peek_token (parser);
return c_token_starts_declspecs (token)
&& (token->id_kind != C_ID_CLASSNAME
|| c_parser_peek_2nd_token (parser)->type != CPP_DOT);
}
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);
parser->tokens_avail = 2;
c_lex_one_token (&parser->tokens[1], parser);
return &parser->tokens[1];
}
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--;
}
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;
}
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;
}
}
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;
c_parser_set_source_position_from_token (token);
c_parse_error (gmsgid,
(token->type == CPP_KEYWORD ? CPP_NAME : token->type),
token->value);
}
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;
}
}
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;
}
}
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;
while (true)
{
c_token *token = c_parser_peek_token (parser);
if (token->type == type && !nesting_depth)
{
c_parser_consume_token (parser);
break;
}
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;
}
c_parser_consume_token (parser);
}
parser->error = false;
}
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 (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;
}
c_parser_consume_token (parser);
}
parser->error = false;
}
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;
}
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;
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 (!nesting_depth)
{
c_parser_consume_token (parser);
goto finished;
}
break;
case CPP_CLOSE_BRACE:
if (nesting_depth == 0 || --nesting_depth == 0)
{
c_parser_consume_token (parser);
goto finished;
}
break;
case CPP_OPEN_BRACE:
++nesting_depth;
break;
case CPP_PRAGMA:
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;
}
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;
}
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;
}
typedef enum c_dtr_syn {
C_DTR_NORMAL,
C_DTR_ABSTRACT,
C_DTR_BLOCK,
C_DTR_PARM
} c_dtr_syn;
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*);
static void c_parser_external_declaration (c_parser *);
static void c_parser_asm_definition (c_parser *);
static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, bool, 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 *);
static tree c_parser_block_literal_expr (c_parser *);
static tree c_parser_asm_operands (c_parser *, bool);
static tree c_parser_asm_clobbers (c_parser *);
static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
static struct c_expr c_parser_conditional_expression (c_parser *,
struct c_expr *);
static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
static struct c_expr c_parser_sizeof_expression (c_parser *);
static struct c_expr c_parser_alignof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
struct c_type_name *);
static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
struct c_expr);
static struct c_expr c_parser_expression (c_parser *);
static struct c_expr c_parser_expression_conv (c_parser *);
static tree c_parser_expr_list (c_parser *, bool);
static void c_parser_omp_construct (c_parser *);
static void c_parser_omp_threadprivate (c_parser *);
static void c_parser_omp_barrier (c_parser *);
static void c_parser_omp_flush (c_parser *);
enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
static bool c_parser_pragma (c_parser *, enum pragma_context);
static void c_parser_objc_class_definition (c_parser *, tree);
static void c_parser_objc_class_instance_variables (c_parser *);
static void c_parser_objc_class_declaration (c_parser *);
static void c_parser_objc_alias_declaration (c_parser *);
static void c_parser_objc_protocol_definition (c_parser *, tree);
static enum tree_code c_parser_objc_method_type (c_parser *);
static void c_parser_objc_method_definition (c_parser *);
static void c_parser_objc_interfacedecllist (c_parser *);
static void c_parser_objc_property_declaration (c_parser *);
static void c_parser_objc_atsynthesize_declaration (c_parser *);
static void c_parser_objc_atdynamic_declaration (c_parser *);
static void c_parser_objc_methodproto (c_parser *);
static tree c_parser_objc_method_decl (c_parser *);
static tree c_parser_objc_type_name (c_parser *);
static tree c_parser_objc_protocol_refs (c_parser *);
static void c_parser_objc_try_catch_statement (c_parser *);
static void c_parser_objc_synchronized_statement (c_parser *);
static tree c_parser_objc_selector (c_parser *);
static tree c_parser_objc_selector_arg (c_parser *);
static tree c_parser_objc_receiver (c_parser *);
static tree c_parser_objc_message_args (c_parser *);
static tree c_parser_objc_keywordexpr (c_parser *);
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));
}
}
static void
c_parser_external_declaration (c_parser *parser)
{
int ext;
switch (c_parser_peek_token (parser)->type)
{
case CPP_KEYWORD:
switch (c_parser_peek_token (parser)->keyword)
{
case RID_EXTENSION:
ext = disable_extension_diagnostics ();
c_parser_consume_token (parser);
c_parser_external_declaration (parser);
restore_extension_diagnostics (ext);
break;
case RID_ASM:
c_parser_asm_definition (parser);
break;
case RID_AT_INTERFACE:
case RID_AT_IMPLEMENTATION:
gcc_assert (c_dialect_objc ());
c_parser_objc_class_definition (parser, NULL_TREE);
break;
case RID_AT_CLASS:
gcc_assert (c_dialect_objc ());
c_parser_objc_class_declaration (parser);
break;
case RID_AT_ALIAS:
gcc_assert (c_dialect_objc ());
c_parser_objc_alias_declaration (parser);
break;
case RID_AT_PROTOCOL:
gcc_assert (c_dialect_objc ());
c_parser_objc_protocol_definition (parser, NULL_TREE);
break;
case RID_AT_PROPERTY:
c_parser_objc_property_declaration (parser);
break;
case RID_AT_SYNTHESIZE:
c_parser_objc_atsynthesize_declaration (parser);
break;
case RID_AT_DYNAMIC:
c_parser_objc_atdynamic_declaration (parser);
break;
case RID_AT_END:
gcc_assert (c_dialect_objc ());
c_parser_consume_token (parser);
objc_finish_implementation ();
break;
default:
goto decl_or_fndef;
}
break;
case CPP_SEMICOLON:
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;
}
default:
decl_or_fndef:
c_parser_declaration_or_fndef (parser, true, true, false, true, NULL);
break;
}
}
static void
c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok,
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;
}
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;
}
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;
}
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;
declarator = c_parser_declarator (parser, specs->type_seen_p,
C_DTR_NORMAL, &dummy);
if (declarator == NULL)
{
c_parser_skip_to_end_of_block_or_statement (parser);
return;
}
if (c_parser_next_token_is (parser, CPP_EQ)
|| c_parser_next_token_is (parser, CPP_COMMA)
|| c_parser_next_token_is (parser, CPP_SEMICOLON)
|| c_parser_next_token_is_keyword (parser, RID_ASM)
|| c_parser_next_token_is_keyword (parser, RID_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");
}
fndef_ok = false;
if (c_parser_next_token_is_keyword (parser, RID_ASM))
asm_name = c_parser_simple_asm_expr (parser);
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
postfix_attrs = c_parser_attributes (parser);
if (c_parser_next_token_is_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;
}
if (c_parser_next_token_is (parser, CPP_EQ))
{
tree d;
struct c_expr init;
c_parser_consume_token (parser);
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;
}
if (nested)
{
if (declarator->declarator && declarator->declarator->kind == cdk_block_pointer)
error ("bad definition of a block");
else if (pedantic)
pedwarn ("ISO C forbids nested functions");
else if (flag_nested_functions == 0)
error ("nested functions are disabled, use -fnested-functions to re-enable");
push_function_context ();
}
if (!start_function (specs, declarator, all_prefix_attrs))
{
c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, %<asm%> "
"or %<__attribute__%>");
if (nested)
pop_function_context ();
break;
}
while (c_parser_next_token_is_not (parser, CPP_EOF)
&& c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
c_parser_declaration_or_fndef (parser, false, false, true, false, 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;
}
}
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);
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;
}
static void
c_parser_asm_definition (c_parser *parser)
{
tree asm_str;
if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN)
{
c_parser_declaration_or_fndef (parser, true, true, false, true, NULL);
return;
}
asm_str = c_parser_simple_asm_expr (parser);
if (asm_str)
cgraph_add_asm_node (asm_str);
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
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;
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;
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))
{
tree proto;
gcc_assert (c_dialect_objc ());
if (!typespec_ok || seen_type)
break;
proto = c_parser_objc_protocol_refs (parser);
t.kind = ctsk_objc;
t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto);
declspecs_add_type (specs, t);
continue;
}
gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD));
switch (c_parser_peek_token (parser)->keyword)
{
case RID_ASM:
if (current_function_decl == NULL_TREE
&& c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN)
goto out;
case RID_STATIC:
case RID_EXTERN:
case RID_REGISTER:
case RID_TYPEDEF:
case RID_INLINE:
case RID_AUTO:
case RID_THREAD:
case RID_PRIVATE_EXTERN:
if (!scspec_ok)
goto out;
attrs_ok = true;
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:
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: ;
}
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))
{
tree type = start_enum (ident);
tree postfix_attrs;
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);
if (pedantic && !COMPLETE_TYPE_P (ret.spec))
pedwarn ("ISO C forbids forward references to %<enum%> types");
return ret;
}
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))
{
tree type = start_struct (code, ident);
tree postfix_attrs;
tree contents = NULL_TREE;
c_parser_consume_token (parser);
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));
if (flag_objc2_check && flag_objc_abi == 1)
warning (0, "@defs will not be supported in future");
else if (flag_objc_abi == 2 && flag_objc_atdefs != 1)
error ("@defs is not supported in new abi");
}
end_at_defs:
while (true)
{
tree decls;
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;
}
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
c_parser_consume_token (parser);
break;
}
if (c_parser_next_token_is (parser, CPP_PRAGMA))
{
c_parser_pragma (parser, pragma_external);
continue;
}
decls = c_parser_struct_declaration (parser);
contents = chainon (decls, contents);
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;
}
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
{
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)
{
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))
{
break;
}
else
{
c_parser_error (parser, "expected %<,%>, %<;%> or %<}%>");
break;
}
}
else
{
c_parser_error (parser,
"expected %<:%>, %<,%>, %<;%>, %<}%> or "
"%<__attribute__%>");
break;
}
}
return decls;
}
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);
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));
was_vm = variably_modified_type_p (ret.spec, NULL_TREE);
if (!skip_evaluation && was_vm)
{
tree e = expr.value;
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;
}
static struct c_declarator *
c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
bool *seen_id)
{
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);
}
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
return make_block_pointer_declarator (quals_attrs, inner);
}
return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id);
}
static struct c_declarator *
c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
bool *seen_id)
{
if ((kind != C_DTR_ABSTRACT && kind != C_DTR_BLOCK)
&& c_parser_next_token_is (parser, CPP_NAME)
&& ((type_seen_p
&& (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
|| c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
|| c_parser_peek_token (parser)->id_kind == C_ID_ID))
{
struct c_declarator *inner
= build_id_declarator (c_parser_peek_token (parser)->value);
*seen_id = true;
inner->id_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
return c_parser_direct_declarator_inner (parser, *seen_id, inner);
}
if (kind != C_DTR_NORMAL
&& c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
{
struct c_declarator *inner = build_id_declarator (NULL_TREE);
return c_parser_direct_declarator_inner (parser, *seen_id, inner);
}
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);
}
}
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);
}
}
static struct c_declarator *
c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
struct c_declarator *inner)
{
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_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;
}
static struct c_arg_info *
c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs)
{
push_scope ();
declare_parm_level ();
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;
}
}
static struct c_arg_info *
c_parser_parms_list_declarator (c_parser *parser, tree attrs)
{
bool good_parm = false;
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;
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;
}
}
while (true)
{
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;
}
}
}
}
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))
{
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);
}
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;
}
static tree
c_parser_simple_asm_expr (c_parser *parser)
{
tree str;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
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;
}
static tree
c_parser_attributes (c_parser *parser)
{
tree attrs = NULL_TREE;
while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
{
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;
}
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))
{
bool ok;
switch (c_parser_peek_token (parser)->keyword)
{
case RID_STATIC:
case RID_UNSIGNED:
case RID_LONG:
case RID_CONST:
case RID_EXTERN:
case RID_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);
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;
}
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;
}
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;
}
}
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
{
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);
}
static void
c_parser_initelt (c_parser *parser)
{
if (c_parser_next_token_is (parser, CPP_NAME)
&& c_parser_peek_2nd_token (parser)->type == CPP_COLON)
{
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
{
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;
if (des_prev == 1 && c_dialect_objc ())
{
des_seen = des_prev;
break;
}
if (des_prev == 0 && c_dialect_objc ())
{
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)))
{
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;
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:
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;
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);
}
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);
}
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);
}
static void
c_parser_compound_statement_nostart (c_parser *parser)
{
bool last_stmt = false;
bool last_label = false;
bool first_stmt = true;
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
c_parser_consume_token (parser);
if (flag_iasm_blocks)
iasm_end_block ();
return;
}
if (c_parser_next_token_is_keyword (parser, RID_LABEL))
{
while (c_parser_next_token_is_keyword (parser, RID_LABEL))
{
c_parser_consume_token (parser);
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 %<;%>");
}
if (pedantic)
pedwarn ("ISO C forbids label declarations");
}
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
c_parser_error (parser, "expected declaration or statement");
c_parser_consume_token (parser);
if (flag_iasm_blocks)
iasm_end_block ();
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)
&& 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;
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))
{
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;
c_parser_declaration_or_fndef (parser, true, true, true, true, NULL);
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))
{
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");
if (flag_iasm_blocks)
iasm_end_block ();
return;
}
else
{
statement:
last_label = false;
last_stmt = true;
c_parser_statement_after_labels (parser);
}
if (flag_iasm_blocks) iasm_in_decl = false;
parser->error = false;
first_stmt = false;
}
if (flag_iasm_blocks)
iasm_end_block ();
if (last_label)
error ("label at end of compound statement");
c_parser_consume_token (parser);
}
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);
}
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);
}
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:
if (cur_block)
error ("goto not allowed in block literal");
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:
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:
if (iasm_state >= iasm_decls)
{
iasm_state = iasm_asm;
inside_iasm_block = true;
iasm_kill_regs = true;
#ifdef ENABLE_LLVM
iasm_label_counter = 0;
#endif
iasm_in_decl = false;
c_parser_iasm_line_seq_opt (parser);
stmt = NULL_TREE;
break;
}
stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value);
expect_semicolon:
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
break;
}
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);
}
}
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;
}
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);
}
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);
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);
}
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));
}
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));
}
static void
c_parser_while_statement (c_parser *parser)
{
\
tree block, cond, body, save_break, save_cont, attrs;
\
location_t loc;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
c_parser_consume_token (parser);
\
attrs = c_parser_attributes (parser);
\
block = c_begin_compound_stmt (flag_isoc99);
loc = c_parser_peek_token (parser)->location;
cond = c_parser_paren_condition (parser);
save_break = c_break_label;
c_break_label = NULL_TREE;
save_cont = c_cont_label;
c_cont_label = NULL_TREE;
body = c_parser_c99_block_statement (parser);
\
c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, attrs,
true);
\
add_stmt (c_end_compound_stmt (block, flag_isoc99));
c_break_label = save_break;
c_cont_label = save_cont;
}
static void
c_parser_do_statement (c_parser *parser)
{
\
tree block, cond, body, save_break, save_cont, new_break, new_cont, attrs;
\
location_t loc;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO));
c_parser_consume_token (parser);
\
attrs = c_parser_attributes (parser);
\
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);
\
c_finish_loop (loc, cond, NULL, body, new_break, new_cont, attrs, false);
\
add_stmt (c_end_compound_stmt (block, flag_isoc99));
}
static void
c_parser_for_statement (c_parser *parser)
{
\
tree block, cond, incr, save_break, save_cont, body, attrs;
\
location_t loc;
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);
\
attrs = c_parser_attributes (parser);
\
block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ());
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
objc_foreach_context = 1;
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))
{
cond = NULL_TREE;
c_parser_declaration_or_fndef (parser, true, true, true, true, &cond);
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 ();
}
else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
{
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);
cond = NULL_TREE;
c_parser_declaration_or_fndef (parser, true, true, true, true, &cond);
restore_extension_diagnostics (ext);
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 ();
}
else
goto init_expr;
}
else
{
init_expr:
cond = c_parser_expression (parser).value;
if (c_parser_next_token_is_keyword (parser, RID_IN))
{
c_parser_consume_token (parser);
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;
loc = c_parser_peek_token (parser)->location;
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
c_parser_consume_token (parser);
cond = NULL_TREE;
}
else if (foreach_p)
;
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 %<;%>");
}
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);
if (foreach_p)
objc_finish_foreach_loop (loc, cond, body, c_break_label, c_cont_label);
else
\
c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, attrs,
true);
\
add_stmt (c_end_compound_stmt (block, flag_isoc99 || c_dialect_objc ()));
c_break_label = save_break;
c_cont_label = save_cont;
}
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);
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;
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;
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;
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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");
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;
}
static struct c_expr
c_parser_binary_expression (c_parser *parser, struct c_expr *after)
{
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 {
struct c_expr expr;
enum prec prec;
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);
if (c_dialect_objc() && flag_objc_gc)
stack[0].expr.value = objc_build_weak_reference_tree (stack[0].expr.value);
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:
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);
if (c_dialect_objc() && flag_objc_gc)
stack[sp].expr.value = objc_build_weak_reference_tree (stack[sp].expr.value);
stack[sp].prec = oprec;
stack[sp].op = ocode;
}
out:
while (sp > 0)
POP;
return stack[0].expr;
#undef POP
}
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 (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;
}
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);
}
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:
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);
}
}
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)))
{
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;
}
skip_evaluation--;
in_sizeof--;
if (type_name->declarator->kind == cdk_array
&& type_name->declarator->u.array.vla_unspec_p)
{
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);
}
}
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)))
{
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;
}
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;
}
}
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:
if (c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME
&& c_parser_peek_2nd_token (parser)->type == CPP_DOT)
{
tree receiver, component;
receiver = c_parser_objc_receiver (parser);
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;
}
if (c_parser_peek_token (parser)->id_kind != C_ID_ID)
{
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;
}
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);
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)) {
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));
}
expr.original_code = ERROR_MARK;
}
break;
case CPP_OPEN_PAREN:
if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE)
{
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)))
{
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
{
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);
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:
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;
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;
case CPP_OPEN_SQUARE:
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;
}
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;
}
default:
if (inside_iasm_block)
{
if (c_parser_next_token_is (parser, CPP_DOT))
{
c_parser_consume_token (parser);
expr.value = get_identifier (".");
expr.original_code = ERROR_MARK;
break;
}
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;
}
}
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);
}
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);
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);
}
static struct c_expr
c_parser_postfix_expression_after_primary (c_parser *parser,
struct c_expr expr)
{
tree ident, idx, exprlist;
while (true)
{
if (inside_iasm_block
&& c_parser_iasm_bol (parser))
return expr;
switch (c_parser_peek_token (parser)->type)
{
case CPP_OPEN_SQUARE:
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:
if (inside_iasm_block)
return expr;
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:
c_parser_consume_token (parser);
expr = default_function_array_conversion (expr);
if (inside_iasm_block)
{
if (c_parser_next_token_is (parser, CPP_NAME)
|| 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;
}
}
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:
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:
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:
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;
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;
default:
return expr;
}
}
}
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;
}
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;
}
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;
}
static void
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))
{
if (prefix_attrs)
{
error ("attributes may not be specified on an implementation");
prefix_attrs = NULL_TREE;
}
iface_p = false;
}
else
gcc_unreachable ();
c_parser_consume_token (parser);
if (c_parser_next_token_is_not (parser, CPP_NAME))
{
c_parser_error (parser, "expected identifier 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))
{
tree id2 = NULL_TREE;
tree proto = NULL_TREE;
c_parser_consume_token (parser);
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);
}
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
if (!iface_p)
{
if (id2 == NULL_TREE)
{
error ("cannot implement anonymous category");
return;
}
objc_start_category_implementation (id1, id2);
return;
}
if (c_parser_next_token_is (parser, CPP_LESS))
proto = c_parser_objc_protocol_refs (parser);
if (prefix_attrs)
error ("attributes may not be specified on a category");
objc_start_category_interface (id1, id2, proto);
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);
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 ();
c_parser_objc_interfacedecllist (parser);
c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
objc_finish_interface ();
}
else
{
objc_continue_implementation ();
return;
}
}
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;
}
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;
}
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);
if (c_parser_next_token_is (parser, CPP_COLON))
c_parser_consume_token (parser);
break;
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;
case RID_NONATOMIC:
c_parser_consume_token (parser);
objc_set_property_attr (13, NULL_TREE);
break;
default:
c_parser_error (parser, "expected a property attribute");
c_parser_consume_token (parser);
}
}
static void
c_parser_objc_property_attrlist (c_parser *parser)
{
while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)
&& c_parser_next_token_is_not (parser, CPP_EOF))
{
c_parser_objc_property_attribute (parser);
if (c_parser_next_token_is_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");
if (c_parser_next_token_is (parser, CPP_COMMA)
|| c_parser_next_token_is (parser, CPP_NAME) )
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;
note_objc_property_decl_context ();
prop = c_parser_component_decl (parser);
note_end_objc_property_decl_context ();
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 %<;%>");
}
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;
}
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;
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;
}
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
c_parser_consume_token (parser);
break;
}
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;
}
else if (c_parser_next_token_is_keyword (parser, RID_AT_PACKAGE))
{
c_parser_consume_token (parser);
objc_set_visibility (3);
continue;
}
else if (c_parser_next_token_is (parser, CPP_PRAGMA))
{
c_parser_pragma (parser, pragma_external);
continue;
}
decls = c_parser_struct_declaration (parser);
{
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 %<;%>");
}
}
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);
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);
}
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);
}
static void
c_parser_objc_protocol_definition (c_parser *parser, tree attributes)
{
gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL));
c_parser_consume_token (parser);
if (c_parser_next_token_is_not (parser, CPP_NAME))
{
c_parser_error (parser, "expected identifier");
return;
}
if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA
|| c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON)
{
tree list = NULL_TREE;
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_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;
objc_start_protocol (id, proto, attributes);
c_parser_objc_interfacedecllist (parser);
c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
objc_pq_context = 0;
objc_finish_interface ();
}
}
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 ();
}
}
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;
}
in_gimple_form = 0;
objc_pq_context = 0;
objc_start_method_definition (decl, objc_method_attributes);
objc_method_attributes = NULL_TREE;
add_stmt (c_parser_compound_statement (parser));
objc_finish_method_definition (current_function_decl);
}
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));
}
static void
c_parser_objc_interfacedecllist (c_parser *parser)
{
while (true)
{
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;
}
if (c_token_starts_methodproto (token))
{
c_parser_objc_methodproto (parser);
continue;
}
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;
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;
c_parser_declaration_or_fndef (parser, false, true, false, true, NULL);
break;
}
}
}
static void
c_parser_objc_methodproto (c_parser *parser)
{
enum tree_code type;
tree decl;
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;
}
type = c_parser_objc_method_type (parser);
objc_set_method_type (type);
objc_pq_context = 1;
decl = c_parser_objc_method_decl (parser);
objc_pq_context = 0;
objc_add_method_declaration (decl, objc_method_attributes);
objc_method_attributes = NULL_TREE;
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
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 (!sel || c_parser_next_token_is (parser, CPP_COLON))
{
tree tsel = sel;
tree list = NULL_TREE;
while (true)
{
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 %<)%>");
}
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
attr = c_parser_attributes (parser);
if (c_parser_next_token_is_not (parser, CPP_NAME))
{
c_parser_error (parser, "expected identifier");
return error_mark_node;
}
id = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
keyworddecl = objc_build_keyword_decl (tsel, atype, id, attr);
list = chainon (list, keyworddecl);
tsel = c_parser_objc_selector (parser);
if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON))
break;
}
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
objc_method_attributes = c_parser_attributes (parser);
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);
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);
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;
}
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);
}
if (sel == NULL)
{
c_parser_error (parser, "objective-c method declaration is expected");
return error_mark_node;
}
return objc_build_method_signature (type, sel, parms, ellipsis);
}
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))
{
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);
}
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);
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;
}
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;
if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
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));
}
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 ();
}
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);
}
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;
stmt = c_parser_objc_synch_compound_statement (parser);
objc_build_synchronized (loc, expr, stmt);
}
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;
}
}
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;
}
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;
}
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;
}
static tree
c_parser_objc_keywordexpr (c_parser *parser)
{
tree list = c_parser_expr_list (parser, true);
if (TREE_CHAIN (list) == NULL_TREE)
{
return TREE_VALUE (list);
}
else
{
return list;
}
}
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);
parser->error = true;
c_parser_skip_to_pragma_eol (parser);
return false;
}
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));
}
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;
}
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;
}
}
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;
}
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;
}
static tree
c_parser_omp_clause_copyin (c_parser *parser, tree list)
{
return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, 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);
}
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;
}
static tree
c_parser_omp_clause_firstprivate (c_parser *parser, tree list)
{
return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list);
}
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;
}
static tree
c_parser_omp_clause_lastprivate (c_parser *parser, tree list)
{
return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list);
}
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;
}
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;
}
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;
}
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;
}
static tree
c_parser_omp_clause_private (c_parser *parser, tree list)
{
return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list);
}
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;
}
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;
}
static tree
c_parser_omp_clause_shared (c_parser *parser, tree list)
{
return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list);
}
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)
{
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);
}
static tree
c_parser_omp_structured_block (c_parser *parser)
{
tree stmt = push_stmt_list ();
c_parser_statement (parser);
return pop_stmt_list (stmt);
}
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 %<;%>");
}
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 ();
}
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);
}
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 ();
}
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;
if (c_parser_next_token_starts_declspecs (parser))
{
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;
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 %<;%>");
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;
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;
}
#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;
}
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));
}
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));
}
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 %<{%>"))
{
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);
}
#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;
}
#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;
}
#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);
}
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);
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);
}
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");
for (t = vars; t; t = TREE_CHAIN (t))
{
tree v = TREE_PURPOSE (t);
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);
#ifndef ENABLE_LLVM
if (DECL_RTL_SET_P (v))
make_decl_rtl (v);
#else
if (DECL_LLVM_SET_P (v))
make_decl_llvm (v);
#endif
}
C_DECL_THREADPRIVATE_P (v) = 1;
}
}
c_parser_skip_to_pragma_eol (parser);
}
void
c_parse_file (void)
{
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;
}
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;
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;
}
static void
c_parser_iasm_maybe_skip_comments (c_parser *parser)
{
if (flag_ms_asms
&& c_parser_next_token_is (parser, CPP_SEMICOLON))
{
c_parser_consume_token (parser);
gcc_assert (parser->tokens_avail == 0);
iasm_skip_to_eol ();
}
}
static void
c_parser_iasm_statement_seq_opt (c_parser* parser)
{
int check;
while (true)
{
check = 0;
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
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
{
c_parser_iasm_statement (parser);
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)
|| 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);
}
static void
c_parser_iasm_line (c_parser* parser)
{
c_parser_iasm_statement_seq_opt (parser);
}
static void
c_parser_iasm_line_seq_opt (c_parser* parser)
{
while (true)
{
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)
|| c_parser_next_token_is (parser, CPP_EOF))
break;
c_parser_iasm_line (parser);
}
}
static void
c_parser_iasm_compound_statement (c_parser *parser)
{
tree stmt;
iasm_state = iasm_asm;
inside_iasm_block = true;
iasm_kill_regs = true;
#ifdef ENABLE_LLVM
iasm_label_counter = 0;
#endif
stmt = c_begin_compound_stmt (true);
c_parser_iasm_line_seq_opt (parser);
add_stmt (c_end_compound_stmt (stmt, true));
c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
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;
#ifdef ENABLE_LLVM
iasm_label_counter = 0;
#endif
stmt = c_begin_compound_stmt (true);
if (!c_parser_iasm_bol (parser))
{
c_parser_iasm_line (parser);
}
add_stmt (c_end_compound_stmt (stmt, true));
iasm_end_block ();
iasm_state = iasm_none;
}
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;
token = c_parser_peek_token (parser);
t = token->value;
if (!c_parser_require (parser, CPP_NAME, "expected identifier"))
return error_mark_node;
return t;
}
static tree
c_parser_iasm_identifier (c_parser* parser)
{
c_token *token;
tree t;
const char *str = "";
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;
}
gcc_assert (s != 0);
c_parser_consume_token (parser);
t = get_identifier (s);
}
else if (token->type == CPP_DOT)
{
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 (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);
}
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;
operand = c_parser_binary_expression (parser, false).value;
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;
}
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);
}
static tree
c_parser_iasm_operands (c_parser *parser)
{
tree operands = NULL_TREE, operand;
while (true)
{
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;
}
static void
c_parser_iasm_statement (c_parser* parser)
{
tree aname, anothername, operands;
int iasm_lineno = input_line;
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);
if (c_parser_next_token_is (parser, CPP_COLON))
c_parser_consume_token (parser);
iasm_label (aname, true);
}
else
{
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);
}
tree
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);
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;
}
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;
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;
}
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));
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);
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 (block_impl->BlockHasCopyDispose));
chainon (field_decl_chain, field_decl);
if (block_impl->BlockHasCopyDispose)
{
if (block_impl->prev_block_info)
block_impl->prev_block_info->BlockHasCopyDispose = TRUE;
}
for (chain = block_impl->block_ref_decl_list; chain; chain = TREE_CHAIN (chain))
{
tree p = TREE_VALUE (chain);
field_decl = build_decl (FIELD_DECL, DECL_NAME (p),
c_build_qualified_type (TREE_TYPE (p),
TYPE_UNQUALIFIED));
chainon (field_decl_chain, field_decl);
}
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;
}
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;
fields = TYPE_FIELDS (descriptor_type);
initlist = build_tree_list (fields, build_int_cst (long_unsigned_type_node, 0));
fields = TREE_CHAIN (fields);
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)
{
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);
}
fields = TREE_CHAIN (fields);
initlist = tree_cons (fields,
build_int_cst (build_pointer_type (char_type_node), 0),
initlist);
fields = TREE_CHAIN (fields);
initlist = tree_cons (fields,
build_int_cst (build_pointer_type (char_type_node), 0),
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;
}
static tree
build_block_struct_initlist (tree block_struct_type,
struct block_sema_info *block_impl)
{
tree initlist, helper_addr;
tree chain, fields;
unsigned int flags = BLOCK_HAS_SIGNATURE;
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)
flags |= BLOCK_HAS_COPY_DISPOSE;
if (block_impl->return_type && aggregate_value_p(block_impl->return_type, 0))
flags |= BLOCK_USE_STRET;
fields = TYPE_FIELDS (block_struct_type);
if (!current_function_decl ||
(block_impl->block_ref_decl_list == NULL_TREE &&
block_impl->block_byref_decl_list == NULL_TREE))
{
if (NSConcreteGlobalBlock_decl == NULL_TREE)
{
tree name_id = get_identifier("_NSConcreteGlobalBlock");
NSConcreteGlobalBlock_decl = lookup_name (name_id);
if (!NSConcreteGlobalBlock_decl)
{
NSConcreteGlobalBlock_decl = build_decl (VAR_DECL, name_id, ptr_type_node);
DECL_EXTERNAL (NSConcreteGlobalBlock_decl) = 1;
TREE_PUBLIC (NSConcreteGlobalBlock_decl) = 1;
pushdecl_top_level (NSConcreteGlobalBlock_decl);
rest_of_decl_compilation (NSConcreteGlobalBlock_decl, 0, 0);
}
}
initlist = build_tree_list (fields,
convert (ptr_type_node,
build_fold_addr_expr (NSConcreteGlobalBlock_decl)));
flags |= BLOCK_IS_GLOBAL;
}
else
{
if (NSConcreteStackBlock_decl == NULL_TREE)
{
tree name_id = get_identifier("_NSConcreteStackBlock");
NSConcreteStackBlock_decl = lookup_name (name_id);
if (!NSConcreteStackBlock_decl)
{
NSConcreteStackBlock_decl = build_decl (VAR_DECL, name_id, ptr_type_node);
DECL_EXTERNAL (NSConcreteStackBlock_decl) = 1;
TREE_PUBLIC (NSConcreteStackBlock_decl) = 1;
pushdecl_top_level (NSConcreteStackBlock_decl);
rest_of_decl_compilation (NSConcreteStackBlock_decl, 0, 0);
}
}
initlist = build_tree_list (fields,
convert (ptr_type_node,
build_fold_addr_expr (NSConcreteStackBlock_decl)));
}
fields = TREE_CHAIN (fields);
initlist = tree_cons (fields,
build_int_cst (integer_type_node, flags),
initlist);
fields = TREE_CHAIN (fields);
initlist = tree_cons (fields,
build_int_cst (integer_type_node, 0),
initlist);
fields = TREE_CHAIN (fields);
helper_addr = build_fold_addr_expr (block_impl->helper_func_decl);
helper_addr = convert (ptr_type_node, helper_addr);
initlist = tree_cons (fields, helper_addr, initlist);
fields = TREE_CHAIN (fields);
initlist = tree_cons (fields,
build_fold_addr_expr (descriptor_block_decl),
initlist);
for (chain = block_impl->block_original_ref_decl_list; chain;
chain = TREE_CHAIN (chain))
{
tree y = TREE_VALUE (chain);
TREE_USED (y) = 1;
fields = TREE_CHAIN (fields);
initlist = tree_cons (fields, 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))
{
if (TREE_CODE (TREE_TYPE (y)) != RECORD_TYPE)
y = build_indirect_ref (y, "unary *");
forwarding_expr = build_component_ref (y, get_identifier ("__forwarding"));
}
else
forwarding_expr = build_fold_addr_expr (y);
fields = TREE_CHAIN (fields);
initlist = tree_cons (fields, forwarding_expr, initlist);
}
return initlist;
}
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);
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);
DECL_CONTEXT (block_holder_tmp_decl) = staticBlockTmp ? NULL_TREE
: current_function_decl;
DECL_CONTEXT (block_impl->helper_func_decl) = NULL_TREE;
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);
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);
}
#ifdef ENABLE_LLVM
TREE_CONSTANT (block_holder_tmp_decl) = 1;
TREE_READONLY (block_holder_tmp_decl) = 1;
#endif
return block_holder_tmp_decl;
}
static tree
clean_and_exit (tree block)
{
pop_function_context ();
free (finish_block (block));
return error_mark_node;
}
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;
dst_arg = build_decl (PARM_DECL, get_identifier ("_dst"),
block_impl->block_arg_ptr_type);
DECL_CONTEXT (dst_arg) = cur_block->copy_helper_func_decl;
TREE_USED (dst_arg) = 1;
DECL_ARG_TYPE (dst_arg) = block_impl->block_arg_ptr_type;
src_arg = build_decl (PARM_DECL, get_identifier ("_src"),
block_impl->block_arg_ptr_type);
DECL_CONTEXT (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));
push_function_context ();
start_block_helper_function (cur_block->copy_helper_func_decl);
store_parm_decls_from (arg_info);
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 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)
flag = BLOCK_FIELD_IS_BLOCK;
else
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);
}
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));
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;
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);
push_function_context ();
start_block_helper_function (cur_block->destroy_helper_func_decl);
store_parm_decls_from (arg_info);
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)
flag = BLOCK_FIELD_IS_BLOCK;
else
flag = BLOCK_FIELD_IS_OBJECT;
rel_exp = build_block_object_dispose_call_exp (src_block_component, flag);
add_stmt (rel_exp);
}
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;
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);
}
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);
}
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;
tree declared_block_return_type = NULL_TREE;
tree attributes = NULL_TREE;
c_parser_consume_token (parser);
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
attributes = c_parser_attributes (parser);
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
{
c_parser_consume_token (parser);
push_scope ();
args = c_parser_parms_declarator (parser, true, NULL_TREE);
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))
{
tree decl;
if (attributes)
{
warning (0, "attributes before block type are ignored");
attributes = NULL_TREE;
}
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;
}
self_arg = build_decl (PARM_DECL, get_identifier (".block_descriptor"),
ptr_type_node);
TREE_USED (self_arg) = 1;
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;
ftype = build_function_type ((!cur_block->block_has_return_type
? void_type_node : cur_block->return_type),
cur_block->arg_info->types);
block_helper_function_decl = build_helper_func_decl (build_block_helper_name (0),
ftype);
DECL_CONTEXT (block_helper_function_decl) = current_function_decl;
#ifdef ENABLE_LLVM
DECL_NO_STATIC_CHAIN (block_helper_function_decl) = 1;
#endif
cur_block->helper_func_decl = block_helper_function_decl;
push_function_context ();
start_block_helper_function (cur_block->helper_func_decl);
cur_block->the_scope = (struct c_scope*)objc_get_current_scope ();
store_parm_decls_from (cur_block->arg_info);
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
attributes = c_parser_attributes (parser);
any_recognized_block_attribute (attributes);
decl_attributes (&cur_block->helper_func_decl, attributes, 0);
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;
c_break_label = c_cont_label = size_zero_node;
c_parser_consume_token (parser);
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);
TREE_TYPE (self_arg) = cur_block->block_arg_ptr_type;
DECL_ARG_TYPE (self_arg) = cur_block->block_arg_ptr_type;
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);
ftype = build_function_type (restype, arg_type);
typelist = TYPE_ARG_TYPES (ftype);
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 ();
if (cur_block->BlockHasCopyDispose)
{
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);
DECL_SOURCE_FILE (cur_block->copy_helper_func_decl) = NULL;
DECL_SOURCE_LINE (cur_block->copy_helper_func_decl) = 0;
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);
DECL_SOURCE_FILE (cur_block->destroy_helper_func_decl) = NULL;
DECL_SOURCE_LINE (cur_block->destroy_helper_func_decl) = 0;
}
block_impl = finish_block (block);
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;
}
#include "gt-c-parser.h"