diff options
author | Thomas Koenig <tkoenig@gcc.gnu.org> | 2021-09-13 19:49:49 +0200 |
---|---|---|
committer | Thomas Koenig <tkoenig@gcc.gnu.org> | 2021-09-13 19:49:49 +0200 |
commit | b18a97e5dd0935e1c4a626c230f21457d0aad3d5 (patch) | |
tree | c1818f41af6fe780deafb6cd6a183f32085fe654 /gcc/cp/parser.c | |
parent | e76a53644c9d70e998c0d050e9a456af388c6b61 (diff) | |
download | gcc-b18a97e5dd0935e1c4a626c230f21457d0aad3d5.zip gcc-b18a97e5dd0935e1c4a626c230f21457d0aad3d5.tar.gz gcc-b18a97e5dd0935e1c4a626c230f21457d0aad3d5.tar.bz2 |
Merged current trunk to branch.
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r-- | gcc/cp/parser.c | 2814 |
1 files changed, 2429 insertions, 385 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index dd8e808..e44c5c6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1,5 +1,5 @@ /* -*- C++ -*- Parser. - Copyright (C) 2000-2020 Free Software Foundation, Inc. + Copyright (C) 2000-2021 Free Software Foundation, Inc. Written by Mark Mitchell <mark@codesourcery.com>. This file is part of GCC. @@ -572,6 +572,8 @@ cp_debug_parser (FILE *file, cp_parser *parser) parser->colon_corrects_to_scope_p); cp_debug_print_flag (file, "Colon doesn't start a class definition", parser->colon_doesnt_start_class_def_p); + cp_debug_print_flag (file, "Parsing an Objective-C++ message context", + parser->objective_c_message_context_p); if (parser->type_definition_forbidden_message) fprintf (file, "Error message for forbidden type definitions: %s %s\n", parser->type_definition_forbidden_message, @@ -1438,6 +1440,24 @@ cp_finalize_omp_declare_simd (cp_parser *parser, tree fndecl) } } +/* Similarly, but for use in declaration parsing functions + which call cp_parser_handle_directive_omp_attributes. */ + +static inline void +cp_finalize_omp_declare_simd (cp_parser *parser, cp_omp_declare_simd_data *data) +{ + if (parser->omp_declare_simd != data) + return; + + if (!parser->omp_declare_simd->error_seen + && !parser->omp_declare_simd->fndecl_seen) + error_at (parser->omp_declare_simd->loc, + "%<declare %s%> directive not immediately followed by " + "function declaration or definition", + parser->omp_declare_simd->variant_p ? "variant" : "simd"); + parser->omp_declare_simd = NULL; +} + /* Diagnose if #pragma acc routine isn't followed immediately by function declaration or definition. */ @@ -2161,7 +2181,7 @@ static enum tree_code cp_parser_assignment_operator_opt 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 *, bool = false, bool * = NULL, bool = false); + (cp_parser *, int = 0, bool * = NULL, bool = false); static cp_expr cp_parser_builtin_offsetof (cp_parser *); static cp_expr cp_parser_lambda_expression @@ -2505,6 +2525,8 @@ static tree cp_parser_std_attribute_spec (cp_parser *); static tree cp_parser_std_attribute_spec_seq (cp_parser *); +static size_t cp_parser_skip_std_attribute_spec_seq + (cp_parser *, size_t); static size_t cp_parser_skip_attributes_opt (cp_parser *, size_t); static bool cp_parser_extension_opt @@ -3469,11 +3491,15 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id, else if (TREE_CODE (id) == IDENTIFIER_NODE && (id_equal (id, "module") || id_equal (id, "import"))) { - if (!modules_p ()) - inform (location, "%qE only available with %<-fmodules-ts%>", id); - else - inform (location, "%qE was not recognized as a module control-line", + if (modules_p ()) + inform (location, "%qE is not recognized as a module control-line", + id); + else if (cxx_dialect < cxx20) + inform (location, "C++20 %qE only available with %<-fmodules-ts%>", id); + else + inform (location, "C++20 %qE only available with %<-fmodules-ts%>" + ", which is not yet enabled with %<-std=c++20%>", id); } else if (cxx_dialect < cxx11 && TREE_CODE (id) == IDENTIFIER_NODE @@ -4054,6 +4080,14 @@ cp_parser_skip_to_pragma_eol (cp_parser* parser, cp_token *pragma_tok) /* Ensure that the pragma is not parsed again. */ cp_lexer_purge_tokens_after (parser->lexer, pragma_tok); parser->lexer->in_pragma = false; + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + { + parser->lexer = parser->lexer->next; + /* Put the current source position back where it was before this + lexer was pushed. */ + cp_lexer_set_source_position_from_token (parser->lexer->next_token); + } } } @@ -4066,6 +4100,14 @@ cp_parser_require_pragma_eol (cp_parser *parser, cp_token *pragma_tok) parser->lexer->in_pragma = false; if (!cp_parser_require (parser, CPP_PRAGMA_EOL, RT_PRAGMA_EOL)) cp_parser_skip_to_pragma_eol (parser, pragma_tok); + else if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + { + parser->lexer = parser->lexer->next; + /* Put the current source position back where it was before this + lexer was pushed. */ + cp_lexer_set_source_position_from_token (parser->lexer->next_token); + } } /* This is a simple wrapper around make_typename_type. When the id is @@ -4372,8 +4414,8 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, rich_location rich_loc (line_table, tok->location); rich_loc.add_range (last_tok_loc); error_at (&rich_loc, - "unsupported non-standard concatenation " - "of string literals"); + "concatenation of string literals with " + "conflicting encoding prefixes"); } } @@ -5316,7 +5358,7 @@ cp_parser_fold_expression (cp_parser *parser, tree expr1) /* The operands of a fold-expression are cast-expressions, so binary or conditional expressions are not allowed. We check this here to avoid tentative parsing. */ - if (EXPR_P (expr1) && TREE_NO_WARNING (expr1)) + if (EXPR_P (expr1) && warning_suppressed_p (expr1, OPT_Wparentheses)) /* OK, the expression was parenthesized. */; else if (is_binary_op (TREE_CODE (expr1))) error_at (location_of (expr1), @@ -5571,8 +5613,9 @@ cp_parser_primary_expression (cp_parser *parser, expr = cp_parser_fold_expression (parser, expr); if (expr != error_mark_node && cxx_dialect < cxx17) - pedwarn (input_location, 0, "fold-expressions only available " - "with %<-std=c++17%> or %<-std=gnu++17%>"); + pedwarn (input_location, OPT_Wc__17_extensions, + "fold-expressions only available with %<-std=c++17%> " + "or %<-std=gnu++17%>"); } else /* Let the front end know that this expression was @@ -5597,7 +5640,10 @@ cp_parser_primary_expression (cp_parser *parser, /* Consume the `)'. */ token = cp_lexer_peek_token (parser->lexer); location_t close_paren_loc = token->location; + bool no_wparens = warning_suppressed_p (expr, OPT_Wparentheses); expr.set_range (open_paren_loc, close_paren_loc); + if (no_wparens) + suppress_warning (expr, OPT_Wparentheses); if (!parens.require_close (parser) && !cp_parser_uncommitted_to_tentative_parse_p (parser)) cp_parser_skip_to_end_of_statement (parser); @@ -5770,7 +5816,9 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_EMPTY: case RID_IS_ENUM: case RID_IS_FINAL: + case RID_IS_LAYOUT_COMPATIBLE: case RID_IS_LITERAL_TYPE: + case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: case RID_IS_POD: case RID_IS_POLYMORPHIC: case RID_IS_SAME_AS: @@ -5942,7 +5990,10 @@ cp_parser_primary_expression (cp_parser *parser, /* Check to see if DECL is a local variable in a context where that is forbidden. */ if ((parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN) - && local_variable_p (decl)) + && local_variable_p (decl) + /* DR 2082 permits local variables in unevaluated contexts + within a default argument. */ + && !cp_unevaluated_operand) { const char *msg = (TREE_CODE (decl) == PARM_DECL @@ -6319,7 +6370,7 @@ cp_parser_unqualified_id (cp_parser* parser, if (cp_parser_is_keyword (token, RID_AUTO)) { if (cxx_dialect < cxx14) - pedwarn (loc, 0, + pedwarn (loc, OPT_Wc__14_extensions, "%<~auto%> only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); cp_lexer_consume_token (parser->lexer); @@ -6622,7 +6673,9 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, if (token->type == CPP_COLON && parser->colon_corrects_to_scope_p - && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_NAME) + && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_NAME + /* name:name is a valid sequence in an Objective C message. */ + && !parser->objective_c_message_context_p) { gcc_rich_location richloc (token->location); richloc.add_fixit_replace ("::"); @@ -7286,11 +7339,10 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, case RID_ADDRESSOF: case RID_BUILTIN_SHUFFLE: + case RID_BUILTIN_SHUFFLEVECTOR: case RID_BUILTIN_LAUNDER: { vec<tree, va_gc> *vec; - unsigned int i; - tree p; cp_lexer_consume_token (parser->lexer); vec = cp_parser_parenthesized_expression_list (parser, non_attr, @@ -7302,7 +7354,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, break; } - FOR_EACH_VEC_ELT (*vec, i, p) + for (tree p : *vec) mark_exp_read (p); switch (keyword) @@ -7348,6 +7400,20 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, } break; + case RID_BUILTIN_SHUFFLEVECTOR: + if (vec->length () < 3) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_shufflevector%>"); + postfix_expression = error_mark_node; + } + else + { + postfix_expression + = build_x_shufflevector (loc, vec, tf_warning_or_error); + } + break; + default: gcc_unreachable (); } @@ -7556,6 +7622,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, tsubst_flags_t complain = complain_flags (decltype_p); vec<tree, va_gc> *args; location_t close_paren_loc = UNKNOWN_LOCATION; + location_t combined_loc = UNKNOWN_LOCATION; is_member_access = false; @@ -7661,6 +7728,17 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, } } + /* Temporarily set input_location to the combined location + with call expression range, as e.g. build_out_target_exprs + called from convert_default_arg relies on input_location, + so updating it only when the call is fully built results + in inconsistencies between location handling in templates + and outside of templates. */ + if (close_paren_loc != UNKNOWN_LOCATION) + combined_loc = make_location (token->location, start_loc, + close_paren_loc); + iloc_sentinel ils (combined_loc); + if (TREE_CODE (postfix_expression) == COMPONENT_REF) { tree instance = TREE_OPERAND (postfix_expression, 0); @@ -7718,12 +7796,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, complain); if (close_paren_loc != UNKNOWN_LOCATION) - { - location_t combined_loc = make_location (token->location, - start_loc, - close_paren_loc); - postfix_expression.set_location (combined_loc); - } + postfix_expression.set_location (combined_loc); /* The POSTFIX_EXPRESSION is certainly no longer an id. */ idk = CP_ID_KIND_NONE; @@ -8338,7 +8411,7 @@ cp_parser_pseudo_destructor_name (cp_parser* parser, && !type_dependent_expression_p (object)) { if (cxx_dialect < cxx14) - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__14_extensions, "%<~auto%> only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); cp_lexer_consume_token (parser->lexer); @@ -8934,7 +9007,7 @@ cp_parser_has_attribute_expression (cp_parser *parser) { if (oper == error_mark_node) /* Nothing. */; - else if (type_dependent_expression_p (oper)) + else if (processing_template_decl && uses_template_parms (oper)) sorry_at (atloc, "%<__builtin_has_attribute%> with dependent argument " "not supported yet"); else @@ -10359,13 +10432,15 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk, If ALLOW_NON_CONSTANT_P a non-constant expression is silently accepted. If ALLOW_NON_CONSTANT_P is true and the expression is not constant, *NON_CONSTANT_P is set to TRUE. If ALLOW_NON_CONSTANT_P - is false, NON_CONSTANT_P should be NULL. If STRICT_P is true, + is false, NON_CONSTANT_P should be NULL. If ALLOW_NON_CONSTANT_P is + greater than 1, this isn't really a constant-expression, only a + potentially constant-evaluated expression. If STRICT_P is true, only parse a conditional-expression, otherwise parse an assignment-expression. See below for rationale. */ static cp_expr cp_parser_constant_expression (cp_parser* parser, - bool allow_non_constant_p, + int allow_non_constant_p, bool *non_constant_p, bool strict_p) { @@ -10401,6 +10476,11 @@ cp_parser_constant_expression (cp_parser* parser, parser->allow_non_integral_constant_expression_p = (allow_non_constant_p || cxx_dialect >= cxx11); parser->non_integral_constant_expression_p = false; + + /* A manifestly constant-evaluated expression is evaluated even in an + unevaluated operand. */ + cp_evaluated ev (/*reset if*/allow_non_constant_p <= 1); + /* Although the grammar says "conditional-expression", when not STRICT_P, we parse an "assignment-expression", which also permits "throw-expression" and the use of assignment operators. In the case @@ -10628,9 +10708,17 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) case RID_IS_FINAL: kind = CPTK_IS_FINAL; break; + case RID_IS_LAYOUT_COMPATIBLE: + kind = CPTK_IS_LAYOUT_COMPATIBLE; + binary = true; + break; case RID_IS_LITERAL_TYPE: kind = CPTK_IS_LITERAL_TYPE; break; + case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: + kind = CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF; + binary = true; + break; case RID_IS_POD: kind = CPTK_IS_POD; break; @@ -10781,7 +10869,21 @@ cp_parser_lambda_expression (cp_parser* parser) LAMBDA_EXPR_LOCATION (lambda_expr) = token->location; if (cxx_dialect >= cxx20) - /* C++20 allows lambdas in unevaluated context. */; + { + /* 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; + } + } else if (cp_unevaluated_operand) { if (!token->error_reported) @@ -10850,6 +10952,11 @@ cp_parser_lambda_expression (cp_parser* parser) bool discarded = in_discarded_stmt; in_discarded_stmt = 0; + /* Similarly the body of a lambda in immediate function context is not + in immediate function context. */ + bool save_in_consteval_if_p = in_consteval_if_p; + in_consteval_if_p = false; + /* By virtue of defining a local class, a lambda expression has access to the private variables of enclosing classes. */ @@ -10880,6 +10987,7 @@ cp_parser_lambda_expression (cp_parser* parser) finish_struct (type, /*attributes=*/NULL_TREE); + in_consteval_if_p = save_in_consteval_if_p; in_discarded_stmt = discarded; parser->num_template_parameter_lists = saved_num_template_parameter_lists; @@ -11006,8 +11114,9 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) { location_t loc = cp_lexer_peek_token (parser->lexer)->location; if (cxx_dialect < cxx17) - pedwarn (loc, 0, "%<*this%> capture only available with " - "%<-std=c++17%> or %<-std=gnu++17%>"); + pedwarn (loc, OPT_Wc__17_extensions, + "%<*this%> capture only available with " + "%<-std=c++17%> or %<-std=gnu++17%>"); cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer); if (LAMBDA_EXPR_THIS_CAPTURE (lambda_expr)) @@ -11045,7 +11154,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) { ellipsis_loc = cp_lexer_peek_token (parser->lexer)->location; if (cxx_dialect < cxx20) - pedwarn (ellipsis_loc, 0, "pack init-capture only available with " + pedwarn (ellipsis_loc, OPT_Wc__20_extensions, + "pack init-capture only available with " "%<-std=c++20%> or %<-std=gnu++20%>"); cp_lexer_consume_token (parser->lexer); init_pack_expansion = true; @@ -11086,7 +11196,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) bool direct, non_constant; /* An explicit initializer exists. */ if (cxx_dialect < cxx14) - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__14_extensions, "lambda capture initializers " "only available with %<-std=c++14%> or %<-std=gnu++14%>"); capture_init_expr = cp_parser_initializer (parser, &direct, @@ -11223,12 +11333,12 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) /* Parse the (optional) middle of a lambda expression. lambda-declarator: - ( parameter-declaration-clause ) - decl-specifier-seq [opt] - noexcept-specifier [opt] - attribute-specifier-seq [opt] - trailing-return-type [opt] - requires-clause [opt] + ( parameter-declaration-clause ) lambda-specifiers requires-clause [opt] + lambda-specifiers (C++23) + + lambda-specifiers: + 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. */ @@ -11248,6 +11358,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) tree tx_qual = NULL_TREE; tree return_type = NULL_TREE; tree trailing_requires_clause = NULL_TREE; + bool has_param_list = false; + location_t omitted_parms_loc = UNKNOWN_LOCATION; cp_decl_specifier_seq lambda_specs; clear_decl_specs (&lambda_specs); /* A lambda op() is const unless explicitly 'mutable'. */ @@ -11258,11 +11370,11 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) if (cp_lexer_next_token_is (parser->lexer, CPP_LESS)) { if (cxx_dialect < cxx14) - pedwarn (parser->lexer->next_token->location, 0, + pedwarn (parser->lexer->next_token->location, OPT_Wc__14_extensions, "lambda templates are only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); - else if (cxx_dialect < cxx20) - pedwarn (parser->lexer->next_token->location, OPT_Wpedantic, + else if (pedantic && cxx_dialect < cxx20) + pedwarn (parser->lexer->next_token->location, OPT_Wc__20_extensions, "lambda templates are only available with " "%<-std=c++20%> or %<-std=gnu++20%>"); @@ -11327,49 +11439,95 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) /* Default arguments shall not be specified in the parameter-declaration-clause of a lambda-declarator. */ - if (cxx_dialect < cxx14) + if (pedantic && cxx_dialect < cxx14) for (tree t = param_list; t; t = TREE_CHAIN (t)) if (TREE_PURPOSE (t) && DECL_P (TREE_VALUE (t))) - pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), OPT_Wpedantic, + pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), + OPT_Wc__14_extensions, "default argument specified for lambda parameter"); parens.require_close (parser); + has_param_list = true; + } + else if (cxx_dialect < cxx23) + omitted_parms_loc = cp_lexer_peek_token (parser->lexer)->location; - /* In the decl-specifier-seq of the lambda-declarator, each - decl-specifier shall either be mutable or constexpr. */ - int declares_class_or_enum; - if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer) - && !cp_next_tokens_can_be_gnu_attribute_p (parser)) - cp_parser_decl_specifier_seq (parser, - CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR, - &lambda_specs, &declares_class_or_enum); - if (lambda_specs.storage_class == sc_mutable) - { - LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1; - quals = TYPE_UNQUALIFIED; - if (lambda_specs.conflicting_specifiers_p) - error_at (lambda_specs.locations[ds_storage_class], - "duplicate %<mutable%>"); - } + /* In the decl-specifier-seq of the lambda-declarator, each + decl-specifier shall either be mutable or constexpr. */ + int declares_class_or_enum; + if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer) + && !cp_next_tokens_can_be_gnu_attribute_p (parser)) + cp_parser_decl_specifier_seq (parser, + CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR, + &lambda_specs, &declares_class_or_enum); - tx_qual = cp_parser_tx_qualifier_opt (parser); + if (omitted_parms_loc && lambda_specs.any_specifiers_p) + { + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, + "parameter declaration before lambda declaration " + "specifiers only optional with %<-std=c++2b%> or " + "%<-std=gnu++2b%>"); + omitted_parms_loc = UNKNOWN_LOCATION; + } - /* Parse optional exception specification. */ - exception_spec - = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE); + if (lambda_specs.storage_class == sc_mutable) + { + LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1; + quals = TYPE_UNQUALIFIED; + if (lambda_specs.conflicting_specifiers_p) + error_at (lambda_specs.locations[ds_storage_class], + "duplicate %<mutable%>"); + } - std_attrs = cp_parser_std_attribute_spec_seq (parser); + tx_qual = cp_parser_tx_qualifier_opt (parser); + if (omitted_parms_loc && tx_qual) + { + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, + "parameter declaration before lambda transaction " + "qualifier only optional with %<-std=c++2b%> or " + "%<-std=gnu++2b%>"); + omitted_parms_loc = UNKNOWN_LOCATION; + } - /* Parse optional trailing return type. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) - { - cp_lexer_consume_token (parser->lexer); - return_type = cp_parser_trailing_type_id (parser); - } + /* Parse optional exception specification. */ + exception_spec + = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE); + + if (omitted_parms_loc && exception_spec) + { + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, + "parameter declaration before lambda exception " + "specification only optional with %<-std=c++2b%> or " + "%<-std=gnu++2b%>"); + omitted_parms_loc = UNKNOWN_LOCATION; + } + + /* GCC 8 accepted attributes here, and this is the place for standard C++11 + attributes that appertain to the function type. */ + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + gnu_attrs = cp_parser_gnu_attributes_opt (parser); + else + std_attrs = cp_parser_std_attribute_spec_seq (parser); - if (cp_next_tokens_can_be_gnu_attribute_p (parser)) - gnu_attrs = cp_parser_gnu_attributes_opt (parser); + /* Parse optional trailing return type. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) + { + if (omitted_parms_loc) + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, + "parameter declaration before lambda trailing " + "return type only optional with %<-std=c++2b%> or " + "%<-std=gnu++2b%>"); + cp_lexer_consume_token (parser->lexer); + return_type = cp_parser_trailing_type_id (parser); + } + + /* Also allow GNU attributes at the very end of the declaration, the usual + place for GNU attributes. */ + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + gnu_attrs = chainon (gnu_attrs, cp_parser_gnu_attributes_opt (parser)); + if (has_param_list) + { /* Parse optional trailing requires clause. */ trailing_requires_clause = cp_parser_requires_clause_opt (parser, false); @@ -11475,6 +11633,9 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) middle of an expression. */ ++function_depth; + auto odsd = make_temp_override (parser->omp_declare_simd, NULL); + auto ord = make_temp_override (parser->oacc_routine, NULL); + auto oafp = make_temp_override (parser->omp_attrs_forbidden_p, false); vec<tree> omp_privatization_save; save_omp_privatization_clauses (omp_privatization_save); /* Clear this in case we're in the middle of a default argument. */ @@ -11521,6 +11682,323 @@ add_debug_begin_stmt (location_t loc) add_stmt (stmt); } +struct cp_omp_attribute_data +{ + cp_token_cache *tokens; + const c_omp_directive *dir; + c_omp_directive_kind kind; +}; + +/* Handle omp::directive and omp::sequence attributes in ATTRS + (if any) at the start of a statement or in attribute-declaration. */ + +static tree +cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) +{ + if (!flag_openmp && !flag_openmp_simd) + return attrs; + + auto_vec<cp_omp_attribute_data, 16> vec; + int cnt = 0; + int tokens = 0; + bool bad = false; + for (tree *pa = &attrs; *pa; ) + if (get_attribute_namespace (*pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (*pa))) + { + cnt++; + for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + if (parser->omp_attrs_forbidden_p) + { + error_at (first->location, + "mixing OpenMP directives with attribute and pragma " + "syntax on the same statement"); + parser->omp_attrs_forbidden_p = false; + bad = true; + } + const char *directive[3] = {}; + for (int i = 0; i < 3; i++) + { + tree id = NULL_TREE; + if (first + i == last) + break; + if (first[i].type == CPP_NAME) + id = first[i].u.value; + else if (first[i].type == CPP_KEYWORD) + id = ridpointers[(int) first[i].keyword]; + else + break; + directive[i] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + { + error_at (first->location, + "unknown OpenMP directive name in %<omp::directive%>" + " attribute argument"); + continue; + } + c_omp_directive_kind kind = dir->kind; + if (dir->id == PRAGMA_OMP_ORDERED) + { + /* ordered is C_OMP_DIR_CONSTRUCT only if it doesn't contain + depend clause. */ + if (directive[1] && strcmp (directive[1], "depend") == 0) + kind = C_OMP_DIR_STANDALONE; + else if (first + 2 < last + && first[1].type == CPP_COMMA + && first[2].type == CPP_NAME + && strcmp (IDENTIFIER_POINTER (first[2].u.value), + "depend") == 0) + kind = C_OMP_DIR_STANDALONE; + } + else if (dir->id == PRAGMA_OMP_ERROR) + { + /* error with at(execution) clause is C_OMP_DIR_STANDALONE. */ + int paren_depth = 0; + for (int i = 1; first + i < last; i++) + if (first[i].type == CPP_OPEN_PAREN) + paren_depth++; + else if (first[i].type == CPP_CLOSE_PAREN) + paren_depth--; + else if (paren_depth == 0 + && first + i + 2 < last + && first[i].type == CPP_NAME + && first[i + 1].type == CPP_OPEN_PAREN + && first[i + 2].type == CPP_NAME + && !strcmp (IDENTIFIER_POINTER (first[i].u.value), + "at") + && !strcmp (IDENTIFIER_POINTER (first[i + + 2].u.value), + "execution")) + { + kind = C_OMP_DIR_STANDALONE; + break; + } + } + cp_omp_attribute_data v = { DEFPARSE_TOKENS (d), dir, kind }; + vec.safe_push (v); + if (flag_openmp || dir->simd) + tokens += (last - first) + 1; + } + cp_omp_attribute_data v = {}; + vec.safe_push (v); + *pa = TREE_CHAIN (*pa); + } + else + pa = &TREE_CHAIN (*pa); + + if (bad) + return attrs; + + unsigned int i; + cp_omp_attribute_data *v; + cp_omp_attribute_data *construct_seen = nullptr; + cp_omp_attribute_data *standalone_seen = nullptr; + cp_omp_attribute_data *prev_standalone_seen = nullptr; + FOR_EACH_VEC_ELT (vec, i, v) + if (v->tokens) + { + if (v->kind == C_OMP_DIR_CONSTRUCT && !construct_seen) + construct_seen = v; + else if (v->kind == C_OMP_DIR_STANDALONE && !standalone_seen) + standalone_seen = v; + } + else + { + if (standalone_seen && !prev_standalone_seen) + { + prev_standalone_seen = standalone_seen; + standalone_seen = nullptr; + } + } + + if (cnt > 1 && construct_seen) + { + error_at (construct_seen->tokens->first->location, + "OpenMP construct among %<omp::directive%> attributes" + " requires all %<omp::directive%> attributes on the" + " same statement to be in the same %<omp::sequence%>"); + return attrs; + } + if (cnt > 1 && standalone_seen && prev_standalone_seen) + { + error_at (standalone_seen->tokens->first->location, + "multiple OpenMP standalone directives among" + " %<omp::directive%> attributes must be all within the" + " same %<omp::sequence%>"); + return attrs; + } + + if (prev_standalone_seen) + standalone_seen = prev_standalone_seen; + if (standalone_seen + && !cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + error_at (standalone_seen->tokens->first->location, + "standalone OpenMP directives in %<omp::directive%> attribute" + " can only appear on an empty statement"); + return attrs; + } + if (cnt && cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + enum pragma_kind kind = cp_parser_pragma_kind (token); + if (kind >= PRAGMA_OMP__START_ && kind <= PRAGMA_OMP__LAST_) + { + error_at (token->location, + "mixing OpenMP directives with attribute and pragma " + "syntax on the same statement"); + return attrs; + } + } + + if (!tokens) + return attrs; + tokens++; + cp_lexer *lexer = cp_lexer_alloc (); + lexer->debugging_p = parser->lexer->debugging_p; + vec_safe_reserve (lexer->buffer, tokens, true); + FOR_EACH_VEC_ELT (vec, i, v) + { + if (!v->tokens) + continue; + if (!flag_openmp && !v->dir->simd) + continue; + cp_token *first = v->tokens->first; + cp_token *last = v->tokens->last; + cp_token tok = {}; + tok.type = CPP_PRAGMA; + tok.keyword = RID_MAX; + tok.u.value = build_int_cst (NULL, v->dir->id); + tok.location = first->location; + lexer->buffer->quick_push (tok); + while (++first < last) + lexer->buffer->quick_push (*first); + tok = {}; + tok.type = CPP_PRAGMA_EOL; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + } + cp_token tok = {}; + tok.type = CPP_EOF; + tok.keyword = RID_MAX; + tok.location = lexer->buffer->last ().location; + lexer->buffer->quick_push (tok); + lexer->next = parser->lexer; + lexer->next_token = lexer->buffer->address (); + lexer->last_token = lexer->next_token + + lexer->buffer->length () + - 1; + lexer->in_omp_attribute_pragma = true; + parser->lexer = lexer; + /* Move the current source position to that of the first token in the + new lexer. */ + cp_lexer_set_source_position_from_token (lexer->next_token); + return attrs; +} + +/* Handle omp::directive and omp::sequence attributes in *PATTRS + (if any) at the start or after declaration-id of a declaration. */ + +static void +cp_parser_handle_directive_omp_attributes (cp_parser *parser, tree *pattrs, + cp_omp_declare_simd_data *data, + bool start) +{ + if (!flag_openmp && !flag_openmp_simd) + return; + + int cnt = 0; + bool bad = false; + bool variant_p = false; + location_t loc = UNKNOWN_LOCATION; + for (tree pa = *pattrs; pa; pa = TREE_CHAIN (pa)) + if (get_attribute_namespace (pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (pa))) + { + for (tree a = TREE_VALUE (pa); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int i = 0; i < 3; i++) + { + tree id = NULL_TREE; + if (first + i == last) + break; + if (first[i].type == CPP_NAME) + id = first[i].u.value; + else if (first[i].type == CPP_KEYWORD) + id = ridpointers[(int) first[i].keyword]; + else + break; + directive[i] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + continue; + if (dir->id == PRAGMA_OMP_DECLARE + && (strcmp (directive[1], "simd") == 0 + || strcmp (directive[1], "variant") == 0)) + { + if (cnt++ == 0) + { + variant_p = strcmp (directive[1], "variant") == 0; + loc = first->location; + } + if (start && parser->omp_declare_simd && !bad) + { + error_at (first->location, + "mixing OpenMP directives with attribute and " + "pragma syntax on the same declaration"); + bad = true; + } + } + } + } + + if (bad) + { + for (tree *pa = pattrs; *pa; ) + if (get_attribute_namespace (*pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (*pa))) + *pa = TREE_CHAIN (*pa); + else + pa = &TREE_CHAIN (*pa); + return; + } + if (cnt == 0) + return; + + if (parser->omp_declare_simd == NULL) + { + data->error_seen = false; + data->fndecl_seen = false; + data->variant_p = variant_p; + data->loc = loc; + data->tokens = vNULL; + data->attribs[0] = NULL; + data->attribs[1] = NULL; + parser->omp_declare_simd = data; + } + parser->omp_declare_simd->attribs[!start] = pattrs; +} + /* Parse a statement. statement: @@ -11571,6 +12049,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, tree statement, std_attrs = NULL_TREE; cp_token *token; location_t statement_location, attrs_loc; + bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; + bool has_std_attrs; restart: if (if_p != NULL) @@ -11579,7 +12059,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, statement = NULL_TREE; saved_token_sentinel saved_tokens (parser->lexer); - attrs_loc = cp_lexer_peek_token (parser->lexer)->location; + token = cp_lexer_peek_token (parser->lexer); + attrs_loc = token->location; if (c_dialect_objc ()) /* In obj-c++, seeing '[[' might be the either the beginning of c++11 attributes, or a nested objc-message-expression. So @@ -11593,9 +12074,59 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, if (!cp_parser_parse_definitely (parser)) std_attrs = NULL_TREE; } + has_std_attrs = cp_lexer_peek_token (parser->lexer) != token; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); + bool omp_attrs_forbidden_p; + omp_attrs_forbidden_p = parser->omp_attrs_forbidden_p; + + if (std_attrs && (flag_openmp || flag_openmp_simd)) + { + bool handle_omp_attribs = false; + if (token->type == CPP_KEYWORD) + switch (token->keyword) + { + case RID_IF: + case RID_SWITCH: + case RID_WHILE: + case RID_DO: + case RID_FOR: + case RID_BREAK: + case RID_CONTINUE: + case RID_RETURN: + case RID_CO_RETURN: + case RID_GOTO: + case RID_AT_TRY: + case RID_AT_CATCH: + case RID_AT_FINALLY: + case RID_AT_SYNCHRONIZED: + case RID_AT_THROW: + case RID_TRY: + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + case RID_SYNCHRONIZED: + case RID_ATOMIC_NOEXCEPT: + case RID_ATOMIC_CANCEL: + case RID_TRANSACTION_CANCEL: + handle_omp_attribs = true; + break; + default: + break; + } + else if (token->type == CPP_SEMICOLON + || token->type == CPP_OPEN_BRACE + || token->type == CPP_PRAGMA) + handle_omp_attribs = true; + if (handle_omp_attribs) + { + std_attrs = cp_parser_handle_statement_omp_attributes (parser, + std_attrs); + token = cp_lexer_peek_token (parser->lexer); + } + } + parser->omp_attrs_forbidden_p = false; + /* Remember the location of the first token in the statement. */ cp_token *statement_token = token; statement_location = token->location; @@ -11615,6 +12146,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, the statement. */ cp_parser_label_for_labeled_statement (parser, std_attrs); in_compound = false; + in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; goto restart; case RID_IF: @@ -11656,7 +12188,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, case RID_NAMESPACE: /* This must be a namespace alias definition. */ - if (std_attrs != NULL_TREE) + if (has_std_attrs) { /* Attributes should be parsed as part of the declaration, so let's un-parse them. */ @@ -11698,6 +12230,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, cp_parser_label_for_labeled_statement (parser, std_attrs); in_compound = false; + in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; goto restart; } } @@ -11711,6 +12244,9 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, a statement all its own. */ else if (token->type == CPP_PRAGMA) { + do_pragma:; + cp_lexer *lexer = parser->lexer; + bool do_restart = false; /* Only certain OpenMP pragmas are attached to statements, and thus are considered statements themselves. All others are not. In the context of a compound, accept the pragma as a "statement" and @@ -11719,7 +12255,29 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, if (in_compound) cp_parser_pragma (parser, pragma_compound, if_p); else if (!cp_parser_pragma (parser, pragma_stmt, if_p)) + do_restart = true; + if (parser->lexer != lexer + && lexer->in_omp_attribute_pragma + && (!in_omp_attribute_pragma || lexer->orphan_p)) + { + if (saved_tokens.lexer == lexer) + { + if (saved_tokens.commit) + cp_lexer_commit_tokens (lexer); + gcc_assert (lexer->saved_tokens.length () == saved_tokens.len); + saved_tokens.lexer = parser->lexer; + saved_tokens.commit = false; + saved_tokens.len = parser->lexer->saved_tokens.length (); + } + cp_lexer_destroy (lexer); + lexer = parser->lexer; + } + if (do_restart) goto restart; + if (parser->lexer == lexer + && lexer->in_omp_attribute_pragma + && !in_omp_attribute_pragma) + parser->lexer->orphan_p = true; return; } else if (token->type == CPP_EOF) @@ -11736,20 +12294,61 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, { if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) { - if (std_attrs != NULL_TREE) + if (has_std_attrs) /* Attributes should be parsed as part of the declaration, so let's un-parse them. */ saved_tokens.rollback(); + parser->omp_attrs_forbidden_p = omp_attrs_forbidden_p; cp_parser_parse_tentatively (parser); /* Try to parse the declaration-statement. */ cp_parser_declaration_statement (parser); + parser->omp_attrs_forbidden_p = false; /* If that worked, we're done. */ if (cp_parser_parse_definitely (parser)) return; /* It didn't work, restore the post-attribute position. */ - if (std_attrs) - cp_lexer_set_token_position (parser->lexer, statement_token); + if (has_std_attrs) + { + cp_lexer_set_token_position (parser->lexer, statement_token); + if (flag_openmp || flag_openmp_simd) + { + size_t i = 1; + bool handle_omp_attribs = true; + while (cp_lexer_peek_nth_token (parser->lexer, i)->keyword + == RID_EXTENSION) + i++; + switch (cp_lexer_peek_nth_token (parser->lexer, i)->keyword) + { + case RID_ASM: + case RID_NAMESPACE: + case RID_USING: + case RID_LABEL: + case RID_STATIC_ASSERT: + /* Don't handle OpenMP attribs on keywords that + always start a declaration statement but don't + accept attribute before it and therefore + the tentative cp_parser_declaration_statement + fails to parse because of that. */ + handle_omp_attribs = false; + break; + default: + break; + } + + if (handle_omp_attribs) + { + parser->omp_attrs_forbidden_p = omp_attrs_forbidden_p; + std_attrs + = cp_parser_handle_statement_omp_attributes + (parser, std_attrs); + parser->omp_attrs_forbidden_p = false; + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_PRAGMA) + goto do_pragma; + } + } + } } /* All preceding labels have been parsed at this point. */ if (loc_after_labels != NULL) @@ -12064,11 +12663,12 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, if (function_body) maybe_splice_retval_cleanup (compound_stmt); - /* Finish the compound-statement. */ - finish_compound_stmt (compound_stmt); /* Consume the `}'. */ braces.require_close (parser); + /* Finish the compound-statement. */ + finish_compound_stmt (compound_stmt); + return compound_stmt; } @@ -12217,8 +12817,105 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, cx = true; cp_token *tok = cp_lexer_consume_token (parser->lexer); if (cxx_dialect < cxx17) - pedwarn (tok->location, 0, "%<if constexpr%> only available " - "with %<-std=c++17%> or %<-std=gnu++17%>"); + pedwarn (tok->location, OPT_Wc__17_extensions, + "%<if constexpr%> only available with " + "%<-std=c++17%> or %<-std=gnu++17%>"); + } + int ce = 0; + if (keyword == RID_IF && !cx) + { + if (cp_lexer_next_token_is_keyword (parser->lexer, + RID_CONSTEVAL)) + ce = 1; + else if (cp_lexer_next_token_is (parser->lexer, CPP_NOT) + && cp_lexer_nth_token_is_keyword (parser->lexer, 2, + RID_CONSTEVAL)) + { + ce = -1; + cp_lexer_consume_token (parser->lexer); + } + } + if (ce) + { + cp_token *tok = cp_lexer_consume_token (parser->lexer); + if (cxx_dialect < cxx23) + pedwarn (tok->location, OPT_Wc__23_extensions, + "%<if consteval%> only available with " + "%<-std=c++2b%> or %<-std=gnu++2b%>"); + + bool save_in_consteval_if_p = in_consteval_if_p; + statement = begin_if_stmt (); + IF_STMT_CONSTEVAL_P (statement) = true; + condition = finish_if_stmt_cond (boolean_false_node, statement); + + gcc_rich_location richloc (tok->location); + bool non_compound_stmt_p = false; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) + { + non_compound_stmt_p = true; + richloc.add_fixit_insert_after (tok->location, "{"); + } + + in_consteval_if_p |= ce > 0; + cp_parser_implicitly_scoped_statement (parser, NULL, guard_tinfo); + + if (non_compound_stmt_p) + { + location_t before_loc + = cp_lexer_peek_token (parser->lexer)->location; + richloc.add_fixit_insert_before (before_loc, "}"); + error_at (&richloc, + "%<if consteval%> requires compound statement"); + non_compound_stmt_p = false; + } + + finish_then_clause (statement); + + /* If the next token is `else', parse the else-clause. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, + RID_ELSE)) + { + cp_token *else_tok = cp_lexer_peek_token (parser->lexer); + gcc_rich_location else_richloc (else_tok->location); + guard_tinfo = get_token_indent_info (else_tok); + /* Consume the `else' keyword. */ + cp_lexer_consume_token (parser->lexer); + + begin_else_clause (statement); + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) + { + non_compound_stmt_p = true; + else_richloc.add_fixit_insert_after (else_tok->location, + "{"); + } + + in_consteval_if_p = save_in_consteval_if_p | (ce < 0); + cp_parser_implicitly_scoped_statement (parser, NULL, + guard_tinfo); + + if (non_compound_stmt_p) + { + location_t before_loc + = cp_lexer_peek_token (parser->lexer)->location; + else_richloc.add_fixit_insert_before (before_loc, "}"); + error_at (&else_richloc, + "%<if consteval%> requires compound statement"); + } + + finish_else_clause (statement); + } + + in_consteval_if_p = save_in_consteval_if_p; + if (ce < 0) + { + std::swap (THEN_CLAUSE (statement), ELSE_CLAUSE (statement)); + if (THEN_CLAUSE (statement) == NULL_TREE) + THEN_CLAUSE (statement) = build_empty_stmt (tok->location); + } + + finish_if_stmt (statement); + return statement; } /* Look for the `('. */ @@ -12243,16 +12940,14 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, { tree decl; if (cxx_dialect < cxx17) - pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0, + pedwarn (cp_lexer_peek_token (parser->lexer)->location, + OPT_Wc__17_extensions, "init-statement in selection statements only available " "with %<-std=c++17%> or %<-std=gnu++17%>"); if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) - { - /* A non-empty init-statement can have arbitrary side - effects. */ - delete chain; - chain = NULL; - } + /* A non-empty init-statement can have arbitrary side + effects. */ + vec_free (chain); cp_parser_init_statement (parser, &decl); } @@ -12343,13 +13038,10 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, } else if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_IF)) - { - /* This is if-else without subsequent if. Zap the - condition chain; we would have already warned at - this point. */ - delete chain; - chain = NULL; - } + /* This is if-else without subsequent if. Zap the + condition chain; we would have already warned at + this point. */ + vec_free (chain); } begin_else_clause (statement); /* Parse the else-clause. */ @@ -12384,11 +13076,8 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, "suggest explicit braces to avoid ambiguous" " %<else%>"); if (warn_duplicated_cond) - { - /* We don't need the condition chain anymore. */ - delete chain; - chain = NULL; - } + /* We don't need the condition chain anymore. */ + vec_free (chain); } /* Now we're all done with the if-statement. */ @@ -12785,17 +13474,15 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, static tree build_range_temp (tree range_expr) { - tree range_type, range_temp; - /* Find out the type deduced by the declaration `auto &&__range = range_expr'. */ - range_type = cp_build_reference_type (make_auto (), true); - range_type = do_auto_deduction (range_type, range_expr, - type_uses_auto (range_type)); + tree auto_node = make_auto (); + tree range_type = cp_build_reference_type (auto_node, true); + range_type = do_auto_deduction (range_type, range_expr, auto_node); /* Create the __range variable. */ - range_temp = build_decl (input_location, VAR_DECL, for_range__identifier, - range_type); + tree range_temp = build_decl (input_location, VAR_DECL, + for_range__identifier, range_type); TREE_USED (range_temp) = 1; DECL_ARTIFICIAL (range_temp) = 1; @@ -12825,7 +13512,9 @@ do_range_for_auto_deduction (tree decl, tree range_expr) RO_UNARY_STAR, tf_warning_or_error); TREE_TYPE (decl) = do_auto_deduction (TREE_TYPE (decl), - iter_decl, auto_node); + iter_decl, auto_node, + tf_warning_or_error, + adc_variable_type); } } } @@ -13321,7 +14010,8 @@ cp_parser_init_statement (cp_parser *parser, tree *decl) if (cxx_dialect < cxx20) { - pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0, + pedwarn (cp_lexer_peek_token (parser->lexer)->location, + OPT_Wc__20_extensions, "range-based %<for%> loops with initializer only " "available with %<-std=c++20%> or %<-std=gnu++20%>"); *decl = error_mark_node; @@ -13345,7 +14035,8 @@ cp_parser_init_statement (cp_parser *parser, tree *decl) cp_lexer_consume_token (parser->lexer); is_range_for = true; if (cxx_dialect < cxx11) - pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0, + pedwarn (cp_lexer_peek_token (parser->lexer)->location, + OPT_Wc__11_extensions, "range-based %<for%> loops only available with " "%<-std=c++11%> or %<-std=gnu++11%>"); } @@ -13707,7 +14398,13 @@ cp_parser_module_declaration (cp_parser *parser, module_parse mp_state, parser->lexer->in_pragma = true; cp_token *token = cp_lexer_consume_token (parser->lexer); - if (mp_state == MP_FIRST && !exporting + if (flag_header_unit) + { + error_at (token->location, + "module-declaration not permitted in header-unit"); + goto skip_eol; + } + else if (mp_state == MP_FIRST && !exporting && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) { /* Start global module fragment. */ @@ -13726,19 +14423,22 @@ cp_parser_module_declaration (cp_parser *parser, module_parse mp_state, cp_lexer_consume_token (parser->lexer); cp_parser_require_pragma_eol (parser, token); - if ((mp_state != MP_PURVIEW && mp_state != MP_PURVIEW_IMPORTS) + if (!(mp_state == MP_PURVIEW || mp_state == MP_PURVIEW_IMPORTS) || !module_interface_p () || module_partition_p ()) error_at (token->location, - "private module fragment not permitted here"); + "private module fragment only permitted in purview" + " of module interface or partition"); else { mp_state = MP_PRIVATE_IMPORTS; sorry_at (token->location, "private module fragment"); } } - else if (mp_state != MP_FIRST && mp_state != MP_GLOBAL) + else if (!(mp_state == MP_FIRST || mp_state == MP_GLOBAL)) { - error_at (token->location, "module-declaration not permitted here"); + /* Neither the first declaration, nor in a GMF. */ + error_at (token->location, "module-declaration only permitted as first" + " declaration, or ending a global module fragment"); skip_eol: cp_parser_skip_to_pragma_eol (parser, token); } @@ -13941,6 +14641,49 @@ cp_parser_declaration (cp_parser* parser, tree prefix_attrs) cp_token *token2 = (token1->type == CPP_EOF ? token1 : cp_lexer_peek_nth_token (parser->lexer, 2)); + if (token1->type == CPP_SEMICOLON) + { + cp_lexer_consume_token (parser->lexer); + /* A declaration consisting of a single semicolon is invalid + * before C++11. Allow it unless we're being pedantic. */ + if (cxx_dialect < cxx11) + pedwarn (input_location, OPT_Wpedantic, "extra %<;%>"); + return; + } + else if (cp_lexer_nth_token_is (parser->lexer, + cp_parser_skip_std_attribute_spec_seq (parser, + 1), + CPP_SEMICOLON)) + { + location_t attrs_loc = token1->location; + tree std_attrs = cp_parser_std_attribute_spec_seq (parser); + + if (std_attrs && (flag_openmp || flag_openmp_simd)) + { + gcc_assert (!parser->lexer->in_omp_attribute_pragma); + std_attrs = cp_parser_handle_statement_omp_attributes (parser, + std_attrs); + if (parser->lexer->in_omp_attribute_pragma) + { + cp_lexer *lexer = parser->lexer; + while (parser->lexer->in_omp_attribute_pragma) + { + gcc_assert (cp_lexer_next_token_is (parser->lexer, + CPP_PRAGMA)); + cp_parser_pragma (parser, pragma_external, NULL); + } + cp_lexer_destroy (lexer); + } + } + + if (std_attrs != NULL_TREE) + warning_at (make_location (attrs_loc, attrs_loc, parser->lexer), + OPT_Wattributes, "attribute ignored"); + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + cp_lexer_consume_token (parser->lexer); + return; + } + /* Get the high-water mark for the DECLARATOR_OBSTACK. */ void *p = obstack_alloc (&declarator_obstack, 0); @@ -14091,14 +14834,6 @@ cp_parser_toplevel_declaration (cp_parser* parser) cp_parser_declaration. (A #pragma at block scope is handled in cp_parser_statement.) */ cp_parser_pragma (parser, pragma_external, NULL); - else if (token->type == CPP_SEMICOLON) - { - cp_lexer_consume_token (parser->lexer); - /* A declaration consisting of a single semicolon is invalid - * before C++11. Allow it unless we're being pedantic. */ - if (cxx_dialect < cxx11) - pedwarn (input_location, OPT_Wpedantic, "extra %<;%>"); - } else /* Parse the declaration itself. */ cp_parser_declaration (parser, NULL_TREE); @@ -14146,6 +14881,7 @@ cp_parser_block_declaration (cp_parser *parser, /* Peek at the next token to figure out which kind of declaration is present. */ cp_token *token1 = cp_lexer_peek_token (parser->lexer); + size_t attr_idx; /* If the next keyword is `asm', we have an asm-definition. */ if (token1->keyword == RID_ASM) @@ -14199,6 +14935,18 @@ 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); + /* If the next tokens after attributes is `using namespace', then we have + a using-directive. */ + else if ((attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1)) != 1 + && cp_lexer_nth_token_is_keyword (parser->lexer, attr_idx, + RID_USING) + && cp_lexer_nth_token_is_keyword (parser->lexer, attr_idx + 1, + RID_NAMESPACE)) + { + if (statement_p) + cp_parser_commit_to_tentative_parse (parser); + cp_parser_using_directive (parser); + } /* Anything else must be a simple-declaration. */ else cp_parser_simple_declaration (parser, !statement_p, @@ -14261,6 +15009,12 @@ cp_parser_simple_declaration (cp_parser* parser, /* We no longer need to defer access checks. */ stop_deferring_access_checks (); + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* In a block scope, a valid declaration must always have a decl-specifier-seq. By not trying to parse declarators, we can resolve the declaration/expression ambiguity more quickly. */ @@ -14453,6 +15207,7 @@ cp_parser_simple_declaration (cp_parser* parser, else { pop_deferring_access_checks (); + cp_finalize_omp_declare_simd (parser, &odsd); return; } } @@ -14533,6 +15288,7 @@ cp_parser_simple_declaration (cp_parser* parser, done: pop_deferring_access_checks (); + cp_finalize_omp_declare_simd (parser, &odsd); } /* Helper of cp_parser_simple_declaration, parse a decomposition declaration. @@ -14579,8 +15335,9 @@ cp_parser_decomposition_declaration (cp_parser *parser, } if (cxx_dialect < cxx17) - pedwarn (loc, 0, "structured bindings only available with " - "%<-std=c++17%> or %<-std=gnu++17%>"); + pedwarn (loc, OPT_Wc__17_extensions, + "structured bindings only available with " + "%<-std=c++17%> or %<-std=gnu++17%>"); tree pushed_scope; cp_declarator *declarator = make_declarator (cdk_decomp); @@ -15060,6 +15817,16 @@ cp_parser_decl_specifier_seq (cp_parser* parser, if (!found_decl_spec) break; + if (decl_specs->std_attributes) + { + error_at (decl_specs->locations[ds_std_attribute], + "standard attributes in middle of decl-specifiers"); + inform (decl_specs->locations[ds_std_attribute], + "standard attributes must precede the decl-specifiers to " + "apply to the declaration, or follow them to apply to " + "the type"); + } + decl_specs->any_specifiers_p = true; /* After we see one decl-specifier, further decl-specifiers are always optional. */ @@ -15165,7 +15932,7 @@ cp_parser_function_specifier_opt (cp_parser* parser, = G_("types may not be defined in explicit-specifier"); if (cxx_dialect < cxx20) - pedwarn (token->location, 0, + pedwarn (token->location, OPT_Wc__20_extensions, "%<explicit(bool)%> only available with %<-std=c++20%> " "or %<-std=gnu++20%>"); @@ -15332,8 +16099,8 @@ cp_parser_static_assert(cp_parser *parser, bool member_p) if (cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN) { - if (cxx_dialect < cxx17) - pedwarn (input_location, OPT_Wpedantic, + if (pedantic && cxx_dialect < cxx17) + pedwarn (input_location, OPT_Wc__17_extensions, "%<static_assert%> without a message " "only available with %<-std=c++17%> or %<-std=gnu++17%>"); /* Eat the ')' */ @@ -16844,6 +17611,10 @@ cp_parser_default_type_template_argument (cp_parser *parser) cp_token *token = cp_lexer_peek_token (parser->lexer); + /* Tell cp_parser_lambda_expression this is a default argument. */ + auto lvf = make_temp_override (parser->local_variables_forbidden_p); + parser->local_variables_forbidden_p = LOCAL_VARS_AND_THIS_FORBIDDEN; + /* Parse the default-argument. */ push_deferring_access_checks (dk_no_deferred); tree default_argument = cp_parser_type_id (parser, @@ -17657,18 +18428,26 @@ cp_parser_template_name (cp_parser* parser, /* If DECL is a template, then the name was a template-name. */ if (TREE_CODE (decl) == TEMPLATE_DECL) { - if (TREE_DEPRECATED (decl) - && deprecated_state != DEPRECATED_SUPPRESS) + if ((TREE_DEPRECATED (decl) || TREE_UNAVAILABLE (decl)) + && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) { tree d = DECL_TEMPLATE_RESULT (decl); tree attr; if (TREE_CODE (d) == TYPE_DECL) - attr = lookup_attribute ("deprecated", - TYPE_ATTRIBUTES (TREE_TYPE (d))); + attr = TYPE_ATTRIBUTES (TREE_TYPE (d)); else - attr = lookup_attribute ("deprecated", - DECL_ATTRIBUTES (d)); - warn_deprecated_use (decl, attr); + attr = DECL_ATTRIBUTES (d); + if (TREE_UNAVAILABLE (decl)) + { + attr = lookup_attribute ("unavailable", attr); + error_unavailable_use (decl, attr); + } + else if (TREE_DEPRECATED (decl) + && deprecated_state != DEPRECATED_SUPPRESS) + { + attr = lookup_attribute ("deprecated", attr); + warn_deprecated_use (decl, attr); + } } } else @@ -17919,7 +18698,9 @@ cp_parser_template_argument (cp_parser* parser) } if (cp_parser_parse_definitely (parser)) { - if (TREE_DEPRECATED (argument)) + if (TREE_UNAVAILABLE (argument)) + error_unavailable_use (argument, NULL_TREE); + else if (TREE_DEPRECATED (argument)) warn_deprecated_use (argument, NULL_TREE); return argument; } @@ -18135,6 +18916,13 @@ cp_parser_explicit_instantiation (cp_parser* parser) CP_PARSER_FLAGS_OPTIONAL, &decl_specifiers, &declares_class_or_enum); + + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* If there was exactly one decl-specifier, and it declared a class, and there's no declarator, then we have an explicit type instantiation. */ @@ -18203,6 +18991,8 @@ cp_parser_explicit_instantiation (cp_parser* parser) cp_parser_consume_semicolon_at_end_of_statement (parser); timevar_pop (TV_TEMPLATE_INST); + + cp_finalize_omp_declare_simd (parser, &odsd); } /* Parse an explicit-specialization. @@ -18282,6 +19072,11 @@ cp_parser_explicit_specialization (cp_parser* parser) --parser->num_template_parameter_lists; } +/* Preserve the attributes across a garbage collect (by making it a GC + root), which can occur when parsing a member function. */ + +static GTY(()) vec<tree, va_gc> *cp_parser_decl_specs_attrs; + /* Parse a type-specifier. type-specifier: @@ -18374,8 +19169,12 @@ cp_parser_type_specifier (cp_parser* parser, /* Parse tentatively so that we can back up if we don't find a class-specifier. */ cp_parser_parse_tentatively (parser); + if (decl_specs->attributes) + vec_safe_push (cp_parser_decl_specs_attrs, decl_specs->attributes); /* Look for the class-specifier. */ type_spec = cp_parser_class_specifier (parser); + if (decl_specs->attributes) + cp_parser_decl_specs_attrs->pop (); invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, type_spec); /* If that worked, we're done. */ if (cp_parser_parse_definitely (parser)) @@ -18569,9 +19368,8 @@ cp_parser_simple_type_specifier (cp_parser* parser, decl_specs->int_n_idx = idx; /* Check if the alternate "__intN__" form has been used instead of "__intN". */ - if (strncmp (IDENTIFIER_POINTER (token->u.value) - + (IDENTIFIER_LENGTH (token->u.value) - 2), - "__", 2) == 0) + if (startswith (IDENTIFIER_POINTER (token->u.value) + + (IDENTIFIER_LENGTH (token->u.value) - 2), "__")) decl_specs->int_n_alt = true; } type = int_n_trees [idx].signed_type; @@ -19666,11 +20464,18 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, && ! processing_explicit_instantiation) warning (OPT_Wattributes, "attributes ignored on template instantiation"); + else if (is_friend && cxx11_attribute_p (attributes)) + { + if (warning (OPT_Wattributes, "attribute ignored")) + inform (input_location, "an attribute that appertains to a friend " + "declaration that is not a definition is ignored"); + } else if (is_declaration && cp_parser_declares_only_class_p (parser)) cplus_decl_attributes (&type, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); else warning (OPT_Wattributes, - "attributes ignored on elaborated-type-specifier that is not a forward declaration"); + "attributes ignored on elaborated-type-specifier that is " + "not a forward declaration"); } if (tag_type == enum_type) @@ -19850,6 +20655,10 @@ cp_parser_enum_specifier (cp_parser* parser) /* Consume the `:'. */ cp_lexer_consume_token (parser->lexer); + auto tdf + = make_temp_override (parser->type_definition_forbidden_message, + G_("types may not be defined in enum-base")); + /* Parse the type-specifier-seq. */ cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE, /*is_declaration=*/false, @@ -20299,10 +21108,11 @@ cp_parser_namespace_definition (cp_parser* parser) RID_INLINE); if (nested_inline_p && nested_definition_count != 0) { - if (cxx_dialect < cxx20) + if (pedantic && cxx_dialect < cxx20) pedwarn (cp_lexer_peek_token (parser->lexer)->location, - OPT_Wpedantic, "nested inline namespace definitions only " - "available with %<-std=c++20%> or %<-std=gnu++20%>"); + OPT_Wc__20_extensions, "nested inline namespace " + "definitions only available with %<-std=c++20%> or " + "%<-std=gnu++20%>"); cp_lexer_consume_token (parser->lexer); } @@ -20329,8 +21139,8 @@ cp_parser_namespace_definition (cp_parser* parser) break; } - if (!nested_definition_count && cxx_dialect < cxx17) - pedwarn (input_location, OPT_Wpedantic, + if (!nested_definition_count && pedantic && cxx_dialect < cxx17) + pedwarn (input_location, OPT_Wc__17_extensions, "nested namespace definitions only available with " "%<-std=c++17%> or %<-std=gnu++17%>"); @@ -20589,7 +21399,7 @@ cp_parser_using_declaration (cp_parser* parser, { cp_token *ell = cp_lexer_consume_token (parser->lexer); if (cxx_dialect < cxx17) - pedwarn (ell->location, 0, + pedwarn (ell->location, OPT_Wc__17_extensions, "pack expansion in using-declaration only available " "with %<-std=c++17%> or %<-std=gnu++17%>"); qscope = make_pack_expansion (qscope); @@ -20622,7 +21432,7 @@ cp_parser_using_declaration (cp_parser* parser, { cp_token *comma = cp_lexer_consume_token (parser->lexer); if (cxx_dialect < cxx17) - pedwarn (comma->location, 0, + pedwarn (comma->location, OPT_Wc__17_extensions, "comma-separated list in using-declaration only available " "with %<-std=c++17%> or %<-std=gnu++17%>"); goto again; @@ -20850,14 +21660,21 @@ cp_parser_alias_declaration (cp_parser* parser) /* Parse a using-directive. using-directive: - using namespace :: [opt] nested-name-specifier [opt] - namespace-name ; */ + attribute-specifier-seq [opt] using namespace :: [opt] + nested-name-specifier [opt] namespace-name ; */ static void cp_parser_using_directive (cp_parser* parser) { tree namespace_decl; - tree attribs; + tree attribs = cp_parser_std_attribute_spec_seq (parser); + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + /* Error during attribute parsing that resulted in skipping + to next semicolon. */ + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + return; + } /* Look for the `using' keyword. */ cp_parser_require_keyword (parser, RID_USING, RT_USING); @@ -20874,8 +21691,9 @@ cp_parser_using_directive (cp_parser* parser) /* Get the namespace being used. */ namespace_decl = cp_parser_namespace_name (parser); cp_warn_deprecated_use_scopes (namespace_decl); - /* And any specified attributes. */ - attribs = cp_parser_attributes_opt (parser); + /* And any specified GNU attributes. */ + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + attribs = chainon (attribs, cp_parser_gnu_attributes_opt (parser)); /* Update the symbol table. */ finish_using_directive (namespace_decl, attribs); @@ -20938,9 +21756,10 @@ cp_parser_asm_definition (cp_parser* parser) functions. */ if (parser->in_function_body && DECL_DECLARED_CONSTEXPR_P (current_function_decl) - && (cxx_dialect < cxx20)) - pedwarn (asm_loc, 0, "%<asm%> in %<constexpr%> function only available " - "with %<-std=c++20%> or %<-std=gnu++20%>"); + && cxx_dialect < cxx20) + pedwarn (asm_loc, OPT_Wc__20_extensions, "%<asm%> in %<constexpr%> " + "function only available with %<-std=c++20%> or " + "%<-std=gnu++20%>"); /* Handle the asm-qualifier-list. */ location_t volatile_loc = UNKNOWN_LOCATION; @@ -21321,6 +22140,37 @@ warn_about_ambiguous_parse (const cp_decl_specifier_seq *decl_specifiers, } } +/* If DECLARATOR with DECL_SPECS is a function declarator that has + the form of a deduction guide, tag it as such. CTOR_DTOR_OR_CONV_P + has the same meaning as in cp_parser_declarator. */ + +static void +cp_parser_maybe_adjust_declarator_for_dguide (cp_parser *parser, + cp_decl_specifier_seq *decl_specs, + cp_declarator *declarator, + int *ctor_dtor_or_conv_p) +{ + if (cxx_dialect >= cxx17 + && *ctor_dtor_or_conv_p <= 0 + && !decl_specs->type + && !decl_specs->any_type_specifiers_p + && function_declarator_p (declarator)) + { + cp_declarator *id = get_id_declarator (declarator); + tree name = id->u.id.unqualified_name; + parser->scope = id->u.id.qualifying_scope; + tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc); + if (tmpl + && (DECL_CLASS_TEMPLATE_P (tmpl) + || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) + { + id->u.id.unqualified_name = dguide_name (tmpl); + id->u.id.sfk = sfk_deduction_guide; + *ctor_dtor_or_conv_p = 1; + } + } +} + /* Declarators [gram.dcl.decl] */ /* Parse an init-declarator. @@ -21410,6 +22260,7 @@ cp_parser_init_declarator (cp_parser* parser, bool is_non_constant_init; int ctor_dtor_or_conv_p; bool friend_p = cp_parser_friend_p (decl_specifiers); + bool static_p = decl_specifiers->storage_class == sc_static; tree pushed_scope = NULL_TREE; bool range_for_decl_p = false; bool saved_default_arg_ok_p = parser->default_arg_ok_p; @@ -21418,10 +22269,6 @@ cp_parser_init_declarator (cp_parser* parser, if (decl_spec_seq_has_spec_p (decl_specifiers, ds_consteval)) flags |= CP_PARSER_FLAGS_CONSTEVAL; - /* Gather the attributes that were provided with the - decl-specifiers. */ - prefix_attributes = decl_specifiers->attributes; - /* Assume that this is not the declarator for a function definition. */ if (function_definition_p) @@ -21443,7 +22290,7 @@ cp_parser_init_declarator (cp_parser* parser, = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, flags, &ctor_dtor_or_conv_p, /*parenthesized_p=*/NULL, - member_p, friend_p, /*static_p=*/false); + member_p, friend_p, static_p); /* Gather up the deferred checks. */ stop_deferring_access_checks (); @@ -21485,6 +22332,10 @@ cp_parser_init_declarator (cp_parser* parser, else asm_specification = NULL_TREE; + /* Gather the attributes that were provided with the + decl-specifiers. */ + prefix_attributes = decl_specifiers->attributes; + /* Look for attributes. */ attributes_start_token = cp_lexer_peek_token (parser->lexer); attributes = cp_parser_attributes_opt (parser); @@ -21496,25 +22347,13 @@ cp_parser_init_declarator (cp_parser* parser, if (function_declarator_p (declarator)) { - /* Handle C++17 deduction guides. */ - if (!decl_specifiers->type - && !decl_specifiers->any_type_specifiers_p - && ctor_dtor_or_conv_p <= 0 - && cxx_dialect >= cxx17) - { - cp_declarator *id = get_id_declarator (declarator); - tree name = id->u.id.unqualified_name; - parser->scope = id->u.id.qualifying_scope; - tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc); - if (tmpl - && (DECL_CLASS_TEMPLATE_P (tmpl) - || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) - { - id->u.id.unqualified_name = dguide_name (tmpl); - id->u.id.sfk = sfk_deduction_guide; - ctor_dtor_or_conv_p = 1; - } - } + /* Handle C++17 deduction guides. Note that class-scope + non-template deduction guides are instead handled in + cp_parser_member_declaration. */ + cp_parser_maybe_adjust_declarator_for_dguide (parser, + decl_specifiers, + declarator, + &ctor_dtor_or_conv_p); if (!member_p && !cp_parser_error_occurred (parser)) warn_about_ambiguous_parse (decl_specifiers, declarator); @@ -21920,12 +22759,10 @@ cp_parser_declarator (cp_parser* parser, cp_parser_parse_tentatively (parser); /* Parse the dependent declarator. */ - declarator = cp_parser_declarator (parser, dcl_kind, - CP_PARSER_FLAGS_NONE, + declarator = cp_parser_declarator (parser, dcl_kind, flags, /*ctor_dtor_or_conv_p=*/NULL, /*parenthesized_p=*/NULL, - /*member_p=*/false, - friend_p, /*static_p=*/false); + member_p, friend_p, static_p); /* If we are parsing an abstract-declarator, we must handle the case where the dependent declarator is absent. */ @@ -22119,7 +22956,7 @@ cp_parser_direct_declarator (cp_parser* parser, tree save_ccp = current_class_ptr; tree save_ccr = current_class_ref; - if (memfn) + if (memfn && !friend_p && !static_p) /* DR 1207: 'this' is in scope after the cv-quals. */ inject_this_parameter (current_class_type, cv_quals); @@ -22135,13 +22972,27 @@ cp_parser_direct_declarator (cp_parser* parser, attrs = cp_parser_std_attribute_spec_seq (parser); + cp_omp_declare_simd_data odsd; + if ((flag_openmp || flag_openmp_simd) + && declarator + && declarator->std_attributes + && declarator->kind == cdk_id) + { + tree *pa = &declarator->std_attributes; + cp_parser_handle_directive_omp_attributes (parser, pa, + &odsd, false); + } + /* In here, we handle cases where attribute is used after the function declaration. For example: void func (int x) __attribute__((vector(..))); */ tree gnu_attrs = NULL_TREE; tree requires_clause = NULL_TREE; - late_return = (cp_parser_late_return_type_opt - (parser, declarator, requires_clause)); + late_return + = cp_parser_late_return_type_opt (parser, declarator, + requires_clause); + + cp_finalize_omp_declare_simd (parser, &odsd); /* Parse the virt-specifier-seq. */ virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); @@ -22857,7 +23708,7 @@ cp_parser_tx_qualifier_opt (cp_parser *parser) tree name = token->u.value; const char *p = IDENTIFIER_POINTER (name); const int len = strlen ("transaction_safe"); - if (!strncmp (p, "transaction_safe", len)) + if (startswith (p, "transaction_safe")) { p += len; if (*p == '\0' @@ -23173,10 +24024,13 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags, location_t loc = type_specifier_seq.locations[ds_type_spec]; if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) { - error_at (loc, "missing template arguments after %qT", - auto_node); - inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", - tmpl); + if (!cp_parser_simulate_error (parser)) + { + error_at (loc, "missing template arguments after %qT", + auto_node); + inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", + tmpl); + } } else if (parser->in_template_argument_list_p) error_at (loc, "%qT not permitted in template argument", @@ -23507,11 +24361,11 @@ cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags) /*template_parm_p=*/false, &parenthesized_p); - /* We don't know yet if the enclosing context is deprecated, so wait - and warn in grokparms if appropriate. */ - deprecated_state = DEPRECATED_SUPPRESS; + /* We don't know yet if the enclosing context is unavailable or deprecated, + so wait and deal with it in grokparms if appropriate. */ + deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS; - if (parameter) + if (parameter && !cp_parser_error_occurred (parser)) { decl = grokdeclarator (parameter->declarator, ¶meter->decl_specifiers, @@ -23726,7 +24580,7 @@ cp_parser_parameter_declaration (cp_parser *parser, parser->default_arg_ok_p = false; /* After seeing a decl-specifier-seq, if the next token is not a - "(", there is no possibility that the code is a valid + "(" or "{", there is no possibility that the code is a valid expression. Therefore, if parsing tentatively, we commit at this point. */ if (!parser->in_template_argument_list_p @@ -23739,9 +24593,18 @@ cp_parser_parameter_declaration (cp_parser *parser, of some object of type "char" to "int". */ && !parser->in_type_id_in_expr_p && cp_parser_uncommitted_to_tentative_parse_p (parser) - && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE) && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)) - cp_parser_commit_to_tentative_parse (parser); + { + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + if (decl_specifiers.type + && template_placeholder_p (decl_specifiers.type)) + /* This is a CTAD expression, not a parameter declaration. */ + cp_parser_simulate_error (parser); + } + else + cp_parser_commit_to_tentative_parse (parser); + } /* Parse the declarator. */ declarator_token_start = token; declarator = cp_parser_declarator (parser, @@ -23941,6 +24804,10 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p) set correctly. */ saved_greater_than_is_operator_p = parser->greater_than_is_operator_p; parser->greater_than_is_operator_p = !template_parm_p; + auto odsd = make_temp_override (parser->omp_declare_simd, NULL); + auto ord = make_temp_override (parser->oacc_routine, NULL); + auto oafp = make_temp_override (parser->omp_attrs_forbidden_p, false); + /* Local variable names (and the `this' keyword) may not appear in a default argument. */ saved_local_variables_forbidden_p = parser->local_variables_forbidden_p; @@ -24008,11 +24875,11 @@ cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser, && cxx_dialect < cxx20) { if (DECL_CONSTRUCTOR_P (current_function_decl)) - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__20_extensions, "function-try-block body of %<constexpr%> constructor only " "available with %<-std=c++20%> or %<-std=gnu++20%>"); else - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__20_extensions, "function-try-block body of %<constexpr%> function only " "available with %<-std=c++20%> or %<-std=gnu++20%>"); } @@ -24139,7 +25006,7 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) { initializer = cp_parser_constant_expression (parser, - /*allow_non_constant_p=*/true, + /*allow_non_constant_p=*/2, non_constant_p); } else @@ -24335,8 +25202,8 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p, || (cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_OPEN_BRACE))) { - if (cxx_dialect < cxx20) - pedwarn (loc, OPT_Wpedantic, + if (pedantic && cxx_dialect < cxx20) + pedwarn (loc, OPT_Wc__20_extensions, "C++ designated initializers only available with " "%<-std=c++20%> or %<-std=gnu++20%>"); /* Consume the `.'. */ @@ -24555,7 +25422,9 @@ cp_parser_class_name (cp_parser *parser, where we first want to look up A<T>::a in the class of the object expression, as per [basic.lookup.classref]. */ tree scope = parser->scope ? parser->scope : parser->context->object_type; - if (scope == error_mark_node) + /* This only checks parser->scope to avoid duplicate errors; if + ->object_type is erroneous, go on to give a parse error. */ + if (parser->scope == error_mark_node) return error_mark_node; /* Any name names a type if we're following the `typename' keyword @@ -24563,7 +25432,7 @@ cp_parser_class_name (cp_parser *parser, const bool typename_p = (typename_keyword_p && parser->scope && TYPE_P (parser->scope) - && dependent_type_p (parser->scope)); + && dependent_scope_p (parser->scope)); /* Handle the common case (an identifier, but not a template-id) efficiently. */ if (token->type == CPP_NAME @@ -24635,9 +25504,7 @@ cp_parser_class_name (cp_parser *parser, decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p); /* If this is a typename, create a TYPENAME_TYPE. */ - if (typename_p - && decl != error_mark_node - && !is_overloaded_fn (decl)) + if (typename_p && decl != error_mark_node) { decl = make_typename_type (scope, decl, typename_type, /*complain=*/tf_error); @@ -24707,7 +25574,6 @@ inject_parm_decls (tree decl) if (args && is_this_parameter (args)) { gcc_checking_assert (current_class_ptr == NULL_TREE); - current_class_ptr = NULL_TREE; current_class_ref = cp_build_fold_indirect_ref (args); current_class_ptr = args; } @@ -24964,7 +25830,6 @@ cp_parser_class_specifier_1 (cp_parser* parser) tree pushed_scope = NULL_TREE; unsigned ix; cp_default_arg_entry *e; - tree save_ccp, save_ccr; if (!type_definition_ok_p || any_erroneous_template_args_p (type)) { @@ -25005,31 +25870,12 @@ cp_parser_class_specifier_1 (cp_parser* parser) maybe_end_member_template_processing (); } vec_safe_truncate (unparsed_funs_with_default_args, 0); - /* Now parse any NSDMIs. */ - save_ccp = current_class_ptr; - save_ccr = current_class_ref; - FOR_EACH_VEC_SAFE_ELT (unparsed_nsdmis, ix, decl) - { - if (class_type != DECL_CONTEXT (decl)) - { - if (pushed_scope) - pop_scope (pushed_scope); - class_type = DECL_CONTEXT (decl); - pushed_scope = push_scope (class_type); - } - inject_this_parameter (class_type, TYPE_UNQUALIFIED); - cp_parser_late_parsing_nsdmi (parser, decl); - } - vec_safe_truncate (unparsed_nsdmis, 0); - current_class_ptr = save_ccp; - current_class_ref = save_ccr; - if (pushed_scope) - pop_scope (pushed_scope); /* If there are noexcept-specifiers that have not yet been processed, - take care of them now. */ - class_type = NULL_TREE; - pushed_scope = NULL_TREE; + take care of them now. Do this before processing NSDMIs as they + may depend on noexcept-specifiers already having been processed. */ + tree save_ccp = current_class_ptr; + tree save_ccr = current_class_ref; FOR_EACH_VEC_SAFE_ELT (unparsed_noexcepts, ix, decl) { tree ctx = DECL_CONTEXT (decl); @@ -25041,13 +25887,15 @@ cp_parser_class_specifier_1 (cp_parser* parser) pushed_scope = push_scope (class_type); } - tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)); - spec = TREE_PURPOSE (spec); + tree def_parse = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)); + def_parse = TREE_PURPOSE (def_parse); /* Make sure that any template parameters are in scope. */ maybe_begin_member_template_processing (decl); - /* Make sure that any member-function parameters are in scope. */ + /* Make sure that any member-function parameters are in scope. + This function doesn't expect ccp to be set. */ + current_class_ptr = current_class_ref = NULL_TREE; inject_parm_decls (decl); /* 'this' is not allowed in static member functions. */ @@ -25057,7 +25905,7 @@ cp_parser_class_specifier_1 (cp_parser* parser) parser->local_variables_forbidden_p |= THIS_FORBIDDEN; /* Now we can parse the noexcept-specifier. */ - spec = cp_parser_late_noexcept_specifier (parser, spec); + tree spec = cp_parser_late_noexcept_specifier (parser, def_parse); if (spec == error_mark_node) spec = NULL_TREE; @@ -25065,6 +25913,13 @@ cp_parser_class_specifier_1 (cp_parser* parser) /* Update the fn's type directly -- it might have escaped beyond this decl :( */ fixup_deferred_exception_variants (TREE_TYPE (decl), spec); + /* Update any instantiations we've already created. We must + keep the new noexcept-specifier wrapped in a DEFERRED_NOEXCEPT + so that maybe_instantiate_noexcept can tsubst the NOEXCEPT_EXPR + in the pattern. */ + for (tree i : DEFPARSE_INSTANTIATIONS (def_parse)) + DEFERRED_NOEXCEPT_PATTERN (TREE_PURPOSE (i)) + = spec ? TREE_PURPOSE (spec) : error_mark_node; /* Restore the state of local_variables_forbidden_p. */ parser->local_variables_forbidden_p = local_variables_forbidden_p; @@ -25081,6 +25936,23 @@ cp_parser_class_specifier_1 (cp_parser* parser) maybe_end_member_template_processing (); } vec_safe_truncate (unparsed_noexcepts, 0); + + /* Now parse any NSDMIs. */ + FOR_EACH_VEC_SAFE_ELT (unparsed_nsdmis, ix, decl) + { + if (class_type != DECL_CONTEXT (decl)) + { + if (pushed_scope) + pop_scope (pushed_scope); + class_type = DECL_CONTEXT (decl); + pushed_scope = push_scope (class_type); + } + inject_this_parameter (class_type, TYPE_UNQUALIFIED); + cp_parser_late_parsing_nsdmi (parser, decl); + } + vec_safe_truncate (unparsed_nsdmis, 0); + current_class_ptr = save_ccp; + current_class_ref = save_ccr; if (pushed_scope) pop_scope (pushed_scope); @@ -25575,16 +26447,14 @@ cp_parser_class_head (cp_parser* parser, is valid. */ - /* Get the list of base-classes, if there is one. */ + /* Get the list of base-classes, if there is one. Defer access checking + until the entire list has been seen, as per [class.access.general]. */ + push_deferring_access_checks (dk_deferred); if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) { - /* PR59482: enter the class scope so that base-specifiers are looked - up correctly. */ if (type) pushclass (type); bases = cp_parser_base_clause (parser); - /* PR59482: get out of the previously pushed class scope so that the - subsequent pops pop the right thing. */ if (type) popclass (); } @@ -25596,6 +26466,20 @@ cp_parser_class_head (cp_parser* parser, if (type && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) xref_basetypes (type, bases); + /* Now that all bases have been seen and attached to the class, check + accessibility of the types named in the base-clause. This must be + done relative to the class scope, so that we accept e.g. + + struct A { protected: struct B {}; }; + struct C : A::B, A {}; // OK: A::B is accessible via base A + + as per [class.access.general]. */ + if (type) + pushclass (type); + pop_to_parent_deferring_access_checks (); + if (type) + popclass (); + done: /* Leave the scope given by the nested-name-specifier. We will enter the class scope itself while processing the members. */ @@ -25661,10 +26545,11 @@ cp_parser_type_parameter_key (cp_parser* parser) if ((tag_type = cp_parser_token_is_type_parameter_key (token)) != none_type) { cp_lexer_consume_token (parser->lexer); - if (pedantic && tag_type == typename_type && cxx_dialect < cxx17) + if (pedantic && tag_type == typename_type + && cxx_dialect < cxx17) /* typename is not allowed in a template template parameter by the standard until C++17. */ - pedwarn (token->location, OPT_Wpedantic, + pedwarn (token->location, OPT_Wc__17_extensions, "ISO C++ forbids typename key in template template parameter;" " use %<-std=c++17%> or %<-std=gnu++17%>"); } @@ -25859,8 +26744,9 @@ cp_parser_member_declaration (cp_parser* parser) parser->colon_corrects_to_scope_p = false; + cp_omp_declare_simd_data odsd; if (cp_parser_using_declaration (parser, /*access_declaration=*/true)) - goto out; + goto out; /* Parse the decl-specifier-seq. */ decl_spec_token_start = cp_lexer_peek_token (parser->lexer); @@ -25869,6 +26755,12 @@ cp_parser_member_declaration (cp_parser* parser) | CP_PARSER_FLAGS_TYPENAME_OPTIONAL), &decl_specifiers, &declares_class_or_enum); + + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* Check for an invalid type-name. */ if (!decl_specifiers.any_type_specifiers_p && cp_parser_parse_and_diagnose_invalid_type_name (parser)) @@ -25928,6 +26820,19 @@ cp_parser_member_declaration (cp_parser* parser) if (type && TREE_CODE (type) == TYPE_DECL) type = TREE_TYPE (type); } + /* Warn if an attribute cannot appear here, as per + [dcl.attr.grammar]/5. But not when declares_class_or_enum: + we ignore attributes in elaborated-type-specifiers. */ + if (!declares_class_or_enum + && cxx11_attribute_p (decl_specifiers.attributes)) + { + decl_specifiers.attributes = NULL_TREE; + if (warning_at (decl_spec_token_start->location, + OPT_Wattributes, "attribute ignored")) + inform (decl_spec_token_start->location, "an attribute " + "that appertains to a friend declaration that " + "is not a definition is ignored"); + } if (!type || !TYPE_P (type)) error_at (decl_spec_token_start->location, "friend declaration does not name a class or " @@ -25975,6 +26880,10 @@ cp_parser_member_declaration (cp_parser* parser) being declared. */ prefix_attributes = decl_specifiers.attributes; decl_specifiers.attributes = NULL_TREE; + if (parser->omp_declare_simd + && (parser->omp_declare_simd->attribs[0] + == &decl_specifiers.attributes)) + parser->omp_declare_simd->attribs[0] = &prefix_attributes; /* See if these declarations will be friends. */ friend_p = cp_parser_friend_p (&decl_specifiers); @@ -26045,7 +26954,7 @@ cp_parser_member_declaration (cp_parser* parser) = cp_lexer_peek_token (parser->lexer)->location; if (cxx_dialect < cxx20 && identifier != NULL_TREE) - pedwarn (loc, 0, + pedwarn (loc, OPT_Wc__20_extensions, "default member initializers for bit-fields " "only available with %<-std=c++20%> or " "%<-std=gnu++20%>"); @@ -26131,6 +27040,12 @@ cp_parser_member_declaration (cp_parser* parser) goto out; } + /* Handle class-scope non-template C++17 deduction guides. */ + cp_parser_maybe_adjust_declarator_for_dguide (parser, + &decl_specifiers, + declarator, + &ctor_dtor_or_conv_p); + if (declares_class_or_enum & 2) cp_parser_check_for_definition_in_return_type (declarator, decl_specifiers.type, @@ -26347,8 +27262,8 @@ cp_parser_member_declaration (cp_parser* parser) || !DECL_DECLARES_FUNCTION_P (decl)) finish_member_declaration (decl); - if (TREE_CODE (decl) == FUNCTION_DECL) - cp_parser_save_default_args (parser, decl); + if (DECL_DECLARES_FUNCTION_P (decl)) + cp_parser_save_default_args (parser, STRIP_TEMPLATE (decl)); else if (TREE_CODE (decl) == FIELD_DECL && DECL_INITIAL (decl)) /* Add DECL to the queue of NSDMI to be parsed later. */ @@ -26363,6 +27278,7 @@ cp_parser_member_declaration (cp_parser* parser) cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); out: parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + cp_finalize_omp_declare_simd (parser, &odsd); } /* Parse a pure-specifier. @@ -26685,6 +27601,7 @@ cp_parser_save_noexcept (cp_parser *parser) /* Save away the noexcept-specifier; we will process it when the class is complete. */ DEFPARSE_TOKENS (expr) = cp_token_cache_new (first, last); + DEFPARSE_INSTANTIATIONS (expr) = nullptr; expr = build_tree_list (expr, NULL_TREE); return expr; } @@ -27005,7 +27922,7 @@ cp_parser_try_block (cp_parser* parser) if (parser->in_function_body && DECL_DECLARED_CONSTEXPR_P (current_function_decl) && cxx_dialect < cxx20) - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__20_extensions, "%<try%> in %<constexpr%> function only " "available with %<-std=c++20%> or %<-std=gnu++20%>"); @@ -27653,6 +28570,92 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */) return nreverse (attribute_list); } +/* Parse arguments of omp::directive attribute. + + ( directive-name ,[opt] clause-list[opt] ) + + For directive just remember the first/last tokens for subsequent + parsing. */ + +static void +cp_parser_omp_directive_args (cp_parser *parser, tree attribute) +{ + cp_token *first = cp_lexer_peek_nth_token (parser->lexer, 2); + if (first->type == CPP_CLOSE_PAREN) + { + cp_lexer_consume_token (parser->lexer); + error_at (first->location, "expected OpenMP directive name"); + cp_lexer_consume_token (parser->lexer); + TREE_VALUE (attribute) = NULL_TREE; + return; + } + for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 2; n; --n) + cp_lexer_consume_token (parser->lexer); + cp_token *last = cp_lexer_peek_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + tree arg = make_node (DEFERRED_PARSE); + DEFPARSE_TOKENS (arg) = cp_token_cache_new (first, last); + DEFPARSE_INSTANTIATIONS (arg) = nullptr; + TREE_VALUE (attribute) = tree_cons (NULL_TREE, arg, TREE_VALUE (attribute)); +} + +/* Parse arguments of omp::sequence attribute. + + ( omp::[opt] directive-attr [ , omp::[opt] directive-attr ]... ) */ + +static void +cp_parser_omp_sequence_args (cp_parser *parser, tree attribute) +{ + matching_parens parens; + parens.consume_open (parser); + do + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_NAME + && token->u.value == omp_identifier + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_SCOPE)) + { + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + token = cp_lexer_peek_token (parser->lexer); + } + bool directive = false; + const char *p; + if (token->type != CPP_NAME) + p = ""; + else + p = IDENTIFIER_POINTER (token->u.value); + if (strcmp (p, "directive") == 0) + directive = true; + else if (strcmp (p, "sequence") != 0) + { + error_at (token->location, "expected %<directive%> or %<sequence%>"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/true, + /*consume_paren=*/false); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + cp_lexer_consume_token (parser->lexer); + } + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)) + cp_parser_required_error (parser, RT_OPEN_PAREN, false, + UNKNOWN_LOCATION); + else if (directive) + cp_parser_omp_directive_args (parser, attribute); + else + cp_parser_omp_sequence_args (parser, attribute); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + cp_lexer_consume_token (parser->lexer); + } + while (1); + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, true, false, + /*consume_paren=*/true); +} + /* Parse a standard C++11 attribute. The returned representation is a TREE_LIST which TREE_PURPOSE is @@ -27784,7 +28787,18 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) /* Now parse the optional argument clause of the attribute. */ if (token->type != CPP_OPEN_PAREN) - return attribute; + { + if ((flag_openmp || flag_openmp_simd) + && attr_ns == omp_identifier + && (is_attribute_p ("directive", attr_id) + || is_attribute_p ("sequence", attr_id))) + { + error_at (token->location, "%<omp::%E%> attribute requires argument", + attr_id); + return NULL_TREE; + } + return attribute; + } { vec<tree, va_gc> *vec; @@ -27811,6 +28825,23 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) if (as == NULL) { + if ((flag_openmp || flag_openmp_simd) && attr_ns == omp_identifier) + { + if (is_attribute_p ("directive", attr_id)) + { + cp_parser_omp_directive_args (parser, attribute); + return attribute; + } + else if (is_attribute_p ("sequence", attr_id)) + { + TREE_VALUE (TREE_PURPOSE (attribute)) + = get_identifier ("directive"); + cp_parser_omp_sequence_args (parser, attribute); + TREE_VALUE (attribute) = nreverse (TREE_VALUE (attribute)); + return attribute; + } + } + /* For unknown attributes, just skip balanced tokens instead of trying to parse the arguments. */ for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1; n; --n) @@ -27964,7 +28995,7 @@ cp_parser_std_attribute_spec (cp_parser *parser) && cp_lexer_nth_token_is (parser->lexer, 3, CPP_COLON)) { if (cxx_dialect < cxx17) - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__17_extensions, "attribute using prefix only available " "with %<-std=c++17%> or %<-std=gnu++17%>"); @@ -28266,6 +29297,9 @@ cp_parser_label_declaration (cp_parser* parser) static tree cp_parser_concept_definition (cp_parser *parser) { + /* A concept definition is an unevaluated context. */ + cp_unevaluated u; + gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT)); cp_lexer_consume_token (parser->lexer); @@ -28421,7 +29455,20 @@ cp_parser_constraint_requires_parens (cp_parser *parser, bool lambda_p) case CPP_PLUS_PLUS: case CPP_MINUS_MINUS: case CPP_DOT: + /* Unenclosed postfix operator. */ + return pce_maybe_postfix; + case CPP_DEREF: + /* A primary constraint that precedes the lambda-declarator of a + lambda expression is followed by trailing return type. + + []<typename T> requires C -> void {} + + Don't try to re-parse this as a postfix expression in + C++23 and later. In C++20 ( needs to come in between but we + allow it to be omitted with pedwarn. */ + if (lambda_p) + return pce_ok; /* Unenclosed postfix operator. */ return pce_maybe_postfix; } @@ -28627,6 +29674,9 @@ cp_parser_constraint_expression (cp_parser *parser) static tree cp_parser_requires_clause_opt (cp_parser *parser, bool lambda_p) { + /* A requires clause is an unevaluated context. */ + cp_unevaluated u; + cp_token *tok = cp_lexer_peek_token (parser->lexer); if (tok->keyword != RID_REQUIRES) { @@ -28762,6 +29812,21 @@ cp_parser_requirement_parameter_list (cp_parser *parser) if (!parens.require_close (parser)) return error_mark_node; + /* Modify the declared parameters by removing their context + so they don't refer to the enclosing scope and explicitly + indicating that they are constraint variables. */ + for (tree parm = parms; parm; parm = TREE_CHAIN (parm)) + { + if (parm == void_list_node || parm == explicit_void_list_node) + break; + tree decl = TREE_VALUE (parm); + if (decl != error_mark_node) + { + DECL_CONTEXT (decl) = NULL_TREE; + CONSTRAINT_VAR_P (decl) = true; + } + } + return parms; } @@ -28799,7 +29864,9 @@ cp_parser_requirement_seq (cp_parser *parser) tree req = cp_parser_requirement (parser); if (req != error_mark_node) result = tree_cons (NULL_TREE, req, result); - } while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE)); + } + while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE) + && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)); /* If there are no valid requirements, this is not a valid expression. */ if (!result) @@ -28853,6 +29920,25 @@ cp_parser_simple_requirement (cp_parser *parser) if (expr.get_location() == UNKNOWN_LOCATION) expr.set_location (start); + for (tree t = expr; ; ) + { + if (TREE_CODE (t) == TRUTH_ANDIF_EXPR + || TREE_CODE (t) == TRUTH_ORIF_EXPR) + { + t = TREE_OPERAND (t, 0); + continue; + } + if (concept_check_p (t)) + { + gcc_rich_location richloc (get_start (start)); + richloc.add_fixit_insert_before (start, "requires "); + warning_at (&richloc, OPT_Wmissing_requires, "testing " + "if a concept-id is a valid expression; add " + "%<requires%> to check satisfaction"); + } + break; + } + return finish_simple_requirement (expr.get_location (), expr); } @@ -29289,6 +30375,19 @@ cp_parser_lookup_name (cp_parser *parser, tree name, if (!decl || decl == error_mark_node) return error_mark_node; + /* If we have resolved the name of a member declaration, check to + see if the declaration is accessible. When the name resolves to + set of overloaded functions, accessibility is checked when + overload resolution is done. If we have a TREE_LIST, then the lookup + is either ambiguous or it found multiple injected-class-names, the + accessibility of which is trivially satisfied. + + During an explicit instantiation, access is not checked at all, + as per [temp.explicit]. */ + if (DECL_P (decl)) + check_accessibility_of_qualified_id (decl, object_type, parser->scope, + tf_warning_or_error); + /* Pull out the template from an injected-class-name (or multiple). */ if (is_template) decl = maybe_get_template_decl_from_type_decl (decl); @@ -29315,17 +30414,6 @@ cp_parser_lookup_name (cp_parser *parser, tree name, || TREE_CODE (decl) == UNBOUND_CLASS_TEMPLATE || BASELINK_P (decl)); - /* If we have resolved the name of a member declaration, check to - see if the declaration is accessible. When the name resolves to - set of overloaded functions, accessibility is checked when - overload resolution is done. - - During an explicit instantiation, access is not checked at all, - as per [temp.explicit]. */ - if (DECL_P (decl)) - check_accessibility_of_qualified_id (decl, object_type, parser->scope, - tf_warning_or_error); - maybe_record_typedef_use (decl); return cp_expr (decl, name_location); @@ -30335,6 +31423,13 @@ cp_parser_single_declaration (cp_parser* parser, | CP_PARSER_FLAGS_TYPENAME_OPTIONAL), &decl_specifiers, &declares_class_or_enum); + + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + if (friend_p) *friend_p = cp_parser_friend_p (&decl_specifiers); @@ -30463,6 +31558,8 @@ cp_parser_single_declaration (cp_parser* parser, parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; + cp_finalize_omp_declare_simd (parser, &odsd); + return decl; } @@ -30822,10 +31919,6 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function) start_preparsed_function (member_function, NULL_TREE, SF_PRE_PARSED | SF_INCLASS_INLINE); - /* Don't do access checking if it is a templated function. */ - if (processing_template_decl) - push_deferring_access_checks (dk_no_check); - /* #pragma omp declare reduction needs special parsing. */ if (DECL_OMP_DECLARE_REDUCTION_P (member_function)) { @@ -30839,9 +31932,6 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function) cp_parser_function_definition_after_declarator (parser, /*inline_p=*/true); - if (processing_template_decl) - pop_deferring_access_checks (); - /* Leave the scope of the containing function. */ if (function_scope) pop_function_context (); @@ -32962,6 +34052,7 @@ cp_parser_objc_message_expression (cp_parser* parser) { tree receiver, messageargs; + parser->objective_c_message_context_p = true; location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '['. */ receiver = cp_parser_objc_message_receiver (parser); @@ -32978,6 +34069,7 @@ cp_parser_objc_message_expression (cp_parser* parser) location_t combined_loc = make_location (start_loc, start_loc, end_loc); protected_set_expr_location (result, combined_loc); + parser->objective_c_message_context_p = false; return result; } @@ -34608,7 +35700,7 @@ cp_parser_objc_at_property_declaration (cp_parser *parser) /* Parse the optional attribute list. A list of parsed, but not verified, attributes. */ - vec<property_attribute_info *> prop_attr_list = vNULL; + auto_delete_vec<property_attribute_info> prop_attr_list; location_t loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '@property'. */ @@ -34784,10 +35876,6 @@ cp_parser_objc_at_property_declaration (cp_parser *parser) } cp_parser_consume_semicolon_at_end_of_statement (parser); - - while (!prop_attr_list.is_empty()) - delete prop_attr_list.pop (); - prop_attr_list.release (); } /* Parse an Objective-C++ @synthesize declaration. The syntax is: @@ -34921,7 +36009,9 @@ cp_parser_omp_clause_name (cp_parser *parser) switch (p[0]) { case 'a': - if (!strcmp ("aligned", p)) + if (!strcmp ("affinity", p)) + result = PRAGMA_OMP_CLAUSE_AFFINITY; + else if (!strcmp ("aligned", p)) result = PRAGMA_OMP_CLAUSE_ALIGNED; else if (!strcmp ("allocate", p)) result = PRAGMA_OMP_CLAUSE_ALLOCATE; @@ -34967,7 +36057,9 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; case 'f': - if (!strcmp ("final", p)) + if (!strcmp ("filter", p)) + result = PRAGMA_OMP_CLAUSE_FILTER; + else if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("finalize", p)) result = PRAGMA_OACC_CLAUSE_FINALIZE; @@ -35019,6 +36111,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OACC_CLAUSE_NO_CREATE; else if (!strcmp ("nogroup", p)) result = PRAGMA_OMP_CLAUSE_NOGROUP; + else if (!strcmp ("nohost", p)) + result = PRAGMA_OACC_CLAUSE_NOHOST; else if (!strcmp ("nontemporal", p)) result = PRAGMA_OMP_CLAUSE_NONTEMPORAL; else if (!strcmp ("notinbranch", p)) @@ -35180,11 +36274,10 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, { tree name, decl; - if (kind == OMP_CLAUSE_DEPEND) + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) cp_parser_parse_tentatively (parser); token = cp_lexer_peek_token (parser->lexer); if (kind != 0 - && current_class_ptr && cp_parser_is_keyword (token, RID_THIS)) { decl = finish_this_expr (); @@ -35210,7 +36303,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, /*optional_p=*/false); if (name == error_mark_node) { - if (kind == OMP_CLAUSE_DEPEND + if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && cp_parser_simulate_error (parser)) goto depend_lvalue; goto skip_comma; @@ -35222,7 +36315,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, decl = name; if (decl == error_mark_node) { - if (kind == OMP_CLAUSE_DEPEND + if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && cp_parser_simulate_error (parser)) goto depend_lvalue; cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, @@ -35268,6 +36361,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, &idk, loc); } /* FALLTHROUGH. */ + case OMP_CLAUSE_AFFINITY: case OMP_CLAUSE_DEPEND: case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_IN_REDUCTION: @@ -35294,12 +36388,12 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, /* Look for `:'. */ if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) { - if (kind == OMP_CLAUSE_DEPEND + if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && cp_parser_simulate_error (parser)) goto depend_lvalue; goto skip_comma; } - if (kind == OMP_CLAUSE_DEPEND) + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) cp_parser_commit_to_tentative_parse (parser); if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) @@ -35313,7 +36407,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)) { - if (kind == OMP_CLAUSE_DEPEND + if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && cp_parser_simulate_error (parser)) goto depend_lvalue; goto skip_comma; @@ -35326,7 +36420,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, break; } - if (kind == OMP_CLAUSE_DEPEND) + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) { if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA) && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN) @@ -36171,7 +37265,10 @@ cp_parser_omp_clause_num_threads (cp_parser *parser, tree list, } /* OpenMP 4.5: - num_tasks ( expression ) */ + num_tasks ( expression ) + + OpenMP 5.1: + num_tasks ( strict : expression ) */ static tree cp_parser_omp_clause_num_tasks (cp_parser *parser, tree list, @@ -36183,6 +37280,19 @@ cp_parser_omp_clause_num_tasks (cp_parser *parser, tree list, if (!parens.require_open (parser)) return list; + bool strict = false; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + if (!strcmp (IDENTIFIER_POINTER (id), "strict")) + { + strict = true; + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } + } + t = cp_parser_assignment_expression (parser); if (t == error_mark_node @@ -36196,13 +37306,17 @@ cp_parser_omp_clause_num_tasks (cp_parser *parser, tree list, c = build_omp_clause (location, OMP_CLAUSE_NUM_TASKS); OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; + OMP_CLAUSE_NUM_TASKS_STRICT (c) = strict; OMP_CLAUSE_CHAIN (c) = list; return c; } /* OpenMP 4.5: - grainsize ( expression ) */ + grainsize ( expression ) + + OpenMP 5.1: + grainsize ( strict : expression ) */ static tree cp_parser_omp_clause_grainsize (cp_parser *parser, tree list, @@ -36214,6 +37328,19 @@ cp_parser_omp_clause_grainsize (cp_parser *parser, tree list, if (!parens.require_open (parser)) return list; + bool strict = false; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + if (!strcmp (IDENTIFIER_POINTER (id), "strict")) + { + strict = true; + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } + } + t = cp_parser_assignment_expression (parser); if (t == error_mark_node @@ -36227,6 +37354,7 @@ cp_parser_omp_clause_grainsize (cp_parser *parser, tree list, c = build_omp_clause (location, OMP_CLAUSE_GRAINSIZE); OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; + OMP_CLAUSE_GRAINSIZE_STRICT (c) = strict; OMP_CLAUSE_CHAIN (c) = list; return c; @@ -36301,6 +37429,34 @@ cp_parser_omp_clause_hint (cp_parser *parser, tree list, location_t location) return c; } +/* OpenMP 5.1: + filter ( integer-expression ) */ + +static tree +cp_parser_omp_clause_filter (cp_parser *parser, tree list, location_t location) +{ + tree t, c; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + t = cp_parser_assignment_expression (parser); + + if (t == 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_FILTER, "filter", location); + + c = build_omp_clause (location, OMP_CLAUSE_FILTER); + OMP_CLAUSE_FILTER_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + /* OpenMP 4.5: defaultmap ( tofrom : scalar ) @@ -37391,13 +38547,14 @@ cp_parser_omp_clause_depend_sink (cp_parser *parser, location_t clause_loc, OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1; } - if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA) + || !cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) break; cp_lexer_consume_token (parser->lexer); } - if (cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN) && vec) + if (vec) { tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK; @@ -37409,6 +38566,52 @@ cp_parser_omp_clause_depend_sink (cp_parser *parser, location_t clause_loc, } /* OpenMP 5.0: + detach ( event-handle ) */ + +static tree +cp_parser_omp_clause_detach (cp_parser *parser, tree list) +{ + matching_parens parens; + + if (!parens.require_open (parser)) + return list; + + cp_token *token; + tree name, decl; + + token = cp_lexer_peek_token (parser->lexer); + name = cp_parser_id_expression (parser, /*template_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + if (name == error_mark_node) + decl = error_mark_node; + else + { + if (identifier_p (name)) + decl = cp_parser_lookup_name_simple (parser, name, token->location); + else + decl = name; + if (decl == error_mark_node) + cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, + token->location); + } + + if (decl == error_mark_node + || !parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + tree u = build_omp_clause (token->location, OMP_CLAUSE_DETACH); + OMP_CLAUSE_DECL (u) = decl; + OMP_CLAUSE_CHAIN (u) = list; + + return u; +} + +/* OpenMP 5.0: iterators ( iterators-definition ) iterators-definition: @@ -37520,6 +38723,64 @@ cp_parser_omp_iterators (cp_parser *parser) return ret ? ret : error_mark_node; } +/* OpenMP 5.0: + affinity ( [aff-modifier :] variable-list ) + aff-modifier: + iterator ( iterators-definition ) */ + +static tree +cp_parser_omp_clause_affinity (cp_parser *parser, tree list) +{ + tree nlist, c, iterators = NULL_TREE; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + bool parse_iter = ((strcmp ("iterator", p) == 0) + && (cp_lexer_nth_token_is (parser->lexer, 2, + CPP_OPEN_PAREN))); + if (parse_iter) + { + size_t n = cp_parser_skip_balanced_tokens (parser, 2); + parse_iter = cp_lexer_nth_token_is (parser->lexer, n, CPP_COLON); + } + if (parse_iter) + { + begin_scope (sk_omp, NULL); + iterators = cp_parser_omp_iterators (parser); + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + { + if (iterators) + poplevel (0, 1, 0); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + } + } + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_AFFINITY, + list, NULL); + if (iterators) + { + tree block = poplevel (1, 1, 0); + if (iterators != error_mark_node) + { + TREE_VEC_ELT (iterators, 5) = block; + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_DECL (c) = build_tree_list (iterators, + OMP_CLAUSE_DECL (c)); + } + } + return nlist; +} + /* OpenMP 4.0: depend ( depend-kind : variable-list ) @@ -37613,7 +38874,13 @@ cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc) goto resync_fail; if (kind == OMP_CLAUSE_DEPEND_SINK) - nlist = cp_parser_omp_clause_depend_sink (parser, loc, list); + { + nlist = cp_parser_omp_clause_depend_sink (parser, loc, list); + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + } else { nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_DEPEND, @@ -37660,40 +38927,90 @@ cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc) map-kind: alloc | to | from | tofrom | release | delete - map ( always [,] map-kind: variable-list ) */ + map ( always [,] map-kind: variable-list ) + + OpenMP 5.0: + map ( [map-type-modifier[,] ...] map-kind: variable-list ) + + map-type-modifier: + always | close */ static tree cp_parser_omp_clause_map (cp_parser *parser, tree list) { tree nlist, c; enum gomp_map_kind kind = GOMP_MAP_TOFROM; - bool always = false; if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + 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) { - tree id = cp_lexer_peek_token (parser->lexer)->u.value; - const char *p = IDENTIFIER_POINTER (id); + if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COLON) + { + map_kind_pos = pos; + break; + } + if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA) + pos++; + pos++; + } + + bool always_modifier = false; + bool close_modifier = false; + for (int pos = 1; pos < map_kind_pos; ++pos) + { + cp_token *tok = cp_lexer_peek_token (parser->lexer); + if (tok->type == CPP_COMMA) + { + cp_lexer_consume_token (parser->lexer); + continue; + } + + const char *p = IDENTIFIER_POINTER (tok->u.value); if (strcmp ("always", p) == 0) { - int nth = 2; - if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COMMA) - nth++; - if ((cp_lexer_peek_nth_token (parser->lexer, nth)->type == CPP_NAME - || (cp_lexer_peek_nth_token (parser->lexer, nth)->keyword - == RID_DELETE)) - && (cp_lexer_peek_nth_token (parser->lexer, nth + 1)->type - == CPP_COLON)) + if (always_modifier) { - always = true; - cp_lexer_consume_token (parser->lexer); - if (nth == 3) - cp_lexer_consume_token (parser->lexer); + cp_parser_error (parser, "too many %<always%> modifiers"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + always_modifier = true; + } + else if (strcmp ("close", p) == 0) + { + if (close_modifier) + { + cp_parser_error (parser, "too many %<close%> modifiers"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; } + close_modifier = true; } + else + { + cp_parser_error (parser, "%<#pragma omp target%> with " + "modifier other than %<always%> or %<close%>" + "on %<map%> clause"); + 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) @@ -37705,11 +39022,11 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) if (strcmp ("alloc", p) == 0) kind = GOMP_MAP_ALLOC; else if (strcmp ("to", p) == 0) - kind = always ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO; + kind = always_modifier ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO; else if (strcmp ("from", p) == 0) - kind = always ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM; + kind = always_modifier ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM; else if (strcmp ("tofrom", p) == 0) - kind = always ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM; + kind = always_modifier ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM; else if (strcmp ("release", p) == 0) kind = GOMP_MAP_RELEASE; else @@ -37741,18 +39058,57 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) } /* OpenMP 4.0: - device ( expression ) */ + device ( expression ) + + OpenMP 5.0: + device ( [device-modifier :] integer-expression ) + + device-modifier: + ancestor | device_num */ static tree cp_parser_omp_clause_device (cp_parser *parser, tree list, location_t location) { tree t, c; + bool ancestor = false; matching_parens parens; if (!parens.require_open (parser)) return list; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + cp_token *tok = cp_lexer_peek_token (parser->lexer); + const char *p = IDENTIFIER_POINTER (tok->u.value); + if (strcmp ("ancestor", p) == 0) + { + ancestor = true; + + /* A requires directive with the reverse_offload clause must be + specified. */ + if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0) + { + error_at (tok->location, "%<ancestor%> device modifier not " + "preceded by %<requires%> directive " + "with %<reverse_offload%> clause"); + cp_parser_skip_to_closing_parenthesis (parser, true, false, true); + return list; + } + } + else if (strcmp ("device_num", p) == 0) + ; + else + { + error_at (tok->location, "expected %<ancestor%> or %<device_num%>"); + cp_parser_skip_to_closing_parenthesis (parser, true, false, true); + return list; + } + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } + t = cp_parser_assignment_expression (parser); if (t == error_mark_node @@ -37767,6 +39123,7 @@ cp_parser_omp_clause_device (cp_parser *parser, tree list, c = build_omp_clause (location, OMP_CLAUSE_DEVICE); OMP_CLAUSE_DEVICE_ID (c) = t; OMP_CLAUSE_CHAIN (c) = list; + OMP_CLAUSE_DEVICE_ANCESTOR (c) = ancestor; return c; } @@ -37827,7 +39184,8 @@ cp_parser_omp_clause_dist_schedule (cp_parser *parser, tree list, proc_bind ( proc-bind-kind ) proc-bind-kind: - master | close | spread */ + primary | master | close | spread + where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ static tree cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, @@ -37844,7 +39202,9 @@ cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (strcmp ("master", p) == 0) + if (strcmp ("primary", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_PRIMARY; + else if (strcmp ("master", p) == 0) kind = OMP_CLAUSE_PROC_BIND_MASTER; else if (strcmp ("close", p) == 0) kind = OMP_CLAUSE_PROC_BIND_CLOSE; @@ -37942,7 +39302,7 @@ cp_parser_oacc_clause_async (cp_parser *parser, tree list) matching_parens parens; parens.consume_open (parser); - t = cp_parser_expression (parser); + t = cp_parser_assignment_expression (parser); if (t == error_mark_node || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, @@ -38088,6 +39448,11 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); c_name = "no_create"; break; + case PRAGMA_OACC_CLAUSE_NOHOST: + clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_NOHOST, + clauses); + c_name = "nohost"; + break; case PRAGMA_OACC_CLAUSE_NUM_GANGS: code = OMP_CLAUSE_NUM_GANGS; c_name = "num_gangs"; @@ -38204,7 +39569,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, if (nested && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) break; - if (!first) + if (!first + /* OpenMP 5.1 allows optional comma in between directive-name and + clauses everywhere, but as we aren't done with OpenMP 5.0 + implementation yet, let's allow it for now only in C++11 + attributes. */ + || (parser->lexer->in_omp_attribute_pragma && nested != 2)) { if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) cp_lexer_consume_token (parser->lexer); @@ -38243,6 +39613,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, token->location, false); c_name = "default"; break; + case PRAGMA_OMP_CLAUSE_FILTER: + clauses = cp_parser_omp_clause_filter (parser, clauses, + token->location); + c_name = "filter"; + break; case PRAGMA_OMP_CLAUSE_FINAL: clauses = cp_parser_omp_clause_final (parser, clauses, token->location); c_name = "final"; @@ -38462,11 +39837,19 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, } c_name = "linear"; break; + case PRAGMA_OMP_CLAUSE_AFFINITY: + clauses = cp_parser_omp_clause_affinity (parser, clauses); + c_name = "affinity"; + break; case PRAGMA_OMP_CLAUSE_DEPEND: clauses = cp_parser_omp_clause_depend (parser, clauses, token->location); c_name = "depend"; break; + case PRAGMA_OMP_CLAUSE_DETACH: + clauses = cp_parser_omp_clause_detach (parser, clauses); + c_name = "detach"; + break; case PRAGMA_OMP_CLAUSE_MAP: clauses = cp_parser_omp_clause_map (parser, clauses); c_name = "map"; @@ -38580,11 +39963,14 @@ cp_parser_end_omp_structured_block (cp_parser *parser, unsigned save) } static tree -cp_parser_omp_structured_block (cp_parser *parser, bool *if_p) +cp_parser_omp_structured_block (cp_parser *parser, bool *if_p, + bool disallow_omp_attrs = true) { tree stmt = begin_omp_structured_block (); unsigned int save = cp_parser_begin_omp_structured_block (parser); + if (disallow_omp_attrs) + parser->omp_attrs_forbidden_p = true; cp_parser_statement (parser, NULL_TREE, false, if_p); cp_parser_end_omp_structured_block (parser, save); @@ -38601,6 +39987,12 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) location_t loc = pragma_tok->location; tree nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_ALLOCATE, NULL_TREE); + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { matching_parens parens; @@ -38692,7 +40084,10 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) { - if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if ((!first || parser->lexer->in_omp_attribute_pragma) + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) cp_lexer_consume_token (parser->lexer); first = false; @@ -38798,7 +40193,6 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) memory_order = OMP_MEMORY_ORDER_ACQUIRE; break; case NOP_EXPR: /* atomic write */ - case OMP_ATOMIC: memory_order = OMP_MEMORY_ORDER_RELEASE; break; default: @@ -38814,31 +40208,24 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) switch (code) { case OMP_ATOMIC_READ: - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL - || memory_order == OMP_MEMORY_ORDER_RELEASE) + if (memory_order == OMP_MEMORY_ORDER_RELEASE) { error_at (loc, "%<#pragma omp atomic read%> incompatible with " - "%<acq_rel%> or %<release%> clauses"); + "%<release%> clause"); memory_order = OMP_MEMORY_ORDER_SEQ_CST; } + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) + memory_order = OMP_MEMORY_ORDER_ACQUIRE; break; case NOP_EXPR: /* atomic write */ - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL - || memory_order == OMP_MEMORY_ORDER_ACQUIRE) + if (memory_order == OMP_MEMORY_ORDER_ACQUIRE) { error_at (loc, "%<#pragma omp atomic write%> incompatible with " - "%<acq_rel%> or %<acquire%> clauses"); - memory_order = OMP_MEMORY_ORDER_SEQ_CST; - } - break; - case OMP_ATOMIC: - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL - || memory_order == OMP_MEMORY_ORDER_ACQUIRE) - { - error_at (loc, "%<#pragma omp atomic update%> incompatible with " - "%<acq_rel%> or %<acquire%> clauses"); + "%<acquire%> clause"); memory_order = OMP_MEMORY_ORDER_SEQ_CST; } + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) + memory_order = OMP_MEMORY_ORDER_RELEASE; break; default: break; @@ -39254,6 +40641,10 @@ cp_parser_omp_depobj (cp_parser *parser, cp_token *pragma_tok) tree clause = NULL_TREE; enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE; location_t c_loc = cp_lexer_peek_token (parser->lexer)->location; + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && 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; @@ -39334,11 +40725,18 @@ static void cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok) { enum memmodel mo = MEMMODEL_LAST; + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + 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; const char *p = IDENTIFIER_POINTER (id); - if (!strcmp (p, "acq_rel")) + if (!strcmp (p, "seq_cst")) + mo = MEMMODEL_SEQ_CST; + else if (!strcmp (p, "acq_rel")) mo = MEMMODEL_ACQ_REL; else if (!strcmp (p, "release")) mo = MEMMODEL_RELEASE; @@ -39346,7 +40744,8 @@ cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok) mo = MEMMODEL_ACQUIRE; else error_at (cp_lexer_peek_token (parser->lexer)->location, - "expected %<acq_rel%>, %<release%> or %<acquire%>"); + "expected %<seq_cst%>, %<acq_rel%>, %<release%> or " + "%<acquire%>"); cp_lexer_consume_token (parser->lexer); } if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) @@ -39918,6 +41317,77 @@ cp_finish_omp_range_for (tree orig, tree begin) cp_finish_decomp (decl, decomp_first_name, decomp_cnt); } +/* Return true if next tokens contain a standard attribute that contains + omp::directive (DIRECTIVE). */ + +static bool +cp_parser_omp_section_scan (cp_parser *parser, const char *directive, + bool tentative) +{ + size_t n = cp_parser_skip_attributes_opt (parser, 1), i; + if (n < 10) + return false; + for (i = 5; i < n - 4; i++) + if (cp_lexer_nth_token_is (parser->lexer, i, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, i + 1, CPP_OPEN_PAREN) + && cp_lexer_nth_token_is (parser->lexer, i + 2, CPP_NAME)) + { + tree first = cp_lexer_peek_nth_token (parser->lexer, i)->u.value; + tree second = cp_lexer_peek_nth_token (parser->lexer, i + 2)->u.value; + if (strcmp (IDENTIFIER_POINTER (first), "directive")) + continue; + if (strcmp (IDENTIFIER_POINTER (second), directive) == 0) + break; + } + if (i == n - 4) + return false; + cp_parser_parse_tentatively (parser); + location_t first_loc = cp_lexer_peek_token (parser->lexer)->location; + location_t last_loc + = cp_lexer_peek_nth_token (parser->lexer, n - 1)->location; + location_t middle_loc = UNKNOWN_LOCATION; + tree std_attrs = cp_parser_std_attribute_spec_seq (parser); + int cnt = 0; + bool seen = false; + for (tree attr = std_attrs; attr; attr = TREE_CHAIN (attr)) + if (get_attribute_namespace (attr) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (attr))) + { + for (tree a = TREE_VALUE (attr); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cnt++; + if (first->type == CPP_NAME + && strcmp (IDENTIFIER_POINTER (first->u.value), + directive) == 0) + { + seen = true; + if (middle_loc == UNKNOWN_LOCATION) + middle_loc = first->location; + } + } + } + if (!seen || tentative) + { + cp_parser_abort_tentative_parse (parser); + return seen; + } + if (cnt != 1 || TREE_CHAIN (std_attrs)) + { + error_at (make_location (first_loc, last_loc, middle_loc), + "%<[[omp::directive(%s)]]%> must be the only specified " + "attribute on a statement", directive); + cp_parser_abort_tentative_parse (parser); + return false; + } + if (!cp_parser_parse_definitely (parser)) + return false; + cp_parser_handle_statement_omp_attributes (parser, std_attrs); + return true; +} + /* OpenMP 5.0: scan-loop-body: @@ -39932,10 +41402,11 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) if (!braces.require_open (parser)) return; - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE); add_stmt (substmt); + cp_parser_omp_section_scan (parser, "scan", false); cp_token *tok = cp_lexer_peek_token (parser->lexer); if (cp_parser_pragma_kind (tok) == PRAGMA_OMP_SCAN) { @@ -39943,6 +41414,10 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) cp_lexer_consume_token (parser->lexer); + if (parser->lexer->in_omp_attribute_pragma + && 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; @@ -39967,7 +41442,7 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) error ("expected %<#pragma omp scan%>"); clauses = finish_omp_clauses (clauses, C_ORT_OMP); - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build2_loc (tok->location, OMP_SCAN, void_type_node, substmt, clauses); add_stmt (substmt); @@ -40400,7 +41875,9 @@ cp_omp_split_clauses (location_t loc, enum tree_code code, c_omp_split_clauses (loc, code, mask, clauses, cclauses); for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) if (cclauses[i]) - cclauses[i] = finish_omp_clauses (cclauses[i], C_ORT_OMP); + cclauses[i] = finish_omp_clauses (cclauses[i], + i == C_OMP_CLAUSE_SPLIT_TARGET + ? C_ORT_OMP_TARGET : C_ORT_OMP); } /* OpenMP 5.0: @@ -40648,7 +42125,9 @@ cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok, tree body = finish_omp_structured_block (sb); if (ret == NULL) return ret; - return c_finish_omp_master (loc, body); + ret = c_finish_omp_master (loc, body); + OMP_MASTER_COMBINED (ret) = 1; + return ret; } } if (!flag_openmp) /* flag_openmp_simd */ @@ -40670,6 +42149,73 @@ cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok, cp_parser_omp_structured_block (parser, if_p)); } +/* OpenMP 5.1: + # pragma omp masked masked-clauses new-line + structured-block */ + +#define OMP_MASKED_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) + +static tree +cp_parser_omp_masked (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " masked"); + mask |= OMP_MASKED_CLAUSE_MASK; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "taskloop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask, + cclauses, if_p); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + ret = cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask, + cclauses, if_p); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + ret = c_finish_omp_masked (loc, body, + cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); + OMP_MASKED_COMBINED (ret) = 1; + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_MASTER, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; + } + + return c_finish_omp_masked (loc, + cp_parser_omp_structured_block (parser, if_p), + clauses); +} + /* OpenMP 2.5: # pragma omp ordered new-line structured-block @@ -40690,10 +42236,16 @@ cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context, bool *if_p) { location_t loc = pragma_tok->location; + int n = 1; - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + n = 2; + + if (cp_lexer_nth_token_is (parser->lexer, n, CPP_NAME)) { - tree id = cp_lexer_peek_token (parser->lexer)->u.value; + tree id = cp_lexer_peek_nth_token (parser->lexer, n)->u.value; const char *p = IDENTIFIER_POINTER (id); if (strcmp (p, "depend") == 0) @@ -40709,7 +42261,7 @@ cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok, "%<depend%> clause may only be used in compound " "statements"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return true; } tree clauses = cp_parser_omp_all_clauses (parser, @@ -40756,9 +42308,10 @@ cp_parser_omp_sections_scope (cp_parser *parser) stmt = push_stmt_list (); if (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer)) - != PRAGMA_OMP_SECTION) + != PRAGMA_OMP_SECTION + && !cp_parser_omp_section_scan (parser, "section", true)) { - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build1 (OMP_SECTION, void_type_node, substmt); add_stmt (substmt); } @@ -40771,6 +42324,8 @@ cp_parser_omp_sections_scope (cp_parser *parser) if (tok->type == CPP_EOF) break; + if (cp_parser_omp_section_scan (parser, "section", false)) + tok = cp_lexer_peek_token (parser->lexer); if (cp_parser_pragma_kind (tok) == PRAGMA_OMP_SECTION) { cp_lexer_consume_token (parser->lexer); @@ -40783,7 +42338,7 @@ cp_parser_omp_sections_scope (cp_parser *parser) error_suppress = true; } - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build1 (OMP_SECTION, void_type_node, substmt); add_stmt (substmt); } @@ -40914,7 +42469,37 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, { tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (cclauses == NULL && strcmp (p, "master") == 0) + if (cclauses == NULL && strcmp (p, "masked") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_masked (parser, pragma_tok, p_name, mask, + cclauses, if_p); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + tree ret = cp_parser_omp_masked (parser, pragma_tok, p_name, mask, + cclauses, if_p); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL_TREE) + return ret; + /* masked does have just filter clause, but during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel masked + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel masked taskloop simd lastprivate (x) */ + if (OMP_MASKED_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses == NULL && strcmp (p, "master") == 0) { tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; cclauses = cclauses_buf; @@ -40932,7 +42517,16 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, block); if (ret == NULL_TREE) return ret; - OMP_PARALLEL_COMBINED (stmt) = 1; + /* master doesn't have any clauses and during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel master don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel master + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel master taskloop simd lastprivate (x) */ + if (OMP_MASTER_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; return stmt; } else if (strcmp (p, "loop") == 0) @@ -40994,6 +42588,7 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, block = begin_omp_parallel (); save = cp_parser_begin_omp_structured_block (parser); + parser->omp_attrs_forbidden_p = true; cp_parser_statement (parser, NULL_TREE, false, if_p); cp_parser_end_omp_structured_block (parser, save); stmt = finish_omp_parallel (clauses, block); @@ -41026,6 +42621,30 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p) return add_stmt (stmt); } +/* OpenMP 5.1: + # pragma omp scope scope-clause[optseq] new-line + structured-block */ + +#define OMP_SCOPE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +cp_parser_omp_scope (cp_parser *parser, cp_token *pragma_tok, bool *if_p) +{ + tree stmt = make_node (OMP_SCOPE); + TREE_TYPE (stmt) = void_type_node; + SET_EXPR_LOCATION (stmt, pragma_tok->location); + + OMP_SCOPE_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, + "#pragma omp scope", pragma_tok); + OMP_SCOPE_BODY (stmt) = cp_parser_omp_structured_block (parser, if_p); + + return add_stmt (stmt); +} + /* OpenMP 3.0: # pragma omp task task-clause[optseq] new-line structured-block */ @@ -41042,7 +42661,9 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_AFFINITY)) static tree cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p) @@ -41054,6 +42675,7 @@ cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p) "#pragma omp task", pragma_tok); block = begin_omp_task (); save = cp_parser_begin_omp_structured_block (parser); + parser->omp_attrs_forbidden_p = true; cp_parser_statement (parser, NULL_TREE, false, if_p); cp_parser_end_omp_structured_block (parser, save); return finish_omp_task (clauses, block); @@ -41163,7 +42785,7 @@ cp_parser_omp_cancel (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) -static void +static bool cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -41185,7 +42807,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %<point%>"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return; + return false; } if (context != pragma_compound) @@ -41197,7 +42819,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, else cp_parser_error (parser, "expected declaration specifiers"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return; + return true; } clauses = cp_parser_omp_all_clauses (parser, @@ -41205,6 +42827,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, "#pragma omp cancellation point", pragma_tok); finish_omp_cancellation_point (clauses); + return true; } /* OpenMP 4.0: @@ -41500,7 +43123,7 @@ cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok, bool *if_p) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -41520,7 +43143,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %<data%>"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -41529,7 +43152,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target enter data"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return true; } tree clauses @@ -41569,14 +43192,15 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target enter data%> must contain at least " "one %<map%> clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_ENTER_DATA); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); - return add_stmt (stmt); + add_stmt (stmt); + return true; } /* OpenMP 4.5: @@ -41590,7 +43214,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -41610,7 +43234,7 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %<data%>"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -41619,7 +43243,7 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target exit data"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return true; } tree clauses @@ -41661,14 +43285,15 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target exit data%> must contain at least " "one %<map%> clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_EXIT_DATA); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); - return add_stmt (stmt); + add_stmt (stmt); + return true; } /* OpenMP 4.0: @@ -41692,7 +43317,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target update"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return true; } tree clauses @@ -41704,7 +43329,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target update%> must contain at least one " "%<from%> or %<to%> clauses"); - return false; + return true; } tree stmt = make_node (OMP_TARGET_UPDATE); @@ -41712,7 +43337,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); add_stmt (stmt); - return false; + return true; } /* OpenMP 4.0: @@ -41729,6 +43354,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, | (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_IN_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)) static bool @@ -41843,6 +43469,7 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, tree stmt = make_node (OMP_TARGET); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); OMP_TARGET_BODY (stmt) = body; OMP_TARGET_COMBINED (stmt) = 1; SET_EXPR_LOCATION (stmt, pragma_tok->location); @@ -41864,14 +43491,12 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, else if (strcmp (p, "enter") == 0) { cp_lexer_consume_token (parser->lexer); - cp_parser_omp_target_enter_data (parser, pragma_tok, context); - return false; + return cp_parser_omp_target_enter_data (parser, pragma_tok, context); } else if (strcmp (p, "exit") == 0) { cp_lexer_consume_token (parser->lexer); - cp_parser_omp_target_exit_data (parser, pragma_tok, context); - return false; + return cp_parser_omp_target_exit_data (parser, pragma_tok, context); } else if (strcmp (p, "update") == 0) { @@ -41890,7 +43515,18 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, OMP_TARGET_CLAUSES (stmt) = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, - "#pragma omp target", pragma_tok); + "#pragma omp target", pragma_tok, false); + for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) + { + tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + OMP_CLAUSE_DECL (nc) = OMP_CLAUSE_DECL (c); + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_ALWAYS_TOFROM); + OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = nc; + } + OMP_TARGET_CLAUSES (stmt) + = finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET); c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); pc = &OMP_TARGET_CLAUSES (stmt); @@ -42512,7 +44148,9 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, data.fndecl_seen = false; data.variant_p = variant_p; data.tokens = vNULL; - data.clauses = NULL_TREE; + data.attribs[0] = NULL; + data.attribs[1] = NULL; + data.loc = UNKNOWN_LOCATION; /* It is safe to take the address of a local variable; it will only be used while this scope is live. */ parser->omp_declare_simd = &data; @@ -43007,6 +44645,12 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, location_t finish_loc = get_finish (varid.get_location ()); location_t varid_loc = make_location (caret_loc, start_loc, finish_loc); + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + const char *clause = ""; location_t match_loc = cp_lexer_peek_token (parser->lexer)->location; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) @@ -43079,6 +44723,11 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) cp_lexer_consume_token (parser->lexer); if (strcmp (kind, "simd") == 0) { + /* For now only in C++ attributes, do it always for OpenMP 5.1. + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); */ + cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, "#pragma omp declare simd", pragma_tok); @@ -43093,11 +44742,151 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) else { gcc_assert (strcmp (kind, "variant") == 0); - attrs = cp_finish_omp_declare_variant (parser, pragma_tok, attrs); + attrs + = cp_finish_omp_declare_variant (parser, pragma_tok, attrs); } cp_parser_pop_lexer (parser); } + cp_lexer *lexer = NULL; + for (int i = 0; i < 2; i++) + { + if (data->attribs[i] == NULL) + continue; + for (tree *pa = data->attribs[i]; *pa; ) + if (get_attribute_namespace (*pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (*pa))) + { + for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int j = 0; j < 3; j++) + { + tree id = NULL_TREE; + if (first + j == last) + break; + if (first[j].type == CPP_NAME) + id = first[j].u.value; + else if (first[j].type == CPP_KEYWORD) + id = ridpointers[(int) first[j].keyword]; + else + break; + directive[j] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + { + error_at (first->location, + "unknown OpenMP directive name in " + "%<omp::directive%> attribute argument"); + continue; + } + if (dir->id != PRAGMA_OMP_DECLARE + || (strcmp (directive[1], "simd") != 0 + && strcmp (directive[1], "variant") != 0)) + { + error_at (first->location, + "OpenMP directive other than %<declare simd%> " + "or %<declare variant%> appertains to a " + "declaration"); + continue; + } + + if (parser->omp_attrs_forbidden_p) + { + error_at (first->location, + "mixing OpenMP directives with attribute and " + "pragma syntax on the same statement"); + parser->omp_attrs_forbidden_p = false; + } + + if (!flag_openmp && strcmp (directive[1], "simd") != 0) + continue; + if (lexer == NULL) + { + lexer = cp_lexer_alloc (); + lexer->debugging_p = parser->lexer->debugging_p; + } + vec_safe_reserve (lexer->buffer, (last - first) + 2); + cp_token tok = {}; + tok.type = CPP_PRAGMA; + tok.keyword = RID_MAX; + tok.u.value = build_int_cst (NULL, PRAGMA_OMP_DECLARE); + tok.location = first->location; + lexer->buffer->quick_push (tok); + while (++first < last) + lexer->buffer->quick_push (*first); + tok = {}; + tok.type = CPP_PRAGMA_EOL; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + tok = {}; + tok.type = CPP_EOF; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + lexer->next = parser->lexer; + lexer->next_token = lexer->buffer->address (); + lexer->last_token = lexer->next_token + + lexer->buffer->length () + - 1; + lexer->in_omp_attribute_pragma = true; + parser->lexer = lexer; + /* Move the current source position to that of the first token + in the new lexer. */ + cp_lexer_set_source_position_from_token (lexer->next_token); + + cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer); + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *kind = IDENTIFIER_POINTER (id); + cp_lexer_consume_token (parser->lexer); + + tree c, cl; + if (strcmp (kind, "simd") == 0) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + + omp_clause_mask mask = OMP_DECLARE_SIMD_CLAUSE_MASK; + cl = cp_parser_omp_all_clauses (parser, mask, + "#pragma omp declare simd", + pragma_tok); + if (cl) + cl = tree_cons (NULL_TREE, cl, NULL_TREE); + c = build_tree_list (get_identifier ("omp declare simd"), + cl); + TREE_CHAIN (c) = attrs; + if (processing_template_decl) + ATTR_IS_DEPENDENT (c) = 1; + attrs = c; + } + else + { + gcc_assert (strcmp (kind, "variant") == 0); + attrs + = cp_finish_omp_declare_variant (parser, pragma_tok, + attrs); + } + gcc_assert (parser->lexer != lexer); + vec_safe_truncate (lexer->buffer, 0); + } + *pa = TREE_CHAIN (*pa); + } + else + pa = &TREE_CHAIN (*pa); + } + if (lexer) + cp_lexer_destroy (lexer); + data->fndecl_seen = true; return attrs; } @@ -43124,7 +44913,11 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) tree clauses = NULL_TREE; int device_type = 0; bool only_device_type = true; - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + || (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))) clauses = cp_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, "#pragma omp declare target", pragma_tok); @@ -43137,8 +44930,10 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) } else { + struct omp_declare_target_attr a + = { parser->lexer->in_omp_attribute_pragma }; + vec_safe_push (scope_chain->omp_declare_target_attribute, a); cp_parser_require_pragma_eol (parser, pragma_tok); - scope_chain->omp_declare_target_attribute++; return; } for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) @@ -43219,6 +45014,7 @@ static void cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) { const char *p = ""; + bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -43249,12 +45045,26 @@ cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) return; } cp_parser_require_pragma_eol (parser, pragma_tok); - if (!scope_chain->omp_declare_target_attribute) + 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%>"); else - scope_chain->omp_declare_target_attribute--; + { + 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, + "%<declare target%> in attribute syntax terminated " + "with %<end declare target%> in pragma syntax"); + else + error_at (pragma_tok->location, + "%<declare target%> in pragma syntax terminated " + "with %<end declare target%> in attribute syntax"); + } + } } /* Helper function of cp_parser_omp_declare_reduction. Parse the combiner @@ -43303,6 +45113,12 @@ cp_parser_omp_declare_reduction_exprs (tree fndecl, cp_parser *parser) if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) return false; + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + const char *p = ""; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { @@ -43737,7 +45553,10 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) location_t loc = pragma_tok->location; while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) { - if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if ((!first || parser->lexer->in_omp_attribute_pragma) + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) cp_lexer_consume_token (parser->lexer); first = false; @@ -43784,9 +45603,18 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) error_at (cp_lexer_peek_token (parser->lexer)->location, "expected %<seq_cst%>, %<relaxed%> or " "%<acq_rel%>"); - if (cp_lexer_nth_token_is (parser->lexer, 2, - CPP_CLOSE_PAREN)) - cp_lexer_consume_token (parser->lexer); + switch (cp_lexer_peek_token (parser->lexer)->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + case CPP_CLOSE_PAREN: + break; + default: + if (cp_lexer_nth_token_is (parser->lexer, 2, + CPP_CLOSE_PAREN)) + cp_lexer_consume_token (parser->lexer); + break; + } } else cp_lexer_consume_token (parser->lexer); @@ -43869,6 +45697,194 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) } +/* OpenMP 5.1: + #pragma omp nothing new-line */ + +static void +cp_parser_omp_nothing (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_require_pragma_eol (parser, pragma_tok); +} + + +/* OpenMP 5.1 + #pragma omp error clauses[optseq] new-line */ + +static bool +cp_parser_omp_error (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + int at_compilation = -1; + int severity_fatal = -1; + tree message = NULL_TREE; + bool first = true; + bool bad = false; + location_t loc = pragma_tok->location; + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + { + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if ((!first || parser->lexer->in_omp_attribute_pragma) + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + + first = false; + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + break; + + const char *p + = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value); + location_t cloc = cp_lexer_peek_token (parser->lexer)->location; + static const char *args[] = { + "execution", "compilation", "warning", "fatal" + }; + int *v = NULL; + int idx = 0, n = -1; + tree m = NULL_TREE; + + if (!strcmp (p, "at")) + v = &at_compilation; + else if (!strcmp (p, "severity")) + { + v = &severity_fatal; + idx += 2; + } + else if (strcmp (p, "message")) + { + error_at (cloc, + "expected %<at%>, %<severity%> or %<message%> clause"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return false; + } + + cp_lexer_consume_token (parser->lexer); + + matching_parens parens; + if (parens.require_open (parser)) + { + if (v == NULL) + { + m = cp_parser_assignment_expression (parser); + if (type_dependent_expression_p (m)) + m = build1 (IMPLICIT_CONV_EXPR, const_string_type_node, m); + else + m = perform_implicit_conversion_flags (const_string_type_node, m, + tf_warning_or_error, + LOOKUP_NORMAL); + } + else + { + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree val = cp_lexer_peek_token (parser->lexer)->u.value; + const char *q = IDENTIFIER_POINTER (val); + + if (!strcmp (q, args[idx])) + n = 0; + else if (!strcmp (q, args[idx + 1])) + n = 1; + } + if (n == -1) + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "expected %qs or %qs", args[idx], args[idx + 1]); + bad = true; + switch (cp_lexer_peek_token (parser->lexer)->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + case CPP_CLOSE_PAREN: + break; + default: + if (cp_lexer_nth_token_is (parser->lexer, 2, + CPP_CLOSE_PAREN)) + cp_lexer_consume_token (parser->lexer); + break; + } + } + else + cp_lexer_consume_token (parser->lexer); + } + + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/ + true); + + if (v == NULL) + { + if (message) + { + error_at (cloc, "too many %qs clauses", p); + bad = true; + } + else + message = m; + } + else if (n != -1) + { + if (*v != -1) + { + error_at (cloc, "too many %qs clauses", p); + bad = true; + } + else + *v = n; + } + } + else + bad = true; + } + cp_parser_require_pragma_eol (parser, pragma_tok); + if (bad) + return true; + + if (at_compilation == -1) + at_compilation = 1; + if (severity_fatal == -1) + severity_fatal = 1; + if (!at_compilation) + { + if (context != pragma_compound) + { + error_at (loc, "%<#pragma omp error%> with %<at(execution)%> clause " + "may only be used in compound statements"); + return true; + } + tree fndecl + = builtin_decl_explicit (severity_fatal ? BUILT_IN_GOMP_ERROR + : BUILT_IN_GOMP_WARNING); + if (!message) + message = build_zero_cst (const_string_type_node); + tree stmt = build_call_expr_loc (loc, fndecl, 2, message, + build_all_ones_cst (size_type_node)); + add_stmt (stmt); + return true; + } + + if (in_discarded_stmt) + return false; + + const char *msg = NULL; + if (message) + { + msg = c_getstr (fold_for_warn (message)); + if (msg == NULL) + msg = _("<message unknown at compile time>"); + } + if (msg) + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "%<pragma omp error%> encountered: %s", msg); + else + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "%<pragma omp error%> encountered"); + return false; +} + /* OpenMP 4.5: #pragma omp taskloop taskloop-clause[optseq] new-line for-loop @@ -43982,8 +45998,8 @@ cp_parser_omp_taskloop (cp_parser *parser, cp_token *pragma_tok, ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ)) - + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NOHOST) ) /* Parse the OpenACC routine pragma. This has an optional '( name )' component, which must resolve to a declared namespace-scope @@ -44291,6 +46307,11 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) stmt = cp_parser_omp_loop (parser, pragma_tok, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_MASKED: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_masked (parser, pragma_tok, p_name, mask, NULL, + if_p); + break; case PRAGMA_OMP_MASTER: strcpy (p_name, "#pragma omp"); stmt = cp_parser_omp_master (parser, pragma_tok, p_name, mask, NULL, @@ -44301,6 +46322,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_SCOPE: + stmt = cp_parser_omp_scope (parser, pragma_tok, if_p); + break; case PRAGMA_OMP_SECTIONS: strcpy (p_name, "#pragma omp"); stmt = cp_parser_omp_sections (parser, pragma_tok, p_name, mask, NULL); @@ -44730,7 +46754,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) cp_token *pragma_tok; unsigned int id; tree stmt; - bool ret; + bool ret = false; pragma_tok = cp_lexer_consume_token (parser->lexer); gcc_assert (pragma_tok->type == CPP_PRAGMA); @@ -44755,6 +46779,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp barrier"); + ret = true; break; default: goto bad_stmt; @@ -44770,6 +46795,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp depobj"); + ret = true; break; default: goto bad_stmt; @@ -44785,6 +46811,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp flush"); + ret = true; break; default: goto bad_stmt; @@ -44801,6 +46828,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp taskwait"); + ret = true; break; default: goto bad_stmt; @@ -44817,6 +46845,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp taskyield"); + ret = true; break; default: goto bad_stmt; @@ -44833,6 +46862,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp cancel"); + ret = true; break; default: goto bad_stmt; @@ -44840,8 +46870,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) break; case PRAGMA_OMP_CANCELLATION_POINT: - cp_parser_omp_cancellation_point (parser, pragma_tok, context); - return false; + return cp_parser_omp_cancellation_point (parser, pragma_tok, context); case PRAGMA_OMP_THREADPRIVATE: cp_parser_omp_threadprivate (parser, pragma_tok); @@ -44860,6 +46889,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc enter data"); + ret = true; break; } else if (context != pragma_compound) @@ -44873,6 +46903,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc exit data"); + ret = true; break; } else if (context != pragma_compound) @@ -44885,6 +46916,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) { error_at (pragma_tok->location, "%<#pragma acc routine%> must be at file scope"); + ret = true; break; } cp_parser_oacc_routine (parser, pragma_tok, context); @@ -44896,6 +46928,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc update"); + ret = true; break; } else if (context != pragma_compound) @@ -44909,6 +46942,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc wait"); + ret = true; break; } else if (context != pragma_compound) @@ -44931,8 +46965,10 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_OMP_DISTRIBUTE: case PRAGMA_OMP_FOR: case PRAGMA_OMP_LOOP: + case PRAGMA_OMP_MASKED: case PRAGMA_OMP_MASTER: case PRAGMA_OMP_PARALLEL: + case PRAGMA_OMP_SCOPE: case PRAGMA_OMP_SECTIONS: case PRAGMA_OMP_SIMD: case PRAGMA_OMP_SINGLE: @@ -44953,10 +46989,18 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma omp requires%> may only be used at file or " "namespace scope"); + ret = true; break; } return cp_parser_omp_requires (parser, pragma_tok); + case PRAGMA_OMP_NOTHING: + cp_parser_omp_nothing (parser, pragma_tok); + return false; + + case PRAGMA_OMP_ERROR: + return cp_parser_omp_error (parser, pragma_tok, context); + case PRAGMA_OMP_ORDERED: if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; @@ -45065,7 +47109,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) } cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return ret; } /* The interface the pragma parsers have to the lexer. */ |