aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c/c-parser.cc')
-rw-r--r--gcc/c/c-parser.cc1885
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);