diff options
Diffstat (limited to 'gcc/c/c-parser.cc')
| -rw-r--r-- | gcc/c/c-parser.cc | 1885 |
1 files changed, 1480 insertions, 405 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index d49d5c5..15bfd0d 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -77,7 +77,7 @@ along with GCC; see the file COPYING3. If not see #include "asan.h" #include "c-family/c-ubsan.h" #include "gcc-urlifier.h" - + /* We need to walk over decls with incomplete struct/union/enum types after parsing the whole translation unit. In finish_decl(), if the decl is static, has incomplete @@ -286,6 +286,19 @@ struct GTY(()) omp_attribute_pragma_state unsigned int save_tokens_avail; }; +/* Holds data for deferred lookup of base functions for OpenMP + "begin declare variant", which are permitted to be declared after + the variant. */ +struct GTY(()) omp_begin_declare_variant_map_entry { + tree variant; /* The variant decl. */ + tree id; /* Name of base function. */ + tree ctx; /* The context selector associated with the variant. */ +}; +vec<omp_begin_declare_variant_map_entry, va_gc> *omp_begin_declare_variant_map; + +static tree omp_start_variant_function (c_declarator *, tree); +static void omp_finish_variant_function (tree, tree, tree); + /* Return a pointer to the Nth token in PARSERs tokens_buf. */ c_token * @@ -675,14 +688,15 @@ c_token_starts_typename (c_token *token) } } -/* Return true if the next token from PARSER can start a type name, - false otherwise. LA specifies how to do lookahead in order to +/* Return true if the next token from PARSER, starting from token N, can start + a type name, false otherwise. LA specifies how to do lookahead in order to detect unknown type names. If unsure, pick CLA_PREFER_ID. */ static inline bool -c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la) +c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la, + unsigned int n = 1) { - c_token *token = c_parser_peek_token (parser); + c_token *token = c_parser_peek_nth_token (parser, n); if (c_token_starts_typename (token)) return true; @@ -695,8 +709,8 @@ c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la) && !parser->objc_could_be_foreach_context && (la == cla_prefer_type - || c_parser_peek_2nd_token (parser)->type == CPP_NAME - || c_parser_peek_2nd_token (parser)->type == CPP_MULT) + || c_parser_peek_nth_token (parser, n + 1)->type == CPP_NAME + || c_parser_peek_nth_token (parser, n + 1)->type == CPP_MULT) /* Only unknown identifiers. */ && !lookup_name (token->value)) @@ -892,30 +906,47 @@ c_parser_next_token_starts_declspecs (c_parser *parser) return c_token_starts_declspecs (token); } -/* Return true if the next tokens from PARSER can start declaration - specifiers (not including standard attributes) or a static - assertion, false otherwise. */ +static bool c_parser_check_balanced_raw_token_sequence (c_parser *, + unsigned int *); + +/* Return true if the next tokens from PARSER (starting with token N, 1-based) + can start declaration specifiers (not including standard attributes) or a + static assertion, false otherwise. */ bool -c_parser_next_tokens_start_declaration (c_parser *parser) +c_parser_next_tokens_start_declaration (c_parser *parser, unsigned int n) { - c_token *token = c_parser_peek_token (parser); + c_token *token = c_parser_peek_nth_token (parser, n); /* Same as above. */ if (c_dialect_objc () && token->type == CPP_NAME && token->id_kind == C_ID_CLASSNAME - && c_parser_peek_2nd_token (parser)->type == CPP_DOT) + && c_parser_peek_nth_token (parser, n + 1)->type == CPP_DOT) return false; /* Labels do not start declarations. */ if (token->type == CPP_NAME - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + && c_parser_peek_nth_token (parser, n + 1)->type == CPP_COLON) return false; + /* A static assertion is only a declaration if followed by a semicolon; + otherwise, it may be an expression in C2Y. */ + if (token->keyword == RID_STATIC_ASSERT + && c_parser_peek_nth_token (parser, n + 1)->type == CPP_OPEN_PAREN) + { + n += 2; + if (!c_parser_check_balanced_raw_token_sequence (parser, &n) + || c_parser_peek_nth_token_raw (parser, n)->type != CPP_CLOSE_PAREN) + /* Invalid static assertion syntax; treat as a declaration and report a + syntax error there. */ + return true; + return c_parser_peek_nth_token_raw (parser, n + 1)->type == CPP_SEMICOLON; + } + if (c_token_starts_declaration (token)) return true; - if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl)) + if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl, n)) return true; return false; @@ -1072,9 +1103,11 @@ c_parser_error_richloc (c_parser *parser, const char *gmsgid, const char *header_hint = get_c_stdlib_header_for_string_macro_name (token_name); if (header_hint != NULL) - h = name_hint (NULL, new suggest_missing_header (token->location, - token_name, - header_hint)); + h = name_hint (nullptr, + std::make_unique<suggest_missing_header> + (token->location, + token_name, + header_hint)); } c_parse_error (gmsgid, @@ -1418,6 +1451,51 @@ c_parser_skip_to_end_of_parameter (c_parser *parser) parser->error = false; } +/* Skip tokens until a non-nested closing curly brace is the next + token, or there are no more tokens. Return true in the first case, + false otherwise. */ + +static bool +c_parser_skip_to_closing_brace (c_parser *parser) +{ + unsigned nesting_depth = 0; + + while (true) + { + c_token *token = c_parser_peek_token (parser); + + switch (token->type) + { + case CPP_PRAGMA_EOL: + if (!parser->in_pragma) + break; + /* FALLTHRU */ + case CPP_EOF: + /* If we've run out of tokens, stop. */ + return false; + + 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) + return true; + 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; + + default: + break; + } + + /* Consume the token. */ + c_parser_consume_token (parser); + } +} + /* Expect to be at the end of the pragma directive and consume an end of line marker. */ @@ -1456,6 +1534,55 @@ c_parser_skip_to_pragma_eol (c_parser *parser, bool error_if_not_eol = true) parser->error = false; } +/* Skip tokens up to and including "#pragma omp end declare variant". + Properly handle nested "#pragma omp begin declare variant" pragmas. */ +static void +c_parser_skip_to_pragma_omp_end_declare_variant (c_parser *parser) +{ + for (int depth = 0; depth >= 0; ) + { + c_token *token = c_parser_peek_token (parser); + + switch (token->type) + { + case CPP_PRAGMA_EOL: + if (!parser->in_pragma) + break; + /* FALLTHRU */ + case CPP_EOF: + /* If we've run out of tokens, stop. */ + return; + + case CPP_PRAGMA: + if ((token->pragma_kind == PRAGMA_OMP_BEGIN + || token->pragma_kind == PRAGMA_OMP_END) + && c_parser_peek_nth_token (parser, 2)->type == CPP_NAME + && c_parser_peek_nth_token (parser, 3)->type == CPP_NAME) + { + tree id1 = c_parser_peek_nth_token (parser, 2)->value; + tree id2 = c_parser_peek_nth_token (parser, 3)->value; + if (strcmp (IDENTIFIER_POINTER (id1), "declare") == 0 + && strcmp (IDENTIFIER_POINTER (id2), "variant") == 0) + { + if (token->pragma_kind == PRAGMA_OMP_BEGIN) + depth++; + else + depth--; + } + } + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser, false); + continue; + + default: + break; + } + + /* Consume the token. */ + c_parser_consume_token (parser); + } +} + /* Skip tokens until we have consumed an entire block, or until we have consumed a non-nested ';'. */ @@ -1533,7 +1660,7 @@ c_parser_skip_to_end_of_block_or_statement (c_parser *parser, here for secondary error recovery, after parser->error has been cleared. */ c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); + c_parser_skip_to_pragma_eol (parser, false); parser->error = save_error; continue; @@ -1702,7 +1829,7 @@ static tree c_parser_simple_asm_expr (c_parser *); static tree c_parser_gnu_attributes (c_parser *); static struct c_expr c_parser_initializer (c_parser *, tree); static struct c_expr c_parser_braced_init (c_parser *, tree, bool, - struct obstack *, tree); + struct obstack *, bool); static void c_parser_initelt (c_parser *, struct obstack *); static void c_parser_initval (c_parser *, struct c_expr *, struct obstack *); @@ -1735,8 +1862,10 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, tree); 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_sizeof_or_countof_expression (c_parser *, + enum rid); static struct c_expr c_parser_alignof_expression (c_parser *); +static struct c_expr c_parser_maxof_or_minof_expression (c_parser *, enum rid); 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_declspecs *, @@ -1986,6 +2115,21 @@ c_parser_translation_unit (c_parser *parser) "#pragma omp begin assumes", "#pragma omp end assumes"); vec_safe_truncate (current_omp_begin_assumes, 0); } + if (vec_safe_length (current_omp_declare_variant_attribute)) + { + if (!errorcount) + error ("%<omp begin declare variant%> without corresponding " + "%<omp end declare variant%>"); + vec_safe_truncate (current_omp_declare_variant_attribute, 0); + } + if (vec_safe_length (omp_begin_declare_variant_map)) + { + unsigned int i; + omp_begin_declare_variant_map_entry *e; + FOR_EACH_VEC_ELT (*omp_begin_declare_variant_map, i, e) + omp_finish_variant_function (e->variant, e->id, e->ctx); + vec_safe_truncate (omp_begin_declare_variant_map, 0); + } #if ENABLE_ANALYZER if (flag_analyzer) @@ -2772,7 +2916,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, specs->constexpr_p, &richloc); /* A parameter is initialized, which is invalid. Don't attempt to instrument the initializer. */ - int flag_sanitize_save = flag_sanitize; + sanitize_code_type flag_sanitize_save = flag_sanitize; if (nested && !empty_ok) flag_sanitize = 0; init = c_parser_expr_no_commas (parser, NULL); @@ -2861,7 +3005,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, specs->constexpr_p, &richloc); /* A parameter is initialized, which is invalid. Don't attempt to instrument the initializer. */ - int flag_sanitize_save = flag_sanitize; + sanitize_code_type flag_sanitize_save = flag_sanitize; if (TREE_CODE (d) == PARM_DECL) flag_sanitize = 0; init = c_parser_initializer (parser, d); @@ -2945,7 +3089,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, && DECL_INITIAL (d) == NULL_TREE) DECL_ARGUMENTS (d) = parms; - warn_parm_array_mismatch (lastloc, d, parms); + warn_parms_array_mismatch (lastloc, d, parms); } } if (omp_declare_simd_clauses @@ -3064,6 +3208,21 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions"); c_push_function_context (); } + + /* If we're in an OpenMP "begin declare variant" block, the + name in the declarator refers to the base function. We need + to save that and modify the declarator to have the mangled + name for the variant function instead. */ + tree dv_base = NULL_TREE; + tree dv_ctx = NULL_TREE; + if (!vec_safe_is_empty (current_omp_declare_variant_attribute)) + { + c_omp_declare_variant_attr a + = current_omp_declare_variant_attribute->last (); + dv_ctx = copy_list (a.selector); + dv_base = omp_start_variant_function (declarator, dv_ctx); + } + if (!start_function (specs, declarator, all_prefix_attrs)) { /* At this point we've consumed: @@ -3141,6 +3300,16 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = startloc; location_t endloc = startloc; + /* If this function was in a "begin declare variant" block, + remember it. We will associate it with the base function at + the end of processing the translation unit, since it is permitted + for the variant definition to appear before the base declaration. */ + if (dv_base && current_function_decl != error_mark_node) + { + omp_begin_declare_variant_map_entry e + = { current_function_decl, dv_base, dv_ctx }; + vec_safe_push (omp_begin_declare_variant_map, e); + } /* If the definition was marked with __RTL, use the RTL parser now, consuming the function body. */ @@ -3172,7 +3341,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, else fnbody = c_parser_compound_statement (parser, &endloc); tree fndecl = current_function_decl; - if (nested) + if (nested && specs->declspec_il == cdil_none) { tree decl = current_function_decl; /* Mark nested functions as needing static-chain initially. @@ -3185,6 +3354,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_pop_function_context (); add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); } + else if (nested) + { + if (specs->declspec_il == cdil_rtl) + error ("%<__RTL%> function cannot be a nested function"); + else + error ("%<__GIMPLE%> function cannot be a nested function"); + finish_function (endloc); + c_pop_function_context (); + } else { if (fnbody) @@ -5796,9 +5974,6 @@ c_parser_balanced_token_sequence (c_parser *parser) } } -static bool c_parser_check_balanced_raw_token_sequence (c_parser *, - unsigned int *); - /* Parse arguments of omp::directive or omp::decl attribute. directive-name ,[opt] clause-list[opt] @@ -6385,7 +6560,9 @@ static struct c_expr c_parser_initializer (c_parser *parser, tree decl) { if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - return c_parser_braced_init (parser, NULL_TREE, false, NULL, decl); + return c_parser_braced_init (parser, NULL_TREE, false, NULL, + decl != error_mark_node + && C_DECL_VARIABLE_SIZE (decl)); else { struct c_expr ret; @@ -6425,12 +6602,12 @@ location_t last_init_list_comma; compound literal, and NULL_TREE for other initializers and for nested braced lists. NESTED_P is true for nested braced lists, false for the list of a compound literal or the list that is the - top-level initializer in a declaration. DECL is the declaration for - the top-level initializer for a declaration, otherwise NULL_TREE. */ + top-level initializer in a declaration. VARSIZE_P indicates + wether the object to be initialized has a variable size. */ static struct c_expr c_parser_braced_init (c_parser *parser, tree type, bool nested_p, - struct obstack *outer_obstack, tree decl) + struct obstack *outer_obstack, bool varsize_p) { struct c_expr ret; struct obstack braced_init_obstack; @@ -6458,7 +6635,7 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, } else { - if (decl && decl != error_mark_node && C_DECL_VARIABLE_SIZE (decl)) + if (varsize_p) error_at (brace_loc, "variable-sized object may not be initialized except " "with an empty initializer"); @@ -6752,7 +6929,7 @@ 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, - braced_init_obstack, NULL_TREE); + braced_init_obstack, false); else { init = c_parser_expr_no_commas (parser, after); @@ -7665,7 +7842,7 @@ c_parser_compound_statement_nostart (c_parser *parser) == RID_EXTENSION)) c_parser_consume_token (parser); if (!have_std_attrs - && (c_token_starts_declaration (c_parser_peek_2nd_token (parser)) + && (c_parser_next_tokens_start_declaration (parser, 2) || c_parser_nth_token_starts_std_attributes (parser, 2))) { int ext; @@ -9073,7 +9250,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, && (c_parser_peek_2nd_token (parser)->keyword == RID_EXTENSION)) c_parser_consume_token (parser); - if (c_token_starts_declaration (c_parser_peek_2nd_token (parser)) + if (c_parser_next_tokens_start_declaration (parser, 2) || c_parser_nth_token_starts_std_attributes (parser, 2)) { int ext; @@ -10450,8 +10627,13 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) ++ unary-expression -- unary-expression unary-operator cast-expression + _Countof unary-expression + _Countof ( type-name ) sizeof unary-expression sizeof ( type-name ) + static-assert-declaration-no-semi + + (_Countof and the use of static assertions in expressions are new in C2y.) unary-operator: one of & * + - ~ ! @@ -10461,6 +10643,8 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) unary-expression: __alignof__ unary-expression __alignof__ ( type-name ) + _Maxof ( type-name ) + _Minof ( type-name ) && identifier (C11 permits _Alignof with type names only.) @@ -10493,15 +10677,31 @@ c_parser_unary_expression (c_parser *parser) c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - - op = default_function_array_read_conversion (exp_loc, op); + if ((VAR_P (op.value) || TREE_CODE (op.value) == PARM_DECL) + && !DECL_READ_P (op.value) + && (VAR_P (op.value) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 1) + { + op = default_function_array_read_conversion (exp_loc, op); + DECL_READ_P (op.value) = 0; + } + else + op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op); case CPP_MINUS_MINUS: c_parser_consume_token (parser); exp_loc = c_parser_peek_token (parser)->location; op = c_parser_cast_expression (parser, NULL); - - op = default_function_array_read_conversion (exp_loc, op); + if ((VAR_P (op.value) || TREE_CODE (op.value) == PARM_DECL) + && !DECL_READ_P (op.value) + && (VAR_P (op.value) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 1) + { + op = default_function_array_read_conversion (exp_loc, op); + DECL_READ_P (op.value) = 0; + } + else + op = default_function_array_read_conversion (exp_loc, op); return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); case CPP_AND: c_parser_consume_token (parser); @@ -10568,62 +10768,85 @@ c_parser_unary_expression (c_parser *parser) } 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_BUILTIN_HAS_ATTRIBUTE: - return c_parser_has_attribute_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); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); - return parser_build_unary_op (op_loc, REALPART_EXPR, op); - case RID_IMAGPART: - c_parser_consume_token (parser); - exp_loc = c_parser_peek_token (parser)->location; - op = c_parser_cast_expression (parser, NULL); - op = default_function_array_conversion (exp_loc, op); - return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); - case RID_TRANSACTION_ATOMIC: - case RID_TRANSACTION_RELAXED: - return c_parser_transaction_expression (parser, - c_parser_peek_token (parser)->keyword); - default: - return c_parser_postfix_expression (parser); - } + { + enum rid rid = c_parser_peek_token (parser)->keyword; + switch (rid) + { + case RID_COUNTOF: + case RID_SIZEOF: + return c_parser_sizeof_or_countof_expression (parser, rid); + case RID_ALIGNOF: + return c_parser_alignof_expression (parser); + case RID_MAXOF: + case RID_MINOF: + return c_parser_maxof_or_minof_expression (parser, rid); + case RID_BUILTIN_HAS_ATTRIBUTE: + return c_parser_has_attribute_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); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, REALPART_EXPR, op); + case RID_IMAGPART: + c_parser_consume_token (parser); + exp_loc = c_parser_peek_token (parser)->location; + op = c_parser_cast_expression (parser, NULL); + op = default_function_array_conversion (exp_loc, op); + return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + return c_parser_transaction_expression (parser, rid); + case RID_STATIC_ASSERT: + c_parser_static_assert_declaration_no_semi (parser); + pedwarn_c23 (op_loc, OPT_Wpedantic, + "ISO C does not support static assertions in " + "expressions before C2Y"); + ret.value = void_node; + set_c_expr_source_range (&ret, op_loc, op_loc); + ret.m_decimal = 0; + return ret; + default: + return c_parser_postfix_expression (parser); + } + } default: return c_parser_postfix_expression (parser); } } -/* Parse a sizeof expression. */ +/* Parse a sizeof or _Countof expression. */ static struct c_expr -c_parser_sizeof_expression (c_parser *parser) +c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid) { + const char *op_name = (rid == RID_COUNTOF) ? "_Countof" : "sizeof"; struct c_expr expr; struct c_expr result; location_t expr_loc; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); + gcc_assert (c_parser_next_token_is_keyword (parser, rid)); location_t start; location_t finish = UNKNOWN_LOCATION; start = c_parser_peek_token (parser)->location; + if (rid == RID_COUNTOF) + pedwarn_c23 (start, OPT_Wpedantic, + "ISO C does not support %qs before C2Y", op_name); + c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; - in_sizeof++; + if (rid == RID_COUNTOF) + in_countof++; + else + in_sizeof++; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser))) { @@ -10644,7 +10867,7 @@ c_parser_sizeof_expression (c_parser *parser) for parsing error; the parsing of the expression could have called record_maybe_used_decl. */ expr.set_error (); - goto sizeof_expr; + goto Xof_expr; } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { @@ -10652,31 +10875,45 @@ c_parser_sizeof_expression (c_parser *parser) type_name, expr_loc); finish = expr.get_finish (); - goto sizeof_expr; + goto Xof_expr; } /* sizeof ( type-name ). */ if (scspecs) - error_at (expr_loc, "storage class specifier in %<sizeof%>"); + error_at (expr_loc, "storage class specifier in %qs", op_name); if (type_name->specs->alignas_p) error_at (type_name->specs->locations[cdw_alignas], - "alignment specified for type name in %<sizeof%>"); + "alignment specified for type name in %qs", op_name); c_inhibit_evaluation_warnings--; - in_sizeof--; - result = c_expr_sizeof_type (expr_loc, type_name); + if (rid == RID_COUNTOF) + { + in_countof--; + result = c_expr_countof_type (expr_loc, type_name); + } + else + { + in_sizeof--; + result = c_expr_sizeof_type (expr_loc, type_name); + } } else { expr_loc = c_parser_peek_token (parser)->location; expr = c_parser_unary_expression (parser); finish = expr.get_finish (); - sizeof_expr: + Xof_expr: c_inhibit_evaluation_warnings--; - in_sizeof--; + if (rid == RID_COUNTOF) + in_countof--; + else + in_sizeof--; mark_exp_read (expr.value); if (TREE_CODE (expr.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) - error_at (expr_loc, "%<sizeof%> applied to a bit-field"); - result = c_expr_sizeof_expr (expr_loc, expr); + error_at (expr_loc, "%qs applied to a bit-field", op_name); + if (rid == RID_COUNTOF) + result = c_expr_countof_expr (expr_loc, expr); + else + result = c_expr_sizeof_expr (expr_loc, expr); } if (finish == UNKNOWN_LOCATION) finish = start; @@ -10786,6 +11023,67 @@ c_parser_alignof_expression (c_parser *parser) } } +/* Parse a _Maxof or _Minof expression. */ + +static struct c_expr +c_parser_maxof_or_minof_expression (c_parser *parser, enum rid rid) +{ + const char *op_name = (rid == RID_MAXOF) ? "_Maxof" : "_Minof"; + struct c_expr result; + location_t expr_loc; + struct c_type_name *type_name; + matching_parens parens; + gcc_assert (c_parser_next_token_is_keyword (parser, rid)); + + location_t start; + location_t finish = UNKNOWN_LOCATION; + + start = c_parser_peek_token (parser)->location; + + pedwarn (start, OPT_Wpedantic, "ISO C does not support %qs", op_name); + + c_parser_consume_token (parser); + c_inhibit_evaluation_warnings++; + if (!c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_error (parser, "expected %<(%>"); + goto fail; + } + parens.consume_open (parser); + expr_loc = c_parser_peek_token (parser)->location; + if (!c_token_starts_typename (c_parser_peek_token (parser))) + { + error_at (expr_loc, "invalid application of %qs to something not a type", op_name); + parens.skip_until_found_close (parser); + goto fail; + } + type_name = c_parser_type_name (parser, true); + if (type_name == NULL) + { + // c_parser_type_name() has already diagnosed the error. + parens.skip_until_found_close (parser); + goto fail; + } + parens.skip_until_found_close (parser); + finish = parser->tokens_buf[0].location; + if (type_name->specs->alignas_p) + error_at (type_name->specs->locations[cdw_alignas], + "alignment specified for type name in %qs", op_name); + c_inhibit_evaluation_warnings--; + if (rid == RID_MAXOF) + result = c_expr_maxof_type (expr_loc, type_name); + else + result = c_expr_minof_type (expr_loc, type_name); + set_c_expr_source_range (&result, start, finish); + return result; +fail: + c_inhibit_evaluation_warnings--; + result.set_error (); + result.original_code = ERROR_MARK; + result.original_type = NULL; + return result; +} + /* Parse the __builtin_has_attribute ([expr|type], attribute-spec) expression. */ @@ -11052,15 +11350,24 @@ c_parser_generic_selection (c_parser *parser) "ISO C does not support use of type name as %<_Generic%> " "controlling operand before C2Y"); struct c_type_name *type = c_parser_type_name (parser); - selector_type = groktypename (type, NULL, NULL); + if (type) + selector_type = groktypename (type, NULL, NULL); c_inhibit_evaluation_warnings--; + if (!type) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return error_expr; + } } else { c_inhibit_evaluation_warnings++; + in_generic++; selector = c_parser_expr_no_commas (parser, NULL); selector = default_function_array_conversion (selector_loc, selector); c_inhibit_evaluation_warnings--; + in_generic--; + pop_maybe_used (!flag_isoc23); if (selector.value == error_mark_node) { @@ -11089,6 +11396,7 @@ c_parser_generic_selection (c_parser *parser) } auto_vec<c_generic_association> associations; + struct maybe_used_decl *maybe_used_default = NULL; while (1) { struct c_generic_association assoc, *iter; @@ -11111,7 +11419,7 @@ c_parser_generic_selection (c_parser *parser) c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return error_expr; } - assoc.type = groktypename (type_name, NULL, NULL); + assoc.type = grokgenassoc (type_name); if (assoc.type == error_mark_node) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); @@ -11128,9 +11436,9 @@ c_parser_generic_selection (c_parser *parser) "incomplete type before C2Y"); if (c_type_variably_modified_p (assoc.type)) - error_at (assoc.type_location, - "%<_Generic%> association has " - "variable length type"); + pedwarn_c23 (assoc.type_location, OPT_Wpedantic, + "ISO C does not support %<_Generic%> association with " + "variably-modified type before C2Y"); } if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) @@ -11144,11 +11452,19 @@ c_parser_generic_selection (c_parser *parser) if (!match) c_inhibit_evaluation_warnings++; + in_generic++; assoc.expression = c_parser_expr_no_commas (parser, NULL); if (!match) c_inhibit_evaluation_warnings--; + in_generic--; + if (!match) + pop_maybe_used (!flag_isoc23); + else if (assoc.type == NULL_TREE) + maybe_used_default = save_maybe_used (); + else + pop_maybe_used (true); if (assoc.expression.value == error_mark_node) { @@ -11209,6 +11525,20 @@ c_parser_generic_selection (c_parser *parser) c_parser_consume_token (parser); } + if (match_found >= 0 && matched_assoc.type == NULL_TREE) + { + /* Declarations referenced in the default association are used. */ + restore_maybe_used (maybe_used_default); + pop_maybe_used (true); + } + else if (maybe_used_default) + { + /* Declarations referenced in the default association are not used, but + are treated as used before C23. */ + restore_maybe_used (maybe_used_default); + pop_maybe_used (!flag_isoc23); + } + unsigned int ix; struct c_generic_association *iter; FOR_EACH_VEC_ELT (associations, ix, iter) @@ -11617,15 +11947,9 @@ c_parser_postfix_expression (c_parser *parser) else { tree type_expr = NULL_TREE; + tree type = groktypename (t1, &type_expr, NULL); expr.value = c_build_va_arg (start_loc, e1.value, loc, - groktypename (t1, &type_expr, NULL)); - if (type_expr) - { - expr.value = build2 (C_MAYBE_CONST_EXPR, - TREE_TYPE (expr.value), type_expr, - expr.value); - C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true; - } + type, type_expr); set_c_expr_source_range (&expr, start_loc, end_loc); } } @@ -11760,12 +12084,9 @@ c_parser_postfix_expression (c_parser *parser) if (c_parser_next_token_is (parser, CPP_NAME)) { c_token *comp_tok = c_parser_peek_token (parser); - /* Ignore the counted_by attribute for reference inside - offsetof since the information is not useful at all. */ offsetof_ref = build_component_ref (loc, offsetof_ref, comp_tok->value, - comp_tok->location, UNKNOWN_LOCATION, - false); + comp_tok->location, UNKNOWN_LOCATION); c_parser_consume_token (parser); while (c_parser_next_token_is (parser, CPP_DOT) || c_parser_next_token_is (parser, @@ -11792,14 +12113,11 @@ c_parser_postfix_expression (c_parser *parser) break; } c_token *comp_tok = c_parser_peek_token (parser); - /* Ignore the counted_by attribute for reference inside - offsetof since the information is not useful. */ offsetof_ref = build_component_ref (loc, offsetof_ref, comp_tok->value, comp_tok->location, - UNKNOWN_LOCATION, - false); + UNKNOWN_LOCATION); c_parser_consume_token (parser); } else @@ -12585,7 +12903,7 @@ c_parser_postfix_expression (c_parser *parser) /* If the array ref is inside TYPEOF or ALIGNOF, the call to .ACCESS_WITH_SIZE was not generated by the routine build_component_ref by default, we should generate it here. */ - if ((in_typeof || in_alignof) && TREE_CODE (ref) == COMPONENT_REF) + if (TREE_CODE (ref) == COMPONENT_REF) ref = handle_counted_by_for_component_ref (loc, ref); if (has_counted_by_object (ref)) @@ -13346,10 +13664,11 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, || (scspecs && scspecs->storage_class == csc_static) || constexpr_p), constexpr_p, &richloc); type = groktypename (type_name, &type_expr, &type_expr_const); + bool varsize_p = false; if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) { - error_at (type_loc, "compound literal has variable size"); - type = error_mark_node; + pedwarn (type_loc, OPT_Wpedantic, "compound literal has variable size"); + varsize_p = true; } else if (TREE_CODE (type) == FUNCTION_TYPE) { @@ -13374,7 +13693,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, (TYPE_QUALS (type_no_array) | TYPE_QUAL_CONST)); } - init = c_parser_braced_init (parser, type, false, NULL, NULL_TREE); + init = c_parser_braced_init (parser, type, false, NULL, varsize_p); if (constexpr_p) finish_underspecified_init (NULL_TREE, underspec_state); finish_init (); @@ -13833,7 +14152,17 @@ c_parser_postfix_expression_after_primary (c_parser *parser, start = expr.get_start (); finish = c_parser_peek_token (parser)->get_finish (); c_parser_consume_token (parser); - expr = default_function_array_read_conversion (expr_loc, expr); + if ((VAR_P (expr.value) || TREE_CODE (expr.value) == PARM_DECL) + && !DECL_READ_P (expr.value) + && (VAR_P (expr.value) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 1 + && TREE_CODE (TREE_TYPE (expr.value)) != ARRAY_TYPE) + { + expr = default_function_array_read_conversion (expr_loc, expr); + DECL_READ_P (expr.value) = 0; + } + else + expr = default_function_array_read_conversion (expr_loc, expr); expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR, expr.value, false); set_c_expr_source_range (&expr, start, finish); @@ -13845,7 +14174,17 @@ c_parser_postfix_expression_after_primary (c_parser *parser, start = expr.get_start (); finish = c_parser_peek_token (parser)->get_finish (); c_parser_consume_token (parser); - expr = default_function_array_read_conversion (expr_loc, expr); + if ((VAR_P (expr.value) || TREE_CODE (expr.value) == PARM_DECL) + && !DECL_READ_P (expr.value) + && (VAR_P (expr.value) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 1 + && TREE_CODE (TREE_TYPE (expr.value)) != ARRAY_TYPE) + { + expr = default_function_array_read_conversion (expr_loc, expr); + DECL_READ_P (expr.value) = 0; + } + else + expr = default_function_array_read_conversion (expr_loc, expr); expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR, expr.value, false); set_c_expr_source_range (&expr, start, finish); @@ -15622,11 +15961,15 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p, gcc_assert (id != PRAGMA_NONE); if (parser->omp_for_parse_state && parser->omp_for_parse_state->in_intervening_code - && id >= PRAGMA_OMP__START_ - && id <= PRAGMA_OMP__LAST_) - { - error_at (input_location, - "intervening code must not contain OpenMP directives"); + && id >= PRAGMA_OMP__START_ && id <= PRAGMA_OMP__LAST_ + /* Allow a safe subset of non-executable directives. See classification in + array c_omp_directives. */ + && id != PRAGMA_OMP_METADIRECTIVE && id != PRAGMA_OMP_NOTHING + && id != PRAGMA_OMP_ASSUME && id != PRAGMA_OMP_ERROR) + { + error_at ( + input_location, + "intervening code must not contain executable OpenMP directives"); parser->omp_for_parse_state->fail = true; c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; @@ -16068,6 +16411,8 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; else if (!strcmp ("doacross", p)) result = PRAGMA_OMP_CLAUSE_DOACROSS; + else if (!strcmp ("dyn_groupprivate", p)) + result = PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE; break; case 'e': if (!strcmp ("enter", p)) @@ -16523,7 +16868,7 @@ c_parser_omp_variable_list (c_parser *parser, || CONVERT_EXPR_P (decl)) decl = TREE_OPERAND (decl, 0); - tree u = build_omp_clause (clause_loc, kind); + tree u = build_omp_clause (loc, kind); OMP_CLAUSE_DECL (u) = decl; OMP_CLAUSE_CHAIN (u) = list; list = u; @@ -19919,6 +20264,96 @@ c_parser_omp_clause_doacross (c_parser *parser, tree list) return list; } +/* OpenMP 6.1: + dyn_groupprivate ( [fallback-modifier : ] integer-expression ) + + fallback-modifier + fallback( abort | default_mem | null ) */ + +static tree +c_parser_omp_clause_dyn_groupprivate (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + enum omp_clause_fallback_kind kind = OMP_CLAUSE_FALLBACK_UNSPECIFIED; + + unsigned n = 3; + if (c_parser_next_token_is (parser, CPP_NAME) + && (c_parser_peek_2nd_token (parser)->type == CPP_COLON + || (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN + && c_parser_check_balanced_raw_token_sequence (parser, &n) + && (c_parser_peek_nth_token_raw (parser, n)->type + == CPP_CLOSE_PAREN) + && (c_parser_peek_nth_token_raw (parser, n + 1)->type + == CPP_COLON)))) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "fallback") != 0) + { + c_parser_error (parser, "expected %<fallback%> modifier"); + return list; + } + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + p = ""; + if (c_parser_next_token_is (parser, CPP_NAME)) + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "abort") == 0) + kind = OMP_CLAUSE_FALLBACK_ABORT; + else if (strcmp (p, "default_mem") == 0) + kind = OMP_CLAUSE_FALLBACK_DEFAULT_MEM; + else if (strcmp (p, "null") == 0) + kind = OMP_CLAUSE_FALLBACK_NULL; + else + { + c_parser_error (parser, "expected %<abort%>, %<default_mem%>, or " + "%<null%> as fallback mode"); + return list; + } + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return list; + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + return list; + } + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree size = c_fully_fold (expr.value, false, NULL); + parens.skip_until_found_close (parser); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (size))) + { + error_at (expr_loc, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number is negative. */ + tree c = fold_build2_loc (expr_loc, LT_EXPR, boolean_type_node, size, + build_int_cst (TREE_TYPE (size), 0)); + protected_set_expr_location (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, OPT_Wopenmp, + "%<dyn_groupprivate%> value must be non-negative"); + size = integer_zero_node; + } + check_no_duplicate_clause (list, OMP_CLAUSE_DYN_GROUPPRIVATE, + "dyn_groupprivate"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_DYN_GROUPPRIVATE); + OMP_CLAUSE_DYN_GROUPPRIVATE_KIND (c) = kind; + OMP_CLAUSE_DYN_GROUPPRIVATE_EXPR (c) = size; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + + return list; +} + /* OpenMP 4.0: map ( map-kind: variable-list ) map ( variable-list ) @@ -19936,14 +20371,14 @@ c_parser_omp_clause_doacross (c_parser *parser, tree list) map ( [map-type-modifier[,] ...] map-kind: variable-list ) map-type-modifier: - always | close */ + always | close | present | iterator (iterators-definition) */ static tree -c_parser_omp_clause_map (c_parser *parser, tree list) +c_parser_omp_clause_map (c_parser *parser, tree list, bool declare_mapper_p) { location_t clause_loc = c_parser_peek_token (parser)->location; - enum gomp_map_kind kind = GOMP_MAP_TOFROM; tree nl, c; + enum gomp_map_kind kind = declare_mapper_p ? GOMP_MAP_UNSET : GOMP_MAP_TOFROM; matching_parens parens; if (!parens.require_open (parser)) @@ -19951,22 +20386,57 @@ c_parser_omp_clause_map (c_parser *parser, tree list) int pos = 1; int map_kind_pos = 0; - while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME) + int iterator_length = 0; + for (;;) { - if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COLON) + c_token *tok = c_parser_peek_nth_token_raw (parser, pos); + if (tok->type != CPP_NAME) + break; + + const char *p = IDENTIFIER_POINTER (tok->value); + c_token *next_tok = c_parser_peek_nth_token_raw (parser, pos + 1); + if (strcmp (p, "iterator") == 0 && next_tok->type == CPP_OPEN_PAREN) + { + unsigned n = pos + 2; + if (c_parser_check_balanced_raw_token_sequence (parser, &n) + && c_parser_peek_nth_token_raw (parser, n)->type + == CPP_CLOSE_PAREN) + { + iterator_length = n - pos + 1; + pos = n; + next_tok = c_parser_peek_nth_token_raw (parser, pos + 1); + } + } + + if (next_tok->type == CPP_COLON) { map_kind_pos = pos; break; } - if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA) + if (next_tok->type == CPP_COMMA) pos++; + else if (c_parser_peek_nth_token_raw (parser, pos + 1)->type + == CPP_OPEN_PAREN) + { + unsigned int npos = pos + 2; + if (c_parser_check_balanced_raw_token_sequence (parser, &npos) + && (c_parser_peek_nth_token_raw (parser, npos)->type + == CPP_CLOSE_PAREN) + && (c_parser_peek_nth_token_raw (parser, npos + 1)->type + == CPP_COMMA)) + pos = npos + 1; + } + pos++; } int always_modifier = 0; int close_modifier = 0; int present_modifier = 0; + int mapper_modifier = 0; + tree mapper_name = NULL_TREE; + tree iterators = NULL_TREE; for (int pos = 1; pos < map_kind_pos; ++pos) { c_token *tok = c_parser_peek_token (parser); @@ -19987,6 +20457,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list) return list; } always_modifier++; + c_parser_consume_token (parser); } else if (strcmp ("close", p) == 0) { @@ -19997,6 +20468,77 @@ c_parser_omp_clause_map (c_parser *parser, tree list) return list; } close_modifier++; + c_parser_consume_token (parser); + } + else if (strcmp ("iterator", p) == 0) + { + if (iterators) + { + c_parser_error (parser, "too many %<iterator%> modifiers"); + parens.skip_until_found_close (parser); + return list; + } + iterators = c_parser_omp_iterators (parser); + pos += iterator_length - 1; + } + else if (strcmp ("mapper", p) == 0) + { + c_parser_consume_token (parser); + + matching_parens mparens; + if (mparens.require_open (parser)) + { + if (mapper_modifier) + { + c_parser_error (parser, "too many %<mapper%> modifiers"); + /* Assume it's a well-formed mapper modifier, even if it + seems to be in the wrong place. */ + c_parser_consume_token (parser); + mparens.require_close (parser); + parens.skip_until_found_close (parser); + return list; + } + + tok = c_parser_peek_token (parser); + + switch (tok->type) + { + case CPP_NAME: + { + mapper_name = tok->value; + c_parser_consume_token (parser); + if (declare_mapper_p) + { + error_at (tok->location, + "in %<declare mapper%> directives, parameter " + "to %<mapper%> modifier must be %<default%>"); + } + } + break; + + case CPP_KEYWORD: + if (tok->keyword == RID_DEFAULT) + { + c_parser_consume_token (parser); + break; + } + /* Fallthrough. */ + + default: + error_at (tok->location, + "expected identifier or %<default%>"); + return list; + } + + if (!mparens.require_close (parser)) + { + parens.skip_until_found_close (parser); + return list; + } + + mapper_modifier++; + pos += 3; + } } else if (strcmp ("present", p) == 0) { @@ -20007,16 +20549,16 @@ c_parser_omp_clause_map (c_parser *parser, tree list) return list; } present_modifier++; + c_parser_consume_token (parser); } else { c_parser_error (parser, "%<map%> clause with map-type modifier other " - "than %<always%>, %<close%> or %<present%>"); + "than %<always%>, %<close%>, %<iterator%>, " + "%<mapper%> or %<present%>"); parens.skip_until_found_close (parser); return list; } - - c_parser_consume_token (parser); } if (c_parser_next_token_is (parser, CPP_NAME) @@ -20060,8 +20602,40 @@ c_parser_omp_clause_map (c_parser *parser, tree list) nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list, true); + tree last_new = NULL_TREE; + + if (iterators) + { + tree block = pop_scope (); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_SET_MAP_KIND (c, kind); + { + OMP_CLAUSE_SET_MAP_KIND (c, kind); + OMP_CLAUSE_ITERATORS (c) = iterators; + last_new = c; + } + + if (mapper_name) + { + tree name = build_omp_clause (input_location, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_PUSH_MAPPER_NAME); + OMP_CLAUSE_DECL (name) = mapper_name; + OMP_CLAUSE_CHAIN (name) = nl; + nl = name; + + gcc_assert (last_new); + + name = build_omp_clause (input_location, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_POP_MAPPER_NAME); + OMP_CLAUSE_DECL (name) = null_pointer_node; + OMP_CLAUSE_CHAIN (name) = OMP_CLAUSE_CHAIN (last_new); + OMP_CLAUSE_CHAIN (last_new) = name; + } parens.skip_until_found_close (parser); return nl; @@ -20301,8 +20875,11 @@ c_parser_omp_clause_device_type (c_parser *parser, tree list) to ( variable-list ) OpenMP 5.1: - from ( [present :] variable-list ) - to ( [present :] variable-list ) */ + from ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list ) + to ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list ) + + motion-modifier: + present | iterator (iterators-definition) */ static tree c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, @@ -20313,18 +20890,85 @@ c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, if (!parens.require_open (parser)) return list; + int pos = 1, colon_pos = 0; + int iterator_length = 0; + + while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME) + { + const char *identifier = + IDENTIFIER_POINTER (c_parser_peek_nth_token_raw (parser, pos)->value); + if (c_parser_peek_nth_token_raw (parser, pos + 1)->type + == CPP_OPEN_PAREN) + { + unsigned int npos = pos + 2; + if (c_parser_check_balanced_raw_token_sequence (parser, &npos) + && (c_parser_peek_nth_token_raw (parser, npos)->type + == CPP_CLOSE_PAREN)) + { + if (strcmp (identifier, "iterator") == 0) + iterator_length = npos - pos + 1; + pos = npos; + } + } + if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA) + pos += 2; + else + pos++; + if (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_COLON) + { + colon_pos = pos; + break; + } + } + bool present = false; - c_token *token = c_parser_peek_token (parser); + tree iterators = NULL_TREE; - if (token->type == CPP_NAME - && strcmp (IDENTIFIER_POINTER (token->value), "present") == 0 - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + for (int pos = 1; pos < colon_pos; ++pos) { - present = true; - c_parser_consume_token (parser); - c_parser_consume_token (parser); + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_COMMA) + { + c_parser_consume_token (parser); + continue; + } + const char *p = IDENTIFIER_POINTER (token->value); + if (strcmp ("present", p) == 0) + { + if (present) + { + c_parser_error (parser, "too many %<present%> modifiers"); + parens.skip_until_found_close (parser); + return list; + } + present = true; + c_parser_consume_token (parser); + } + else if (strcmp ("iterator", p) == 0) + { + if (iterators) + { + c_parser_error (parser, "too many %<iterator%> modifiers"); + parens.skip_until_found_close (parser); + return list; + } + iterators = c_parser_omp_iterators (parser); + pos += iterator_length - 1; + } + else + { + error_at (token->location, + "%qs clause with modifier other than %<iterator%> or " + "%<present%>", + kind == OMP_CLAUSE_TO ? "to" : "from"); + parens.skip_until_found_close (parser); + return list; + } } + if (colon_pos) + c_parser_require (parser, CPP_COLON, "expected %<:%>"); + tree nl = c_parser_omp_variable_list (parser, loc, kind, list); parens.skip_until_found_close (parser); @@ -20332,6 +20976,19 @@ c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_MOTION_PRESENT (c) = 1; + if (iterators) + { + tree block = pop_scope (); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + + if (iterators) + for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ITERATORS (c) = iterators; + return nl; } @@ -20519,7 +21176,10 @@ c_parser_omp_clause_detach (c_parser *parser, tree list) static tree c_parser_omp_clause_destroy (c_parser *parser, tree list) { - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_DESTROY, list); + tree nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_DESTROY, list); + for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + TREE_ADDRESSABLE (OMP_CLAUSE_DECL (c)) = 1; + return nl; } /* OpenMP 5.1: @@ -20834,8 +21494,8 @@ c_parser_omp_clause_init_modifiers (c_parser *parser, bool *target, while (true); fail: - c_parser_error (parser, "%<init%> clause with modifier other than " - "%<prefer_type%>, %<target%> or %<targetsync%>"); + c_parser_error (parser, + "expected %<prefer_type%>, %<target%>, or %<targetsync%>"); return false; } @@ -20856,51 +21516,30 @@ c_parser_omp_clause_init (c_parser *parser, tree list) if (!parens.require_open (parser)) return list; - unsigned raw_pos = 1; - while (c_parser_peek_nth_token_raw (parser, raw_pos)->type == CPP_NAME) - { - raw_pos++; - if (c_parser_peek_nth_token_raw (parser, raw_pos)->type == CPP_OPEN_PAREN) - { - raw_pos++; - c_parser_check_balanced_raw_token_sequence (parser, &raw_pos); - if (c_parser_peek_nth_token_raw (parser, raw_pos)->type != CPP_CLOSE_PAREN) - { - raw_pos = 0; - break; - } - raw_pos++; - } - if (c_parser_peek_nth_token_raw (parser, raw_pos)->type == CPP_COLON) - break; - if (c_parser_peek_nth_token_raw (parser, raw_pos)->type != CPP_COMMA) - { - raw_pos = 0; - break; - } - raw_pos++; - } - bool target = false; bool targetsync = false; tree prefer_type_tree = NULL_TREE; - if (raw_pos > 1 - && (!c_parser_omp_clause_init_modifiers (parser, &target, &targetsync, - &prefer_type_tree) - || !c_parser_require (parser, CPP_COLON, "expected %<:%>"))) + if (!c_parser_omp_clause_init_modifiers (parser, &target, &targetsync, + &prefer_type_tree) + || !c_parser_require (parser, CPP_COLON, "expected %<:%>")) { if (prefer_type_tree != error_mark_node) parens.skip_until_found_close (parser); return list; } + if (!target && !targetsync) + error_at (loc, + "missing required %<target%> and/or %<targetsync%> modifier"); + tree nl = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_INIT, list, false); parens.skip_until_found_close (parser); for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) { + TREE_ADDRESSABLE (OMP_CLAUSE_DECL (c)) = 1; if (target) OMP_CLAUSE_INIT_TARGET (c) = 1; if (targetsync) @@ -21435,6 +22074,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_destroy (parser, clauses); c_name = "destroy"; break; + case PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE: + clauses = c_parser_omp_clause_dyn_groupprivate (parser, clauses); + c_name = "dyn_groupprivate"; + break; case PRAGMA_OMP_CLAUSE_INIT: clauses = c_parser_omp_clause_init (parser, clauses); c_name = "init"; @@ -21448,7 +22091,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, c_name = "interop"; break; case PRAGMA_OMP_CLAUSE_MAP: - clauses = c_parser_omp_clause_map (parser, clauses); + clauses = c_parser_omp_clause_map (parser, clauses, false); c_name = "map"; break; case PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR: @@ -22322,7 +22965,8 @@ c_parser_oacc_update (c_parser *parser) */ #define OACC_WAIT_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) ) + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) ) static tree c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name) @@ -26248,26 +26892,27 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, structured-block */ #define OMP_TARGET_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)\ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT)) static bool c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) { location_t loc = c_parser_peek_token (parser)->location; c_parser_consume_pragma (parser); - tree *pc = NULL, stmt, block; + tree *pc = NULL, stmt, block, body, clauses; if (context != pragma_stmt && context != pragma_compound) { @@ -26422,10 +27067,9 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) stmt = make_node (OMP_TARGET); TREE_TYPE (stmt) = void_type_node; - OMP_TARGET_CLAUSES (stmt) - = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, - "#pragma omp target", false); - for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) + clauses = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, + "#pragma omp target", false); + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) { tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); @@ -26434,14 +27078,19 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); OMP_CLAUSE_CHAIN (c) = nc; } - OMP_TARGET_CLAUSES (stmt) - = c_finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET); - c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); + clauses = c_omp_instantiate_mappers (clauses); + clauses = c_finish_omp_clauses (clauses, C_ORT_OMP_TARGET); + c_omp_adjust_map_clauses (clauses, true); - pc = &OMP_TARGET_CLAUSES (stmt); keep_next_level (); block = c_begin_compound_stmt (true); - add_stmt (c_parser_omp_structured_block (parser, if_p)); + body = c_parser_omp_structured_block (parser, if_p); + + c_omp_scan_mapper_bindings (loc, &clauses, body); + + add_stmt (body); + OMP_TARGET_CLAUSES (stmt) = clauses; + pc = &OMP_TARGET_CLAUSES (stmt); OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true); SET_EXPR_LOCATION (stmt, loc); @@ -26789,20 +27438,31 @@ c_parser_omp_context_selector (c_parser *parser, enum omp_tss_code set, break; case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR: case OMP_TRAIT_PROPERTY_BOOL_EXPR: - t = c_parser_expr_no_commas (parser, NULL).value; - if (t != error_mark_node) + { + c_expr texpr = c_parser_expr_no_commas (parser, NULL); + texpr = convert_lvalue_to_rvalue (token->location, texpr, + true, true); + t = texpr.value; + } + if (t == error_mark_node) + return error_mark_node; + mark_exp_read (t); + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) { - mark_exp_read (t); - t = c_fully_fold (t, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) - error_at (token->location, - "property must be integer expression"); - else - properties = make_trait_property (NULL_TREE, t, - properties); + t = c_objc_common_truthvalue_conversion (token->location, + t, + boolean_type_node); + if (t == error_mark_node) + return error_mark_node; } - else - return error_mark_node; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (token->location, + "property must be integer expression"); + return error_mark_node; + } + t = c_fully_fold (t, false, NULL); + properties = make_trait_property (NULL_TREE, t, properties); break; case OMP_TRAIT_PROPERTY_CLAUSE_LIST: if (sel == OMP_TRAIT_CONSTRUCT_SIMD) @@ -26904,11 +27564,14 @@ c_parser_omp_context_selector_specification (c_parser *parser, tree parms) tree selectors = c_parser_omp_context_selector (parser, set, parms); if (selectors == error_mark_node) - ret = error_mark_node; + { + c_parser_skip_to_closing_brace (parser); + ret = error_mark_node; + } else if (ret != error_mark_node) ret = make_trait_set_selector (set, selectors, ret); - braces.skip_until_found_close (parser); + braces.require_close (parser); if (c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); @@ -26951,6 +27614,30 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) undeclared_variable (token->location, token->value); variant = error_mark_node; } + else if (TREE_CODE (variant) != FUNCTION_DECL) + { + error_at (token->location, "variant %qD is not a function", + variant); + variant = error_mark_node; + } + else if (fndecl_built_in_p (variant) + && (strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), + "__builtin_", strlen ("__builtin_")) == 0 + || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), + "__sync_", strlen ("__sync_")) == 0 + || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), + "__atomic_", strlen ("__atomic_")) == 0)) + { + error_at (token->location, "variant %qD is a built-in", + variant); + variant = error_mark_node; + } + else if (variant == fndecl) + { + error_at (token->location, "variant %qD is the same as base function", + variant); + variant = error_mark_node; + } c_parser_consume_token (parser); @@ -27024,29 +27711,19 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) goto fail; ctx = omp_check_context_selector (match_loc, ctx, OMP_CTX_DECLARE_VARIANT); - if (ctx != error_mark_node && variant != error_mark_node) + + /* The OpenMP spec says the merging rules for enclosing + "begin declare variant" contexts apply to "declare variant + directives" -- the term it uses to refer to both directive + forms. */ + if (ctx != error_mark_node + && !vec_safe_is_empty (current_omp_declare_variant_attribute)) { - if (TREE_CODE (variant) != FUNCTION_DECL) - { - error_at (token->location, "variant %qD is not a function", - variant); - variant = error_mark_node; - } - else if (fndecl_built_in_p (variant) - && (strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), - "__builtin_", strlen ("__builtin_")) - == 0 - || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), - "__sync_", strlen ("__sync_")) - == 0 - || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), - "__atomic_", strlen ("__atomic_")) - == 0)) - { - error_at (token->location, "variant %qD is a built-in", - variant); - variant = error_mark_node; - } + c_omp_declare_variant_attr a + = current_omp_declare_variant_attribute->last (); + tree outer_ctx = a.selector; + ctx = omp_merge_context_selectors (match_loc, outer_ctx, ctx, + OMP_CTX_DECLARE_VARIANT); } } else if (ccode == adjust_args) @@ -27162,6 +27839,10 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) || !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%> or %<,%>")) goto fail; + if (!target && !targetsync) + error_at (loc, + "missing required %<target%> and/or " + "%<targetsync%> modifier"); tree t = build_tree_list (target ? boolean_true_node : boolean_false_node, targetsync ? boolean_true_node @@ -27185,18 +27866,64 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) parens.require_close (parser); } while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)); + if (variant != error_mark_node && !has_match) + { + c_parser_error (parser, "expected %<match%> clause"); + variant = error_mark_node; + } c_parser_skip_to_pragma_eol (parser); - if ((ctx != error_mark_node && variant != error_mark_node) + /* At this point, we have completed parsing of the pragma, now it's + on to error checking. */ + if (variant == error_mark_node || ctx == error_mark_node) + /* Previously diagnosed error. */ + return; + + if ((has_adjust_args || append_args_tree) && !omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT, - OMP_TRAIT_CONSTRUCT_SIMD)) + OMP_TRAIT_CONSTRUCT_DISPATCH)) { - bool fail = false; - if (append_args_tree) + error_at (has_adjust_args ? adjust_args_loc : append_args_loc, + "an %qs clause can only be specified if the " + "%<dispatch%> selector of the %<construct%> selector " + "set appears in the %<match%> clause", + has_adjust_args ? "adjust_args" : "append_args"); + return; + } + + if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT, + OMP_TRAIT_CONSTRUCT_SIMD)) + /* Check that the base and variant have compatible types. */ + { + tree base_type = TREE_TYPE (fndecl); + tree variant_type = TREE_TYPE (variant); + bool unprototyped_variant + = (TYPE_ARG_TYPES (variant_type) == NULL_TREE + && !TYPE_NO_NAMED_ARGS_STDARG_P (variant_type)); + + if (append_args_tree + && TYPE_ARG_TYPES (base_type) == NULL_TREE + && !TYPE_NO_NAMED_ARGS_STDARG_P (base_type)) + { + /* The base function is a pre-C23 unprototyped function. Without + a prototype, we don't know the offset where the append_args go. + That offset needs to be stored with the append_args in the + variant function attributes, so we cannot presently handle + this case. */ + sorry_at (append_args_loc, + "%<append_args%> with unprototyped base function " + "is not supported yet"); + inform (DECL_SOURCE_LOCATION (fndecl), + "base function %qD declared here", fndecl); + return; + } + else if (append_args_tree) { + /* Find nbase_args, the number of fixed arguments in the base + function. */ int nappend_args = 0; int nbase_args = 0; - for (tree t = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); + for (tree t = TYPE_ARG_TYPES (base_type); t && TREE_VALUE (t) != void_type_node; t = TREE_CHAIN (t)) nbase_args++; for (tree t = append_args_tree; t; t = TREE_CHAIN (t)) @@ -27207,135 +27934,117 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) append_args_tree = build_tree_list (build_int_cst (integer_type_node, nbase_args), append_args_tree); - tree args, arg; - args = arg = TYPE_ARG_TYPES (TREE_TYPE (variant)); - for (int j = 0; j < nbase_args && arg; j++, arg = TREE_CHAIN (arg)) - args = arg; - for (int i = 0; i < nappend_args && arg; i++) - arg = TREE_CHAIN (arg); - tree saved_args; - if (nbase_args && args) - { - saved_args = TREE_CHAIN (args); - TREE_CHAIN (args) = arg; + + /* Give a specific diagnostic if the append_args parameters + of the variant are of the wrong type, or missing. The + compatible types test below could fail to detect this if + the variant is a varargs function. */ + if (!unprototyped_variant) + { + tree args = TYPE_ARG_TYPES (variant_type); + for (int i = 0; args && i < nbase_args; + i++, args = TREE_CHAIN (args)) + ; + for (int i = 0; i < nappend_args; i++, args = TREE_CHAIN (args)) + if (!args || !c_omp_interop_t_p (TREE_VALUE (args))) + { + error_at (DECL_SOURCE_LOCATION (variant), + "argument %d of %qD must be of " + "%<omp_interop_t%>", + nbase_args + i + 1, variant); + inform (append_args_loc, + "%<append_args%> specified here"); + return; + } } - else + + /* Perform the "implementation defined transformation" on the type + of the base function to add the append_args before checking it + for compatibility with the function variant's type. */ + tree args = TYPE_ARG_TYPES (base_type); + tree newargs = NULL_TREE; + tree lastarg = NULL_TREE; + for (int j = 0; j < nbase_args; j++, args = TREE_CHAIN (args)) { - saved_args = args; - TYPE_ARG_TYPES (TREE_TYPE (variant)) = arg; - TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (variant)) = 1; + tree t = tree_cons (TREE_PURPOSE (args), + TREE_VALUE (args), NULL_TREE); + if (lastarg) + TREE_CHAIN (lastarg) = t; + else + newargs = t; + lastarg = t; } - if (!comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant))) - fail = true; - if (nbase_args && args) - TREE_CHAIN (args) = saved_args; - else + tree type = lookup_name (get_identifier ("omp_interop_t")); + type = type ? TREE_TYPE (type) : pointer_sized_int_node; + for (int j = 0; j < nappend_args; j++) { - TYPE_ARG_TYPES (TREE_TYPE (variant)) = saved_args; - TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (variant)) = 0; + tree t = tree_cons (NULL_TREE, type, NULL_TREE); + if (lastarg) + TREE_CHAIN (lastarg) = t; + else + newargs = t; + lastarg = t; } - arg = saved_args; - if (!fail) - for (int i = 0; i < nappend_args; i++, arg = TREE_CHAIN (arg)) - if (!arg || !c_omp_interop_t_p (TREE_VALUE (arg))) - { - error_at (DECL_SOURCE_LOCATION (variant), - "argument %d of %qD must be of %<omp_interop_t%>", - nbase_args + i + 1, variant); - inform (append_args_loc, "%<append_args%> specified here"); - break; - } - } - else - { - if (comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant))) + TREE_CHAIN (lastarg) = args; + + /* Temporarily stuff newargs into the original base_type. */ + tree saveargs = TYPE_ARG_TYPES (base_type); + TYPE_ARG_TYPES (base_type) = newargs; + bool fail = !comptypes (base_type, variant_type); + TYPE_ARG_TYPES (base_type) = saveargs; + + if (fail) { - if (TYPE_ARG_TYPES (TREE_TYPE (variant)) == NULL_TREE - && TYPE_ARG_TYPES (TREE_TYPE (fndecl)) != NULL_TREE) - { - if (!append_args_tree) - TYPE_ARG_TYPES (TREE_TYPE (variant)) - = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); - else - { - tree new_args = NULL_TREE; - tree arg, last_arg = NULL_TREE; - for (arg = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); - arg && arg != void_type_node; arg = TREE_CHAIN (arg)) - { - if (new_args == NULL_TREE) - new_args = last_arg = copy_node (arg); - else - { - TREE_CHAIN (last_arg) = copy_node (arg); - last_arg = TREE_CHAIN (last_arg); - } - } - for (tree t3 = append_args_tree; t3; t3 = TREE_CHAIN (t3)) - { - tree type = lookup_name (get_identifier ("omp_interop_t")); - type = type ? TREE_TYPE (type) : ptr_type_node; - last_arg = tree_cons (NULL_TREE, type, last_arg); - } - TREE_CHAIN (last_arg) = arg; - TYPE_ARG_TYPES (TREE_TYPE (variant)) = new_args; - } - } + error_at (token->location, + "variant %qD and base %qD have incompatible types " + "after %<append_args%> adjustment", + variant, fndecl); + inform (DECL_SOURCE_LOCATION (variant), + "%<declare variant%> candidate %qD declared here", + variant); + return; } - else - fail = true; - } - if (fail) - { - error_at (token->location, - "variant %qD and base %qD have incompatible types", - variant, fndecl); - variant = error_mark_node; + else if (unprototyped_variant) + /* If we've got an unprototyped variant, copy the transformed + base arg types to the variant. This is needed later by + modify_call_for_omp_dispatch. */ + TYPE_ARG_TYPES (variant_type) = newargs; } - } - if (ctx != error_mark_node && variant != error_mark_node) - { - C_DECL_USED (variant) = 1; - tree construct = omp_get_context_selector_list (ctx, - OMP_TRAIT_SET_CONSTRUCT); - omp_mark_declare_variant (match_loc, variant, construct); - if (omp_context_selector_matches (ctx, NULL_TREE, false)) + else /* No append_args present. */ { - tree attr = tree_cons (get_identifier ("omp declare variant base"), - build_tree_list (variant, ctx), - DECL_ATTRIBUTES (fndecl)); - DECL_ATTRIBUTES (fndecl) = attr; + if (!comptypes (base_type, variant_type)) + { + error_at (token->location, + "variant %qD and base %qD have incompatible types", + variant, fndecl); + inform (DECL_SOURCE_LOCATION (variant), + "%<declare variant%> candidate %qD declared here", + variant); + return; + } + else if (TYPE_ARG_TYPES (variant_type) == NULL_TREE + && !TYPE_NO_NAMED_ARGS_STDARG_P (variant_type) + && TYPE_ARG_TYPES (base_type) != NULL_TREE) + /* If we've got an unprototyped variant but the base has + a prototype, copy the base arg types to the variant. */ + TYPE_ARG_TYPES (variant_type) = TYPE_ARG_TYPES (base_type); } } - if (has_adjust_args || append_args_tree) + /* If we made it here, store the parsed information. */ + C_DECL_USED (variant) = 1; + tree construct = omp_get_context_selector_list (ctx, + OMP_TRAIT_SET_CONSTRUCT); + omp_mark_declare_variant (match_loc, variant, construct); + if (omp_context_selector_matches (ctx, NULL_TREE, false)) { - if (!has_match) - { - error_at (has_adjust_args ? adjust_args_loc : append_args_loc, - "an %qs clause requires a %<match%> clause", - has_adjust_args ? "adjust_args" : "append_args"); - } - else if (ctx != error_mark_node && variant != error_mark_node) - { - tree attr = lookup_attribute ("omp declare variant base", - DECL_ATTRIBUTES (fndecl)); - if (attr != NULL_TREE) - { - tree ctx = TREE_VALUE (TREE_VALUE (attr)); - if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT, - OMP_TRAIT_CONSTRUCT_DISPATCH)) - error_at (has_adjust_args ? adjust_args_loc : append_args_loc, - "an %qs clause can only be specified if the " - "%<dispatch%> selector of the %<construct%> selector " - "set appears in the %<match%> clause", - has_adjust_args ? "adjust_args" : "append_args"); - } - } + tree attr = tree_cons (get_identifier ("omp declare variant base"), + build_tree_list (variant, ctx), + DECL_ATTRIBUTES (fndecl)); + DECL_ATTRIBUTES (fndecl) = attr; } - if ((ctx != error_mark_node && variant != error_mark_node) - && (need_device_ptr_list || append_args_tree)) + if (need_device_ptr_list || append_args_tree) { tree variant_decl = tree_strip_nop_conversions (variant); tree t = build_tree_list (need_device_ptr_list, @@ -27382,6 +28091,13 @@ c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms, clauses[0].type = CPP_EOF; return; } + if (DECL_FUNCTION_VERSIONED (fndecl)) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "%<#pragma omp declare %s%> cannot be used with function " + "multi-versioning", kind); + return; + } if (parms == NULL_TREE) parms = DECL_ARGUMENTS (fndecl); @@ -27426,6 +28142,90 @@ c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms, clauses[0].type = CPP_PRAGMA; } +/* This is consistent with the C++ front end. */ + +#if !defined (NO_DOT_IN_LABEL) +#define JOIN_STR "." +#elif !defined (NO_DOLLAR_IN_LABEL) +#define JOIN_STR "$" +#else +#define JOIN_STR "_" +#endif + +/* Helper function for OpenMP "begin declare variant" directives. + Function definitions inside the construct need to have their names + mangled according to the context selector CTX. The DECLARATOR is + modified in place to point to a new identifier; the original name of + the function is returned. */ +static tree +omp_start_variant_function (c_declarator *declarator, tree ctx) +{ + c_declarator *id = declarator; + while (id->kind != cdk_id) + { + id = id->declarator; + gcc_assert (id); + } + tree name = id->u.id.id; + id->u.id.id = omp_mangle_variant_name (name, ctx, JOIN_STR); + return name; +} + +/* Helper function for OpenMP "begin declare variant" directives. Now + that we have a DECL for the variant function, and BASE_NAME for the + base function, add an "omp declare variant base" attribute pointing + at CTX to the base decl, and an "omp declare variant variant" + attribute to the variant DECL. */ +static void +omp_finish_variant_function (tree decl, tree base_name, tree ctx) +{ + /* First look up BASE_NAME and ensure it matches DECL. */ + tree base_decl = lookup_name (base_name); + if (base_decl == error_mark_node) + base_decl = NULL_TREE; + if (!base_decl) + { + error_at (DECL_SOURCE_LOCATION (decl), + "no declaration of base function %qs", + IDENTIFIER_POINTER (base_name)); + return; + } + + if (!comptypes (TREE_TYPE (decl), TREE_TYPE (base_decl))) + { + error_at (DECL_SOURCE_LOCATION (decl), + "variant function definition does not match " + "declaration of %qE", base_decl); + inform (DECL_SOURCE_LOCATION (base_decl), + "%qE declared here", base_decl); + return; + } + + /* Now set the attributes on the base and variant decls for the middle + end. */ + omp_check_for_duplicate_variant (DECL_SOURCE_LOCATION (decl), + base_decl, ctx); + tree construct + = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT); + omp_mark_declare_variant (DECL_SOURCE_LOCATION (decl), decl, construct); + tree attrs = DECL_ATTRIBUTES (base_decl); + tree match_loc_node + = maybe_wrap_with_location (integer_zero_node, + DECL_SOURCE_LOCATION (base_decl)); + tree loc_node = tree_cons (match_loc_node, integer_zero_node, + build_tree_list (match_loc_node, + integer_zero_node)); + attrs = tree_cons (get_identifier ("omp declare variant base"), + tree_cons (decl, ctx, loc_node), attrs); + DECL_ATTRIBUTES (base_decl) = attrs; + + /* Variant functions are essentially anonymous and cannot be referenced + outside the compilation unit. */ + TREE_PUBLIC (decl) = 0; + DECL_COMDAT (decl) = 0; +} + + /* D should be C_TOKEN_VEC from omp::decl attribute. If it contains a threadprivate, groupprivate, allocate or declare target directive, return true and parse it for DECL. */ @@ -27658,7 +28458,9 @@ c_parser_omp_declare_target (c_parser *parser) /* OpenMP 5.1 #pragma omp begin assumes clauses[optseq] new-line - #pragma omp begin declare target clauses[optseq] new-line */ + #pragma omp begin declare target clauses[optseq] new-line + + #pragma omp begin declare variant match (context-selector) new-line */ #define OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE) \ @@ -27698,11 +28500,77 @@ c_parser_omp_begin (c_parser *parser) indirect }; vec_safe_push (current_omp_declare_target_attribute, attr); } - else + else if (strcmp (p, "variant") == 0) { - c_parser_error (parser, "expected %<target%>"); + c_parser_consume_token (parser); + const char *clause = ""; + matching_parens parens; + location_t match_loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree id = c_parser_peek_token (parser)->value; + clause = IDENTIFIER_POINTER (id); + } + if (strcmp (clause, "match") != 0) + { + c_parser_error (parser, "expected %<match%>"); + c_parser_skip_to_pragma_eol (parser); + return; + } + + c_parser_consume_token (parser); + + if (!parens.require_open (parser)) + { + c_parser_skip_to_pragma_eol (parser, false); + return; + } + + tree ctx = + c_parser_omp_context_selector_specification (parser, NULL_TREE); + if (ctx != error_mark_node) + ctx = omp_check_context_selector (match_loc, ctx, + OMP_CTX_BEGIN_DECLARE_VARIANT); + + if (ctx != error_mark_node + && !vec_safe_is_empty (current_omp_declare_variant_attribute)) + { + c_omp_declare_variant_attr a + = current_omp_declare_variant_attribute->last (); + tree outer_ctx = a.selector; + ctx = omp_merge_context_selectors (match_loc, outer_ctx, ctx, + OMP_CTX_BEGIN_DECLARE_VARIANT); + } + + if (ctx == error_mark_node + || !omp_context_selector_matches (ctx, NULL_TREE, false, true)) + { + /* The context is either invalid or cannot possibly match. + In the latter case the spec says all code in the begin/end + sequence will be elided. In the former case we'll get bogus + errors from trying to parse it without a valid context to + use for name-mangling, so elide that too. */ + c_parser_skip_to_pragma_eol (parser, false); + c_parser_skip_to_pragma_omp_end_declare_variant (parser); + return; + } + else + { + bool attr_syntax = parser->in_omp_attribute_pragma != NULL; + c_omp_declare_variant_attr a = { attr_syntax, ctx }; + vec_safe_push (current_omp_declare_variant_attribute, a); + } + + parens.require_close (parser); c_parser_skip_to_pragma_eol (parser); } + else + { + c_parser_error (parser, "expected %<target%> or %<variant%>"); + c_parser_skip_to_pragma_eol (parser, false); + } } else if (strcmp (p, "assumes") == 0) { @@ -27714,7 +28582,8 @@ c_parser_omp_begin (c_parser *parser) } else { - c_parser_error (parser, "expected %<declare target%> or %<assumes%>"); + c_parser_error (parser, "expected %<declare target%>, " + "%<declare variant%>, or %<assumes%>"); c_parser_skip_to_pragma_eol (parser); } } @@ -27723,7 +28592,8 @@ c_parser_omp_begin (c_parser *parser) #pragma omp end declare target OpenMP 5.1 - #pragma omp end assumes */ + #pragma omp end assumes + #pragma omp end declare variant */ static void c_parser_omp_end (c_parser *parser) @@ -27736,44 +28606,74 @@ c_parser_omp_end (c_parser *parser) if (strcmp (p, "declare") == 0) { c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_NAME) - && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), - "target") == 0) - c_parser_consume_token (parser); - else + p = ""; + if (c_parser_next_token_is (parser, CPP_NAME)) + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "target") == 0) { - c_parser_error (parser, "expected %<target%>"); + c_parser_consume_token (parser); + bool attr_syntax = parser->in_omp_attribute_pragma != NULL; c_parser_skip_to_pragma_eol (parser); - return; + if (!vec_safe_length (current_omp_declare_target_attribute)) + error_at (loc, "%<#pragma omp end declare target%> without " + "corresponding %<#pragma omp declare target%> or " + "%<#pragma omp begin declare target%>"); + else + { + c_omp_declare_target_attr + a = current_omp_declare_target_attribute->pop (); + if (a.attr_syntax != attr_syntax) + { + if (a.attr_syntax) + error_at (loc, + "%qs in attribute syntax terminated " + "with %qs in pragma syntax", + a.device_type >= 0 ? "begin declare target" + : "declare target", + "end declare target"); + else + error_at (loc, + "%qs in pragma syntax terminated " + "with %qs in attribute syntax", + a.device_type >= 0 ? "begin declare target" + : "declare target", + "end declare target"); + } + } } - bool attr_syntax = parser->in_omp_attribute_pragma != NULL; - c_parser_skip_to_pragma_eol (parser); - if (!vec_safe_length (current_omp_declare_target_attribute)) - error_at (loc, "%<#pragma omp end declare target%> without " - "corresponding %<#pragma omp declare target%> or " - "%<#pragma omp begin declare target%>"); - else + else if (strcmp (p, "variant") == 0) { - c_omp_declare_target_attr - a = current_omp_declare_target_attribute->pop (); - if (a.attr_syntax != attr_syntax) + c_parser_consume_token (parser); + bool attr_syntax = parser->in_omp_attribute_pragma != NULL; + c_parser_skip_to_pragma_eol (parser); + if (!vec_safe_length (current_omp_declare_variant_attribute)) + error_at (loc, "%<#pragma omp end declare variant%> without " + "corresponding %<#pragma omp begin declare variant%>"); + else { - if (a.attr_syntax) - error_at (loc, - "%qs in attribute syntax terminated " - "with %qs in pragma syntax", - a.device_type >= 0 ? "begin declare target" - : "declare target", - "end declare target"); - else - error_at (loc, - "%qs in pragma syntax terminated " - "with %qs in attribute syntax", - a.device_type >= 0 ? "begin declare target" - : "declare target", - "end declare target"); + c_omp_declare_variant_attr + a = current_omp_declare_variant_attribute->pop (); + if (a.attr_syntax != attr_syntax) + { + if (a.attr_syntax) + error_at (loc, + "%<begin declare variant%> in attribute syntax " + "terminated with " + "%<end declare variant%> in pragma syntax"); + else + error_at (loc, + "%<begin declare variant%> in pragma syntax " + "terminated with " + "%<end declare variant%> in attribute syntax"); + } } } + else + { + c_parser_error (parser, "expected %<target%> or %<variant%>"); + c_parser_skip_to_pragma_eol (parser); + return; + } } else if (strcmp (p, "assumes") == 0) { @@ -27809,6 +28709,151 @@ c_parser_omp_end (c_parser *parser) } } +/* OpenMP 5.0 + #pragma omp declare mapper ([mapper-identifier :] type var) \ + [clause [ [,] clause ] ... ] new-line */ + +static void +c_parser_omp_declare_mapper (c_parser *parser, enum pragma_context context) +{ + tree type, mapper_name = NULL_TREE, var = NULL_TREE, stmt, stmtlist; + tree maplist = NULL_TREE, mapper_id, mapper_decl, t; + c_token *token; + + if (context == pragma_struct || context == pragma_param) + { + error ("%<#pragma omp declare mapper%> not at file or block scope"); + goto fail; + } + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + goto fail; + + token = c_parser_peek_token (parser); + + if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + switch (token->type) + { + case CPP_NAME: + mapper_name = token->value; + c_parser_consume_token (parser); + break; + case CPP_KEYWORD: + if (token->keyword == RID_DEFAULT) + { + mapper_name = NULL_TREE; + c_parser_consume_token (parser); + break; + } + /* Fallthrough. */ + default: + error_at (token->location, "expected identifier or %<default%>"); + c_parser_skip_to_pragma_eol (parser, false); + return; + } + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto fail; + } + + mapper_id = c_omp_mapper_id (mapper_name); + mapper_decl = c_omp_mapper_decl (mapper_id); + + { + location_t loc = c_parser_peek_token (parser)->location; + struct c_type_name *ctype = c_parser_type_name (parser); + type = groktypename (ctype, NULL, NULL); + if (type == error_mark_node) + goto fail; + if (!RECORD_OR_UNION_TYPE_P (type)) + { + error_at (loc, "%qT is not a struct or union type in " + "%<#pragma omp declare mapper%>", type); + c_parser_skip_to_pragma_eol (parser, false); + return; + } + for (tree t = DECL_INITIAL (mapper_decl); t; t = TREE_CHAIN (t)) + if (comptypes (TREE_PURPOSE (t), type)) + { + error_at (loc, "redeclaration of %qs %<#pragma omp declare " + "mapper%> for type %qT", IDENTIFIER_POINTER (mapper_id) + + sizeof ("omp declare mapper ") - 1, + type); + tree prevmapper = TREE_VALUE (t); + /* Hmm, this location might not be very accurate. */ + location_t ploc + = DECL_SOURCE_LOCATION (OMP_DECLARE_MAPPER_DECL (prevmapper)); + inform (ploc, "%<#pragma omp declare mapper%> " + "previously declared here"); + c_parser_skip_to_pragma_eol (parser, false); + return; + } + } + + token = c_parser_peek_token (parser); + if (token->type == CPP_NAME) + { + var = build_decl (token->location, VAR_DECL, token->value, type); + c_parser_consume_token (parser); + DECL_ARTIFICIAL (var) = 1; + } + else + { + error_at (token->location, "expected identifier"); + goto fail; + } + + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + goto fail; + + push_scope (); + stmtlist = push_stmt_list (); + pushdecl (var); + DECL_CONTEXT (var) = current_function_decl; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + location_t here; + pragma_omp_clause c_kind; + here = c_parser_peek_token (parser)->location; + c_kind = c_parser_omp_clause_name (parser); + if (c_kind != PRAGMA_OMP_CLAUSE_MAP) + { + error_at (here, "unexpected clause"); + goto fail; + } + maplist = c_parser_omp_clause_map (parser, maplist, true); + } + + if (maplist == NULL_TREE) + { + error_at (input_location, "missing %<map%> clause"); + goto fail; + } + + stmt = make_node (OMP_DECLARE_MAPPER); + TREE_TYPE (stmt) = type; + OMP_DECLARE_MAPPER_ID (stmt) = mapper_name; + OMP_DECLARE_MAPPER_DECL (stmt) = var; + OMP_DECLARE_MAPPER_CLAUSES (stmt) = maplist; + + add_stmt (stmt); + + pop_stmt_list (stmtlist); + pop_scope (); + + c_parser_skip_to_pragma_eol (parser); + + t = tree_cons (type, stmt, DECL_INITIAL (mapper_decl)); + DECL_INITIAL (mapper_decl) = t; + + return; + + fail: + c_parser_skip_to_pragma_eol (parser); +} + /* OpenMP 4.0 #pragma omp declare reduction (reduction-id : typename-list : expression) \ initializer-clause[opt] new-line @@ -27935,8 +28980,8 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) location_t ploc = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t), 0)); - error_at (ploc, "previous %<#pragma omp declare " - "reduction%>"); + inform (ploc, "%<#pragma omp declare reduction%> " + "previously declared here"); break; } if (t == NULL_TREE) @@ -28200,6 +29245,12 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context) c_parser_omp_declare_reduction (parser, context); return false; } + if (strcmp (p, "mapper") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_declare_mapper (parser, context); + return false; + } if (!flag_openmp) /* flag_openmp_simd */ { c_parser_skip_to_pragma_eol (parser, false); @@ -28756,6 +29807,14 @@ c_parser_omp_error (c_parser *parser, enum pragma_context context) "may only be used in compound statements"); return true; } + if (parser->omp_for_parse_state + && parser->omp_for_parse_state->in_intervening_code) + { + error_at (loc, "%<#pragma omp error%> with %<at(execution)%> clause " + "may not be used in intervening code"); + parser->omp_for_parse_state->fail = true; + return true; + } tree fndecl = builtin_decl_explicit (severity_fatal ? BUILT_IN_GOMP_ERROR : BUILT_IN_GOMP_WARNING); @@ -28773,11 +29832,14 @@ c_parser_omp_error (c_parser *parser, enum pragma_context context) if (msg == NULL) msg = _("<message unknown at compile time>"); } + const enum diagnostics::kind diag_kind = (severity_fatal + ? diagnostics::kind::error + : diagnostics::kind::warning); if (msg) - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + emit_diagnostic (diag_kind, loc, 0, "%<pragma omp error%> encountered: %s", msg); else - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + emit_diagnostic (diag_kind, loc, 0, "%<pragma omp error%> encountered"); return false; } @@ -28899,6 +29961,7 @@ c_parser_omp_assumption_clauses (c_parser *parser, bool is_assume) directive[1], directive[2]); if (dir + && dir->id != PRAGMA_OMP_END && (dir->kind == C_OMP_DIR_DECLARATIVE || dir->kind == C_OMP_DIR_INFORMATIONAL || dir->kind == C_OMP_DIR_META)) @@ -29109,7 +30172,6 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) { error_at (match_loc, "too many %<otherwise%> or %<default%> " "clauses in %<metadirective%>"); - c_parser_skip_to_end_of_block_or_statement (parser, true); goto error; } default_seen = true; @@ -29118,14 +30180,12 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) { error_at (match_loc, "%<otherwise%> or %<default%> clause " "must appear last in %<metadirective%>"); - c_parser_skip_to_end_of_block_or_statement (parser, true); goto error; } if (!default_p && strcmp (p, "when") != 0) { error_at (match_loc, "%qs is not valid for %qs", p, "metadirective"); - c_parser_skip_to_end_of_block_or_statement (parser, true); goto error; } @@ -29193,7 +30253,6 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) if (i == 0) { error_at (loc, "expected directive name"); - c_parser_skip_to_end_of_block_or_statement (parser, true); goto error; } @@ -29261,7 +30320,10 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) goto add; case CPP_CLOSE_PAREN: if (nesting_depth-- == 0) - break; + { + c_parser_consume_token (parser); + break; + } goto add; default: add: @@ -29273,8 +30335,6 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) break; } - c_parser_consume_token (parser); - if (!skip) { c_token eol_token; @@ -29285,6 +30345,17 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) } c_parser_skip_to_pragma_eol (parser); + /* If only one selector matches and it evaluates to 'omp nothing', no need to + proceed. */ + if (ctxs.length () == 1) + { + tree ctx = ctxs[0]; + if (ctx == NULL_TREE + || (omp_context_selector_matches (ctx, NULL_TREE, false) == 1 + && directive_tokens[0].pragma_kind == PRAGMA_OMP_NOTHING)) + return; + } + if (!default_seen) { /* Add a default clause that evaluates to 'omp nothing'. */ @@ -29365,7 +30436,7 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) if (standalone_body == NULL_TREE) { standalone_body = push_stmt_list (); - c_parser_statement (parser, if_p); + c_parser_statement (parser, if_p); // TODO skip this standalone_body = pop_stmt_list (standalone_body); } else @@ -29401,9 +30472,9 @@ c_parser_omp_metadirective (c_parser *parser, bool *if_p) return; error: + /* Skip the metadirective pragma. Do not skip the metadirective body. */ if (parser->in_pragma) - c_parser_skip_to_pragma_eol (parser); - c_parser_skip_to_end_of_block_or_statement (parser, true); + c_parser_skip_to_pragma_eol (parser, false); } /* Main entry point to parsing most OpenMP pragmas. */ @@ -29637,10 +30708,12 @@ c_parser_transaction (c_parser *parser, enum rid keyword) if (flag_tm) stmt = c_finish_transaction (loc, stmt, this_in); else - error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? - "%<__transaction_atomic%> without transactional memory support enabled" - : "%<__transaction_relaxed %> " - "without transactional memory support enabled")); + error_at (loc, + keyword == RID_TRANSACTION_ATOMIC + ? G_("%<__transaction_atomic%> without transactional memory " + "support enabled") + : G_("%<__transaction_relaxed%> without transactional memory " + "support enabled")); return stmt; } @@ -29704,10 +30777,12 @@ c_parser_transaction_expression (c_parser *parser, enum rid keyword) parser->in_transaction = old_in; if (!flag_tm) - error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? - "%<__transaction_atomic%> without transactional memory support enabled" - : "%<__transaction_relaxed %> " - "without transactional memory support enabled")); + error_at (loc, + keyword == RID_TRANSACTION_ATOMIC + ? G_("%<__transaction_atomic%> without transactional memory " + "support enabled") + : G_("%<__transaction_relaxed%> without transactional memory " + "support enabled")); set_c_expr_source_range (&ret, loc, loc); |
