X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fc-parser.c;h=29148266f9a1db26b5c4f6421976d70be9238832;hb=8c37d3591562e19a7820e8d8c1186f9e5e5f9d60;hp=1207e66135d11e0bf9d6d4541441537cef30fb3b;hpb=caa9f6a77d8f97a00f46dbf9a5d82705ae5bd968;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 1207e66135d..29148266f9a 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -1,6 +1,6 @@ /* Parser for C and Objective-C. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc. Parser actions based on the old Bison parser; structure somewhat influenced by and fragments based on the C++ parser. @@ -9,7 +9,7 @@ This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -18,9 +18,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* TODO: @@ -42,6 +41,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "coretypes.h" #include "tm.h" #include "tree.h" +#include "rtl.h" #include "langhooks.h" #include "input.h" #include "cpplib.h" @@ -53,27 +53,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "toplev.h" #include "ggc.h" #include "c-common.h" +#include "vec.h" +#include "target.h" +#include "cgraph.h" -/* Miscellaneous data and functions needed for the parser. */ - -int yydebug; - -/* Objective-C specific parser/lexer information. */ - -static int objc_pq_context = 0; - -/* The following flag is needed to contextualize Objective-C lexical - analysis. In some cases (e.g., 'int NSObject;'), it is undesirable - to bind an identifier to an Objective-C class, even if a class with - that name exists. */ -static int objc_need_raw_identifier = 0; -#define OBJC_NEED_RAW_IDENTIFIER(VAL) \ - do { \ - if (c_dialect_objc ()) \ - objc_need_raw_identifier = VAL; \ - } while (0) - /* The reserved keyword table. */ struct resword { @@ -93,6 +77,12 @@ static const struct resword reswords[] = { { "_Bool", RID_BOOL, 0 }, { "_Complex", RID_COMPLEX, 0 }, + { "_Decimal32", RID_DFLOAT32, D_EXT }, + { "_Decimal64", RID_DFLOAT64, D_EXT }, + { "_Decimal128", RID_DFLOAT128, D_EXT }, + { "_Fract", RID_FRACT, D_EXT }, + { "_Accum", RID_ACCUM, D_EXT }, + { "_Sat", RID_SAT, D_EXT }, { "__FUNCTION__", RID_FUNCTION_NAME, 0 }, { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 }, { "__alignof", RID_ALIGNOF, 0 }, @@ -263,6 +253,9 @@ typedef struct c_token GTY (()) /* If this token is a keyword, this value indicates which keyword. Otherwise, this value is RID_MAX. */ ENUM_BITFIELD (rid) keyword : 8; + /* If this token is a CPP_PRAGMA, this indicates the pragma that + was seen. Otherwise it is PRAGMA_NONE. */ + ENUM_BITFIELD (pragma_kind) pragma_kind : 7; /* True if this token is from a system header. */ BOOL_BITFIELD in_system_header : 1; /* The value associated with this token, if any. */ @@ -284,26 +277,51 @@ typedef struct c_parser GTY(()) c_parser_error sets this flag. It should clear this flag when enough tokens have been consumed to recover from the error. */ BOOL_BITFIELD error : 1; + /* True if we're processing a pragma, and shouldn't automatically + consume CPP_PRAGMA_EOL. */ + BOOL_BITFIELD in_pragma : 1; + /* True if we want to lex an untranslated string. */ + BOOL_BITFIELD lex_untranslated_string : 1; + /* Objective-C specific parser/lexer information. */ + BOOL_BITFIELD objc_pq_context : 1; + /* The following flag is needed to contextualize Objective-C lexical + analysis. In some cases (e.g., 'int NSObject;'), it is + undesirable to bind an identifier to an Objective-C class, even + if a class with that name exists. */ + BOOL_BITFIELD objc_need_raw_identifier : 1; } c_parser; + +/* The actual parser and external interface. ??? Does this need to be + garbage-collected? */ + +static GTY (()) c_parser *the_parser; + + /* Read in and lex a single token, storing it in *TOKEN. */ static void -c_lex_one_token (c_token *token) +c_lex_one_token (c_parser *parser, c_token *token) { timevar_push (TV_LEX); - token->type = c_lex_with_flags (&token->value, &token->location, NULL); + + token->type = c_lex_with_flags (&token->value, &token->location, NULL, + (parser->lex_untranslated_string + ? C_LEX_STRING_NO_TRANSLATE : 0)); + token->id_kind = C_ID_NONE; + token->keyword = RID_MAX; + token->pragma_kind = PRAGMA_NONE; token->in_system_header = in_system_header; + switch (token->type) { case CPP_NAME: - token->id_kind = C_ID_NONE; - token->keyword = RID_MAX; { tree decl; - int objc_force_identifier = objc_need_raw_identifier; - OBJC_NEED_RAW_IDENTIFIER (0); + bool objc_force_identifier = parser->objc_need_raw_identifier; + if (c_dialect_objc ()) + parser->objc_need_raw_identifier = false; if (C_IS_RESERVED_WORD (token->value)) { @@ -312,7 +330,8 @@ c_lex_one_token (c_token *token) if (c_dialect_objc ()) { if (!OBJC_IS_AT_KEYWORD (rid_code) - && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context)) + && (!OBJC_IS_PQ_KEYWORD (rid_code) + || parser->objc_pq_context)) { /* Return the canonical spelling for this keyword. */ token->value = ridpointers[(int) rid_code]; @@ -355,13 +374,12 @@ c_lex_one_token (c_token *token) break; } } + token->id_kind = C_ID_ID; } - token->id_kind = C_ID_ID; break; case CPP_AT_NAME: /* This only happens in Objective-C; it must be a keyword. */ token->type = CPP_KEYWORD; - token->id_kind = C_ID_NONE; token->keyword = C_RID_CODE (token->value); break; case CPP_COLON: @@ -370,13 +388,15 @@ c_lex_one_token (c_token *token) case CPP_SEMICOLON: /* These tokens may affect the interpretation of any identifiers following, if doing Objective-C. */ - OBJC_NEED_RAW_IDENTIFIER (0); - token->id_kind = C_ID_NONE; - token->keyword = RID_MAX; + if (c_dialect_objc ()) + parser->objc_need_raw_identifier = false; + break; + case CPP_PRAGMA: + /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */ + token->pragma_kind = TREE_INT_CST_LOW (token->value); + token->value = NULL; break; default: - token->id_kind = C_ID_NONE; - token->keyword = RID_MAX; break; } timevar_pop (TV_LEX); @@ -390,7 +410,7 @@ c_parser_peek_token (c_parser *parser) { if (parser->tokens_avail == 0) { - c_lex_one_token (&parser->tokens[0]); + c_lex_one_token (parser, &parser->tokens[0]); parser->tokens_avail = 1; } return &parser->tokens[0]; @@ -461,6 +481,9 @@ c_token_starts_typename (c_token *token) 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: @@ -470,6 +493,9 @@ c_token_starts_typename (c_token *token) case RID_VOLATILE: case RID_RESTRICT: case RID_ATTRIBUTE: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: return true; default: return false; @@ -532,6 +558,9 @@ c_token_starts_declspecs (c_token *token) 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: @@ -541,6 +570,9 @@ c_token_starts_declspecs (c_token *token) case RID_VOLATILE: case RID_RESTRICT: case RID_ATTRIBUTE: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: return true; default: return false; @@ -573,7 +605,8 @@ c_parser_peek_2nd_token (c_parser *parser) return &parser->tokens[1]; gcc_assert (parser->tokens_avail == 1); gcc_assert (parser->tokens[0].type != CPP_EOF); - c_lex_one_token (&parser->tokens[1]); + gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL); + c_lex_one_token (parser, &parser->tokens[1]); parser->tokens_avail = 2; return &parser->tokens[1]; } @@ -583,14 +616,28 @@ c_parser_peek_2nd_token (c_parser *parser) static void c_parser_consume_token (c_parser *parser) { + gcc_assert (parser->tokens_avail >= 1); + gcc_assert (parser->tokens[0].type != CPP_EOF); + gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL); + gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA); + if (parser->tokens_avail == 2) + parser->tokens[0] = parser->tokens[1]; + parser->tokens_avail--; +} + +/* Expect the current token to be a #pragma. Consume it and remember + that we've begun parsing a pragma. */ + +static void +c_parser_consume_pragma (c_parser *parser) +{ + gcc_assert (!parser->in_pragma); + gcc_assert (parser->tokens_avail >= 1); + gcc_assert (parser->tokens[0].type == CPP_PRAGMA); if (parser->tokens_avail == 2) parser->tokens[0] = parser->tokens[1]; - else - { - gcc_assert (parser->tokens_avail == 1); - gcc_assert (parser->tokens[0].type != CPP_EOF); - } parser->tokens_avail--; + parser->in_pragma = true; } /* Update the globals input_location and in_system_header from @@ -605,23 +652,6 @@ c_parser_set_source_position_from_token (c_token *token) } } -/* Allocate a new parser. */ - -static c_parser * -c_parser_new (void) -{ - /* Use local storage to lex the first token because loading a PCH - file may cause garbage collection. */ - c_parser tparser; - c_parser *ret; - memset (&tparser, 0, sizeof tparser); - c_lex_one_token (&tparser.tokens[0]); - tparser.tokens_avail = 1; - ret = GGC_NEW (c_parser); - memcpy (ret, &tparser, sizeof tparser); - return ret; -} - /* Issue a diagnostic of the form FILE:LINE: MESSAGE before TOKEN where TOKEN is the next token in the input stream of PARSER. @@ -635,18 +665,18 @@ c_parser_new (void) used. */ static void -c_parser_error (c_parser *parser, const char *msgid) +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 (!msgid) + if (!gmsgid) return; /* This diagnostic makes more sense if it is tagged to the line of the token we just peeked at. */ c_parser_set_source_position_from_token (token); - c_parse_error (msgid, + c_parse_error (gmsgid, /* Because c_parse_error does not understand CPP_KEYWORD, keywords are treated like identifiers. */ @@ -723,9 +753,12 @@ c_parser_skip_until_found (c_parser *parser, c_parser_consume_token (parser); break; } + /* If we've run out of tokens, stop. */ if (token->type == CPP_EOF) return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; if (token->type == CPP_OPEN_BRACE || token->type == CPP_OPEN_PAREN || token->type == CPP_OPEN_SQUARE) @@ -760,6 +793,8 @@ c_parser_skip_to_end_of_parameter (c_parser *parser) /* If we've run out of tokens, stop. */ if (token->type == CPP_EOF) return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; if (token->type == CPP_OPEN_BRACE || token->type == CPP_OPEN_PAREN || token->type == CPP_OPEN_SQUARE) @@ -777,6 +812,32 @@ c_parser_skip_to_end_of_parameter (c_parser *parser) parser->error = false; } +/* Expect to be at the end of the pragma directive and consume an + end of line marker. */ + +static void +c_parser_skip_to_pragma_eol (c_parser *parser) +{ + gcc_assert (parser->in_pragma); + parser->in_pragma = false; + + if (!c_parser_require (parser, CPP_PRAGMA_EOL, "expected end of line")) + while (true) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF) + break; + if (token->type == CPP_PRAGMA_EOL) + { + c_parser_consume_token (parser); + break; + } + c_parser_consume_token (parser); + } + + parser->error = false; +} + /* Skip tokens until we have consumed an entire block, or until we have consumed a non-nested ';'. */ @@ -784,6 +845,7 @@ 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) { @@ -791,35 +853,67 @@ c_parser_skip_to_end_of_block_or_statement (c_parser *parser) /* Peek at the next token. */ token = c_parser_peek_token (parser); - /* If we've run out of tokens, stop. */ - if (token->type == CPP_EOF) - return; - /* If the next token is a ';', we have reached the end of the - statement. */ - if (token->type == CPP_SEMICOLON && !nesting_depth) + + switch (token->type) { - /* Consume the ';'. */ - c_parser_consume_token (parser); + case CPP_EOF: + return; + + case CPP_PRAGMA_EOL: + if (parser->in_pragma) + return; break; - } - /* If the next token is a non-nested '}', then we have reached - the end of the current block. */ - if (token->type == CPP_CLOSE_BRACE - && (nesting_depth == 0 || --nesting_depth == 0)) - { - c_parser_consume_token (parser); + + case CPP_SEMICOLON: + /* If the next token is a ';', we have reached the + end of the statement. */ + if (!nesting_depth) + { + /* Consume the ';'. */ + c_parser_consume_token (parser); + goto finished; + } + break; + + case CPP_CLOSE_BRACE: + /* If the next token is a non-nested '}', then we have + reached the end of the current block. */ + if (nesting_depth == 0 || --nesting_depth == 0) + { + c_parser_consume_token (parser); + goto finished; + } + break; + + case CPP_OPEN_BRACE: + /* If it the next token is a '{', then we are entering a new + block. Consume the entire block. */ + ++nesting_depth; + break; + + case CPP_PRAGMA: + /* If we see a pragma, consume the whole thing at once. We + have some safeguards against consuming pragmas willy-nilly. + Normally, we'd expect to be here with parser->error set, + which disables these safeguards. But it's possible to get + here for secondary error recovery, after parser->error has + been cleared. */ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + parser->error = save_error; + continue; + + default: break; } - /* If it the next token is a '{', then we are entering a new - block. Consume the entire block. */ - if (token->type == CPP_OPEN_BRACE) - ++nesting_depth; + c_parser_consume_token (parser); } + + finished: parser->error = false; } - /* Save the warning flags which are controlled by __extension__. */ static inline int @@ -904,7 +998,7 @@ static void c_parser_while_statement (c_parser *); static void c_parser_do_statement (c_parser *); static void c_parser_for_statement (c_parser *); static tree c_parser_asm_statement (c_parser *); -static tree c_parser_asm_operands (c_parser *); +static tree c_parser_asm_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 *, @@ -920,7 +1014,15 @@ static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *, 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 tree c_parser_expr_list (c_parser *); +static struct c_expr c_parser_expression_conv (c_parser *); +static tree c_parser_expr_list (c_parser *, bool); +static void c_parser_omp_construct (c_parser *); +static void c_parser_omp_threadprivate (c_parser *); +static void c_parser_omp_barrier (c_parser *); +static void c_parser_omp_flush (c_parser *); + +enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +static bool c_parser_pragma (c_parser *, enum pragma_context); /* These Objective-C parser functions are only ever called when compiling Objective-C. */ @@ -1053,6 +1155,9 @@ c_parser_external_declaration (c_parser *parser) 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 ()) @@ -1072,6 +1177,7 @@ c_parser_external_declaration (c_parser *parser) } } + /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 6.7, 6.9.1). If FNDEF_OK is true, a function definition is accepted; otherwise (old-style parameter declarations) only other @@ -1122,7 +1228,12 @@ c_parser_external_declaration (c_parser *parser) absence is diagnosed through the diagnosis of implicit int. In GNU C we also allow but diagnose declarations without declaration specifiers, but only at top level (elsewhere they conflict with - other syntax). */ + other syntax). + + OpenMP: + + declaration: + threadprivate-directive */ static void c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, @@ -1132,6 +1243,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, 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) @@ -1320,12 +1432,8 @@ static void c_parser_asm_definition (c_parser *parser) { tree asm_str = c_parser_simple_asm_expr (parser); - /* ??? This only works sensibly in the presence of - -fno-unit-at-a-time; file-scope asms really need to be passed to - cgraph which needs to preserve the order of functions and - file-scope asms. */ if (asm_str) - assemble_asm (asm_str); + cgraph_add_asm_node (asm_str); c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } @@ -1395,6 +1503,15 @@ c_parser_asm_definition (c_parser *parser) type-specifier: typeof-specifier + _Decimal32 + _Decimal64 + _Decimal128 + _Fract + _Accum + _Sat + + (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037: + http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf) Objective-C: @@ -1493,12 +1610,19 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, case RID_FLOAT: case RID_DOUBLE: case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: case RID_BOOL: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: if (!typespec_ok) goto out; attrs_ok = true; seen_type = true; - OBJC_NEED_RAW_IDENTIFIER (1); + if (c_dialect_objc ()) + parser->objc_need_raw_identifier = true; t.kind = ctsk_resword; t.spec = c_parser_peek_token (parser)->value; declspecs_add_type (specs, t); @@ -1583,6 +1707,8 @@ c_parser_enum_specifier (c_parser *parser) gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); c_parser_consume_token (parser); attrs = c_parser_attributes (parser); + /* Set the location in case we create a decl now. */ + c_parser_set_source_position_from_token (c_parser_peek_token (parser)); if (c_parser_next_token_is (parser, CPP_NAME)) { ident = c_parser_peek_token (parser)->value; @@ -1591,7 +1717,8 @@ c_parser_enum_specifier (c_parser *parser) if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { /* Parse an enum definition. */ - tree type = start_enum (ident); + struct c_enum_contents the_enum; + tree type = start_enum (&the_enum, ident); tree postfix_attrs; /* We chain the enumerators in reverse order, then put them in forward order at the end. */ @@ -1603,6 +1730,7 @@ c_parser_enum_specifier (c_parser *parser) tree enum_value; tree enum_decl; bool seen_comma; + c_token *token; if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); @@ -1610,7 +1738,10 @@ c_parser_enum_specifier (c_parser *parser) values = error_mark_node; break; } - enum_id = c_parser_peek_token (parser)->value; + token = c_parser_peek_token (parser); + enum_id = token->value; + /* Set the location in case we create a decl now. */ + c_parser_set_source_position_from_token (token); c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_EQ)) { @@ -1619,7 +1750,7 @@ c_parser_enum_specifier (c_parser *parser) } else enum_value = NULL_TREE; - enum_decl = build_enumerator (enum_id, enum_value); + enum_decl = build_enumerator (&the_enum, enum_id, enum_value); TREE_CHAIN (enum_decl) = values; values = enum_decl; seen_comma = false; @@ -1723,6 +1854,8 @@ c_parser_struct_or_union_specifier (c_parser *parser) } c_parser_consume_token (parser); attrs = c_parser_attributes (parser); + /* Set the location in case we create a decl now. */ + c_parser_set_source_position_from_token (c_parser_peek_token (parser)); if (c_parser_next_token_is (parser, CPP_NAME)) { ident = c_parser_peek_token (parser)->value; @@ -1792,6 +1925,12 @@ c_parser_struct_or_union_specifier (c_parser *parser) c_parser_consume_token (parser); break; } + /* Accept #pragmas at struct scope. */ + if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + c_parser_pragma (parser, pragma_external); + continue; + } /* Parse some comma-separated declarations, but not the trailing semicolon if any. */ decls = c_parser_struct_declaration (parser); @@ -1903,7 +2042,11 @@ c_parser_struct_declaration (c_parser *parser) /* Support for unnamed structs or unions as members of structs or unions (which is [a] useful and [b] supports MS P-SDK). */ - ret = grokfield (build_id_declarator (NULL_TREE), specs, NULL_TREE); + tree attrs = NULL; + ret = grokfield (build_id_declarator (NULL_TREE), specs, + NULL_TREE, &attrs); + if (ret) + decl_attributes (&ret, attrs, 0); } return ret; } @@ -1943,7 +2086,7 @@ c_parser_struct_declaration (c_parser *parser) } if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) postfix_attrs = c_parser_attributes (parser); - d = grokfield (declarator, specs, width); + d = grokfield (declarator, specs, width, &all_prefix_attrs); decl_attributes (&d, chainon (postfix_attrs, all_prefix_attrs), 0); TREE_CHAIN (d) = decls; @@ -2014,6 +2157,7 @@ c_parser_typeof_specifier (c_parser *parser) } else { + bool was_vm; struct c_expr expr = c_parser_expression (parser); skip_evaluation--; in_typeof--; @@ -2021,7 +2165,25 @@ c_parser_typeof_specifier (c_parser *parser) && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) error ("% applied to a bit-field"); ret.spec = TREE_TYPE (expr.value); - pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE)); + was_vm = variably_modified_type_p (ret.spec, NULL_TREE); + /* This should be returned with the type so that when the type + is evaluated, this can be evaluated. For now, we avoid + evaluation when the context might. */ + if (!skip_evaluation && was_vm) + { + tree e = expr.value; + + /* If the expression is not of a type to which we cannot assign a line + number, wrap the thing in a no-op NOP_EXPR. */ + if (DECL_P (e) || CONSTANT_CLASS_P (e)) + e = build1 (NOP_EXPR, void_type_node, e); + + if (CAN_HAVE_LOCATION_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; @@ -2088,7 +2250,7 @@ c_parser_typeof_specifier (c_parser *parser) parameter-type-list[opt] ) direct-abstract-declarator: - direct-abstract-declarator[opt] ( parameter-forward-declarations + direct-abstract-declarator[opt] ( parameter-forward-declarations parameter-type-list[opt] ) parameter-forward-declarations: @@ -2317,6 +2479,8 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present, } 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); } @@ -2379,6 +2543,8 @@ c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs) 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; @@ -2420,6 +2586,8 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) 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; } @@ -2429,6 +2597,8 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) ret->parms = 0; ret->tags = 0; ret->others = 0; + ret->pending_sizes = 0; + ret->had_vla_unspec = 0; /* Suppress -Wold-style-definition for this case. */ ret->types = error_mark_node; error ("ISO C requires a named argument before %<...%>"); @@ -2462,6 +2632,7 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) { 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); } @@ -2478,6 +2649,8 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) ret->tags = 0; ret->types = 0; ret->others = 0; + ret->pending_sizes = 0; + ret->had_vla_unspec = 0; return ret; } } @@ -2503,6 +2676,8 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs) ret->tags = 0; ret->types = 0; ret->others = 0; + ret->pending_sizes = 0; + ret->had_vla_unspec = 0; return ret; } } @@ -2568,8 +2743,8 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs) string-literal ??? At present, following the old parser, the caller needs to have - set c_lex_string_translate to 0. It would be better to follow the - C++ parser rather than using the c_lex_string_translate kludge. */ + set lex_untranslated_string to 1. It would be better to follow the + C++ parser rather than using this kludge. */ static tree c_parser_asm_string_literal (c_parser *parser) @@ -2608,16 +2783,16 @@ c_parser_simple_asm_expr (c_parser *parser) tree str; gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); /* ??? Follow the C++ parser rather than using the - c_lex_string_translate kludge. */ - c_lex_string_translate = 0; + lex_untranslated_string kludge. */ + parser->lex_untranslated_string = true; c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; return NULL_TREE; } str = c_parser_asm_string_literal (parser); - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); @@ -2660,17 +2835,17 @@ c_parser_attributes (c_parser *parser) while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) { /* ??? Follow the C++ parser rather than using the - c_lex_string_translate kludge. */ - c_lex_string_translate = 0; + lex_untranslated_string kludge. */ + parser->lex_untranslated_string = true; c_parser_consume_token (parser); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; return attrs; } if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return attrs; } @@ -2712,7 +2887,13 @@ c_parser_attributes (c_parser *parser) case RID_FLOAT: case RID_DOUBLE: case RID_VOID: + case RID_DFLOAT32: + case RID_DFLOAT64: + case RID_DFLOAT128: case RID_BOOL: + case RID_FRACT: + case RID_ACCUM: + case RID_SAT: ok = true; break; default: @@ -2749,7 +2930,7 @@ c_parser_attributes (c_parser *parser) { c_parser_consume_token (parser); attr_args = tree_cons (NULL_TREE, arg1, - c_parser_expr_list (parser)); + c_parser_expr_list (parser, false)); } } else @@ -2757,14 +2938,14 @@ c_parser_attributes (c_parser *parser) if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) attr_args = NULL_TREE; else - attr_args = c_parser_expr_list (parser); + 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; + parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return attrs; @@ -2775,7 +2956,7 @@ c_parser_attributes (c_parser *parser) c_parser_consume_token (parser); else { - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return attrs; @@ -2784,12 +2965,12 @@ c_parser_attributes (c_parser *parser) c_parser_consume_token (parser); else { - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return attrs; } - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; } return attrs; } @@ -2874,7 +3055,14 @@ 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 - return c_parser_expr_no_commas (parser, NULL); + { + struct c_expr ret; + ret = c_parser_expr_no_commas (parser, NULL); + if (TREE_CODE (ret.value) != STRING_CST + && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR) + ret = default_function_array_conversion (ret); + return ret; + } } /* Parse a braced initializer list. TYPE is the type specified for a @@ -3028,10 +3216,11 @@ c_parser_initelt (c_parser *parser) rec = first; while (c_parser_next_token_is (parser, CPP_COMMA)) { - tree next; + struct c_expr next; c_parser_consume_token (parser); - next = c_parser_expr_no_commas (parser, NULL).value; - rec = build_compound_expr (rec, next); + next = c_parser_expr_no_commas (parser, NULL); + next = default_function_array_conversion (next); + rec = build_compound_expr (rec, next.value); } parse_message_args: /* Now parse the objc-message-args. */ @@ -3116,7 +3305,13 @@ c_parser_initval (c_parser *parser, struct c_expr *after) 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); + { + 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); } @@ -3162,7 +3357,16 @@ c_parser_initval (c_parser *parser, struct c_expr *after) prefix attributes on the declaration. ??? The syntax follows the old parser in requiring something after label declarations. Although they are erroneous if the labels declared aren't defined, - is it useful for the syntax to be this way? */ + is it useful for the syntax to be this way? + + OpenMP: + + block-item: + openmp-directive + + openmp-directive: + barrier-directive + flush-directive */ static tree c_parser_compound_statement (c_parser *parser) @@ -3234,11 +3438,6 @@ c_parser_compound_statement_nostart (c_parser *parser) 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 (parser, CPP_EOF)) - { - c_parser_error (parser, "expected declaration or statement"); - return; - } 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) @@ -3291,6 +3490,21 @@ c_parser_compound_statement_nostart (c_parser *parser) else goto statement; } + else if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + /* External pragmas, and some omp pragmas, are not associated + with regular c code, and so are not to be considered statements + syntactically. This ensures that the user doesn't put them + places that would turn into syntax errors if the directive + were ignored. */ + if (c_parser_pragma (parser, pragma_compound)) + last_label = false, last_stmt = true; + } + else if (c_parser_next_token_is (parser, CPP_EOF)) + { + c_parser_error (parser, "expected declaration or statement"); + return; + } else { statement: @@ -3298,6 +3512,8 @@ c_parser_compound_statement_nostart (c_parser *parser) last_stmt = true; c_parser_statement_after_labels (parser); } + + parser->error = false; } if (last_label) error ("label at end of compound statement"); @@ -3423,7 +3639,53 @@ c_parser_label (c_parser *parser) objc-throw-statement: @throw expression ; @throw ; -*/ + + OpenMP: + + statement: + openmp-construct + + openmp-construct: + parallel-construct + for-construct + sections-construct + single-construct + parallel-for-construct + parallel-sections-construct + master-construct + critical-construct + atomic-construct + ordered-construct + + parallel-construct: + parallel-directive structured-block + + for-construct: + for-directive iteration-statement + + sections-construct: + sections-directive section-scope + + single-construct: + single-directive structured-block + + parallel-for-construct: + parallel-for-directive iteration-statement + + parallel-sections-construct: + parallel-sections-directive section-scope + + master-construct: + master-directive structured-block + + critical-construct: + critical-directive structured-block + + atomic-construct: + atomic-directive expression-statement + + ordered-construct: + ordered-directive structured-block */ static void c_parser_statement (c_parser *parser) @@ -3498,7 +3760,7 @@ c_parser_statement_after_labels (c_parser *parser) } else { - stmt = c_finish_return (c_parser_expression (parser).value); + stmt = c_finish_return (c_parser_expression_conv (parser).value); goto expect_semicolon; } break; @@ -3544,9 +3806,12 @@ c_parser_statement_after_labels (c_parser *parser) c_parser_error (parser, "expected statement"); c_parser_consume_token (parser); break; + case CPP_PRAGMA: + c_parser_pragma (parser, pragma_stmt); + break; default: expr_stmt: - stmt = c_finish_expr_stmt (c_parser_expression (parser).value); + stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value); expect_semicolon: c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); break; @@ -3561,7 +3826,7 @@ c_parser_statement_after_labels (c_parser *parser) (recursively) all of the component statements should already have line numbers assigned. ??? Can we discard no-op statements earlier? */ - if (stmt && EXPR_P (stmt)) + if (stmt && CAN_HAVE_LOCATION_P (stmt)) SET_EXPR_LOCATION (stmt, loc); } @@ -3579,8 +3844,8 @@ c_parser_paren_condition (c_parser *parser) return error_mark_node; loc = c_parser_peek_token (parser)->location; cond = c_objc_common_truthvalue_conversion - (c_parser_expression (parser).value); - if (EXPR_P (cond)) + (c_parser_expression_conv (parser).value); + if (CAN_HAVE_LOCATION_P (cond)) SET_EXPR_LOCATION (cond, loc); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return cond; @@ -3600,7 +3865,7 @@ c_parser_c99_block_statement (c_parser *parser) is just parsing a statement but (a) it is a block in C99, (b) we track whether the body is an if statement for the sake of -Wparentheses warnings, (c) we handle an empty body specially for - the sake of -Wextra warnings. */ + the sake of -Wempty-body warnings. */ static tree c_parser_if_body (c_parser *parser, bool *if_p) @@ -3612,8 +3877,8 @@ c_parser_if_body (c_parser *parser, bool *if_p) && 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 (extra_warnings && c_parser_next_token_is (parser, CPP_SEMICOLON)) - add_stmt (build (NOP_EXPR, NULL_TREE, NULL_TREE)); + 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); } @@ -3676,7 +3941,7 @@ c_parser_switch_statement (c_parser *parser) body = c_parser_c99_block_statement (parser); c_finish_case (body); if (c_break_label) - add_stmt (build (LABEL_EXPR, void_type_node, 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)); } @@ -3721,6 +3986,9 @@ c_parser_do_statement (c_parser *parser) location_t loc; gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO)); c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + warning (OPT_Wempty_body, + "suggest braces around empty body in % statement"); block = c_begin_compound_stmt (flag_isoc99); loc = c_parser_peek_token (parser)->location; save_break = c_break_label; @@ -3760,8 +4028,9 @@ static void c_parser_for_statement (c_parser *parser) { tree block, cond, incr, save_break, save_cont, body; - location_t loc = UNKNOWN_LOCATION; + location_t loc; gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); + loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); block = c_begin_compound_stmt (flag_isoc99); if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) @@ -3814,9 +4083,9 @@ c_parser_for_statement (c_parser *parser) } else { - tree ocond = c_parser_expression (parser).value; + tree ocond = c_parser_expression_conv (parser).value; cond = c_objc_common_truthvalue_conversion (ocond); - if (EXPR_P (cond)) + if (CAN_HAVE_LOCATION_P (cond)) SET_EXPR_LOCATION (cond, loc); c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } @@ -3882,11 +4151,11 @@ c_parser_asm_statement (c_parser *parser) else quals = NULL_TREE; /* ??? Follow the C++ parser rather than using the - c_lex_string_translate kludge. */ - c_lex_string_translate = 0; + lex_untranslated_string kludge. */ + parser->lex_untranslated_string = true; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; return NULL_TREE; } str = c_parser_asm_string_literal (parser); @@ -3900,7 +4169,7 @@ c_parser_asm_statement (c_parser *parser) } if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")) { - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return NULL_TREE; } @@ -3910,7 +4179,7 @@ c_parser_asm_statement (c_parser *parser) || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) outputs = NULL_TREE; else - outputs = c_parser_asm_operands (parser); + outputs = c_parser_asm_operands (parser, false); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { inputs = NULL_TREE; @@ -3919,7 +4188,7 @@ c_parser_asm_statement (c_parser *parser) } if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")) { - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return NULL_TREE; } @@ -3928,7 +4197,7 @@ c_parser_asm_statement (c_parser *parser) || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) inputs = NULL_TREE; else - inputs = c_parser_asm_operands (parser); + inputs = c_parser_asm_operands (parser, true); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { clobbers = NULL_TREE; @@ -3936,14 +4205,14 @@ c_parser_asm_statement (c_parser *parser) } if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")) { - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return NULL_TREE; } /* Parse clobbers. */ clobbers = c_parser_asm_clobbers (parser); done_asm: - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); @@ -3956,7 +4225,9 @@ c_parser_asm_statement (c_parser *parser) return ret; } -/* Parse asm operands, a GNU extension. +/* Parse asm operands, a GNU extension. If CONVERT_P (for inputs but + not outputs), apply the default conversion of functions and arrays + to pointers. asm-operands: asm-operand @@ -3968,12 +4239,13 @@ c_parser_asm_statement (c_parser *parser) */ static tree -c_parser_asm_operands (c_parser *parser) +c_parser_asm_operands (c_parser *parser, bool convert_p) { tree list = NULL_TREE; while (true) { - tree name, str, expr; + tree name, str; + struct c_expr expr; if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) { c_parser_consume_token (parser); @@ -3998,21 +4270,23 @@ c_parser_asm_operands (c_parser *parser) str = c_parser_asm_string_literal (parser); if (str == NULL_TREE) return NULL_TREE; - c_lex_string_translate = 1; + parser->lex_untranslated_string = false; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - c_lex_string_translate = 0; + parser->lex_untranslated_string = true; return NULL_TREE; } - expr = c_parser_expression (parser).value; - c_lex_string_translate = 0; + expr = c_parser_expression (parser); + if (convert_p) + expr = default_function_array_conversion (expr); + parser->lex_untranslated_string = true; if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return NULL_TREE; } list = chainon (list, build_tree_list (build_tree_list (name, str), - expr)); + expr.value)); if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); else @@ -4110,6 +4384,7 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) } 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; @@ -4143,6 +4418,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) 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)) { @@ -4159,7 +4435,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) = c_objc_common_truthvalue_conversion (default_conversion (cond.value)); skip_evaluation += cond.value == truthvalue_false_node; - exp1 = c_parser_expression (parser); + exp1 = c_parser_expression_conv (parser); skip_evaluation += ((cond.value == truthvalue_true_node) - (cond.value == truthvalue_false_node)); } @@ -4171,6 +4447,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) 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; @@ -4294,6 +4571,10 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) 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); \ @@ -4394,11 +4675,15 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after) 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; @@ -4442,7 +4727,7 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) { struct c_type_name *type_name; struct c_expr ret; - tree expr; + 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 %<)%>"); @@ -4452,11 +4737,16 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) ret.original_code = ERROR_MARK; return ret; } + + /* Save casted types in the function's used types hash table. */ + used_types_insert (type_name->specs->type); + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) return c_parser_postfix_expression_after_paren_type (parser, type_name); - expr = c_parser_cast_expression (parser, NULL).value; - ret.value = c_cast_expr (type_name, expr); + 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; } @@ -4495,26 +4785,28 @@ static struct c_expr c_parser_unary_expression (c_parser *parser) { int ext; - struct c_expr ret; + struct c_expr ret, op; switch (c_parser_peek_token (parser)->type) { case CPP_PLUS_PLUS: c_parser_consume_token (parser); - return parser_build_unary_op (PREINCREMENT_EXPR, - c_parser_cast_expression (parser, NULL)); + 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); - return parser_build_unary_op (PREDECREMENT_EXPR, - c_parser_cast_expression (parser, NULL)); + 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); - ret.value - = build_indirect_ref (c_parser_cast_expression (parser, NULL).value, - "unary *"); + 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: @@ -4522,20 +4814,24 @@ c_parser_unary_expression (c_parser *parser) if (!c_dialect_objc () && !in_system_header) warning (OPT_Wtraditional, "traditional C rejects the unary plus operator"); - return parser_build_unary_op (CONVERT_EXPR, - c_parser_cast_expression (parser, NULL)); + 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); - return parser_build_unary_op (NEGATE_EXPR, - c_parser_cast_expression (parser, NULL)); + 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); - return parser_build_unary_op (BIT_NOT_EXPR, - c_parser_cast_expression (parser, NULL)); + 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); - return parser_build_unary_op (TRUTH_NOT_EXPR, - c_parser_cast_expression (parser, NULL)); + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_conversion (op); + return parser_build_unary_op (TRUTH_NOT_EXPR, op); case CPP_AND_AND: /* Refer to the address of a label as a pointer. */ c_parser_consume_token (parser); @@ -4567,14 +4863,14 @@ c_parser_unary_expression (c_parser *parser) return ret; case RID_REALPART: c_parser_consume_token (parser); - return parser_build_unary_op (REALPART_EXPR, - c_parser_cast_expression (parser, - NULL)); + 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); - return parser_build_unary_op (IMAGPART_EXPR, - c_parser_cast_expression (parser, - NULL)); + 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); } @@ -4620,6 +4916,12 @@ c_parser_sizeof_expression (c_parser *parser) /* sizeof ( type-name ). */ skip_evaluation--; in_sizeof--; + if (type_name->declarator->kind == cdk_array + && type_name->declarator->u.array.vla_unspec_p) + { + /* C99 6.7.5.2p4 */ + error ("%<[*]%> not allowed in other than a declaration"); + } return c_expr_sizeof_type (type_name); } else @@ -4918,7 +5220,7 @@ c_parser_postfix_expression (c_parser *parser) if (type == error_mark_node) offsetof_ref = error_mark_node; else - offsetof_ref = build1 (INDIRECT_REF, type, NULL); + offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node); /* Parse the second argument to __builtin_offsetof. We must have one identifier, and beyond that we want to accept sub structure and sub array references. */ @@ -4960,7 +5262,7 @@ c_parser_postfix_expression (c_parser *parser) c_parser_error (parser, "expected identifier"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - expr.value = fold_offsetof (offsetof_ref); + expr.value = fold_offsetof (offsetof_ref, NULL_TREE); expr.original_code = ERROR_MARK; } break; @@ -5161,7 +5463,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, struct c_expr expr; start_init (NULL_TREE, NULL, 0); type = groktypename (type_name); - if (C_TYPE_VARIABLE_SIZE (type)) + if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) { error ("compound literal has variable size"); type = error_mark_node; @@ -5204,7 +5506,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) exprlist = NULL_TREE; else - exprlist = c_parser_expr_list (parser); + 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); @@ -5213,6 +5515,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, case CPP_DOT: /* Structure element reference. */ c_parser_consume_token (parser); + expr = default_function_array_conversion (expr); if (c_parser_next_token_is (parser, CPP_NAME)) ident = c_parser_peek_token (parser)->value; else @@ -5229,6 +5532,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, case CPP_DEREF: /* Structure element reference. */ c_parser_consume_token (parser); + expr = default_function_array_conversion (expr); if (c_parser_next_token_is (parser, CPP_NAME)) ident = c_parser_peek_token (parser)->value; else @@ -5246,12 +5550,14 @@ c_parser_postfix_expression_after_primary (c_parser *parser, case CPP_PLUS_PLUS: /* Postincrement. */ c_parser_consume_token (parser); + expr = default_function_array_conversion (expr); expr.value = build_unary_op (POSTINCREMENT_EXPR, expr.value, 0); expr.original_code = ERROR_MARK; break; case CPP_MINUS_MINUS: /* Postdecrement. */ c_parser_consume_token (parser); + expr = default_function_array_conversion (expr); expr.value = build_unary_op (POSTDECREMENT_EXPR, expr.value, 0); expr.original_code = ERROR_MARK; break; @@ -5278,13 +5584,27 @@ c_parser_expression (c_parser *parser) struct c_expr next; c_parser_consume_token (parser); next = c_parser_expr_no_commas (parser, NULL); + next = default_function_array_conversion (next); expr.value = build_compound_expr (expr.value, next.value); expr.original_code = COMPOUND_EXPR; } return expr; } -/* Parse a non-empty list of expressions. +/* Parse an expression and convert functions or arrays to + pointers. */ + +static struct c_expr +c_parser_expression_conv (c_parser *parser) +{ + struct c_expr expr; + expr = c_parser_expression (parser); + expr = default_function_array_conversion (expr); + return expr; +} + +/* Parse a non-empty list of expressions. If CONVERT_P, convert + functions and arrays to pointers. nonempty-expr-list: assignment-expression @@ -5292,16 +5612,20 @@ c_parser_expression (c_parser *parser) */ static tree -c_parser_expr_list (c_parser *parser) +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; @@ -5478,6 +5802,12 @@ c_parser_objc_class_instance_variables (c_parser *parser) objc_set_visibility (1); continue; } + else if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + c_parser_pragma (parser, pragma_external); + continue; + } + /* Parse some comma-separated declarations. */ decls = c_parser_struct_declaration (parser); { @@ -5610,11 +5940,11 @@ c_parser_objc_protocol_definition (c_parser *parser) 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; + parser->objc_pq_context = true; objc_start_protocol (id, proto); c_parser_objc_methodprotolist (parser); c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>"); - objc_pq_context = 0; + parser->objc_pq_context = false; objc_finish_interface (); } } @@ -5654,7 +5984,7 @@ 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; + parser->objc_pq_context = true; decl = c_parser_objc_method_decl (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { @@ -5662,7 +5992,12 @@ c_parser_objc_method_definition (c_parser *parser) if (pedantic) pedwarn ("extra semicolon in method definition specified"); } - objc_pq_context = 0; + if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + c_parser_error (parser, "expected %<{%>"); + return; + } + parser->objc_pq_context = false; objc_start_method_definition (decl); add_stmt (c_parser_compound_statement (parser)); objc_finish_method_definition (current_function_decl); @@ -5699,6 +6034,9 @@ c_parser_objc_methodprotolist (c_parser *parser) case CPP_MINUS: c_parser_objc_methodproto (parser); break; + case CPP_PRAGMA: + c_parser_pragma (parser, pragma_external); + break; case CPP_EOF: return; default: @@ -5723,10 +6061,10 @@ c_parser_objc_methodproto (c_parser *parser) tree decl; objc_set_method_type (type); /* Remember protocol qualifiers in prototypes. */ - objc_pq_context = 1; + parser->objc_pq_context = true; decl = c_parser_objc_method_decl (parser); /* Forget protocol qualifiers here. */ - objc_pq_context = 0; + parser->objc_pq_context = false; objc_add_method_declaration (decl); c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } @@ -6162,7 +6500,7 @@ c_parser_objc_message_args (c_parser *parser) static tree c_parser_objc_keywordexpr (c_parser *parser) { - tree list = c_parser_expr_list (parser); + tree list = c_parser_expr_list (parser, true); if (TREE_CHAIN (list) == NULL_TREE) { /* Just return the expression, remove a level of @@ -6177,17 +6515,1361 @@ c_parser_objc_keywordexpr (c_parser *parser) } -/* The actual parser and external interface. ??? Does this need to be - garbage-collected? */ +/* Handle pragmas. Some OpenMP pragmas are associated with, and therefore + should be considered, statements. ALLOW_STMT is true if we're within + the context of a function and such pragmas are to be allowed. Returns + true if we actually parsed such a pragma. */ -static GTY (()) c_parser *the_parser; +static bool +c_parser_pragma (c_parser *parser, enum pragma_context context) +{ + unsigned int id; -/* Parse a single source file. */ + id = c_parser_peek_token (parser)->pragma_kind; + gcc_assert (id != PRAGMA_NONE); -void -c_parse_file (void) + switch (id) + { + case PRAGMA_OMP_BARRIER: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp barrier%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_barrier (parser); + return false; + + case PRAGMA_OMP_FLUSH: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp flush%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_flush (parser); + return false; + + case PRAGMA_OMP_THREADPRIVATE: + c_parser_omp_threadprivate (parser); + return false; + + case PRAGMA_OMP_SECTION: + error ("%<#pragma omp section%> may only be used in " + "%<#pragma omp sections%> construct"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + + case PRAGMA_GCC_PCH_PREPROCESS: + c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + + default: + if (id < PRAGMA_FIRST_EXTERNAL) + { + if (context == pragma_external) + { + bad_stmt: + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + c_parser_omp_construct (parser); + return true; + } + break; + } + + c_parser_consume_pragma (parser); + c_invoke_pragma_handler (id); + + /* Skip to EOL, but suppress any error message. Those will have been + generated by the handler routine through calling error, as opposed + to calling c_parser_error. */ + parser->error = true; + c_parser_skip_to_pragma_eol (parser); + + return false; +} + +/* The interface the pragma parsers have to the lexer. */ + +enum cpp_ttype +pragma_lex (tree *value) +{ + c_token *tok = c_parser_peek_token (the_parser); + enum cpp_ttype ret = tok->type; + + *value = tok->value; + if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) + ret = CPP_EOF; + else + { + if (ret == CPP_KEYWORD) + ret = CPP_NAME; + c_parser_consume_token (the_parser); + } + + return ret; +} + +static void +c_parser_pragma_pch_preprocess (c_parser *parser) +{ + tree name = NULL; + + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_STRING)) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + c_parser_error (parser, "expected string literal"); + c_parser_skip_to_pragma_eol (parser); + + if (name) + c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); +} + +/* OpenMP 2.5 parsing routines. */ + +/* Returns name of the next clause. + If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and + the token is not consumed. Otherwise appropriate pragma_omp_clause is + returned and the token is consumed. */ + +static pragma_omp_clause +c_parser_omp_clause_name (c_parser *parser) +{ + pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; + + if (c_parser_next_token_is_keyword (parser, RID_IF)) + result = PRAGMA_OMP_CLAUSE_IF; + else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) + result = PRAGMA_OMP_CLAUSE_DEFAULT; + else if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + switch (p[0]) + { + case 'c': + if (!strcmp ("copyin", p)) + result = PRAGMA_OMP_CLAUSE_COPYIN; + else if (!strcmp ("copyprivate", p)) + result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; + break; + case 'f': + if (!strcmp ("firstprivate", p)) + result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + break; + case 'l': + if (!strcmp ("lastprivate", p)) + result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + break; + case 'n': + if (!strcmp ("nowait", p)) + result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_threads", p)) + result = PRAGMA_OMP_CLAUSE_NUM_THREADS; + break; + case 'o': + if (!strcmp ("ordered", p)) + result = PRAGMA_OMP_CLAUSE_ORDERED; + break; + case 'p': + if (!strcmp ("private", p)) + result = PRAGMA_OMP_CLAUSE_PRIVATE; + break; + case 'r': + if (!strcmp ("reduction", p)) + result = PRAGMA_OMP_CLAUSE_REDUCTION; + break; + case 's': + if (!strcmp ("schedule", p)) + result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("shared", p)) + result = PRAGMA_OMP_CLAUSE_SHARED; + break; + } + } + + if (result != PRAGMA_OMP_CLAUSE_NONE) + c_parser_consume_token (parser); + + return result; +} + +/* Validate that a clause of the given type does not already exist. */ + +static void +check_no_duplicate_clause (tree clauses, enum tree_code code, const char *name) { - the_parser = c_parser_new (); + tree c; + + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == code) + { + error ("too many %qs clauses", name); + break; + } +} + +/* OpenMP 2.5: + variable-list: + identifier + variable-list , identifier + + If KIND is nonzero, create the appropriate node and install the decl + in OMP_CLAUSE_DECL and add the node to the head of the list. + + If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; + return the list created. */ + +static tree +c_parser_omp_variable_list (c_parser *parser, enum omp_clause_code kind, + tree list) +{ + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + c_parser_error (parser, "expected identifier"); + + while (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + tree t = lookup_name (c_parser_peek_token (parser)->value); + + if (t == NULL_TREE) + undeclared_variable (c_parser_peek_token (parser)->value, + c_parser_peek_token (parser)->location); + else if (t == error_mark_node) + ; + else if (kind != 0) + { + tree u = build_omp_clause (kind); + OMP_CLAUSE_DECL (u) = t; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } + else + list = tree_cons (t, NULL_TREE, list); + + c_parser_consume_token (parser); + + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + + c_parser_consume_token (parser); + } + + return list; +} + +/* Similarly, but expect leading and trailing parenthesis. This is a very + common case for omp clauses. */ + +static tree +c_parser_omp_var_list_parens (c_parser *parser, enum tree_code kind, tree list) +{ + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + list = c_parser_omp_variable_list (parser, kind, list); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + return list; +} + +/* OpenMP 2.5: + copyin ( variable-list ) */ + +static tree +c_parser_omp_clause_copyin (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list); +} + +/* OpenMP 2.5: + copyprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_copyprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list); +} + +/* OpenMP 2.5: + default ( shared | none ) */ + +static tree +c_parser_omp_clause_default (c_parser *parser, tree list) +{ + enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; + tree c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + switch (p[0]) + { + case 'n': + if (strcmp ("none", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_NONE; + break; + + case 's': + if (strcmp ("shared", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_SHARED; + break; + + default: + goto invalid_kind; + } + + c_parser_consume_token (parser); + } + else + { + invalid_kind: + c_parser_error (parser, "expected % or %"); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default"); + c = build_omp_clause (OMP_CLAUSE_DEFAULT); + OMP_CLAUSE_CHAIN (c) = list; + OMP_CLAUSE_DEFAULT_KIND (c) = kind; + + return c; +} + +/* OpenMP 2.5: + firstprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_firstprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list); +} + +/* OpenMP 2.5: + if ( expression ) */ + +static tree +c_parser_omp_clause_if (c_parser *parser, tree list) +{ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + tree t = c_parser_paren_condition (parser); + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if"); + + c = build_omp_clause (OMP_CLAUSE_IF); + OMP_CLAUSE_IF_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + else + c_parser_error (parser, "expected %<(%>"); + + return list; +} + +/* OpenMP 2.5: + lastprivate ( variable-list ) */ + +static tree +c_parser_omp_clause_lastprivate (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list); +} + +/* OpenMP 2.5: + nowait */ + +static tree +c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait"); + + c = build_omp_clause (OMP_CLAUSE_NOWAIT); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + num_threads ( expression ) */ + +static tree +c_parser_omp_clause_num_threads (c_parser *parser, tree list) +{ + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + tree c, t = c_parser_expression (parser).value; + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2 (LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (c == boolean_true_node) + { + warning (0, "% value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads"); + + c = build_omp_clause (OMP_CLAUSE_NUM_THREADS); + OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 2.5: + ordered */ + +static tree +c_parser_omp_clause_ordered (c_parser *parser ATTRIBUTE_UNUSED, tree list) +{ + tree c; + + check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered"); + + c = build_omp_clause (OMP_CLAUSE_ORDERED); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 2.5: + private ( variable-list ) */ + +static tree +c_parser_omp_clause_private (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list); +} + +/* OpenMP 2.5: + reduction ( reduction-operator : variable-list ) + + reduction-operator: + One of: + * - & ^ | && || */ + +static tree +c_parser_omp_clause_reduction (c_parser *parser, tree list) +{ + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + enum tree_code code; + + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + code = PLUS_EXPR; + break; + case CPP_MULT: + code = MULT_EXPR; + break; + case CPP_MINUS: + code = MINUS_EXPR; + break; + case CPP_AND: + code = BIT_AND_EXPR; + break; + case CPP_XOR: + code = BIT_XOR_EXPR; + break; + case CPP_OR: + code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + code = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + code = TRUTH_ORIF_EXPR; + break; + default: + c_parser_error (parser, + "expected %<+%>, %<*%>, %<-%>, %<&%>, " + "%<^%>, %<|%>, %<&&%>, or %<||%>"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); + return list; + } + c_parser_consume_token (parser); + if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) + { + tree nl, c; + + nl = c_parser_omp_variable_list (parser, OMP_CLAUSE_REDUCTION, list); + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_REDUCTION_CODE (c) = code; + + list = nl; + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + return list; +} + +/* OpenMP 2.5: + schedule ( schedule-kind ) + schedule ( schedule-kind , expression ) + + schedule-kind: + static | dynamic | guided | runtime +*/ + +static tree +c_parser_omp_clause_schedule (c_parser *parser, tree list) +{ + tree c, t; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + c = build_omp_clause (OMP_CLAUSE_SCHEDULE); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree kind = c_parser_peek_token (parser)->value; + const char *p = IDENTIFIER_POINTER (kind); + + switch (p[0]) + { + case 'd': + if (strcmp ("dynamic", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC; + break; + + case 'g': + if (strcmp ("guided", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED; + break; + + case 'r': + if (strcmp ("runtime", p) != 0) + goto invalid_kind; + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME; + break; + + default: + goto invalid_kind; + } + } + else if (c_parser_next_token_is_keyword (parser, RID_STATIC)) + OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; + else + goto invalid_kind; + + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + + t = c_parser_expr_no_commas (parser, NULL).value; + + if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) + error ("schedule % does not take " + "a % parameter"); + else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE) + OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; + else + c_parser_error (parser, "expected integer expression"); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<,%> or %<)%>"); + + check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule"); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + c_parser_error (parser, "invalid schedule kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0); + return list; +} + +/* OpenMP 2.5: + shared ( variable-list ) */ + +static tree +c_parser_omp_clause_shared (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list); +} + +/* Parse all OpenMP clauses. The set clauses allowed by the directive + is a bitmask in MASK. Return the list of clauses found; the result + of clause default goes in *pdefault. */ + +static tree +c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, + const char *where) +{ + tree clauses = NULL; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + const pragma_omp_clause c_kind = c_parser_omp_clause_name (parser); + const char *c_name; + tree prev = clauses; + + switch (c_kind) + { + case PRAGMA_OMP_CLAUSE_COPYIN: + clauses = c_parser_omp_clause_copyin (parser, clauses); + c_name = "copyin"; + break; + case PRAGMA_OMP_CLAUSE_COPYPRIVATE: + clauses = c_parser_omp_clause_copyprivate (parser, clauses); + c_name = "copyprivate"; + break; + case PRAGMA_OMP_CLAUSE_DEFAULT: + clauses = c_parser_omp_clause_default (parser, clauses); + c_name = "default"; + break; + case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + c_name = "firstprivate"; + break; + case PRAGMA_OMP_CLAUSE_IF: + clauses = c_parser_omp_clause_if (parser, clauses); + c_name = "if"; + break; + case PRAGMA_OMP_CLAUSE_LASTPRIVATE: + clauses = c_parser_omp_clause_lastprivate (parser, clauses); + c_name = "lastprivate"; + break; + case PRAGMA_OMP_CLAUSE_NOWAIT: + clauses = c_parser_omp_clause_nowait (parser, clauses); + c_name = "nowait"; + break; + case PRAGMA_OMP_CLAUSE_NUM_THREADS: + clauses = c_parser_omp_clause_num_threads (parser, clauses); + c_name = "num_threads"; + break; + case PRAGMA_OMP_CLAUSE_ORDERED: + clauses = c_parser_omp_clause_ordered (parser, clauses); + c_name = "ordered"; + break; + case PRAGMA_OMP_CLAUSE_PRIVATE: + clauses = c_parser_omp_clause_private (parser, clauses); + c_name = "private"; + break; + case PRAGMA_OMP_CLAUSE_REDUCTION: + clauses = c_parser_omp_clause_reduction (parser, clauses); + c_name = "reduction"; + break; + case PRAGMA_OMP_CLAUSE_SCHEDULE: + clauses = c_parser_omp_clause_schedule (parser, clauses); + c_name = "schedule"; + break; + case PRAGMA_OMP_CLAUSE_SHARED: + clauses = c_parser_omp_clause_shared (parser, clauses); + c_name = "shared"; + break; + default: + c_parser_error (parser, "expected %<#pragma omp%> clause"); + goto saw_error; + } + + if (((mask >> c_kind) & 1) == 0 && !parser->error) + { + /* Remove the invalid clause(s) from the list to avoid + confusing the rest of the compiler. */ + clauses = prev; + error ("%qs is not valid for %qs", c_name, where); + } + } + + saw_error: + c_parser_skip_to_pragma_eol (parser); + + return c_finish_omp_clauses (clauses); +} + +/* OpenMP 2.5: + structured-block: + statement + + In practice, we're also interested in adding the statement to an + outer node. So it is convenient if we work around the fact that + c_parser_statement calls add_stmt. */ + +static tree +c_parser_omp_structured_block (c_parser *parser) +{ + tree stmt = push_stmt_list (); + c_parser_statement (parser); + return pop_stmt_list (stmt); +} + +/* OpenMP 2.5: + # pragma omp atomic new-line + expression-stmt + + expression-stmt: + x binop= expr | x++ | ++x | x-- | --x + binop: + +, *, -, /, &, ^, |, <<, >> + + where x is an lvalue expression with scalar type. */ + +static void +c_parser_omp_atomic (c_parser *parser) +{ + tree lhs, rhs; + tree stmt; + enum tree_code code; + + c_parser_skip_to_pragma_eol (parser); + + lhs = c_parser_unary_expression (parser).value; + switch (TREE_CODE (lhs)) + { + case ERROR_MARK: + saw_error: + c_parser_skip_to_end_of_block_or_statement (parser); + return; + + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + code = PLUS_EXPR; + rhs = integer_one_node; + break; + + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + code = MINUS_EXPR; + rhs = integer_one_node; + break; + + default: + switch (c_parser_peek_token (parser)->type) + { + case CPP_MULT_EQ: + code = MULT_EXPR; + break; + case CPP_DIV_EQ: + code = TRUNC_DIV_EXPR; + break; + case CPP_PLUS_EQ: + code = PLUS_EXPR; + break; + case CPP_MINUS_EQ: + code = MINUS_EXPR; + break; + case CPP_LSHIFT_EQ: + code = LSHIFT_EXPR; + break; + case CPP_RSHIFT_EQ: + code = RSHIFT_EXPR; + break; + case CPP_AND_EQ: + code = BIT_AND_EXPR; + break; + case CPP_OR_EQ: + code = BIT_IOR_EXPR; + break; + case CPP_XOR_EQ: + code = BIT_XOR_EXPR; + break; + default: + c_parser_error (parser, + "invalid operator for %<#pragma omp atomic%>"); + goto saw_error; + } + + c_parser_consume_token (parser); + rhs = c_parser_expression (parser).value; + break; + } + stmt = c_finish_omp_atomic (code, lhs, rhs); + if (stmt != error_mark_node) + add_stmt (stmt); + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); +} + + +/* OpenMP 2.5: + # pragma omp barrier new-line +*/ + +static void +c_parser_omp_barrier (c_parser *parser) +{ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_barrier (); +} + +/* OpenMP 2.5: + # pragma omp critical [(name)] new-line + structured-block +*/ + +static tree +c_parser_omp_critical (c_parser *parser) +{ + tree stmt, name = NULL; + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + c_parser_error (parser, "expected identifier"); + } + else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + c_parser_error (parser, "expected %<(%> or end of line"); + c_parser_skip_to_pragma_eol (parser); + + stmt = c_parser_omp_structured_block (parser); + return c_finish_omp_critical (stmt, name); +} + +/* OpenMP 2.5: + # pragma omp flush flush-vars[opt] new-line + + flush-vars: + ( variable-list ) */ + +static void +c_parser_omp_flush (c_parser *parser) +{ + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + c_parser_omp_var_list_parens (parser, 0, NULL); + else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + c_parser_error (parser, "expected %<(%> or end of line"); + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_flush (); +} + +/* Parse the restricted form of the for statment allowed by OpenMP. + The real trick here is to determine the loop control variable early + so that we can push a new decl if necessary to make it private. */ + +static tree +c_parser_omp_for_loop (c_parser *parser) +{ + tree decl, cond, incr, save_break, save_cont, body, init; + location_t loc; + + if (!c_parser_next_token_is_keyword (parser, RID_FOR)) + { + c_parser_error (parser, "for statement expected"); + return NULL; + } + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return NULL; + + /* Parse the initialization declaration or expression. */ + if (c_parser_next_token_starts_declspecs (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true); + decl = check_for_loop_decls (); + if (decl == NULL) + goto error_init; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + decl = c_parser_postfix_expression (parser).value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init = c_parser_expr_no_commas (parser, NULL).value; + init = build_modify_expr (decl, NOP_EXPR, init); + init = c_process_expr_stmt (init); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + goto error_init; + + /* Parse the loop condition. */ + cond = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + { + cond = c_parser_expression_conv (parser).value; + cond = c_objc_common_truthvalue_conversion (cond); + if (CAN_HAVE_LOCATION_P (cond)) + SET_EXPR_LOCATION (cond, input_location); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + + /* Parse the increment expression. */ + incr = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + incr = c_process_expr_stmt (c_parser_expression (parser).value); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + parse_body: + save_break = c_break_label; + c_break_label = size_one_node; + save_cont = c_cont_label; + c_cont_label = NULL_TREE; + body = push_stmt_list (); + + add_stmt (c_parser_c99_block_statement (parser)); + if (c_cont_label) + add_stmt (build1 (LABEL_EXPR, void_type_node, c_cont_label)); + + body = pop_stmt_list (body); + c_break_label = save_break; + c_cont_label = save_cont; + + /* Only bother calling c_finish_omp_for if we havn't already generated + an error from the initialization parsing. */ + if (decl != NULL && decl != error_mark_node && init != error_mark_node) + return c_finish_omp_for (loc, decl, init, cond, incr, body, NULL); + return NULL; + + error_init: + c_parser_error (parser, "expected iteration declaration or initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + decl = init = cond = incr = NULL_TREE; + goto parse_body; +} + +/* OpenMP 2.5: + #pragma omp for for-clause[optseq] new-line + for-loop +*/ + +#define OMP_FOR_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ + | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_for (c_parser *parser) +{ + tree block, clauses, ret; + + clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, + "#pragma omp for"); + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (parser); + if (ret) + OMP_FOR_CLAUSES (ret) = clauses; + block = c_end_compound_stmt (block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 2.5: + # pragma omp master new-line + structured-block +*/ + +static tree +c_parser_omp_master (c_parser *parser) +{ + c_parser_skip_to_pragma_eol (parser); + return c_finish_omp_master (c_parser_omp_structured_block (parser)); +} + +/* OpenMP 2.5: + # pragma omp ordered new-line + structured-block +*/ + +static tree +c_parser_omp_ordered (c_parser *parser) +{ + c_parser_skip_to_pragma_eol (parser); + return c_finish_omp_ordered (c_parser_omp_structured_block (parser)); +} + +/* OpenMP 2.5: + + section-scope: + { section-sequence } + + section-sequence: + section-directive[opt] structured-block + section-sequence section-directive structured-block */ + +static tree +c_parser_omp_sections_scope (c_parser *parser) +{ + tree stmt, substmt; + bool error_suppress = false; + location_t loc; + + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + { + /* Avoid skipping until the end of the block. */ + parser->error = false; + return NULL_TREE; + } + + stmt = push_stmt_list (); + + loc = c_parser_peek_token (parser)->location; + if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION) + { + substmt = push_stmt_list (); + + while (1) + { + c_parser_statement (parser); + + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) + break; + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + break; + if (c_parser_next_token_is (parser, CPP_EOF)) + break; + } + + substmt = pop_stmt_list (substmt); + substmt = build1 (OMP_SECTION, void_type_node, substmt); + SET_EXPR_LOCATION (substmt, loc); + add_stmt (substmt); + } + + while (1) + { + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) + break; + if (c_parser_next_token_is (parser, CPP_EOF)) + break; + + loc = c_parser_peek_token (parser)->location; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) + { + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + error_suppress = false; + } + else if (!error_suppress) + { + error ("expected %<#pragma omp section%> or %<}%>"); + error_suppress = true; + } + + substmt = c_parser_omp_structured_block (parser); + substmt = build1 (OMP_SECTION, void_type_node, substmt); + SET_EXPR_LOCATION (substmt, loc); + add_stmt (substmt); + } + c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, + "expected %<#pragma omp section%> or %<}%>"); + + substmt = pop_stmt_list (stmt); + + stmt = make_node (OMP_SECTIONS); + TREE_TYPE (stmt) = void_type_node; + OMP_SECTIONS_BODY (stmt) = substmt; + + return add_stmt (stmt); +} + +/* OpenMP 2.5: + # pragma omp sections sections-clause[optseq] newline + sections-scope +*/ + +#define OMP_SECTIONS_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_sections (c_parser *parser) +{ + tree block, clauses, ret; + + clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, + "#pragma omp sections"); + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_sections_scope (parser); + if (ret) + OMP_SECTIONS_CLAUSES (ret) = clauses; + block = c_end_compound_stmt (block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 2.5: + # pragma parallel parallel-clause new-line + # pragma parallel for parallel-for-clause new-line + # pragma parallel sections parallel-sections-clause new-line +*/ + +#define OMP_PARALLEL_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_IF) \ + | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ + | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ + | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + +static tree +c_parser_omp_parallel (c_parser *parser) +{ + enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; + const char *p_name = "#pragma omp parallel"; + tree stmt, clauses, par_clause, ws_clause, block; + unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; + + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + { + c_parser_consume_token (parser); + p_kind = PRAGMA_OMP_PARALLEL_FOR; + p_name = "#pragma omp parallel for"; + mask |= OMP_FOR_CLAUSE_MASK; + mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + } + else if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "sections") == 0) + { + c_parser_consume_token (parser); + p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; + p_name = "#pragma omp parallel sections"; + mask |= OMP_SECTIONS_CLAUSE_MASK; + mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + } + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name); + + switch (p_kind) + { + case PRAGMA_OMP_PARALLEL: + block = c_begin_omp_parallel (); + c_parser_statement (parser); + stmt = c_finish_omp_parallel (clauses, block); + break; + + case PRAGMA_OMP_PARALLEL_FOR: + block = c_begin_omp_parallel (); + c_split_parallel_clauses (clauses, &par_clause, &ws_clause); + stmt = c_parser_omp_for_loop (parser); + if (stmt) + OMP_FOR_CLAUSES (stmt) = ws_clause; + stmt = c_finish_omp_parallel (par_clause, block); + OMP_PARALLEL_COMBINED (stmt) = 1; + break; + + case PRAGMA_OMP_PARALLEL_SECTIONS: + block = c_begin_omp_parallel (); + c_split_parallel_clauses (clauses, &par_clause, &ws_clause); + stmt = c_parser_omp_sections_scope (parser); + if (stmt) + OMP_SECTIONS_CLAUSES (stmt) = ws_clause; + stmt = c_finish_omp_parallel (par_clause, block); + OMP_PARALLEL_COMBINED (stmt) = 1; + break; + + default: + gcc_unreachable (); + } + + return stmt; +} + +/* OpenMP 2.5: + # pragma omp single single-clause[optseq] new-line + structured-block +*/ + +#define OMP_SINGLE_CLAUSE_MASK \ + ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_single (c_parser *parser) +{ + tree stmt = make_node (OMP_SINGLE); + TREE_TYPE (stmt) = void_type_node; + + OMP_SINGLE_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, + "#pragma omp single"); + OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser); + + return add_stmt (stmt); +} + + +/* Main entry point to parsing most OpenMP pragmas. */ + +static void +c_parser_omp_construct (c_parser *parser) +{ + enum pragma_kind p_kind; + location_t loc; + tree stmt; + + loc = c_parser_peek_token (parser)->location; + p_kind = c_parser_peek_token (parser)->pragma_kind; + c_parser_consume_pragma (parser); + + /* For all constructs below except #pragma omp atomic + MUST_NOT_THROW catch handlers are needed when exceptions + are enabled. */ + if (p_kind != PRAGMA_OMP_ATOMIC) + c_maybe_initialize_eh (); + + switch (p_kind) + { + case PRAGMA_OMP_ATOMIC: + c_parser_omp_atomic (parser); + return; + case PRAGMA_OMP_CRITICAL: + stmt = c_parser_omp_critical (parser); + break; + case PRAGMA_OMP_FOR: + stmt = c_parser_omp_for (parser); + break; + case PRAGMA_OMP_MASTER: + stmt = c_parser_omp_master (parser); + break; + case PRAGMA_OMP_ORDERED: + stmt = c_parser_omp_ordered (parser); + break; + case PRAGMA_OMP_PARALLEL: + stmt = c_parser_omp_parallel (parser); + break; + case PRAGMA_OMP_SECTIONS: + stmt = c_parser_omp_sections (parser); + break; + case PRAGMA_OMP_SINGLE: + stmt = c_parser_omp_single (parser); + break; + default: + gcc_unreachable (); + } + + if (stmt) + SET_EXPR_LOCATION (stmt, loc); +} + + +/* OpenMP 2.5: + # pragma omp threadprivate (variable-list) */ + +static void +c_parser_omp_threadprivate (c_parser *parser) +{ + tree vars, t; + + c_parser_consume_pragma (parser); + vars = c_parser_omp_var_list_parens (parser, 0, NULL); + + /* Mark every variable in VARS to be assigned thread local storage. */ + for (t = vars; t; t = TREE_CHAIN (t)) + { + tree v = TREE_PURPOSE (t); + + /* If V had already been marked threadprivate, it doesn't matter + whether it had been used prior to this point. */ + if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v)) + error ("%qE declared % after first use", v); + else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v)) + error ("automatic variable %qE cannot be %", v); + else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) + error ("% %qE has incomplete type", v); + else + { + if (! DECL_THREAD_LOCAL_P (v)) + { + DECL_TLS_MODEL (v) = decl_default_tls_model (v); + /* If rtl has been already set for this var, call + make_decl_rtl once again, so that encode_section_info + has a chance to look at the new decl flags. */ + if (DECL_RTL_SET_P (v)) + make_decl_rtl (v); + } + C_DECL_THREADPRIVATE_P (v) = 1; + } + } + + c_parser_skip_to_pragma_eol (parser); +} + + +/* Parse a single source file. */ + +void +c_parse_file (void) +{ + /* Use local storage to begin. If the first token is a pragma, parse it. + If it is #pragma GCC pch_preprocess, then this will load a PCH file + which will cause garbage collection. */ + c_parser tparser; + + memset (&tparser, 0, sizeof tparser); + the_parser = &tparser; + + if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) + c_parser_pragma_pch_preprocess (&tparser); + + the_parser = GGC_NEW (c_parser); + *the_parser = tparser; + c_parser_translation_unit (the_parser); the_parser = NULL; }