aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/parser.cc')
-rw-r--r--gcc/cp/parser.cc2735
1 files changed, 2351 insertions, 384 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 812a7c5..cdfa8f0 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see
#include "contracts.h"
#include "bitmap.h"
#include "builtins.h"
+#include "analyzer/analyzer-language.h"
/* The lexer. */
@@ -82,7 +83,7 @@ enum non_integral_constant {
NIC_FUNC_CALL,
/* an increment */
NIC_INC,
- /* an decrement */
+ /* a decrement */
NIC_DEC,
/* an array reference */
NIC_ARRAY_REF,
@@ -272,6 +273,10 @@ static void cp_finalize_oacc_routine
static void check_omp_intervening_code
(cp_parser *);
+static tree omp_start_variant_function
+ (cp_declarator *, tree);
+static int omp_finish_variant_function
+ (cp_parser *, tree, tree, tree, bool, bool);
/* Manifest constants. */
#define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
@@ -286,6 +291,37 @@ static FILE *cp_lexer_debug_stream;
sizeof, typeof, or alignof. */
int cp_unevaluated_operand;
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* Concrete implementation of ana::translation_unit for the C++ frontend. */
+
+class cp_translation_unit : public translation_unit
+{
+public:
+ tree lookup_constant_by_id (tree /*id*/) const final override
+ {
+ return NULL_TREE;
+ }
+
+ tree
+ lookup_type_by_id (tree /*id*/) const final override
+ {
+ return NULL_TREE;
+ }
+
+ tree
+ lookup_global_var_by_id (tree /*id*/) const final override
+ {
+ return NULL_TREE;
+ }
+};
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
+
/* Dump up to NUM tokens in BUFFER to FILE starting with token
START_TOKEN. If START_TOKEN is NULL, the dump starts with the
first token in BUFFER. If NUM is 0, dump all the tokens. If
@@ -569,6 +605,8 @@ cp_debug_parser (FILE *file, cp_parser *parser)
parser->in_template_argument_list_p);
cp_debug_print_flag (file, "Parsing an iteration statement",
parser->in_statement & IN_ITERATION_STMT);
+ cp_debug_print_flag (file, "Parsing an expansion statement",
+ parser->in_statement & IN_EXPANSION_STMT);
cp_debug_print_flag (file, "Parsing a switch statement",
parser->in_statement & IN_SWITCH_STMT);
cp_debug_print_flag (file, "Parsing a structured OpenMP block",
@@ -2487,7 +2525,7 @@ static cp_expr cp_parser_id_expression
static cp_expr cp_parser_unqualified_id
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_nested_name_specifier_opt
- (cp_parser *, bool, bool, bool, bool, bool = false);
+ (cp_parser *, bool, bool, bool, bool, bool = false, bool = false);
static tree cp_parser_nested_name_specifier
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_qualifying_entity
@@ -2541,14 +2579,15 @@ static cp_expr cp_parser_expression
(cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false);
static cp_expr cp_parser_constant_expression
(cp_parser *, int = 0, bool * = NULL, bool = false);
+static cp_expr cp_parser_builtin_c23_va_start (cp_parser *);
static cp_expr cp_parser_builtin_offsetof
(cp_parser *);
static cp_expr cp_parser_lambda_expression
- (cp_parser *);
+ (cp_parser *, bool = false);
static void cp_parser_lambda_introducer
(cp_parser *, tree);
static bool cp_parser_lambda_declarator_opt
- (cp_parser *, tree);
+ (cp_parser *, tree, bool = false);
static void cp_parser_lambda_body
(cp_parser *, tree);
@@ -2579,11 +2618,11 @@ static tree cp_parser_c_for
static tree cp_parser_range_for
(cp_parser *, tree, tree, tree, bool, tree, bool, bool);
static void do_range_for_auto_deduction
- (tree, tree, cp_decomp *);
-static tree cp_parser_perform_range_for_lookup
- (tree, tree *, tree *);
-static tree cp_parser_range_for_member_function
+ (tree, tree, cp_decomp *, bool);
+static tree cp_range_for_member_function
(tree, tree);
+static tree cp_parser_expansion_statement
+ (cp_parser *, bool *);
static tree cp_parser_jump_statement
(cp_parser *, tree &);
static void cp_parser_declaration_statement
@@ -2889,7 +2928,7 @@ static size_t cp_parser_skip_std_attribute_spec_seq
static size_t cp_parser_skip_attributes_opt
(cp_parser *, size_t);
static bool cp_parser_extension_opt
- (cp_parser *, int *);
+ (cp_parser *, int *, int *);
static void cp_parser_label_declaration
(cp_parser *);
@@ -3059,8 +3098,8 @@ static cp_token *cp_parser_require_keyword
(cp_parser *, enum rid, required_token);
static bool cp_parser_token_starts_function_definition_p
(cp_token *);
-static bool cp_parser_next_token_starts_class_definition_p
- (cp_parser *);
+static bool cp_parser_nth_token_starts_class_definition_p
+ (cp_parser *, size_t);
static bool cp_parser_next_token_ends_template_argument_p
(cp_parser *);
static bool cp_parser_nth_token_starts_template_argument_list_p
@@ -3434,9 +3473,11 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid,
const char *header_hint
= get_cp_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));
}
/* Actually emit the error. */
@@ -3745,7 +3786,7 @@ cp_parser_non_integral_constant_expression (cp_parser *parser,
"cannot appear in a constant-expression");
return true;
case NIC_DEC:
- error ("an decrement "
+ error ("a decrement "
"cannot appear in a constant-expression");
return true;
case NIC_ARRAY_REF:
@@ -4524,6 +4565,54 @@ cp_parser_require_pragma_eol (cp_parser *parser, cp_token *pragma_tok)
}
}
+/* Skip tokens up to and including "#pragma omp end declare variant".
+ Properly handle nested "#pragma omp begin declare variant" pragmas. */
+static void
+cp_parser_skip_to_pragma_omp_end_declare_variant (cp_parser *parser)
+{
+ for (int depth = 0; depth >= 0; )
+ {
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ switch (token->type)
+ {
+ case CPP_PRAGMA_EOL:
+ if (!parser->lexer->in_pragma)
+ break;
+ /* FALLTHRU */
+ case CPP_EOF:
+ /* If we've run out of tokens, stop. */
+ return;
+
+ case CPP_PRAGMA:
+ if ((cp_parser_pragma_kind (token) == PRAGMA_OMP_BEGIN
+ || cp_parser_pragma_kind (token) == PRAGMA_OMP_END)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)
+ && cp_lexer_nth_token_is (parser->lexer, 3, CPP_NAME))
+ {
+ tree id1 = cp_lexer_peek_nth_token (parser->lexer, 2)->u.value;
+ tree id2 = cp_lexer_peek_nth_token (parser->lexer, 3)->u.value;
+ if (strcmp (IDENTIFIER_POINTER (id1), "declare") == 0
+ && strcmp (IDENTIFIER_POINTER (id2), "variant") == 0)
+ {
+ if (cp_parser_pragma_kind (token) == PRAGMA_OMP_BEGIN)
+ depth++;
+ else
+ depth--;
+ }
+ }
+ cp_parser_skip_to_pragma_eol (parser, token);
+ continue;
+
+ default:
+ break;
+ }
+
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ }
+}
+
/* This is a simple wrapper around make_typename_type. When the id is
an unresolved identifier node, we can provide a superior diagnostic
using cp_parser_diagnose_invalid_type_name. */
@@ -5232,7 +5321,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
&& (id_equal (suffix_id, "i")
|| id_equal (suffix_id, "if")
|| id_equal (suffix_id, "il")));
- diagnostic_t kind = DK_ERROR;
+ enum diagnostics::kind kind = diagnostics::kind::error;
int opt = 0;
if (i14 && ext)
@@ -5242,7 +5331,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
if (cxlit == error_mark_node)
{
/* No <complex>, so pedwarn and use GNU semantics. */
- kind = DK_PEDWARN;
+ kind = diagnostics::kind::pedwarn;
opt = OPT_Wpedantic;
}
}
@@ -5269,7 +5358,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
"to enable more built-in suffixes");
}
- if (kind == DK_ERROR)
+ if (kind == diagnostics::kind::error)
value = error_mark_node;
else
{
@@ -5469,6 +5558,30 @@ cp_parser_translation_unit (cp_parser* parser)
cp_parser_toplevel_declaration (parser);
}
+ /* Register any functions found in "begin declare variant" blocks, whose
+ base function declarations may be found "elsewhere" in the translation
+ unit. */
+ /* FIXME: we could probably just diagnose any leftover functions as an
+ error directly here, all valid cases were supposed to have been
+ caught already. */
+ if (vec_safe_length (parser->omp_begin_declare_variant_map))
+ {
+ unsigned int i;
+ omp_begin_declare_variant_map_entry *e;
+ FOR_EACH_VEC_ELT (*parser->omp_begin_declare_variant_map, i, e)
+ omp_finish_variant_function (parser, e->variant, e->id, e->ctx,
+ false, true);
+ parser->omp_begin_declare_variant_map = NULL;
+ }
+
+#if ENABLE_ANALYZER
+ if (flag_analyzer)
+ {
+ ana::cp_translation_unit tu;
+ ana::on_finish_translation_unit (tu);
+ }
+#endif
+
/* Get rid of the token array; we don't need it any more. */
cp_lexer_destroy (parser->lexer);
parser->lexer = NULL;
@@ -6265,7 +6378,10 @@ cp_parser_primary_expression (cp_parser *parser,
/* Recognize the `this' keyword. */
case RID_THIS:
cp_lexer_consume_token (parser->lexer);
- if (parser->local_variables_forbidden_p & THIS_FORBIDDEN)
+ if ((parser->local_variables_forbidden_p & THIS_FORBIDDEN)
+ /* It's OK to refer to 'this' in an unevaluated operand in a
+ lambda default argument (lambda-targ16.C). */
+ && !cp_unevaluated_operand)
{
error_at (token->location,
"%<this%> may not be used in this context");
@@ -6360,6 +6476,9 @@ cp_parser_primary_expression (cp_parser *parser,
return build_x_va_arg (combined_loc, expression, type);
}
+ case RID_C23_VA_START:
+ return cp_parser_builtin_c23_va_start (parser);
+
case RID_OFFSETOF:
return cp_parser_builtin_offsetof (parser);
@@ -6602,7 +6721,8 @@ cp_parser_primary_expression (cp_parser *parser,
member template. */
static void
-missing_template_diag (location_t loc, diagnostic_t diag_kind = DK_WARNING)
+missing_template_diag (location_t loc,
+ enum diagnostics::kind diag_kind = diagnostics::kind::warning)
{
if (warning_suppressed_at (loc, OPT_Wmissing_template_keyword))
return;
@@ -7197,18 +7317,22 @@ check_template_keyword_in_nested_name_spec (tree name)
nested-name-specifier template [opt] simple-template-id ::
PARSER->SCOPE should be set appropriately before this function is
- called. TYPENAME_KEYWORD_P is TRUE if the `typename' keyword is in
- effect. TYPE_P is TRUE if we non-type bindings should be ignored
- in name lookups.
+ called. TYPENAME_KEYWORD_P is true if the `typename' keyword is in
+ effect. TYPE_P is true if we non-type bindings should be ignored
+ in name lookups. TEMPLATE_KEYWORD_P is true if the `template' keyword
+ was seen. GLOBAL_P is true if `::' has already been parsed.
+ TODO: This function doesn't handle the C++14 change to make `::'
+ a nested-name-specifier by itself. If it did, GLOBAL_P could probably
+ go.
Sets PARSER->SCOPE to the class (TYPE) or namespace
(NAMESPACE_DECL) specified by the nested-name-specifier, or leaves
it unchanged if there is no nested-name-specifier. Returns the new
scope iff there is a nested-name-specifier, or NULL_TREE otherwise.
- If CHECK_DEPENDENCY_P is FALSE, names are looked up in dependent scopes.
+ If CHECK_DEPENDENCY_P is false, names are looked up in dependent scopes.
- If IS_DECLARATION is TRUE, the nested-name-specifier is known to be
+ If IS_DECLARATION is true, the nested-name-specifier is known to be
part of a declaration and/or decl-specifier. */
static tree
@@ -7217,7 +7341,8 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
bool check_dependency_p,
bool type_p,
bool is_declaration,
- bool template_keyword_p /* = false */)
+ bool template_keyword_p /* = false */,
+ bool global_p /* = false */)
{
bool success = false;
cp_token_position start = 0;
@@ -7265,8 +7390,9 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
/* Spot cases that cannot be the beginning of a
nested-name-specifier. On the second and subsequent times
- through the loop, we look for the `template' keyword. */
- if (success && token->keyword == RID_TEMPLATE)
+ (or the first, if '::' has already been parsed) through the
+ loop, we look for the `template' keyword. */
+ if ((success || global_p) && token->keyword == RID_TEMPLATE)
;
/* A template-id can start a nested-name-specifier. */
else if (token->type == CPP_TEMPLATE_ID)
@@ -7314,8 +7440,11 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
cp_parser_parse_tentatively (parser);
/* Look for the optional `template' keyword, if this isn't the
- first time through the loop. */
- if (success)
+ first time through the loop, or if we've already parsed '::';
+ this is then the
+ nested-name-specifier template [opt] simple-template-id ::
+ production. */
+ if (success || global_p)
{
template_keyword_p = cp_parser_optional_template_keyword (parser);
/* DR1710: "In a qualified-id used as the name in
@@ -8800,8 +8929,10 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression,
{
/* In a template, be permissive by treating an object expression
of incomplete type as dependent (after a pedwarn). */
- diagnostic_t kind = (processing_template_decl
- && MAYBE_CLASS_TYPE_P (*scope) ? DK_PEDWARN : DK_ERROR);
+ enum diagnostics::kind kind = ((processing_template_decl
+ && MAYBE_CLASS_TYPE_P (*scope))
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::error);
switch (TREE_CODE (*postfix_expression))
{
@@ -8813,27 +8944,27 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression,
case IMPLICIT_CONV_EXPR:
case VIEW_CONVERT_EXPR:
case NON_LVALUE_EXPR:
- kind = DK_ERROR;
+ kind = diagnostics::kind::error;
break;
case OVERLOAD:
/* Don't emit any diagnostic for OVERLOADs. */
- kind = DK_IGNORED;
+ kind = diagnostics::kind::ignored;
break;
default:
/* Avoid clobbering e.g. DECLs. */
if (!EXPR_P (*postfix_expression))
- kind = DK_ERROR;
+ kind = diagnostics::kind::error;
break;
}
- if (kind == DK_IGNORED)
+ if (kind == diagnostics::kind::ignored)
return false;
location_t exploc = location_of (*postfix_expression);
cxx_incomplete_type_diagnostic (exploc, *postfix_expression, *scope, kind);
if (!MAYBE_CLASS_TYPE_P (*scope))
return true;
- if (kind == DK_ERROR)
+ if (kind == diagnostics::kind::error)
*scope = *postfix_expression = error_mark_node;
else if (processing_template_decl)
{
@@ -9447,21 +9578,23 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
case RID_EXTENSION:
{
/* The saved value of the PEDANTIC flag. */
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
tree expr;
/* Save away the PEDANTIC flag. */
- cp_parser_extension_opt (parser, &saved_pedantic);
+ cp_parser_extension_opt (parser, &saved_pedantic,
+ &saved_long_long);
/* Also suppress -Wconditionally-supported. */
diagnostic_push_diagnostics (global_dc, input_location);
diagnostic_classify_diagnostic
(global_dc, OPT_Wconditionally_supported,
- DK_IGNORED, input_location);
+ diagnostics::kind::ignored, input_location);
/* Parse the cast-expression. */
expr = cp_parser_simple_cast_expression (parser);
/* Restore the PEDANTIC flag. */
diagnostic_pop_diagnostics (global_dc, input_location);
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return expr;
}
@@ -10793,6 +10926,14 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
goto pop;
}
+ /* If we skipped build_cplus_new in build_cxx_call because of decltype_p,
+ call it now that we know current.lhs is a subexpression. */
+ if (decltype_p && !processing_template_decl
+ && TREE_CODE (current.lhs) == CALL_EXPR
+ && CLASS_TYPE_P (TREE_TYPE (current.lhs)))
+ current.lhs = build_cplus_new (TREE_TYPE (current.lhs), current.lhs,
+ tf_warning_or_error);
+
get_rhs:
current.tree_type = binops_by_token[token->type].tree_type;
current.loc = token->location;
@@ -11428,6 +11569,133 @@ cp_parser_constant_expression (cp_parser* parser,
return expression;
}
+/* Parse __builtin_c23_va_start.
+
+ c23-va-start-expression:
+ __builtin_c23_va_start ( assignment-expression )
+ __builtin_c23_va_start ( assignment-expression , identifier )
+ __builtin_c23_va_start ( assignment-expression , tokens[opt] )
+
+ The first form is the expected new C++26 form, the second if
+ identifier is the name of the last parameter before ... is meant
+ for backwards compatibility with C++23 and older.
+ The third form where LWG4388 requires all the preprocessing tokens
+ to be convertible to tokens and it can't contain unbalanced
+ parentheses is parsed with a warning and the tokens are just skipped.
+ This is because C++26 like C23 defines va_start macro as
+ va_start (ap, ...) and says second and later arguments to the macro
+ are discarded, yet we want to diagnose when people use something
+ which wasn't valid before C++26 and is not the single argument
+ va_start either. */
+
+static cp_expr
+cp_parser_builtin_c23_va_start (cp_parser *parser)
+{
+ location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
+ cp_lexer_consume_token (parser->lexer);
+ /* Look for the opening `('. */
+ matching_parens parens;
+ parens.require_open (parser);
+ location_t arg_loc = cp_lexer_peek_token (parser->lexer)->location;
+ /* Now, parse the assignment-expression. */
+ tree expression = cp_parser_assignment_expression (parser);
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
+ {
+ location_t cloc = cp_lexer_peek_token (parser->lexer)->location;
+ if (!cp_parser_require (parser, CPP_COMMA, RT_COMMA))
+ {
+ cp_parser_skip_to_closing_parenthesis (parser, false, false,
+ /*consume_paren=*/ true);
+ return error_mark_node;
+ }
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_CLOSE_PAREN))
+ {
+ tree name = cp_lexer_peek_token (parser->lexer)->u.value;
+ location_t nloc = cp_lexer_peek_token (parser->lexer)->location;
+ tree decl = lookup_name (name);
+ tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
+ if (!last_parm || decl != last_parm)
+ warning_at (nloc, OPT_Wvarargs, "optional second parameter of "
+ "%<va_start%> not last named argument");
+ else
+ {
+ /* __builtin_va_start parsing does mark the argument as used and
+ read, for -Wunused* purposes mark it the same. */
+ TREE_USED (last_parm) = 1;
+ mark_exp_read (last_parm);
+ }
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else
+ {
+ unsigned nesting_depth = 0;
+ location_t sloc = cp_lexer_peek_token (parser->lexer)->location;
+ location_t eloc = sloc;
+
+ /* For va_start (ap,) the ) comes from stdarg.h.
+ Use location of , in that case, otherwise without -Wsystem-headers
+ nothing is reported. After all, the problematic token is the
+ comma in that case. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
+ sloc = eloc = cloc;
+ /* Not using cp_parser_skip_to_closing_parenthesis here, because
+ the tokens in second and further arguments don't have to be
+ fully balanced, only can't contain unbalanced parentheses.
+ So, va_start (ap, [[[[[[[[[{{{{{{{{{}]);
+ is valid C++ for which we want to warn,
+ #define X id); something (
+ va_start (ap, X);
+ is IFNDR (not detectable unless the preprocessor special cases
+ va_start macro). */
+ while (true)
+ {
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_CLOSE_PAREN && !nesting_depth)
+ break;
+
+ if (token->type == CPP_EOF)
+ break;
+ if (token->type == CPP_OPEN_PAREN)
+ ++nesting_depth;
+ else if (token->type == CPP_CLOSE_PAREN)
+ --nesting_depth;
+ else if (token->type == CPP_PRAGMA)
+ {
+ cp_parser_skip_to_pragma_eol (parser, token);
+ continue;
+ }
+ eloc = token->location;
+ cp_lexer_consume_token (parser->lexer);
+ }
+ if (sloc != eloc)
+ sloc = make_location (sloc, sloc, eloc);
+ warning_at (sloc, OPT_Wvarargs,
+ "%<va_start%> macro used with additional "
+ "arguments other than identifier of the "
+ "last named argument");
+ }
+ }
+ /* Look for the closing `)'. */
+ location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
+ /* Construct a location of the form:
+ __builtin_c23_va_start (ap, arg)
+ ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
+ with the caret at the first argument, ranging from the start
+ of the "__builtin_c23_va_start" token to the close paren. */
+ location_t combined_loc = make_location (arg_loc, start_loc, finish_loc);
+ parens.require_close (parser);
+ tree fndecl = builtin_decl_explicit (BUILT_IN_VA_START);
+ releasing_vec args;
+ vec_safe_push (args, expression);
+ vec_safe_push (args, integer_zero_node);
+ tree ret = finish_call_expr (fndecl, &args, false, true,
+ tf_warning_or_error);
+ if (TREE_CODE (ret) == CALL_EXPR)
+ SET_EXPR_LOCATION (ret, combined_loc);
+ return cp_expr (ret, combined_loc);
+}
+
/* Parse __builtin_offsetof.
offsetof-expression:
@@ -11677,10 +11945,14 @@ cp_parser_trait (cp_parser* parser, const cp_trait* trait)
lambda-introducer < template-parameter-list > requires-clause [opt]
lambda-declarator [opt] compound-statement
+ If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which
+ is syntactic sugar for a consteval lambda.
+
Returns a representation of the expression. */
static cp_expr
-cp_parser_lambda_expression (cp_parser* parser)
+cp_parser_lambda_expression (cp_parser* parser,
+ bool consteval_block_p/*=false*/)
{
tree lambda_expr = build_lambda_expr ();
tree type;
@@ -11689,23 +11961,10 @@ cp_parser_lambda_expression (cp_parser* parser)
cp_token_position start = 0;
LAMBDA_EXPR_LOCATION (lambda_expr) = token->location;
+ LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lambda_expr) = consteval_block_p;
if (cxx_dialect >= cxx20)
- {
- /* C++20 allows lambdas in unevaluated context, but one in the type of a
- non-type parameter is nonsensical.
-
- Distinguish a lambda in the parameter type from a lambda in the
- default argument by looking at local_variables_forbidden_p, which is
- only set in default arguments. */
- if (processing_template_parmlist && !parser->local_variables_forbidden_p)
- {
- error_at (token->location,
- "lambda-expression in template parameter type");
- token->error_reported = true;
- ok = false;
- }
- }
+ /* C++20 allows lambdas in unevaluated context. */;
else if (cp_unevaluated_operand)
{
if (!token->error_reported)
@@ -11732,9 +11991,14 @@ cp_parser_lambda_expression (cp_parser* parser)
it now. */
push_deferring_access_checks (dk_no_deferred);
- cp_parser_lambda_introducer (parser, lambda_expr);
- if (cp_parser_error_occurred (parser))
- return error_mark_node;
+ auto gr = make_temp_override (parser->greater_than_is_operator_p, true);
+
+ if (!consteval_block_p)
+ {
+ cp_parser_lambda_introducer (parser, lambda_expr);
+ if (cp_parser_error_occurred (parser))
+ return error_mark_node;
+ }
{
/* OK, this is a bit tricksy. cp_parser_requires_expression sets
@@ -11776,6 +12040,7 @@ cp_parser_lambda_expression (cp_parser* parser)
bool auto_is_implicit_function_template_parm_p
= parser->auto_is_implicit_function_template_parm_p;
bool saved_omp_array_section_p = parser->omp_array_section_p;
+ bool saved_in_targ = parser->in_template_argument_list_p;
parser->num_template_parameter_lists = 0;
parser->in_statement = 0;
@@ -11785,6 +12050,7 @@ cp_parser_lambda_expression (cp_parser* parser)
parser->implicit_template_scope = 0;
parser->auto_is_implicit_function_template_parm_p = false;
parser->omp_array_section_p = false;
+ parser->in_template_argument_list_p = false;
/* Inside the lambda, outside unevaluated context do not apply. */
cp_evaluated ev;
@@ -11798,13 +12064,22 @@ cp_parser_lambda_expression (cp_parser* parser)
bool save_in_consteval_if_p = in_consteval_if_p;
in_consteval_if_p = false;
+ /* Similarly the body of a lambda is not part of expansion statement. */
+ bool save_in_expansion_stmt = in_expansion_stmt;
+ in_expansion_stmt = 0;
+
/* By virtue of defining a local class, a lambda expression has access to
the private variables of enclosing classes. */
if (cp_parser_start_tentative_firewall (parser))
start = token;
- ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr);
+ /* A lambda scope starts immediately after the lambda-introducer of E
+ and extends to the end of the compound-statement of E. */
+ begin_scope (sk_lambda, NULL_TREE);
+
+ ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr,
+ consteval_block_p);
if (ok && cp_parser_error_occurred (parser))
ok = false;
@@ -11824,8 +12099,11 @@ cp_parser_lambda_expression (cp_parser* parser)
if (ok)
maybe_add_lambda_conv_op (type);
+ /* Leave the lambda scope. */
+ pop_bindings_and_leave_scope ();
finish_struct (type, /*attributes=*/NULL_TREE);
+ in_expansion_stmt = save_in_expansion_stmt;
in_consteval_if_p = save_in_consteval_if_p;
in_discarded_stmt = discarded;
@@ -11839,6 +12117,7 @@ cp_parser_lambda_expression (cp_parser* parser)
parser->auto_is_implicit_function_template_parm_p
= auto_is_implicit_function_template_parm_p;
parser->omp_array_section_p = saved_omp_array_section_p;
+ parser->in_template_argument_list_p = saved_in_targ;
}
/* This lambda shouldn't have any proxies left at this point. */
@@ -12186,10 +12465,13 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
decl-specifier-seq [opt] noexcept-specifier [opt]
attribute-specifier-seq [opt] trailing-return-type [opt]
- LAMBDA_EXPR is the current representation of the lambda expression. */
+ LAMBDA_EXPR is the current representation of the lambda expression.
+ If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which
+ is syntactic sugar for a consteval lambda. */
static bool
-cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
+cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr,
+ bool consteval_block_p/*=false*/)
{
/* 5.1.1.4 of the standard says:
If a lambda-expression does not include a lambda-declarator, it is as if
@@ -12210,6 +12492,13 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
clear_decl_specs (&lambda_specs);
/* A lambda op() is const unless explicitly 'mutable'. */
cp_cv_quals quals = TYPE_QUAL_CONST;
+ /* Don't add "const" to entities in the parameter-declaration-clause. */
+ LAMBDA_EXPR_CONST_QUAL_P (lambda_expr) = false;
+
+ /* Inject the captures into the lambda scope as they may be used in the
+ declarator and we have to be able to look them up. */
+ tree dummy_fco = maybe_add_dummy_lambda_op (lambda_expr);
+ push_capture_proxies (lambda_expr, /*early_p=*/true);
/* The template-parameter-list is optional, but must begin with
an opening angle if present. */
@@ -12292,6 +12581,18 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
&lambda_specs, &declares_class_or_enum);
+ /* [dcl.pre] For a consteval-block-declaration D, the expression E
+ corresponding to D is:
+ [] -> void static consteval compound-statement ()
+ Make it so. */
+ if (consteval_block_p)
+ {
+ return_type = void_type_node;
+ lambda_specs.storage_class = sc_static;
+ set_and_check_decl_spec_loc (&lambda_specs, ds_consteval,
+ cp_lexer_peek_token (parser->lexer));
+ }
+
if (omitted_parms_loc && lambda_specs.any_specifiers_p)
{
pedwarn (omitted_parms_loc, OPT_Wc__23_extensions,
@@ -12388,6 +12689,10 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
}
}
+ /* Now we're done with the parameter-declaration-clause, and should
+ assume "const" unless "mutable" was present. */
+ LAMBDA_EXPR_CONST_QUAL_P (lambda_expr) = quals == TYPE_QUAL_CONST;
+
tx_qual = cp_parser_tx_qualifier_opt (parser);
if (omitted_parms_loc && tx_qual)
{
@@ -12445,6 +12750,10 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
pop_bindings_and_leave_scope ();
}
+ /* We are about to create the real operator(), so get rid of the old one. */
+ if (dummy_fco)
+ remove_dummy_lambda_op (dummy_fco, lambda_expr);
+
/* Create the function call operator.
Messing with declarators like this is no uglier than building up the
@@ -12524,6 +12833,79 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
}
}
+/* Create a fake operator() for a lambda. We do this so that we can
+ build_capture_proxy even before start_lambda_function. */
+
+static tree
+make_dummy_lambda_op ()
+{
+ cp_decl_specifier_seq return_type_specs;
+ cp_cv_quals quals = TYPE_UNQUALIFIED;
+
+ clear_decl_specs (&return_type_specs);
+ return_type_specs.type = make_auto ();
+
+ void *p = obstack_alloc (&declarator_obstack, 0);
+
+ cp_declarator *declarator = make_id_declarator (NULL_TREE,
+ call_op_identifier,
+ sfk_none,
+ input_location);
+
+ declarator = make_call_declarator (declarator, void_list_node, quals,
+ VIRT_SPEC_UNSPECIFIED,
+ REF_QUAL_NONE, NULL_TREE,
+ NULL_TREE, NULL_TREE, NULL_TREE,
+ NULL_TREE, UNKNOWN_LOCATION);
+
+ tree fco = grokmethod (&return_type_specs, declarator, NULL_TREE);
+ obstack_free (&declarator_obstack, p);
+
+ return fco;
+}
+
+/* We need to push early capture proxies (for parsing the lambda-declarator),
+ and we may need a dummy operator() to be able to build the proxies.
+ LAMBDA_EXPR is the lambda we are building the captures for. */
+
+tree
+maybe_add_dummy_lambda_op (tree lambda_expr)
+{
+ /* If there are no captures, we don't need this. */
+ if (!LAMBDA_EXPR_CAPTURE_LIST (lambda_expr))
+ return NULL_TREE;
+
+ tree fco = make_dummy_lambda_op ();
+ if (fco != error_mark_node)
+ finish_member_declaration (fco);
+
+ return fco;
+}
+
+/* Remove the dummy operator() DUMMY_FCO we built for parsing the
+ lambda-declarator of LAMBDA_EXPR. */
+
+void
+remove_dummy_lambda_op (tree dummy_fco, tree lambda_expr)
+{
+ tree type = TREE_TYPE (lambda_expr);
+ if (TYPE_FIELDS (type) == dummy_fco)
+ {
+ /* Stitch out the dummy operator(). */
+ TYPE_FIELDS (type) = DECL_CHAIN (TYPE_FIELDS (type));
+ /* And clear the member vector as well. */
+ auto *member_vec = CLASSTYPE_MEMBER_VEC (type);
+ gcc_assert (member_vec->length () == 1);
+ member_vec->truncate (0);
+ }
+ /* Class templates will have the dummy operator() stashed here too. */
+ tree &list = CLASSTYPE_DECL_LIST (type);
+ if (list && TREE_VALUE (list) == dummy_fco)
+ list = TREE_CHAIN (list);
+ /* ??? We can't ggc_free dummy_fco yet. There's still a binding in the
+ closure to it, and the captures have it as their DECL_CONTEXT. */
+}
+
/* Parse the body of a lambda expression, which is simply
compound-statement
@@ -13070,6 +13452,11 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
case RID_TRANSACTION_CANCEL:
handle_omp_attribs = true;
break;
+ case RID_TEMPLATE:
+ if (cxx_dialect >= cxx11
+ && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR))
+ handle_omp_attribs = true;
+ break;
default:
break;
}
@@ -13122,6 +13509,16 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
NULL_TREE, false);
break;
+ case RID_TEMPLATE:
+ if (cxx_dialect >= cxx11
+ && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR))
+ {
+ std_attrs = process_stmt_hotness_attribute (std_attrs,
+ attrs_loc);
+ statement = cp_parser_expansion_statement (parser, if_p);
+ }
+ break;
+
case RID_BREAK:
case RID_CONTINUE:
case RID_RETURN:
@@ -13524,6 +13921,13 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
default:
/* Anything else must be an ordinary label. */
cp_expr identifier = cp_parser_identifier (parser);
+ if (in_expansion_stmt && identifier != error_mark_node)
+ {
+ error_at (token->location,
+ "identifier label %qE in %<template for%> body",
+ *identifier);
+ break;
+ }
if (identifier != error_mark_node
&& parser->omp_metadirective_state)
*identifier = mangle_metadirective_region_label (parser, *identifier);
@@ -14550,6 +14954,73 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep,
return stmt;
}
+/* Helper function for cp_parser_range_for and cp_parser_expansion_statement.
+ Get the range declaration momentarily out of the way so that the range
+ expression doesn't clash with it. */
+
+static cp_decomp *
+cp_hide_range_decl (tree *range_decl_p, cp_decomp *decomp_d,
+ auto_vec <cxx_binding *> &bindings,
+ auto_vec <tree> &names)
+{
+ tree range_decl = *range_decl_p;
+ cp_decomp *decomp = NULL;
+ if (range_decl == error_mark_node)
+ return decomp;
+
+ if (DECL_HAS_VALUE_EXPR_P (range_decl))
+ {
+ tree v = DECL_VALUE_EXPR (range_decl);
+ /* For decomposition declaration get all of the corresponding
+ declarations out of the way. */
+ if ((TREE_CODE (v) == ARRAY_REF
+ && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+ || (TREE_CODE (v) == TREE_VEC
+ && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0))))
+ {
+ tree d = range_decl;
+ decomp = decomp_d;
+ if (TREE_CODE (v) == ARRAY_REF)
+ {
+ *range_decl_p = range_decl = TREE_OPERAND (v, 0);
+ decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
+ }
+ else
+ {
+ *range_decl_p = range_decl = TREE_VEC_ELT (v, 0);
+ decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1;
+ }
+ decomp->decl = d;
+ bool seen_name_independent_decl = false;
+ names.reserve (decomp->count);
+ bindings.reserve (decomp->count);
+ for (unsigned int i = 0; i < decomp->count; i++, d = DECL_CHAIN (d))
+ {
+ if (name_independent_decl_p (d))
+ {
+ /* If there is more than one _ decl in the structured
+ binding, just push and move it away once. */
+ if (seen_name_independent_decl)
+ continue;
+ seen_name_independent_decl = true;
+ }
+ tree name = DECL_NAME (d);
+ names.quick_push (name);
+ bindings.quick_push (IDENTIFIER_BINDING (name));
+ IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
+ }
+ }
+ }
+ if (names.is_empty ())
+ {
+ tree name = DECL_NAME (range_decl);
+ names.safe_push (name);
+ bindings.safe_push (IDENTIFIER_BINDING (name));
+ IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
+ }
+ return decomp;
+}
+
/* Tries to parse a range-based for-statement:
range-based-for:
@@ -14565,56 +15036,14 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
bool ivdep, tree unroll, bool novector, bool is_omp)
{
tree stmt, range_expr;
- auto_vec <cxx_binding *, 16> bindings;
- auto_vec <tree, 16> names;
- cp_decomp decomp_d, *decomp = NULL;
+ auto_vec <cxx_binding *> bindings;
+ auto_vec <tree> names;
+ cp_decomp decomp_d;
/* Get the range declaration momentarily out of the way so that
the range expression doesn't clash with it. */
- if (range_decl != error_mark_node)
- {
- if (DECL_HAS_VALUE_EXPR_P (range_decl))
- {
- tree v = DECL_VALUE_EXPR (range_decl);
- /* For decomposition declaration get all of the corresponding
- declarations out of the way. */
- if (TREE_CODE (v) == ARRAY_REF
- && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
- {
- tree d = range_decl;
- range_decl = TREE_OPERAND (v, 0);
- decomp = &decomp_d;
- decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
- decomp->decl = d;
- bool seen_name_independent_decl = false;
- for (unsigned int i = 0; i < decomp->count;
- i++, d = DECL_CHAIN (d))
- {
- if (name_independent_decl_p (d))
- {
- /* If there is more than one _ decl in
- the structured binding, just push and move it
- away once. */
- if (seen_name_independent_decl)
- continue;
- seen_name_independent_decl = true;
- }
- tree name = DECL_NAME (d);
- names.safe_push (name);
- bindings.safe_push (IDENTIFIER_BINDING (name));
- IDENTIFIER_BINDING (name)
- = IDENTIFIER_BINDING (name)->previous;
- }
- }
- }
- if (names.is_empty ())
- {
- tree name = DECL_NAME (range_decl);
- names.safe_push (name);
- bindings.safe_push (IDENTIFIER_BINDING (name));
- IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
- }
- }
+ cp_decomp *decomp = cp_hide_range_decl (&range_decl, &decomp_d, bindings,
+ names);
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
range_expr = cp_parser_braced_list (parser);
@@ -14651,7 +15080,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
if (!type_dependent_expression_p (range_expr)
/* do_auto_deduction doesn't mess with template init-lists. */
&& !BRACE_ENCLOSED_INITIALIZER_P (range_expr))
- do_range_for_auto_deduction (range_decl, range_expr, decomp);
+ do_range_for_auto_deduction (range_decl, range_expr, decomp, false);
}
else
{
@@ -14665,7 +15094,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
/* Subroutine of cp_convert_range_for: given the initializer expression,
builds up the range temporary. */
-static tree
+tree
build_range_temp (tree range_expr)
{
/* Find out the type deduced by the declaration
@@ -14689,15 +15118,22 @@ build_range_temp (tree range_expr)
a shortcut version of cp_convert_range_for. */
static void
-do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp)
+do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp,
+ bool expansion_stmt)
{
tree auto_node = type_uses_auto (TREE_TYPE (decl));
if (auto_node)
{
tree begin_dummy, end_dummy, range_temp, iter_type, iter_decl;
range_temp = convert_from_reference (build_range_temp (range_expr));
- iter_type = (cp_parser_perform_range_for_lookup
- (range_temp, &begin_dummy, &end_dummy));
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_dummy,
+ &end_dummy,
+ expansion_stmt ? tf_none
+ : tf_warning_or_error);
+ if (expansion_stmt
+ && (begin_dummy == error_mark_node
+ || end_dummy == error_mark_node))
+ return;
if (iter_type)
{
iter_decl = build_decl (input_location, VAR_DECL, NULL_TREE,
@@ -14798,6 +15234,89 @@ warn_for_range_copy (tree decl, tree expr)
}
}
+/* Helper function for cp_convert_range_for and finish_expansion_stmt.
+ Build the __range, __begin and __end declarations. Return the
+ __begin VAR_DECL, set *END_P to the __end VAR_DECL. */
+
+tree
+cp_build_range_for_decls (location_t loc, tree range_expr, tree *end_p,
+ bool expansion_stmt_p)
+{
+ tree iter_type, begin_expr, end_expr;
+
+ if (range_expr == error_mark_node)
+ /* If an error happened previously do nothing or else a lot of
+ unhelpful errors would be issued. */
+ begin_expr = end_expr = iter_type = error_mark_node;
+ else
+ {
+ tree range_temp;
+
+ if (!expansion_stmt_p
+ && VAR_P (range_expr)
+ && array_of_runtime_bound_p (TREE_TYPE (range_expr)))
+ /* Can't bind a reference to an array of runtime bound. */
+ range_temp = range_expr;
+ else
+ {
+ range_temp = build_range_temp (range_expr);
+ if (expansion_stmt_p)
+ {
+ /* Depending on CWG3044 resolution, we might want to remove
+ these 3 sets of TREE_STATIC (on range_temp, begin and end).
+ Although it can only be done when P2686R4 is fully
+ implemented. */
+ TREE_STATIC (range_temp) = 1;
+ TREE_PUBLIC (range_temp) = 0;
+ DECL_COMMON (range_temp) = 0;
+ DECL_INTERFACE_KNOWN (range_temp) = 1;
+ DECL_DECLARED_CONSTEXPR_P (range_temp) = 1;
+ TREE_READONLY (range_temp) = 1;
+ }
+ pushdecl (range_temp);
+ cp_finish_decl (range_temp, range_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ range_temp = convert_from_reference (range_temp);
+ }
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr,
+ &end_expr);
+ }
+
+ /* The new for initialization statement. */
+ tree begin = build_decl (loc, VAR_DECL, for_begin__identifier, iter_type);
+ TREE_USED (begin) = 1;
+ DECL_ARTIFICIAL (begin) = 1;
+ if (expansion_stmt_p)
+ {
+ TREE_STATIC (begin) = 1;
+ DECL_DECLARED_CONSTEXPR_P (begin) = 1;
+ TREE_READONLY (begin) = 1;
+ }
+ pushdecl (begin);
+ cp_finish_decl (begin, begin_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+
+ if (cxx_dialect >= cxx17)
+ iter_type = cv_unqualified (TREE_TYPE (end_expr));
+ tree end = build_decl (loc, VAR_DECL, for_end__identifier, iter_type);
+ TREE_USED (end) = 1;
+ DECL_ARTIFICIAL (end) = 1;
+ if (expansion_stmt_p)
+ {
+ TREE_STATIC (end) = 1;
+ DECL_DECLARED_CONSTEXPR_P (end) = 1;
+ TREE_READONLY (end) = 1;
+ }
+ pushdecl (end);
+ cp_finish_decl (end, end_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ *end_p = end;
+ return begin;
+}
+
/* Converts a range-based for-statement into a normal
for-statement, as per the definition.
@@ -14838,56 +15357,14 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
cp_decomp *decomp, bool ivdep, tree unroll,
bool novector)
{
- tree begin, end;
- tree iter_type, begin_expr, end_expr;
- tree condition, expression;
+ tree end, condition, expression;
range_expr = mark_lvalue_use (range_expr);
- if (range_decl == error_mark_node || range_expr == error_mark_node)
- /* If an error happened previously do nothing or else a lot of
- unhelpful errors would be issued. */
- begin_expr = end_expr = iter_type = error_mark_node;
- else
- {
- tree range_temp;
-
- if (VAR_P (range_expr)
- && array_of_runtime_bound_p (TREE_TYPE (range_expr)))
- /* Can't bind a reference to an array of runtime bound. */
- range_temp = range_expr;
- else
- {
- range_temp = build_range_temp (range_expr);
- pushdecl (range_temp);
- cp_finish_decl (range_temp, range_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
- range_temp = convert_from_reference (range_temp);
- }
- iter_type = cp_parser_perform_range_for_lookup (range_temp,
- &begin_expr, &end_expr);
- }
-
- /* The new for initialization statement. */
- begin = build_decl (input_location, VAR_DECL, for_begin__identifier,
- iter_type);
- TREE_USED (begin) = 1;
- DECL_ARTIFICIAL (begin) = 1;
- pushdecl (begin);
- cp_finish_decl (begin, begin_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
-
- if (cxx_dialect >= cxx17)
- iter_type = cv_unqualified (TREE_TYPE (end_expr));
- end = build_decl (input_location, VAR_DECL, for_end__identifier, iter_type);
- TREE_USED (end) = 1;
- DECL_ARTIFICIAL (end) = 1;
- pushdecl (end);
- cp_finish_decl (end, end_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
+ if (range_decl == error_mark_node)
+ range_expr = error_mark_node;
+ tree begin
+ = cp_build_range_for_decls (input_location, range_expr, &end, false);
finish_init_stmt (statement);
@@ -14921,8 +15398,10 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
depends on the existence of members begin or end.
Returns the type deduced for the iterator expression. */
-static tree
-cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
+tree
+cp_perform_range_for_lookup (tree range, tree *begin, tree *end,
+ tsubst_flags_t complain
+ /* = tf_warning_or_error */)
{
if (error_operand_p (range))
{
@@ -14932,8 +15411,9 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (range))))
{
- error ("range-based %<for%> expression of type %qT "
- "has incomplete type", TREE_TYPE (range));
+ if (complain & tf_error)
+ error ("range-based %<for%> expression of type %qT "
+ "has incomplete type", TREE_TYPE (range));
*begin = *end = error_mark_node;
return error_mark_node;
}
@@ -14959,16 +15439,16 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
id_end = get_identifier ("end");
member_begin = lookup_member (TREE_TYPE (range), id_begin,
/*protect=*/2, /*want_type=*/false,
- tf_warning_or_error);
+ complain);
member_end = lookup_member (TREE_TYPE (range), id_end,
/*protect=*/2, /*want_type=*/false,
- tf_warning_or_error);
+ complain);
if (member_begin != NULL_TREE && member_end != NULL_TREE)
{
/* Use the member functions. */
- *begin = cp_parser_range_for_member_function (range, id_begin);
- *end = cp_parser_range_for_member_function (range, id_end);
+ *begin = cp_range_for_member_function (range, id_begin);
+ *end = cp_range_for_member_function (range, id_end);
}
else
{
@@ -14978,13 +15458,20 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
vec_safe_push (vec, range);
member_begin = perform_koenig_lookup (id_begin, vec,
- tf_warning_or_error);
+ complain);
+ if ((complain & tf_error) == 0 && member_begin == id_begin)
+ return error_mark_node;
*begin = finish_call_expr (member_begin, &vec, false, true,
- tf_warning_or_error);
+ complain);
member_end = perform_koenig_lookup (id_end, vec,
tf_warning_or_error);
+ if ((complain & tf_error) == 0 && member_end == id_end)
+ {
+ *begin = error_mark_node;
+ return error_mark_node;
+ }
*end = finish_call_expr (member_end, &vec, false, true,
- tf_warning_or_error);
+ complain);
}
/* Last common checks. */
@@ -15015,7 +15502,7 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
/* P0184R0 allows __begin and __end to have different types,
but make sure they are comparable so we can give a better
diagnostic. */;
- else
+ else if (complain & tf_error)
error ("inconsistent begin/end types in range-based %<for%> "
"statement: %qT and %qT",
TREE_TYPE (*begin), TREE_TYPE (*end));
@@ -15025,11 +15512,11 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
}
}
-/* Helper function for cp_parser_perform_range_for_lookup.
+/* Helper function for cp_perform_range_for_lookup.
Builds a tree for RANGE.IDENTIFIER(). */
static tree
-cp_parser_range_for_member_function (tree range, tree identifier)
+cp_range_for_member_function (tree range, tree identifier)
{
tree member, res;
@@ -15248,6 +15735,183 @@ cp_parser_init_statement (cp_parser *parser, tree *decl)
return false;
}
+/* Parse an expansion-statement.
+
+ expansion-statement:
+ template for ( init-statement[opt]
+ for-range-declaration : expansion-initializer )
+ statement
+
+ expansion-initializer:
+ expression
+ expansion-init-list
+
+ expansion-init-list:
+ { expression-list } */
+
+static tree
+cp_parser_expansion_statement (cp_parser* parser, bool *if_p)
+{
+ /* Peek at the next token. */
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ gcc_assert (token->keyword == RID_TEMPLATE);
+ gcc_assert (cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR));
+ cp_lexer_consume_token (parser->lexer);
+ cp_token *for_token = cp_lexer_peek_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+
+ if (cxx_dialect < cxx26)
+ pedwarn (make_location (token->location, token->location,
+ for_token->location), OPT_Wc__26_extensions,
+ "%<template for%> only available with %<-std=c++2c%> "
+ "or %<-std=gnu++2c%>");
+
+ token_indent_info guard_tinfo = get_token_indent_info (token);
+
+ /* Remember whether or not we are already within an iteration
+ statement. */
+ unsigned char in_statement = parser->in_statement;
+ /* And whether we are already in expansion-statement. */
+ auto save_in_expansion_stmt = in_expansion_stmt;
+
+ /* Look for the `('. */
+ matching_parens parens;
+ parens.require_open (parser);
+
+ tree init;
+ tree scope = begin_template_for_scope (&init);
+
+ /* Maybe parse the optional init-statement in a expansion-statement. */
+ if (cp_parser_range_based_for_with_init_p (parser)
+ /* Checked for diagnostic purposes only. */
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ {
+ tree dummy;
+ cp_parser_init_statement (parser, &dummy);
+ }
+
+ bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+
+ /* A colon is used in expansion-statement. */
+ parser->colon_corrects_to_scope_p = false;
+
+ /* Parse the declaration. */
+ tree range_decl;
+ cp_parser_simple_declaration (parser,
+ /*function_definition_allowed_p=*/false,
+ &range_decl);
+ if (range_decl == NULL_TREE)
+ range_decl = error_mark_node;
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+
+ cp_parser_require (parser, CPP_COLON, RT_COLON);
+
+ auto_vec <cxx_binding *> bindings;
+ auto_vec <tree> names;
+ cp_decomp decomp_d;
+
+ /* Get the range declaration momentarily out of the way so that
+ the range expression doesn't clash with it. */
+ cp_decomp *decomp = cp_hide_range_decl (&range_decl, &decomp_d, bindings,
+ names);
+
+ tree expansion_init;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ expansion_init = cp_parser_braced_list (parser);
+ if (TREE_CODE (expansion_init) == CONSTRUCTOR
+ && CONSTRUCTOR_IS_DESIGNATED_INIT (expansion_init))
+ error_at (EXPR_LOC_OR_LOC (expansion_init, token->location),
+ "designators in %<template for%> initializer");
+ }
+ else
+ expansion_init = cp_parser_expression (parser);
+
+ /* Put the range declaration(s) back into scope. */
+ for (unsigned int i = 0; i < names.length (); i++)
+ {
+ cxx_binding *binding = bindings[i];
+ binding->previous = IDENTIFIER_BINDING (names[i]);
+ IDENTIFIER_BINDING (names[i]) = binding;
+ }
+
+ /* Look for the `)'. */
+ parens.require_close (parser);
+
+ if (processing_template_decl
+ && check_for_bare_parameter_packs (expansion_init))
+ expansion_init = error_mark_node;
+
+ if (expansion_init != error_mark_node
+ && !type_dependent_expression_p (expansion_init)
+ && TREE_CODE (TREE_TYPE (expansion_init)) != ARRAY_TYPE
+ && !BRACE_ENCLOSED_INITIALIZER_P (expansion_init))
+ do_range_for_auto_deduction (range_decl, expansion_init, decomp,
+ true);
+
+ bool outside_of_template = !processing_template_decl;
+ if (outside_of_template)
+ {
+ ++processing_template_decl;
+ current_template_parms
+ = tree_cons (size_int (current_template_depth + 1),
+ make_tree_vec (0), current_template_parms);
+ }
+ in_expansion_stmt = true;
+
+ tree r = build_stmt (token->location, TEMPLATE_FOR_STMT, NULL_TREE,
+ NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+
+ current_binding_level->this_entity = r;
+ TEMPLATE_FOR_INIT_STMT (r) = init;
+ TEMPLATE_FOR_SCOPE (r) = scope;
+ if (!outside_of_template)
+ TEMPLATE_FOR_INIT_STMT (r) = pop_stmt_list (TEMPLATE_FOR_INIT_STMT (r));
+ TEMPLATE_FOR_DECL (r) = range_decl;
+ TEMPLATE_FOR_EXPR (r) = expansion_init;
+ TEMPLATE_FOR_BODY (r) = do_pushlevel (sk_block);
+
+ /* Parse the body of the expansion-statement. */
+ parser->in_statement = IN_EXPANSION_STMT;
+ bool prev = note_iteration_stmt_body_start ();
+ cp_parser_already_scoped_statement (parser, if_p, guard_tinfo);
+ note_iteration_stmt_body_end (prev);
+ parser->in_statement = in_statement;
+ in_expansion_stmt = save_in_expansion_stmt;
+
+ TEMPLATE_FOR_BODY (r) = do_poplevel (TEMPLATE_FOR_BODY (r));
+
+ if (outside_of_template)
+ {
+ current_template_parms = TREE_CHAIN (current_template_parms);
+ --processing_template_decl;
+ }
+
+ if (VAR_P (range_decl) && DECL_DECLARED_CONSTINIT_P (range_decl))
+ error_at (DECL_SOURCE_LOCATION (range_decl),
+ "for-range-declaration cannot be 'constinit'");
+
+ if (decomp)
+ {
+ tree v = make_tree_vec (decomp->count + 1);
+ TREE_VEC_ELT (v, 0) = TEMPLATE_FOR_DECL (r);
+ tree d = decomp->decl;
+ for (unsigned i = 0; i < decomp->count; ++i, d = DECL_CHAIN (d))
+ TREE_VEC_ELT (v, decomp->count - i) = d;
+ TEMPLATE_FOR_DECL (r) = v;
+ }
+
+ if (processing_template_decl)
+ add_stmt (r);
+ else
+ finish_expansion_stmt (r, NULL_TREE, tf_warning_or_error, NULL_TREE);
+
+ add_stmt (do_poplevel (TEMPLATE_FOR_SCOPE (r)));
+ TEMPLATE_FOR_SCOPE (r) = NULL_TREE;
+
+ return r;
+}
+
/* Parse a jump-statement.
jump-statement:
@@ -15292,7 +15956,8 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs)
break;
default:
gcc_assert ((in_statement & IN_SWITCH_STMT)
- || in_statement == IN_ITERATION_STMT);
+ || in_statement == IN_ITERATION_STMT
+ || in_statement == IN_EXPANSION_STMT);
statement = finish_break_stmt ();
if (in_statement == IN_ITERATION_STMT)
break_maybe_infinite_loop ();
@@ -15315,6 +15980,7 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs)
break;
/* Fall through. */
case IN_ITERATION_STMT:
+ case IN_EXPANSION_STMT:
case IN_OMP_FOR:
statement = finish_continue_stmt ();
break;
@@ -15389,11 +16055,12 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs)
case RID_GOTO:
if (parser->in_function_body
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ && maybe_constexpr_fn (current_function_decl)
&& cxx_dialect < cxx23)
{
- error ("%<goto%> in %<constexpr%> function only available with "
- "%<-std=c++23%> or %<-std=gnu++23%>");
+ if (DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+ error ("%<goto%> in %<constexpr%> function only available with "
+ "%<-std=c++23%> or %<-std=gnu++23%>");
cp_function_chain->invalid_constexpr = true;
}
@@ -15972,15 +16639,16 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
static void
cp_parser_declaration (cp_parser* parser, tree prefix_attrs)
{
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
/* Check for the `__extension__' keyword. */
- if (cp_parser_extension_opt (parser, &saved_pedantic))
+ if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long))
{
/* Parse the qualified declaration. */
cp_parser_declaration (parser, prefix_attrs);
/* Restore the PEDANTIC flag. */
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return;
}
@@ -16222,6 +16890,56 @@ cp_parser_toplevel_declaration (cp_parser* parser)
cp_parser_declaration (parser, NULL_TREE);
}
+/* Build an empty string for static_assert. */
+
+static tree
+build_empty_string ()
+{
+ tree message = build_string (1, "");
+ TREE_TYPE (message) = char_array_type_node;
+ fix_string_type (message);
+ return message;
+}
+
+/* Return true iff the next tokens start a C++26 consteval block. */
+
+static bool
+cp_parser_next_tokens_are_consteval_block_p (cp_parser *parser)
+{
+ return (cxx_dialect >= cxx26
+ && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONSTEVAL)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_BRACE));
+}
+
+/* Parse a consteval-block-declaration.
+
+ consteval-block-declaration:
+ consteval compound-statement
+
+ If MEMBER_P, this consteval block is a member declaration. */
+
+static void
+cp_parser_consteval_block (cp_parser *parser, bool member_p)
+{
+ const location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ /* Consume the 'consteval'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* We know the next token is '{'. Let cp_parser_lambda_body handle it. */
+ cp_expr lam = cp_parser_lambda_expression (parser,
+ /*consteval_block_p=*/true);
+ if (!cp_parser_error_occurred (parser))
+ {
+ releasing_vec args;
+ tree call = finish_call_expr (lam, &args,
+ /*disallow_virtual=*/false,
+ /*koenig_p=*/false,
+ tf_warning_or_error);
+ finish_static_assert (call, build_empty_string (), loc, member_p,
+ /*show_expr_p=*/false, /*consteval_block_p=*/true);
+ }
+}
+
/* Parse a block-declaration.
block-declaration:
@@ -16229,18 +16947,18 @@ cp_parser_toplevel_declaration (cp_parser* parser)
asm-definition
namespace-alias-definition
using-declaration
+ using-enum-declaration
using-directive
+ static_assert-declaration
+ consteval-block-declaration
+ alias-declaration
+ opaque-enum-declaration
GNU Extension:
block-declaration:
__extension__ block-declaration
- C++0x Extension:
-
- block-declaration:
- static_assert-declaration
-
If STATEMENT_P is TRUE, then this block-declaration is occurring as
part of a declaration-statement. */
@@ -16248,15 +16966,16 @@ static void
cp_parser_block_declaration (cp_parser *parser,
bool statement_p)
{
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
/* Check for the `__extension__' keyword. */
- if (cp_parser_extension_opt (parser, &saved_pedantic))
+ if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long))
{
/* Parse the qualified declaration. */
cp_parser_block_declaration (parser, statement_p);
/* Restore the PEDANTIC flag. */
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return;
}
@@ -16317,6 +17036,8 @@ cp_parser_block_declaration (cp_parser *parser,
/* If the next token is `static_assert' we have a static assertion. */
else if (token1->keyword == RID_STATIC_ASSERT)
cp_parser_static_assert (parser, /*member_p=*/false);
+ else if (cp_parser_next_tokens_are_consteval_block_p (parser))
+ cp_parser_consteval_block (parser, /*member_p=*/false);
else
{
size_t attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1);
@@ -16365,8 +17086,9 @@ cp_parser_block_declaration (cp_parser *parser,
If MAYBE_RANGE_FOR_DECL is not NULL, the pointed tree will be set to the
parsed declaration if it is an uninitialized single declarator not followed
- by a `;', or to error_mark_node otherwise. Either way, the trailing `;',
- if present, will not be consumed. */
+ by a `;', or to NULL_TREE when not followed by `:' or to error_mark_node
+ otherwise. Either way, the trailing `;', if present, will not be
+ consumed. */
static void
cp_parser_simple_declaration (cp_parser* parser,
@@ -16418,7 +17140,7 @@ cp_parser_simple_declaration (cp_parser* parser,
&& !decl_specifiers.any_specifiers_p)
{
cp_parser_error (parser, "expected declaration");
- goto done;
+ goto error_out;
}
/* If the next two tokens are both identifiers, the code is
@@ -16434,7 +17156,7 @@ cp_parser_simple_declaration (cp_parser* parser,
looking at a declaration. */
cp_parser_commit_to_tentative_parse (parser);
/* Give up. */
- goto done;
+ goto error_out;
}
cp_parser_maybe_commit_to_declaration (parser, &decl_specifiers);
@@ -16459,11 +17181,7 @@ cp_parser_simple_declaration (cp_parser* parser,
if (token->type == CPP_SEMICOLON)
goto finish;
else if (maybe_range_for_decl)
- {
- if (*maybe_range_for_decl == NULL_TREE)
- *maybe_range_for_decl = error_mark_node;
- goto finish;
- }
+ goto finish;
/* Anything else is an error. */
else
{
@@ -16542,7 +17260,7 @@ cp_parser_simple_declaration (cp_parser* parser,
statement is treated as a declaration-statement until proven
otherwise.) */
if (cp_parser_error_occurred (parser))
- goto done;
+ goto error_out;
if (auto_specifier_p && cxx_dialect >= cxx14)
{
@@ -16680,6 +17398,9 @@ cp_parser_simple_declaration (cp_parser* parser,
if (comma_loc != UNKNOWN_LOCATION)
error_at (comma_loc,
"multiple declarations in range-based %<for%> loop");
+ error_out:
+ if (maybe_range_for_decl && *maybe_range_for_decl == NULL_TREE)
+ *maybe_range_for_decl = error_mark_node;
}
done:
@@ -16688,7 +17409,7 @@ cp_parser_simple_declaration (cp_parser* parser,
}
/* Helper of cp_parser_simple_declaration, parse a decomposition declaration.
- decl-specifier-seq ref-qualifier [opt] [ identifier-list ]
+ decl-specifier-seq ref-qualifier [opt] [ sb-identifier-list ]
initializer ; */
static tree
@@ -16701,21 +17422,45 @@ cp_parser_decomposition_declaration (cp_parser *parser,
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE);
- /* Parse the identifier-list. */
+ /* Parse the sb-identifier-list. */
auto_vec<cp_expr, 10> v;
bool attr_diagnosed = false;
int first_attr = -1;
+ int pack = -1;
unsigned int cnt = 0;
if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE))
while (true)
{
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ location_t elloc = cp_lexer_peek_token (parser->lexer)->location;
+ if (!processing_template_decl)
+ error_at (elloc, "structured binding pack outside of template");
+ else if (pack != -1)
+ error_at (elloc,
+ "multiple packs in structured binding declaration");
+ else
+ {
+ if (keyword == RID_MAX
+ && cxx_dialect >= cxx17
+ && cxx_dialect < cxx26)
+ pedwarn (elloc, OPT_Wc__26_extensions,
+ "structured binding packs only available with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>");
+ pack = cnt;
+ }
+ cp_lexer_consume_token (parser->lexer);
+ }
cp_expr e = cp_parser_identifier (parser);
if (e.get_value () == error_mark_node)
break;
tree attr = NULL_TREE;
if (cp_next_tokens_can_be_std_attribute_p (parser))
{
- if (cxx_dialect >= cxx17 && cxx_dialect < cxx26 && !attr_diagnosed)
+ if (keyword == RID_MAX
+ && cxx_dialect >= cxx17
+ && cxx_dialect < cxx26
+ && !attr_diagnosed)
{
pedwarn (cp_lexer_peek_token (parser->lexer)->location,
OPT_Wc__26_extensions,
@@ -16776,7 +17521,7 @@ cp_parser_decomposition_declaration (cp_parser *parser,
&pushed_scope);
tree orig_decl = decl;
- unsigned int i;
+ unsigned int i, j;
cp_expr e;
cp_decl_specifier_seq decl_specs;
clear_decl_specs (&decl_specs);
@@ -16784,6 +17529,7 @@ cp_parser_decomposition_declaration (cp_parser *parser,
if (decl_specifiers->storage_class == sc_static)
decl_specs.storage_class = sc_static;
tree prev = decl;
+ j = 0;
FOR_EACH_VEC_ELT (v, i, e)
{
if (i == 0)
@@ -16810,9 +17556,31 @@ cp_parser_decomposition_declaration (cp_parser *parser,
decl = error_mark_node;
}
else
- prev = decl2;
+ {
+ prev = decl2;
+ if (decl != error_mark_node)
+ {
+ DECL_DECLARED_CONSTEXPR_P (decl2)
+ = DECL_DECLARED_CONSTEXPR_P (decl);
+ DECL_DECLARED_CONSTINIT_P (decl2)
+ = DECL_DECLARED_CONSTINIT_P (decl);
+ }
+ if (j == (unsigned) pack)
+ {
+ tree dtype = cxx_make_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (dtype) = decl2;
+ DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1;
+ SET_TYPE_STRUCTURAL_EQUALITY (dtype);
+ tree type = cxx_make_type (TYPE_PACK_EXPANSION);
+ PACK_EXPANSION_PATTERN (type) = dtype;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+ PACK_EXPANSION_PARAMETER_PACKS (type) = decl2;
+ TREE_TYPE (decl2) = type;
+ }
+ }
if (elt_pushed_scope)
pop_scope (elt_pushed_scope);
+ ++j;
}
if (v.is_empty ())
@@ -16859,6 +17627,15 @@ cp_parser_decomposition_declaration (cp_parser *parser,
/* Ensure DECL_VALUE_EXPR is created for all the decls but
the underlying DECL. */
cp_finish_decomp (decl, &decomp);
+ if (decl_spec_seq_has_spec_p (decl_specifiers, ds_thread))
+ pedwarn (decl_specifiers->locations[ds_thread],
+ 0, "for-range-declaration cannot be %qs",
+ decl_specifiers->gnu_thread_keyword_p
+ ? "__thread" : "thread_local");
+ else if (decl_specifiers->storage_class == sc_static)
+ pedwarn (decl_specifiers->locations[ds_storage_class],
+ 0, "for-range-declaration cannot be %qs",
+ "static");
}
if (pushed_scope)
@@ -17607,9 +18384,7 @@ cp_parser_static_assert (cp_parser *parser, bool member_p)
"only available with %<-std=c++17%> or %<-std=gnu++17%>");
/* Eat the ')' */
cp_lexer_consume_token (parser->lexer);
- message = build_string (1, "");
- TREE_TYPE (message) = char_array_type_node;
- fix_string_type (message);
+ message = build_empty_string ();
}
else
{
@@ -18058,9 +18833,14 @@ cp_parser_conversion_type_id (cp_parser* parser)
error ("invalid use of %<auto%> in conversion operator");
return error_mark_node;
}
- else if (template_parm_scope_p ())
- warning (0, "use of %<auto%> in member template "
- "conversion operator can never be deduced");
+ else
+ {
+ pedwarn (input_location, OPT_Wpedantic,
+ "invalid use of %<auto%> in conversion operator");
+ if (template_parm_scope_p ())
+ warning (0, "use of %<auto%> in member template "
+ "conversion operator can never be deduced");
+ }
}
return type_specified;
@@ -18370,7 +19150,7 @@ cp_parser_mem_initializer_id (cp_parser* parser)
return cp_parser_class_name (parser,
/*typename_keyword_p=*/true,
/*template_keyword_p=*/template_p,
- typename_type,
+ class_type,
/*check_dependency_p=*/true,
/*class_head_p=*/false,
/*is_declaration=*/true);
@@ -20952,9 +21732,6 @@ cp_parser_simple_type_specifier (cp_parser* parser,
"only available with "
"%<-std=c++14%> or %<-std=gnu++14%>");
}
- else if (parser->in_template_argument_list_p)
- error_at (token->location,
- "use of %<auto%> in template argument");
else if (!flag_concepts)
pedwarn (token->location, OPT_Wc__20_extensions,
"use of %<auto%> in parameter declaration "
@@ -20964,6 +21741,11 @@ cp_parser_simple_type_specifier (cp_parser* parser,
"use of %<auto%> in parameter declaration "
"only available with "
"%<-std=c++14%> or %<-std=gnu++14%>");
+
+ if (parser->in_template_argument_list_p)
+ permerror_opt (token->location,
+ OPT_Wabbreviated_auto_in_template_arg,
+ "use of %<auto%> in template argument");
}
else
type = make_auto ();
@@ -21092,7 +21874,9 @@ cp_parser_simple_type_specifier (cp_parser* parser,
/*typename_keyword_p=*/false,
/*check_dependency_p=*/true,
/*type_p=*/false,
- /*is_declaration=*/false)
+ /*is_declaration=*/false,
+ /*template_keyword_p=*/false,
+ global_p)
!= NULL_TREE);
/* If we have seen a nested-name-specifier, and the next token
is `template', then we are using the template-id production. */
@@ -21410,6 +22194,10 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
error_at (loc, "cannot declare a parameter with %<decltype(auto)%>");
return error_mark_node;
}
+ if (parser->in_template_argument_list_p)
+ permerror_opt (placeholder->location,
+ OPT_Wabbreviated_auto_in_template_arg,
+ "use of %<auto%> in template argument");
tree parm = build_constrained_parameter (con, proto, args);
return synthesize_implicit_template_parm (parser, parm);
}
@@ -21938,7 +22726,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
bool template_p =
(template_parm_lists_apply
- && (cp_parser_next_token_starts_class_definition_p (parser)
+ && (cp_parser_nth_token_starts_class_definition_p (parser, 1)
|| cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)));
/* An unqualified name was used to reference this type, so
there were no qualifying templates. */
@@ -23781,6 +24569,278 @@ cp_parser_maybe_adjust_declarator_for_dguide (cp_parser *parser,
}
}
+/* 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 (cp_declarator *declarator, tree ctx)
+{
+ cp_declarator *id = get_id_declarator (declarator);
+ tree name = id->u.id.unqualified_name;
+ tree scope = id->u.id.qualifying_scope;
+ enum special_function_kind sfk = id->u.id.sfk;
+
+ /* There seems to be no reasonable interpretation of what the behavior
+ should be if the name is qualified. You cannot add the variant function
+ to a class or namespace from outside of that scope. */
+ if (scope)
+ {
+ sorry_at (id->id_loc,
+ "cannot handle qualified name for variant function");
+ return NULL_TREE;
+ }
+
+ /* Catch disallowed constructors and destructors now. We can't mangle
+ destructor names (which are not IDENTIFIER_NODEs) in any case. */
+ if (sfk == sfk_constructor)
+ {
+ error_at (id->id_loc,
+ "declare variant directives are not allowed on constructors");
+ return NULL_TREE;
+ }
+ if (sfk == sfk_destructor)
+ {
+ error_at (id->id_loc,
+ "declare variant directives are not allowed on destructors");
+ return NULL_TREE;
+ }
+ if (TREE_CODE (name) != IDENTIFIER_NODE)
+ {
+ sorry_at (id->id_loc,
+ "cannot handle %s identifier name",
+ get_tree_code_name (TREE_CODE (name)));
+ return NULL_TREE;
+ }
+
+ /* Mangle the name in the declarator. If we're in a module interface,
+ add an additional prefix on the name ("mi" == "module interface"),
+ so that it will not collide with names in the module purview that
+ are defined locally within module interface TUs. Note that the
+ module name mangling of this name happens after this step. */
+ const char *sep
+ = (module_interface_p () ? JOIN_STR "mi" : JOIN_STR);
+ id->u.id.unqualified_name = omp_mangle_variant_name (name, ctx, sep);
+
+ 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, look up the decl for BASE_NAME in the same scope as
+ DECL, 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. IN_CLASS_P is true for DECLs appearing in a class
+ scope, and if DIAGNOSE_ERROR_P is false do not diagnose errors about
+ failure to match at this time (although other semantic errors when a
+ match is found are always diagnosed). Returns 1 on success, 0 for no
+ match, and -1 for a match with semantic errors. */
+static int
+omp_finish_variant_function (cp_parser *parser, tree decl, tree base_name,
+ tree ctx, bool in_class_p, bool diagnose_error_p)
+{
+ tree match = NULL_TREE;
+ bool is_template = false;
+ tree decl_context = CP_DECL_CONTEXT (decl);
+ tree base_decl;
+
+ /* First find the base_decl in the same scope as decl. If we are in
+ a class scope the parser still points at the scope, otherwise
+ look up base_name in the same namespace as decl appeared in. */
+ if (in_class_p)
+ base_decl = cp_parser_lookup_name_simple (parser, base_name,
+ DECL_SOURCE_LOCATION (decl));
+ else
+ base_decl = lookup_qualified_name (decl_context, base_name);
+
+ if (base_decl == error_mark_node)
+ base_decl = NULL_TREE;
+ if (!base_decl)
+ {
+ if (!diagnose_error_p)
+ return 0;
+ /* We previously rejected non-identifier base function names. */
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "no declaration of base function %qs in this scope",
+ IDENTIFIER_POINTER (base_name));
+ return -1;
+ }
+
+ /* Find the right overloaded function. */
+ if (TREE_CODE (base_decl) == OVERLOAD)
+ {
+ for (ovl_iterator iter (base_decl); iter; ++iter)
+ {
+ tree bb = *iter;
+ if (decls_match (decl, bb))
+ {
+ match = bb;
+ break;
+ }
+ else if (TREE_CODE (bb) == TEMPLATE_DECL
+ && TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_TEMPLATE_INFO (decl))
+ {
+ tree decl_template = DECL_TI_TEMPLATE (decl);
+ if (decl_template
+ && PRIMARY_TEMPLATE_P (decl_template)
+ && decls_match (bb, decl_template))
+ {
+ /* We want to put the attributes on the function rather
+ than on the TEMPLATE_DECL that points to it. */
+ match = DECL_TEMPLATE_RESULT (bb);
+ is_template = true;
+ break;
+ }
+ }
+ }
+ }
+ else if (decls_match (decl, base_decl))
+ match = base_decl;
+ else if (TREE_CODE (base_decl) == TEMPLATE_DECL)
+ /* Per comment in cp-tree.h, TEMPLATE_DECLs are always wrapped in an
+ OVERLOAD, so we should never see them here. */
+ gcc_unreachable ();
+ else if (TREE_CODE (base_decl) == TREE_LIST)
+ {
+ error_at (DECL_SOURCE_LOCATION (decl), "base function is ambiguous");
+ return -1;
+ }
+ else if (BASELINK_P (base_decl))
+ {
+ /* Baselink tree nodes do not have a DECL_NAME so we can't use it
+ in the error message. */
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "variant function must be in the same scope as the "
+ "base function %qs", IDENTIFIER_POINTER (base_name));
+ return -1;
+ }
+ if (!match)
+ {
+ /* We get here if base_decl doesn't match DECL or have an
+ overload matching DECL. */
+ if (!diagnose_error_p)
+ return 0;
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "variant function definition does not match "
+ "declaration of %qE", base_decl);
+ if (TREE_CODE (base_decl) != OVERLOAD)
+ inform (DECL_SOURCE_LOCATION (base_decl), "declared here");
+ return -1;
+ }
+ else if (CP_DECL_CONTEXT (match) != decl_context)
+ {
+ /* Reject inherited or using decls. */
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "variant function must be in the same scope as the "
+ "base function %qE", base_decl);
+ return -1;
+ }
+ else if (DECL_VIRTUAL_P (decl) || DECL_VIRTUAL_P (match))
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "declare variant directives are not allowed on "
+ "virtual functions");
+ return -1;
+ }
+ else if (DECL_DEFAULTED_FN (decl) || DECL_DEFAULTED_FN (match))
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "declare variant directives are not allowed on "
+ "defaulted functions");
+ return -1;
+ }
+ else if (DECL_DELETED_FN (decl) || DECL_DELETED_FN (match))
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "declare variant directives are not allowed on "
+ "deleted functions");
+ return -1;
+ }
+ else if (DECL_IMMEDIATE_FUNCTION_P (decl)
+ || DECL_IMMEDIATE_FUNCTION_P (match))
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "declare variant directives are not allowed on "
+ "immediate functions");
+ return -1;
+ }
+
+ /* Inside a template, make the "omp declare variant base" attribute
+ point to the name of DECL rather than DECL itself. During template
+ instantiation, omp_declare_variant_finalize_one will handle this
+ using the same logic as for the non-delimited form of "declare variant",
+ causing template instantiation as needed. For the non-template case,
+ there is nothing that will trigger omp_declare_variant_finalize_one;
+ so we create the final form of the attribute here, which points
+ directly to DECL rather than its name. */
+ tree decl_or_name = decl;
+ cp_id_kind idk = CP_ID_KIND_NONE;
+ if (processing_template_decl && is_template)
+ {
+ decl_or_name = DECL_NAME (decl);
+ idk = CP_ID_KIND_TEMPLATE_ID;
+ }
+
+ omp_check_for_duplicate_variant (DECL_SOURCE_LOCATION (decl),
+ match, 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 (match);
+ tree match_loc_node = build_empty_stmt (DECL_SOURCE_LOCATION (match));
+ tree loc_node = tree_cons (match_loc_node,
+ build_int_cst (integer_type_node, idk),
+ build_tree_list (match_loc_node,
+ integer_zero_node));
+ attrs = tree_cons (get_identifier ("omp declare variant base"),
+ tree_cons (decl_or_name, ctx, loc_node), attrs);
+ if (processing_template_decl)
+ ATTR_IS_DEPENDENT (attrs) = 1;
+ DECL_ATTRIBUTES (match) = attrs;
+
+ /* Except for variants defined in a module interface, variant functions
+ are essentially anonymous and cannot be referenced by name, so make
+ them have internal linkage. Note that class methods in C++ normally
+ have external linkage with weak/comdat semantics; this prevents that. */
+ if (!module_interface_p ())
+ {
+ TREE_PUBLIC (decl) = 0;
+ DECL_COMDAT (decl) = 0;
+ DECL_INTERFACE_KNOWN (decl) = 1;
+ DECL_NOT_REALLY_EXTERN (decl) = 1;
+ }
+ return 1;
+}
+
+/* Called when we have seen a function declaration or definition DECL.
+ OpenMP "begin declare variant" allows variant definitions to precede
+ the declaration of the base function. If DECL is a newly-declared
+ function matching some variant that hasn't been recorded on its base
+ function yet, do that now. */
+
+static void
+omp_maybe_record_variant_base (cp_parser* parser, tree decl)
+{
+ if (vec_safe_length (parser->omp_begin_declare_variant_map))
+ {
+ unsigned int i;
+ omp_begin_declare_variant_map_entry *e;
+ FOR_EACH_VEC_ELT (*parser->omp_begin_declare_variant_map, i, e)
+ {
+ if (DECL_NAME (decl) == e->id
+ && omp_finish_variant_function (parser, e->variant, e->id,
+ e->ctx, false, false))
+ {
+ parser->omp_begin_declare_variant_map->unordered_remove (i);
+ break;
+ }
+ }
+ }
+}
+
/* Declarators [gram.dcl.decl] */
/* Parse an init-declarator.
@@ -23997,6 +25057,27 @@ cp_parser_init_declarator (cp_parser* parser,
/* This is a function-definition. */
*function_definition_p = true;
+ /* 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;
+ vec<cp_omp_declare_variant_attr, va_gc> *dv_state
+ = scope_chain->omp_declare_variant_attribute;
+
+ if (!vec_safe_is_empty (dv_state))
+ {
+ cp_omp_declare_variant_attr a = dv_state->last ();
+ dv_ctx = copy_list (a.selector);
+ dv_base = omp_start_variant_function (declarator, dv_ctx);
+ if (dv_base == NULL_TREE)
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ return error_mark_node;
+ }
+ }
+
/* Parse the function definition. */
if (member_p)
decl = cp_parser_save_member_function_body (parser,
@@ -24015,6 +25096,20 @@ cp_parser_init_declarator (cp_parser* parser,
= func_brace_location;
}
+ /* If this function was in a "begin declare variant" block,
+ store the pointer back to the base function and fix up
+ the attributes for the middle end. Do it now if the base
+ function has already been declared, otherwise save the info. */
+ if (dv_base && decl != error_mark_node
+ && !omp_finish_variant_function (parser, decl, dv_base, dv_ctx,
+ false, false))
+ {
+ omp_begin_declare_variant_map_entry e = { decl, dv_base, dv_ctx };
+ vec_safe_push (parser->omp_begin_declare_variant_map, e);
+ }
+ else if (flag_openmp && !member_p)
+ omp_maybe_record_variant_base (parser, decl);
+
return decl;
}
}
@@ -24092,6 +25187,27 @@ cp_parser_init_declarator (cp_parser* parser,
is_initialized = SD_DEFAULTED;
else if (t2->keyword == RID_DELETE)
is_initialized = SD_DELETED;
+ if (!vec_safe_is_empty (scope_chain->omp_declare_variant_attribute))
+ {
+ /* We're in a "begin declare variant" construct. The parser
+ doesn't go through the normal function definition path for
+ these and hence doesn't invoke omp_finish_variant_function
+ where these errors would otherwise be caught. */
+ if (is_initialized == SD_DEFAULTED)
+ {
+ error_at (declarator->init_loc,
+ "declare variant directives are not allowed on "
+ "defaulted functions");
+ return error_mark_node;
+ }
+ else if (is_initialized == SD_DELETED)
+ {
+ error_at (declarator->init_loc,
+ "declare variant directives are not allowed on "
+ "deleted functions");
+ return error_mark_node;
+ }
+ }
}
}
else
@@ -24102,7 +25218,26 @@ cp_parser_init_declarator (cp_parser* parser,
&& token->type != CPP_SEMICOLON)
{
if (maybe_range_for_decl && *maybe_range_for_decl != error_mark_node)
- range_for_decl_p = true;
+ {
+ range_for_decl_p = true;
+ if (decl_spec_seq_has_spec_p (decl_specifiers, ds_thread))
+ pedwarn (decl_specifiers->locations[ds_thread],
+ 0, "for-range-declaration cannot be %qs",
+ decl_specifiers->gnu_thread_keyword_p
+ ? "__thread" : "thread_local");
+ else if (decl_specifiers->storage_class == sc_static)
+ pedwarn (decl_specifiers->locations[ds_storage_class],
+ 0, "for-range-declaration cannot be %qs",
+ "static");
+ else if (decl_specifiers->storage_class == sc_extern)
+ pedwarn (decl_specifiers->locations[ds_storage_class],
+ 0, "for-range-declaration cannot be %qs",
+ "extern");
+ else if (decl_specifiers->storage_class == sc_register)
+ pedwarn (decl_specifiers->locations[ds_storage_class],
+ 0, "for-range-declaration cannot be %qs",
+ "register");
+ }
else
{
if (!maybe_range_for_decl)
@@ -24322,6 +25457,19 @@ cp_parser_init_declarator (cp_parser* parser,
&& type_uses_auto (decl_specifiers->type))
*auto_result = strip_declarator_types (TREE_TYPE (decl), declarator);
+ /* Check whether a function declaration might be a base function for a
+ variant previously declared in an OpenMP "begin declare variant" block
+ that has not been recorded yet. Class members are ignored here because
+ they are all processed after parsing the whole class.
+ FIXME: We store these variants in a vector and use a linear search here.
+ We don't expect gazillions of these variant functions to be provided
+ without an earlier declaration, but if it's problematical we could
+ use a hash table instead. */
+ if (flag_openmp
+ && !member_p
+ && function_declarator_p (declarator))
+ omp_maybe_record_variant_base (parser, decl);
+
return decl;
}
@@ -26893,6 +28041,10 @@ cp_parser_braced_list (cp_parser *parser, bool *non_constant_p /*=nullptr*/)
location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
auto oas = make_temp_override (parser->omp_array_section_p, false);
+ /* Within a brace-enclosed initializer list, a `>' token is always the
+ greater-than operator. */
+ auto gto = make_temp_override (parser->greater_than_is_operator_p, true);
+
/* Consume the `{' token. */
matching_braces braces;
bool found_opening_brace = braces.require_open (parser);
@@ -27402,8 +28554,7 @@ cp_parser_class_name (cp_parser *parser,
/* If this is a typename, create a TYPENAME_TYPE. */
if (typename_p && decl != error_mark_node)
{
- decl = make_typename_type (scope, decl, typename_type,
- /*complain=*/tf_error);
+ decl = make_typename_type (scope, decl, tag_type, /*complain=*/tf_error);
if (decl != error_mark_node)
decl = TYPE_NAME (decl);
}
@@ -27503,6 +28654,7 @@ cp_parser_class_specifier (cp_parser* parser)
bool in_switch_statement_p;
bool saved_in_unbraced_linkage_specification_p;
bool saved_in_unbraced_export_declaration_p;
+ bool saved_auto_is_implicit_function_template_parm_p;
tree old_scope = NULL_TREE;
tree scope = NULL_TREE;
cp_token *closing_brace;
@@ -27560,11 +28712,20 @@ cp_parser_class_specifier (cp_parser* parser)
saved_in_unbraced_export_declaration_p
= parser->in_unbraced_export_declaration_p;
parser->in_unbraced_export_declaration_p = false;
+ saved_auto_is_implicit_function_template_parm_p
+ = parser->auto_is_implicit_function_template_parm_p;
+ parser->auto_is_implicit_function_template_parm_p = false;
+
/* 'this' from an enclosing non-static member function is unavailable. */
tree saved_ccp = current_class_ptr;
tree saved_ccr = current_class_ref;
current_class_ptr = NULL_TREE;
current_class_ref = NULL_TREE;
+ /* Set up for deferred lookup of "omp begin declare variant" base functions
+ in the class. */
+ vec<omp_begin_declare_variant_map_entry, va_gc> *save_variant_map
+ = parser->omp_begin_declare_variant_map;
+ parser->omp_begin_declare_variant_map = NULL;
/* Start the class. */
if (nested_name_specifier_p)
@@ -27586,6 +28747,19 @@ cp_parser_class_specifier (cp_parser* parser)
/* Parse the member-specification. */
cp_parser_member_specification_opt (parser);
+ /* Register any "begin declare variant" functions in this class, since
+ references to the base function can only be resolved after the
+ entire class is seen. */
+ if (vec_safe_length (parser->omp_begin_declare_variant_map))
+ {
+ unsigned int i;
+ omp_begin_declare_variant_map_entry *e;
+ FOR_EACH_VEC_ELT (*parser->omp_begin_declare_variant_map, i, e)
+ omp_finish_variant_function (parser, e->variant, e->id, e->ctx,
+ true, true);
+ }
+ parser->omp_begin_declare_variant_map = save_variant_map;
+
/* Look for the trailing `}'. */
closing_brace = braces.require_close (parser);
/* Look for trailing attributes to apply to this class. */
@@ -27950,12 +29124,72 @@ cp_parser_class_specifier (cp_parser* parser)
= saved_in_unbraced_linkage_specification_p;
parser->in_unbraced_export_declaration_p
= saved_in_unbraced_export_declaration_p;
+ parser->auto_is_implicit_function_template_parm_p
+ = saved_auto_is_implicit_function_template_parm_p;
current_class_ptr = saved_ccp;
current_class_ref = saved_ccr;
return type;
}
+/* Parse an (optional) class-property-specifier-seq.
+
+ class-property-specifier-seq:
+ class-property-specifier class-property-specifier-seq [opt]
+
+ class-property-specifier:
+ final
+
+ Returns a bitmask representing the class-property-specifiers. */
+
+static cp_virt_specifiers
+cp_parser_class_property_specifier_seq_opt (cp_parser *parser)
+{
+ cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED;
+
+ while (true)
+ {
+ cp_token *token;
+ cp_virt_specifiers virt_specifier;
+
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ /* See if it's a class-property-specifier. */
+ if (token->type != CPP_NAME)
+ break;
+ if (id_equal (token->u.value, "final"))
+ {
+ /* For C++98, quietly ignore final in e.g.
+ struct S final = 24; */
+ if (cxx_dialect == cxx98
+ && virt_specifiers == VIRT_SPEC_UNSPECIFIED
+ && !cp_parser_nth_token_starts_class_definition_p (parser, 2)
+ && !cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
+ break;
+ maybe_warn_cpp0x (CPP0X_OVERRIDE_CONTROLS);
+ virt_specifier = VIRT_SPEC_FINAL;
+ }
+ else if (id_equal (token->u.value, "__final"))
+ virt_specifier = VIRT_SPEC_FINAL;
+ else
+ break;
+
+ if (virt_specifiers & virt_specifier)
+ {
+ gcc_rich_location richloc (token->location);
+ richloc.add_fixit_remove ();
+ error_at (&richloc, "duplicate %qD specifier", token->u.value);
+ cp_lexer_purge_token (parser->lexer);
+ }
+ else
+ {
+ cp_lexer_consume_token (parser->lexer);
+ virt_specifiers |= virt_specifier;
+ }
+ }
+ return virt_specifiers;
+}
+
/* Parse a class-head.
class-head:
@@ -28146,18 +29380,16 @@ cp_parser_class_head (cp_parser* parser,
pop_deferring_access_checks ();
if (id)
- {
- cp_parser_check_for_invalid_template_id (parser, id,
- class_key,
- type_start_token->location);
- }
- virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
+ cp_parser_check_for_invalid_template_id (parser, id,
+ class_key,
+ type_start_token->location);
+ virt_specifiers = cp_parser_class_property_specifier_seq_opt (parser);
/* If it's not a `:' or a `{' then we can't really be looking at a
class-head, since a class-head only appears as part of a
class-specifier. We have to detect this situation before calling
xref_tag, since that has irreversible side-effects. */
- if (!cp_parser_next_token_starts_class_definition_p (parser))
+ if (!cp_parser_nth_token_starts_class_definition_p (parser, 1))
{
cp_parser_error (parser, "expected %<{%> or %<:%>");
type = error_mark_node;
@@ -28167,13 +29399,6 @@ cp_parser_class_head (cp_parser* parser,
/* At this point, we're going ahead with the class-specifier, even
if some other problem occurs. */
cp_parser_commit_to_tentative_parse (parser);
- if (virt_specifiers & VIRT_SPEC_OVERRIDE)
- {
- cp_parser_error (parser,
- "cannot specify %<override%> for a class");
- type = error_mark_node;
- goto out;
- }
/* Issue the error about the overly-qualified name now. */
if (qualified_p)
{
@@ -28619,12 +29844,20 @@ cp_parser_member_specification_opt (cp_parser* parser)
/* Parse a member-declaration.
member-declaration:
- decl-specifier-seq [opt] member-declarator-list [opt] ;
- function-definition ; [opt]
- :: [opt] nested-name-specifier template [opt] unqualified-id ;
+ attribute-specifier-seq [opt] decl-specifier-seq [opt]
+ member-declarator-list [opt] ;
+ function-definition
+ friend-type-declaration
using-declaration
+ using-enum-declaration
+ static_assert-declaration
+ consteval-block-declaration
template-declaration
+ explicit-specialization
+ deduction-guide
alias-declaration
+ opaque-enum-declaration
+ empty-declaration
member-declarator-list:
member-declarator
@@ -28643,12 +29876,7 @@ cp_parser_member_specification_opt (cp_parser* parser)
member-declarator:
declarator attributes [opt] pure-specifier [opt]
declarator attributes [opt] constant-initializer [opt]
- identifier [opt] attributes [opt] : constant-expression
-
- C++0x Extensions:
-
- member-declaration:
- static_assert-declaration */
+ identifier [opt] attributes [opt] : constant-expression */
static void
cp_parser_member_declaration (cp_parser* parser)
@@ -28661,16 +29889,17 @@ cp_parser_member_declaration (cp_parser* parser)
cp_token *token = NULL;
cp_token *decl_spec_token_start = NULL;
cp_token *initializer_token_start = NULL;
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
/* Check for the `__extension__' keyword. */
- if (cp_parser_extension_opt (parser, &saved_pedantic))
+ if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long))
{
/* Recurse. */
cp_parser_member_declaration (parser);
/* Restore the old value of the PEDANTIC flag. */
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return;
}
@@ -28747,6 +29976,12 @@ cp_parser_member_declaration (cp_parser* parser)
return;
}
+ if (cp_parser_next_tokens_are_consteval_block_p (parser))
+ {
+ cp_parser_consteval_block (parser, /*member_p=*/true);
+ return;
+ }
+
parser->colon_corrects_to_scope_p = false;
cp_omp_declare_simd_data odsd;
@@ -29248,6 +30483,28 @@ cp_parser_member_declaration (cp_parser* parser)
if (initializer && initializer_token_start)
error_at (initializer_token_start->location,
"pure-specifier on function-definition");
+
+ /* 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;
+ vec<cp_omp_declare_variant_attr, va_gc> *dv_state
+ = scope_chain->omp_declare_variant_attribute;
+ if (!vec_safe_is_empty (dv_state))
+ {
+ cp_omp_declare_variant_attr a = dv_state->last ();
+ dv_ctx = copy_list (a.selector);
+ dv_base = omp_start_variant_function (declarator,
+ dv_ctx);
+ if (dv_base == NULL_TREE)
+ {
+ cp_parser_skip_to_end_of_statement (parser);
+ goto out;
+ }
+ }
+
decl = cp_parser_save_member_function_body (parser,
&decl_specifiers,
declarator,
@@ -29258,6 +30515,20 @@ cp_parser_member_declaration (cp_parser* parser)
/* If the member was not a friend, declare it here. */
if (!friend_p)
finish_member_declaration (decl);
+
+ /* If this function was in a "begin declare variant"
+ block, record the information we need to find the
+ base function and fix it up later. At this point in
+ parsing, we may not have seen the base function yet
+ so we defer looking it up and registering the variant
+ until the class is complete. */
+ if (dv_base && decl != error_mark_node)
+ {
+ omp_begin_declare_variant_map_entry e
+ = { decl, dv_base, dv_ctx };
+ vec_safe_push (parser->omp_begin_declare_variant_map, e);
+ }
+
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If the next token is a semicolon, consume it. */
@@ -29694,7 +30965,7 @@ cp_parser_base_specifier (cp_parser* parser)
type = cp_parser_class_name (parser,
class_scope_p,
template_p,
- typename_type,
+ class_type,
/*check_dependency_p=*/true,
/*class_head_p=*/false,
/*is_declaration=*/true);
@@ -30372,6 +31643,9 @@ cp_parser_asm_operand_list (cp_parser* parser)
parens.require_open (parser);
/* Parse the expression. */
tree expression = cp_parser_expression (parser);
+ if (check_for_bare_parameter_packs (expression))
+ expression = error_mark_node;
+
/* Look for the `)'. */
parens.require_close (parser);
@@ -30452,10 +31726,10 @@ cp_parser_asm_label_list (cp_parser* parser)
if (TREE_CODE (label) == LABEL_DECL)
{
TREE_USED (label) = 1;
- check_goto (label);
name = build_string (IDENTIFIER_LENGTH (identifier),
IDENTIFIER_POINTER (identifier));
labels = tree_cons (name, label, labels);
+ check_goto (&TREE_VALUE (labels));
}
}
/* If the next token is not a `,', then the list is
@@ -31809,13 +33083,16 @@ cp_parser_skip_attributes_opt (cp_parser *parser, size_t n)
present, and FALSE otherwise. *SAVED_PEDANTIC is set to the
current value of the PEDANTIC flag, regardless of whether or not
the `__extension__' keyword is present. The caller is responsible
- for restoring the value of the PEDANTIC flag. */
+ for restoring the value of the PEDANTIC flag. Similarly *SAVED_LONG_LONG
+ for warn_long_long flag. */
static bool
-cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic)
+cp_parser_extension_opt (cp_parser *parser, int *saved_pedantic,
+ int *saved_long_long)
{
/* Save the old value of the PEDANTIC flag. */
*saved_pedantic = pedantic;
+ *saved_long_long = warn_long_long;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTENSION))
{
@@ -31824,6 +33101,8 @@ cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic)
/* We're not being pedantic while the `__extension__' keyword is
in effect. */
pedantic = 0;
+ /* And we don't want -Wlong-long warning. */
+ warn_long_long = 0;
return true;
}
@@ -31855,6 +33134,8 @@ cp_parser_label_declaration (cp_parser* parser)
/* If we failed, stop. */
if (identifier == error_mark_node)
break;
+ if (parser->omp_metadirective_state)
+ identifier = mangle_metadirective_region_label (parser, identifier);
/* Declare it as a label. */
finish_label_decl (identifier);
/* If the next token is a `;', stop. */
@@ -32671,9 +33952,12 @@ cp_parser_compound_requirement (cp_parser *parser)
}
}
else
- /* P1452R2 removed the trailing-return-type option. */
- error_at (type_loc,
- "return-type-requirement is not a type-constraint");
+ {
+ /* P1452R2 removed the trailing-return-type option. */
+ error_at (type_loc,
+ "return-type-requirement is not a type-constraint");
+ type = NULL_TREE;
+ }
}
location_t loc = make_location (expr_token->location,
@@ -33498,7 +34782,9 @@ cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags,
&& cp_lexer_peek_token (parser->lexer)->type == CPP_TEMPLATE_ID)
{
auto_diagnostic_group d;
- if (emit_diagnostic (cxx_dialect >= cxx20 ? DK_PEDWARN : DK_WARNING,
+ if (emit_diagnostic ((cxx_dialect >= cxx20
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning),
input_location, OPT_Wtemplate_id_cdtor,
"template-id not allowed for constructor in C++20"))
inform (input_location, "remove the %qs", "< >");
@@ -33634,6 +34920,8 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
+ int errs = errorcount + sorrycount;
+
/* If the next token is `try', `__transaction_atomic', or
`__transaction_relaxed`, then we are looking at either function-try-block
or function-transaction-block. Note that all of these include the
@@ -33653,6 +34941,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
fn = finish_function (inline_p);
check_module_decl_linkage (fn);
+ if ((errorcount + sorrycount) > errs)
+ DECL_STRUCT_FUNCTION (fn)->language->erroneous = true;
+
if (modules_p ()
&& !inline_p
&& TYPE_P (DECL_CONTEXT (fn))
@@ -35534,15 +36825,15 @@ cp_parser_token_starts_function_definition_p (cp_token* token)
|| token->keyword == RID_RETURN);
}
-/* Returns TRUE iff the next token is the ":" or "{" beginning a class
+/* Returns TRUE iff the Nth token is the ":" or "{" beginning a class
definition. */
static bool
-cp_parser_next_token_starts_class_definition_p (cp_parser *parser)
+cp_parser_nth_token_starts_class_definition_p (cp_parser *parser, size_t n)
{
cp_token *token;
- token = cp_lexer_peek_token (parser->lexer);
+ token = cp_lexer_peek_nth_token (parser->lexer, n);
return (token->type == CPP_OPEN_BRACE
|| (token->type == CPP_COLON
&& !parser->colon_doesnt_start_class_def_p));
@@ -35822,7 +37113,9 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc,
return;
bool seen_as_union = TREE_CODE (type) == UNION_TYPE;
- if (seen_as_union != (class_key == union_type))
+ if (class_key != typename_type
+ && TREE_CODE (type) != TYPENAME_TYPE
+ && seen_as_union != (class_key == union_type))
{
auto_diagnostic_group d;
if (permerror (input_location, "%qs tag used in naming %q#T",
@@ -36433,7 +37726,11 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
case CPP_CLOSE_SQUARE:
if (depth == 0
/* Handle correctly int n = sizeof ... ( p ); */
- && token->type != CPP_ELLIPSIS)
+ && (token->type != CPP_ELLIPSIS
+ /* For int n = 42 ...) handle ... as variadic arguments. */
+ || (!nsdmi
+ && cp_lexer_nth_token_is (parser->lexer, 2,
+ CPP_CLOSE_PAREN))))
done = true;
/* Update DEPTH, if necessary. */
else if (token->type == CPP_CLOSE_PAREN
@@ -36596,7 +37893,7 @@ static void
cp_parser_abort_tentative_parse (cp_parser* parser)
{
gcc_assert (parser->context->status != CP_PARSER_STATUS_KIND_COMMITTED
- || errorcount > 0);
+ || seen_error ());
cp_parser_simulate_error (parser);
/* Now, pretend that we want to see if the construct was
successfully parsed. */
@@ -38750,6 +40047,8 @@ cp_parser_omp_clause_name (cp_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))
@@ -42323,8 +43622,11 @@ cp_parser_omp_clause_doacross (cp_parser *parser, tree list, location_t loc)
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
cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind,
@@ -42333,26 +43635,201 @@ cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind,
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return list;
- bool present = false;
- cp_token *token = cp_lexer_peek_token (parser->lexer);
+ int pos = 1;
+ int colon_pos = 0;
+ int iterator_length = 0;
- if (token->type == CPP_NAME
- && strcmp (IDENTIFIER_POINTER (token->u.value), "present") == 0
- && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON))
+ while (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_NAME)
{
- present = true;
- cp_lexer_consume_token (parser->lexer);
- cp_lexer_consume_token (parser->lexer);
+ const char *identifier =
+ IDENTIFIER_POINTER (cp_lexer_peek_nth_token (parser->lexer,
+ pos)->u.value);
+ if (cp_lexer_nth_token_is (parser->lexer, pos + 1, CPP_OPEN_PAREN))
+ {
+ int n = cp_parser_skip_balanced_tokens (parser, pos + 1);
+ if (n != pos + 1)
+ {
+ if (strcmp (identifier, "iterator") == 0)
+ iterator_length = n - pos;
+ pos = n - 1;
+ }
+ }
+ if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA)
+ pos += 2;
+ else
+ pos++;
+ if (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_COLON)
+ {
+ colon_pos = pos;
+ break;
+ }
}
+ bool present = false;
+ tree iterators = NULL_TREE;
+
+ for (int pos = 1; pos < colon_pos; ++pos)
+ {
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_COMMA)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ continue;
+ }
+ const char *p = IDENTIFIER_POINTER (token->u.value);
+ if (strcmp ("present", p) == 0)
+ {
+ if (present)
+ {
+ cp_parser_error (parser, "too many %<present%> modifiers");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ present = true;
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else if (strcmp ("iterator", p) == 0)
+ {
+ if (iterators)
+ {
+ cp_parser_error (parser, "too many %<iterator%> modifiers");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ begin_scope (sk_omp, NULL);
+ iterators = cp_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");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ }
+
+ if (colon_pos)
+ cp_parser_require (parser, CPP_COLON, RT_COLON);
+
tree nl = cp_parser_omp_var_list_no_open (parser, kind, list, NULL, true);
if (present)
for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
OMP_CLAUSE_MOTION_PRESENT (c) = 1;
+ if (iterators)
+ {
+ tree block = poplevel (1, 1, 0);
+ 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;
}
+/* OpenMP 6.1:
+ dyn_groupprivate ( [fallback-modifier : ] integer-expression )
+
+ fallback-modifier
+ fallback( abort | default_mem | null ) */
+
+static tree
+cp_parser_omp_clause_dyn_groupprivate (cp_parser *parser, tree list,
+ location_t location)
+{
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ enum omp_clause_fallback_kind kind = OMP_CLAUSE_FALLBACK_UNSPECIFIED;
+
+ size_t n;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && (cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)
+ || (cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)
+ && (n = cp_parser_skip_balanced_tokens (parser, 2)) != 3
+ && cp_lexer_nth_token_is (parser->lexer, n, CPP_COLON))))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ if (strcmp (IDENTIFIER_POINTER (id), "fallback") != 0)
+ {
+ cp_parser_error (parser, "expected %<fallback%> modifier");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ cp_lexer_consume_token (parser->lexer);
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return list;
+ const char *p = "";
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ id = cp_lexer_peek_token (parser->lexer)->u.value;
+ p = IDENTIFIER_POINTER (id);
+ }
+ 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
+ {
+ cp_parser_error (parser, "expected %<abort%>, %<default_mem%>, or "
+ "%<null%> as fallback mode");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ cp_lexer_consume_token (parser->lexer);
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ return list;
+ if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+ return list;
+ }
+
+ tree size = cp_parser_assignment_expression (parser);
+
+ if (size == error_mark_node
+ || !parens.require_close (parser))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_DYN_GROUPPRIVATE,
+ "dyn_groupprivate", location);
+
+ tree c = build_omp_clause (location, 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 )
@@ -42370,36 +43847,60 @@ cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind,
map ( [map-type-modifier[,] ...] map-kind: variable-list )
map-type-modifier:
- always | close */
+ always | close | mapper ( mapper-name ) */
static tree
-cp_parser_omp_clause_map (cp_parser *parser, tree list)
+cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p)
{
tree nlist, c;
- enum gomp_map_kind kind = GOMP_MAP_TOFROM;
+ enum gomp_map_kind kind = declare_mapper_p ? GOMP_MAP_UNSET : GOMP_MAP_TOFROM;
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return list;
int pos = 1;
int map_kind_pos = 0;
- while (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_NAME
- || cp_lexer_peek_nth_token (parser->lexer, pos)->keyword == RID_DELETE)
+ int iterator_length = 0;
+ for (;;)
{
- if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COLON)
+ cp_token *tok = cp_lexer_peek_nth_token (parser->lexer, pos);
+ if (!(tok->type == CPP_NAME || tok->keyword == RID_DELETE))
+ break;
+
+ cp_token *next_tok = cp_lexer_peek_nth_token (parser->lexer, pos + 1);
+ if (tok->type == CPP_NAME
+ && strcmp (IDENTIFIER_POINTER (tok->u.value), "iterator") == 0
+ && next_tok->type == CPP_OPEN_PAREN)
+ {
+ int n = cp_parser_skip_balanced_tokens (parser, pos + 1);
+ if (n != pos + 1)
+ {
+ iterator_length = n - pos;
+ pos = n - 1;
+ next_tok = cp_lexer_peek_nth_token (parser->lexer, n);
+ }
+ }
+
+ if (next_tok->type == CPP_COLON)
{
map_kind_pos = pos;
break;
}
- if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA)
+ if (next_tok->type == CPP_COMMA)
pos++;
+ else if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type
+ == CPP_OPEN_PAREN)
+ pos = cp_parser_skip_balanced_tokens (parser, pos + 1);
pos++;
}
bool always_modifier = false;
bool close_modifier = false;
bool present_modifier = false;
+ bool mapper_modifier = false;
+ tree mapper_name = NULL_TREE;
+ tree iterators = NULL_TREE;
for (int pos = 1; pos < map_kind_pos; ++pos)
{
cp_token *tok = cp_lexer_peek_token (parser->lexer);
@@ -42422,6 +43923,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
return list;
}
always_modifier = true;
+ cp_lexer_consume_token (parser->lexer);
}
else if (strcmp ("close", p) == 0)
{
@@ -42435,6 +43937,92 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
return list;
}
close_modifier = true;
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else if (strcmp ("iterator", p) == 0)
+ {
+ if (iterators)
+ {
+ cp_parser_error (parser, "too many %<iterator%> modifiers");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ begin_scope (sk_omp, NULL);
+ iterators = cp_parser_omp_iterators (parser);
+ pos += iterator_length - 1;
+ }
+ else if (strcmp ("mapper", p) == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ if (mapper_modifier)
+ {
+ cp_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. */
+ cp_lexer_consume_token (parser->lexer);
+ parens.require_close (parser);
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/
+ true);
+ return list;
+ }
+
+ tok = cp_lexer_peek_token (parser->lexer);
+ switch (tok->type)
+ {
+ case CPP_NAME:
+ {
+ cp_expr e = cp_parser_identifier (parser);
+ if (e != error_mark_node)
+ mapper_name = e;
+ else
+ goto err;
+ if (declare_mapper_p)
+ {
+ error_at (e.get_location (),
+ "in %<declare mapper%> directives, parameter "
+ "to %<mapper%> modifier must be %<default%>");
+ }
+ }
+ break;
+
+ case CPP_KEYWORD:
+ if (tok->keyword == RID_DEFAULT)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ break;
+ }
+ /* Fallthrough. */
+
+ default:
+ err:
+ cp_parser_error (parser,
+ "expected identifier or %<default%>");
+ return list;
+ }
+
+ if (!parens.require_close (parser))
+ {
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/
+ true);
+ return list;
+ }
+
+ mapper_modifier = true;
+ pos += 3;
+ }
}
else if (strcmp ("present", p) == 0)
{
@@ -42448,19 +44036,19 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
return list;
}
present_modifier = true;
- }
+ cp_lexer_consume_token (parser->lexer);
+ }
else
{
- cp_parser_error (parser, "%<map%> clause with map-type modifier other"
- " than %<always%>, %<close%> or %<present%>");
+ cp_parser_error (parser, "%<map%> clause with map-type modifier "
+ "other than %<always%>, %<close%>, "
+ "%<iterator%>, %<mapper%> or %<present%>");
cp_parser_skip_to_closing_parenthesis (parser,
/*recovering=*/true,
/*or_comma=*/false,
/*consume_paren=*/true);
return list;
}
-
- cp_lexer_consume_token (parser->lexer);
}
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
@@ -42516,8 +44104,40 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
NULL, true);
finish_scope ();
+ tree last_new = NULL_TREE;
+
+ if (iterators)
+ {
+ tree block = poplevel (1, 1, 0);
+ if (iterators == error_mark_node)
+ iterators = NULL_TREE;
+ else
+ TREE_VEC_ELT (iterators, 5) = block;
+ }
+
for (c = nlist; 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) = nlist;
+ nlist = 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;
+ }
return nlist;
}
@@ -43819,6 +45439,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
clauses);
c_name = "destroy";
break;
+ case PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE:
+ clauses = cp_parser_omp_clause_dyn_groupprivate (parser, clauses,
+ token->location);
+ c_name = "dyn_groupprivate";
+ break;
case PRAGMA_OMP_CLAUSE_INIT:
{
/* prefer_type parsing fails often such that many follow-up errors
@@ -43845,7 +45470,8 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
c_name = "detach";
break;
case PRAGMA_OMP_CLAUSE_MAP:
- clauses = cp_parser_omp_clause_map (parser, clauses);
+ clauses = cp_parser_omp_clause_map (parser, clauses,
+ /*mapper=*/false);
c_name = "map";
break;
case PRAGMA_OMP_CLAUSE_DEVICE:
@@ -45750,8 +47376,16 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl,
decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
decomp->decl = decl;
}
+ else if (TREE_CODE (v) == TREE_VEC
+ && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0)))
+ {
+ d = TREE_VEC_ELT (v, 0);
+ decomp = &decomp_d;
+ decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1;
+ decomp->decl = decl;
+ }
}
- do_range_for_auto_deduction (d, init, decomp);
+ do_range_for_auto_deduction (d, init, decomp, false);
}
cond = global_namespace;
incr = NULL_TREE;
@@ -45807,8 +47441,8 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl,
range_temp_decl = range_temp;
range_temp = convert_from_reference (range_temp);
}
- iter_type = cp_parser_perform_range_for_lookup (range_temp,
- &begin_expr, &end_expr);
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr,
+ &end_expr);
}
tree end_iter_type = iter_type;
@@ -45873,6 +47507,15 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl,
decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
decomp->decl = d;
}
+ else if (TREE_CODE (v) == TREE_VEC
+ && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0)))
+ {
+ tree d = orig_decl;
+ orig_decl = TREE_VEC_ELT (v, 0);
+ decomp = &decomp_d;
+ decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1;
+ decomp->decl = d;
+ }
}
tree auto_node = type_uses_auto (TREE_TYPE (orig_decl));
@@ -48679,19 +50322,20 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok,
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_DEFAULTMAP) \
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR) \
| (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_IF) \
| (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
cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
@@ -48851,6 +50495,8 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
OMP_CLAUSE_CHAIN (c) = nc;
}
+ if (!processing_template_decl)
+ clauses = c_omp_instantiate_mappers (clauses);
clauses = finish_omp_clauses (clauses, C_ORT_OMP_TARGET);
c_omp_adjust_map_clauses (clauses, true);
@@ -49545,7 +51191,8 @@ cp_parser_oacc_update (cp_parser *parser, cp_token *pragma_tok)
*/
#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
cp_parser_oacc_wait (cp_parser *parser, cp_token *pragma_tok)
@@ -49830,12 +51477,25 @@ cp_parser_omp_context_selector (cp_parser *parser, enum omp_tss_code set,
&& !value_dependent_expression_p (t))
{
t = fold_non_dependent_expr (t);
- if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
{
- error_at (token->location,
- "property must be integer expression");
- return error_mark_node;
+ t = maybe_convert_cond (t);
+ if (t == error_mark_node)
+ return error_mark_node;
}
+ else
+ {
+ t = convert_from_reference (t);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error_at (token->location,
+ "property must be integer expression");
+ return error_mark_node;
+ }
+ }
+ if (!processing_template_decl
+ && TREE_CODE (t) != CLEANUP_POINT_EXPR)
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
}
properties = make_trait_property (NULL_TREE, t, properties);
break;
@@ -50078,6 +51738,7 @@ cp_parser_omp_assumption_clauses (cp_parser *parser, cp_token *pragma_tok,
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))
@@ -50086,9 +51747,9 @@ cp_parser_omp_assumption_clauses (cp_parser *parser, cp_token *pragma_tok,
"informational, and meta directives "
"not permitted", p);
else if (dir == NULL
- || dir->id == PRAGMA_OMP_END
- || (!dir->second && directive[1])
- || (!dir->third && directive[2]))
+ || dir->id == PRAGMA_OMP_END
+ || (!dir->second && directive[1])
+ || (!dir->third && directive[2]))
error_at (dloc, "unknown OpenMP directive name in "
"%qs clause argument", p);
else
@@ -50447,6 +52108,20 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
goto fail;
ctx = omp_check_context_selector (match_loc, ctx,
OMP_CTX_DECLARE_VARIANT);
+
+ /* 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 (scope_chain->omp_declare_variant_attribute))
+ {
+ cp_omp_declare_variant_attr a
+ = scope_chain->omp_declare_variant_attribute->last ();
+ tree outer_ctx = a.selector;
+ ctx = omp_merge_context_selectors (match_loc, outer_ctx, ctx,
+ OMP_CTX_DECLARE_VARIANT);
+ }
if (ctx != error_mark_node && variant != error_mark_node)
{
tree match_loc_node
@@ -50620,41 +52295,41 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
append_args_tree);
}
} while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL));
+ if (variant != error_mark_node && !has_match)
+ {
+ cp_parser_error (parser, "expected %<match%> clause");
+ variant = error_mark_node;
+ }
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+
+ /* 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 attrs;
- if ((ctx != error_mark_node && variant != error_mark_node)
- && (has_adjust_args || append_args_tree))
+ if (has_adjust_args || append_args_tree)
{
- if (!has_match)
+ 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 requires a %<match%> clause",
+ "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 attrs;
}
- else
- {
- gcc_assert (TREE_PURPOSE (attrs)
- == get_identifier ("omp declare variant base"));
- gcc_assert (TREE_PURPOSE (TREE_VALUE (attrs)) == variant);
- ctx = TREE_VALUE (TREE_VALUE (attrs));
- 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");
- // We might not have a DECL for the variant yet. So we store the
- // need_device_ptr list in the base function attribute, after loc
- // nodes.
- tree t = build_tree_list (need_device_ptr_list,
- NULL_TREE /* need_device_addr */);
- TREE_CHAIN (t) = append_args_tree;
- TREE_VALUE (attrs) = chainon (TREE_VALUE (attrs),
- build_tree_list ( NULL_TREE, t));
- }
+ // We might not have a DECL for the variant yet. So we store the
+ // need_device_ptr list in the base function attribute, after loc
+ // nodes.
+ tree t = build_tree_list (need_device_ptr_list,
+ NULL_TREE /* need_device_addr */);
+ TREE_CHAIN (t) = append_args_tree;
+ TREE_VALUE (attrs) = chainon (TREE_VALUE (attrs),
+ build_tree_list (NULL_TREE, t));
}
- cp_parser_skip_to_pragma_eol (parser, pragma_tok);
return attrs;
}
@@ -51108,7 +52783,9 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok)
/* 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) \
@@ -51154,9 +52831,75 @@ cp_parser_omp_begin (cp_parser *parser, cp_token *pragma_tok)
= { in_omp_attribute_pragma, device_type, indirect };
vec_safe_push (scope_chain->omp_declare_target_attribute, a);
}
+ else if (strcmp (p, "variant") == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ const char *clause = "";
+ matching_parens parens;
+ location_t match_loc = cp_lexer_peek_token (parser->lexer)->location;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ clause = IDENTIFIER_POINTER (id);
+ }
+ if (strcmp (clause, "match") != 0)
+ {
+ cp_parser_error (parser, "expected %<match%>");
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return;
+ }
+
+ cp_lexer_consume_token (parser->lexer);
+
+ if (!parens.require_open (parser))
+ {
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return;
+ }
+
+ tree ctx = cp_parser_omp_context_selector_specification (parser,
+ true);
+ 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 (scope_chain->omp_declare_variant_attribute))
+ {
+ cp_omp_declare_variant_attr a
+ = scope_chain->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. */
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ cp_parser_skip_to_pragma_omp_end_declare_variant (parser);
+ return;
+ }
+ else
+ {
+ cp_omp_declare_variant_attr a
+ = { parser->lexer->in_omp_attribute_pragma, ctx };
+ vec_safe_push (scope_chain->omp_declare_variant_attribute, a);
+ }
+
+ parens.require_close (parser);
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ }
else
{
- cp_parser_error (parser, "expected %<target%>");
+ cp_parser_error (parser, "expected %<target%> or %<variant%>");
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
}
}
@@ -51169,7 +52912,8 @@ cp_parser_omp_begin (cp_parser *parser, cp_token *pragma_tok)
}
else
{
- cp_parser_error (parser, "expected %<declare target%> or %<assumes%>");
+ cp_parser_error (parser, "expected %<declare target%>, "
+ "%<declare variant%>, or %<assumes%>");
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
}
}
@@ -51178,7 +52922,8 @@ cp_parser_omp_begin (cp_parser *parser, cp_token *pragma_tok)
# pragma omp end declare target new-line
OpenMP 5.1:
- # pragma omp end assumes new-line */
+ # pragma omp end assumes new-line
+ # pragma omp end declare variant new-line */
static void
cp_parser_omp_end (cp_parser *parser, cp_token *pragma_tok)
@@ -51200,41 +52945,70 @@ cp_parser_omp_end (cp_parser *parser, cp_token *pragma_tok)
p = IDENTIFIER_POINTER (id);
}
if (strcmp (p, "target") == 0)
- cp_lexer_consume_token (parser->lexer);
- else
{
- cp_parser_error (parser, "expected %<target%>");
- cp_parser_skip_to_pragma_eol (parser, pragma_tok);
- return;
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ if (!vec_safe_length (scope_chain->omp_declare_target_attribute))
+ error_at (pragma_tok->location,
+ "%<#pragma omp end declare target%> without "
+ "corresponding %<#pragma omp declare target%> or "
+ "%<#pragma omp begin declare target%>");
+ else
+ {
+ cp_omp_declare_target_attr
+ a = scope_chain->omp_declare_target_attribute->pop ();
+ if (a.attr_syntax != in_omp_attribute_pragma)
+ {
+ if (a.attr_syntax)
+ error_at (pragma_tok->location,
+ "%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 (pragma_tok->location,
+ "%qs in pragma syntax terminated "
+ "with %qs in attribute syntax",
+ a.device_type >= 0 ? "begin declare target"
+ : "declare target",
+ "end declare target");
+ }
+ }
}
- cp_parser_require_pragma_eol (parser, pragma_tok);
- if (!vec_safe_length (scope_chain->omp_declare_target_attribute))
- error_at (pragma_tok->location,
- "%<#pragma omp end declare target%> without corresponding "
- "%<#pragma omp declare target%> or "
- "%<#pragma omp begin declare target%>");
- else
+ else if (strcmp (p, "variant") == 0)
{
- cp_omp_declare_target_attr
- a = scope_chain->omp_declare_target_attribute->pop ();
- if (a.attr_syntax != in_omp_attribute_pragma)
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ if (!vec_safe_length (scope_chain->omp_declare_variant_attribute))
+ error_at (pragma_tok->location,
+ "%<#pragma omp end declare variant%> without "
+ "corresponding %<#pragma omp begin declare variant%>");
+ else
{
- if (a.attr_syntax)
- error_at (pragma_tok->location,
- "%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 (pragma_tok->location,
- "%qs in pragma syntax terminated "
- "with %qs in attribute syntax",
- a.device_type >= 0 ? "begin declare target"
- : "declare target",
- "end declare target");
+ cp_omp_declare_variant_attr
+ a = scope_chain->omp_declare_variant_attribute->pop ();
+ if (a.attr_syntax != in_omp_attribute_pragma)
+ {
+ if (a.attr_syntax)
+ error_at (pragma_tok->location,
+ "%<begin declare variant%> in attribute syntax "
+ "terminated with %<end declare variant%> in "
+ "pragma syntax");
+ else
+ error_at (pragma_tok->location,
+ "%<begin declare variant%> in pragma syntax "
+ "terminated with %<end declare variant%> in "
+ "attribute syntax");
+ }
}
}
+ else
+ {
+ cp_parser_error (parser, "expected %<target%>");
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return;
+ }
}
else if (strcmp (p, "assumes") == 0)
{
@@ -51404,7 +53178,6 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
{
error_at (match_loc, "too many %<otherwise%> or %<default%> "
"clauses in %<metadirective%>");
- cp_parser_skip_to_end_of_block_or_statement (parser, true);
goto fail;
}
else
@@ -51414,14 +53187,12 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
{
error_at (match_loc, "%<otherwise%> or %<default%> clause "
"must appear last in %<metadirective%>");
- cp_parser_skip_to_end_of_block_or_statement (parser, true);
goto fail;
}
if (!default_p && strcmp (p, "when") != 0)
{
error_at (match_loc, "%qs is not valid for %qs",
p, "metadirective");
- cp_parser_skip_to_end_of_block_or_statement (parser, true);
goto fail;
}
@@ -51490,7 +53261,6 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
if (i == 0)
{
error_at (loc, "expected directive name");
- cp_parser_skip_to_end_of_block_or_statement (parser, true);
goto fail;
}
@@ -51563,7 +53333,10 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
goto add;
case CPP_CLOSE_PAREN:
if (nesting_depth-- == 0)
- break;
+ {
+ cp_lexer_consume_token (parser->lexer);
+ break;
+ }
goto add;
default:
add:
@@ -51575,8 +53348,6 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
break;
}
- cp_lexer_consume_token (parser->lexer);
-
if (!skip)
{
cp_token eol_token = {};
@@ -51587,6 +53358,18 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
}
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ /* 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
+ && cp_parser_pragma_kind (&directive_tokens[0])
+ == PRAGMA_OMP_NOTHING))
+ return;
+ }
+
if (!default_seen)
{
/* Add a default clause that evaluates to 'omp nothing'. */
@@ -51708,11 +53491,8 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
return;
fail:
- /* Skip the metadirective pragma. */
+ /* Skip the metadirective pragma. Do not skip the metadirective body. */
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
-
- /* Skip the metadirective body. */
- cp_parser_skip_to_end_of_block_or_statement (parser, true);
}
@@ -52050,10 +53830,7 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok,
fndecl = push_template_decl (fndecl);
if (block_scope)
- {
- if (!processing_template_decl)
- pushdecl (fndecl);
- }
+ pushdecl (fndecl);
else if (current_class_type)
{
if (cp == NULL)
@@ -52131,6 +53908,175 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok,
obstack_free (&declarator_obstack, p);
}
+/* OpenMP 5.0
+ #pragma omp declare mapper([mapper-identifier:]type var) \
+ [clause[[,] clause] ... ] new-line */
+
+static void
+cp_parser_omp_declare_mapper (cp_parser *parser, cp_token *pragma_tok,
+ enum pragma_context)
+{
+ cp_token *token = NULL;
+ tree type = NULL_TREE, vardecl = NULL_TREE, block = NULL_TREE;
+ bool block_scope = false;
+ /* Don't create location wrapper nodes within "declare mapper"
+ directives. */
+ auto_suppress_location_wrappers sentinel;
+ tree mapper_name = NULL_TREE;
+ tree mapper_id, id, placeholder, mapper, maplist = NULL_TREE;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ goto fail;
+
+ if (current_function_decl)
+ block_scope = true;
+
+ token = cp_lexer_peek_token (parser->lexer);
+
+ if (cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON))
+ {
+ switch (token->type)
+ {
+ case CPP_NAME:
+ {
+ cp_expr e = cp_parser_identifier (parser);
+ if (e != error_mark_node)
+ mapper_name = e;
+ else
+ goto fail;
+ }
+ break;
+
+ case CPP_KEYWORD:
+ if (token->keyword == RID_DEFAULT)
+ {
+ mapper_name = NULL_TREE;
+ cp_lexer_consume_token (parser->lexer);
+ break;
+ }
+ /* Fallthrough. */
+
+ default:
+ cp_parser_error (parser, "expected identifier or %<default%>");
+ }
+
+ if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+ goto fail;
+ }
+
+ {
+ const char *saved_message = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined within %<declare mapper%>");
+ type_id_in_expr_sentinel s (parser);
+ type = cp_parser_type_id (parser);
+ parser->type_definition_forbidden_message = saved_message;
+ }
+
+ if (type == error_mark_node)
+ goto fail;
+ if (dependent_type_p (type))
+ mapper_id = omp_mapper_id (mapper_name, NULL_TREE);
+ else
+ mapper_id = omp_mapper_id (mapper_name, type);
+
+ vardecl = build_lang_decl (VAR_DECL, mapper_id, type);
+ DECL_ARTIFICIAL (vardecl) = 1;
+ TREE_STATIC (vardecl) = 1;
+ TREE_PUBLIC (vardecl) = 0;
+ DECL_EXTERNAL (vardecl) = 0;
+ DECL_DECLARED_CONSTEXPR_P (vardecl) = 1;
+ DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (vardecl) = 1;
+ DECL_OMP_DECLARE_MAPPER_P (vardecl) = 1;
+
+ keep_next_level (true);
+ block = begin_omp_structured_block ();
+
+ if (block_scope)
+ DECL_CONTEXT (vardecl) = current_function_decl;
+ else if (current_class_type)
+ DECL_CONTEXT (vardecl) = current_class_type;
+ else
+ DECL_CONTEXT (vardecl) = current_namespace;
+
+ if (processing_template_decl)
+ vardecl = push_template_decl (vardecl);
+
+ if ((id = cp_parser_declarator_id (parser, false)) == error_mark_node)
+ goto fail;
+
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ {
+ finish_omp_structured_block (block);
+ goto fail;
+ }
+
+ placeholder = build_lang_decl (VAR_DECL, id, type);
+ DECL_CONTEXT (placeholder) = DECL_CONTEXT (vardecl);
+ if (processing_template_decl)
+ placeholder = push_template_decl (placeholder);
+ pushdecl (placeholder);
+ cp_finish_decl (placeholder, NULL_TREE, 0, NULL_TREE, 0);
+ DECL_ARTIFICIAL (placeholder) = 1;
+ TREE_USED (placeholder) = 1;
+
+ while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
+ {
+ pragma_omp_clause c_kind = cp_parser_omp_clause_name (parser);
+ if (c_kind != PRAGMA_OMP_CLAUSE_MAP)
+ {
+ if (c_kind != PRAGMA_OMP_CLAUSE_NONE)
+ cp_parser_error (parser, "unexpected clause");
+ finish_omp_structured_block (block);
+ goto fail;
+ }
+ maplist = cp_parser_omp_clause_map (parser, maplist, /*mapper=*/true);
+ if (maplist == NULL_TREE)
+ break;
+ }
+
+ if (maplist == NULL_TREE)
+ {
+ cp_parser_error (parser, "missing %<map%> clause");
+ finish_omp_structured_block (block);
+ goto fail;
+ }
+
+ mapper = make_node (OMP_DECLARE_MAPPER);
+ TREE_TYPE (mapper) = type;
+ OMP_DECLARE_MAPPER_ID (mapper) = mapper_name;
+ OMP_DECLARE_MAPPER_DECL (mapper) = placeholder;
+ OMP_DECLARE_MAPPER_CLAUSES (mapper) = maplist;
+
+ finish_omp_structured_block (block);
+
+ DECL_INITIAL (vardecl) = mapper;
+
+ if (current_class_type)
+ {
+ if (processing_template_decl)
+ {
+ retrofit_lang_decl (vardecl);
+ SET_DECL_VAR_DECLARED_INLINE_P (vardecl);
+ }
+ finish_static_data_member_decl (vardecl, mapper,
+ /*init_const_expr_p=*/true, NULL_TREE, 0);
+ finish_member_declaration (vardecl);
+ }
+ else if (processing_template_decl && block_scope)
+ add_decl_expr (vardecl);
+ else
+ pushdecl (vardecl);
+
+ cp_check_omp_declare_mapper (vardecl);
+
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return;
+
+fail:
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+}
+
/* OpenMP 4.0
#pragma omp declare simd declare-simd-clauses[optseq] new-line
#pragma omp declare reduction (reduction-id : typename-list : expression) \
@@ -52175,6 +54121,12 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
context);
return false;
}
+ if (strcmp (p, "mapper") == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_omp_declare_mapper (parser, pragma_tok, context);
+ return false;
+ }
if (!flag_openmp) /* flag_openmp_simd */
{
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
@@ -52188,7 +54140,7 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
}
}
cp_parser_error (parser, "expected %<simd%>, %<reduction%>, "
- "%<target%> or %<variant%>");
+ "%<target%>, %<mapper%> or %<variant%>");
cp_parser_require_pragma_eol (parser, pragma_tok);
return false;
}
@@ -52527,6 +54479,14 @@ cp_parser_omp_error (cp_parser *parser, cp_token *pragma_tok,
"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);
@@ -52548,11 +54508,14 @@ cp_parser_omp_error (cp_parser *parser, cp_token *pragma_tok,
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;
}
@@ -53441,11 +55404,15 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
id = cp_parser_pragma_kind (pragma_tok);
if (parser->omp_for_parse_state
&& parser->omp_for_parse_state->in_intervening_code
- && id >= PRAGMA_OMP__START_
- && id <= PRAGMA_OMP__LAST_)
- {
- error_at (pragma_tok->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 (
+ pragma_tok->location,
+ "intervening code must not contain executable OpenMP directives");
parser->omp_for_parse_state->fail = true;
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
return false;