diff options
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r-- | gcc/cp/parser.c | 2489 |
1 files changed, 2205 insertions, 284 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0a7d18a..e44c5c6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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 @@ -4058,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); + } } } @@ -4070,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 @@ -4376,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"); } } @@ -5320,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), @@ -5575,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 @@ -5601,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); @@ -5774,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: @@ -5946,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 @@ -6323,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); @@ -6626,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 ("::"); @@ -7290,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, @@ -7306,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) @@ -7352,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 (); } @@ -7560,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; @@ -7665,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); @@ -7722,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; @@ -8342,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); @@ -10363,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) { @@ -10405,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 @@ -10632,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; @@ -10785,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) @@ -10854,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. */ @@ -10884,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; @@ -11010,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)) @@ -11049,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; @@ -11090,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, @@ -11264,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%>"); @@ -11333,10 +11439,11 @@ 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); @@ -11356,7 +11463,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) if (omitted_parms_loc && lambda_specs.any_specifiers_p) { - pedwarn (omitted_parms_loc, 0, + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, "parameter declaration before lambda declaration " "specifiers only optional with %<-std=c++2b%> or " "%<-std=gnu++2b%>"); @@ -11375,7 +11482,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) tx_qual = cp_parser_tx_qualifier_opt (parser); if (omitted_parms_loc && tx_qual) { - pedwarn (omitted_parms_loc, 0, + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, "parameter declaration before lambda transaction " "qualifier only optional with %<-std=c++2b%> or " "%<-std=gnu++2b%>"); @@ -11388,7 +11495,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) if (omitted_parms_loc && exception_spec) { - pedwarn (omitted_parms_loc, 0, + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, "parameter declaration before lambda exception " "specification only optional with %<-std=c++2b%> or " "%<-std=gnu++2b%>"); @@ -11406,7 +11513,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) { if (omitted_parms_loc) - pedwarn (omitted_parms_loc, 0, + 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%>"); @@ -11526,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. */ @@ -11572,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: @@ -11622,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) @@ -11630,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 @@ -11644,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; @@ -11666,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: @@ -11707,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. */ @@ -11749,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; } } @@ -11762,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 @@ -11770,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) @@ -11787,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) @@ -12115,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; } @@ -12268,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 `('. */ @@ -12294,7 +12940,8 @@ 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)) @@ -12827,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; @@ -12867,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); } } } @@ -13363,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; @@ -13387,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%>"); } @@ -13992,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); @@ -14142,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); @@ -14197,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) @@ -14250,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, @@ -14312,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. */ @@ -14504,6 +15207,7 @@ cp_parser_simple_declaration (cp_parser* parser, else { pop_deferring_access_checks (); + cp_finalize_omp_declare_simd (parser, &odsd); return; } } @@ -14584,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. @@ -14630,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); @@ -15111,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. */ @@ -15216,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%>"); @@ -15383,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 ')' */ @@ -16895,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, @@ -17708,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 @@ -17970,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; } @@ -18186,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. */ @@ -18254,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. @@ -18333,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: @@ -18425,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)) @@ -18620,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; @@ -19717,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) @@ -19901,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, @@ -20350,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); } @@ -20380,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%>"); @@ -20640,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); @@ -20673,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; @@ -20901,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); @@ -20925,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); @@ -20989,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; @@ -21372,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. @@ -21470,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) @@ -21537,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); @@ -21548,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); @@ -21972,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. */ @@ -22171,7 +22956,7 @@ cp_parser_direct_declarator (cp_parser* parser, tree save_ccp = current_class_ptr; tree save_ccr = current_class_ref; - if (memfn && !friend_p) + if (memfn && !friend_p && !static_p) /* DR 1207: 'this' is in scope after the cv-quals. */ inject_this_parameter (current_class_type, cv_quals); @@ -22187,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); @@ -22909,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' @@ -23225,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", @@ -23559,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, @@ -23778,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 @@ -23791,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, @@ -23993,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; @@ -24060,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%>"); } @@ -24191,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 @@ -24387,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 `.'. */ @@ -24617,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 @@ -24689,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); @@ -25105,7 +25918,8 @@ cp_parser_class_specifier_1 (cp_parser* parser) 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)) = TREE_PURPOSE (spec); + 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; @@ -25637,7 +26451,13 @@ cp_parser_class_head (cp_parser* parser, 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)) - bases = cp_parser_base_clause (parser); + { + if (type) + pushclass (type); + bases = cp_parser_base_clause (parser); + if (type) + popclass (); + } else bases = NULL_TREE; @@ -25725,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%>"); } @@ -25923,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); @@ -25933,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)) @@ -25992,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 " @@ -26039,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); @@ -26109,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%>"); @@ -26195,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, @@ -26411,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. */ @@ -26427,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. @@ -27070,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%>"); @@ -27718,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 @@ -27849,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; @@ -27876,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) @@ -28029,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%>"); @@ -28331,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); @@ -28486,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; } @@ -28692,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) { @@ -28835,8 +29820,11 @@ cp_parser_requirement_parameter_list (cp_parser *parser) if (parm == void_list_node || parm == explicit_void_list_node) break; tree decl = TREE_VALUE (parm); - DECL_CONTEXT (decl) = NULL_TREE; - CONSTRAINT_VAR_P (decl) = true; + if (decl != error_mark_node) + { + DECL_CONTEXT (decl) = NULL_TREE; + CONSTRAINT_VAR_P (decl) = true; + } } return parms; @@ -28932,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); } @@ -29368,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); @@ -29394,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); @@ -30414,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); @@ -30542,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; } @@ -33034,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); @@ -33050,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; } @@ -34680,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'. */ @@ -34856,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: @@ -34993,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; @@ -35039,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; @@ -35091,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)) @@ -35252,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 (); @@ -35282,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; @@ -35294,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, @@ -35340,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: @@ -35366,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)) @@ -35385,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; @@ -35398,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) @@ -36243,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, @@ -36255,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 @@ -36268,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, @@ -36286,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 @@ -36299,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; @@ -36373,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 ) @@ -37463,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; @@ -37638,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 ) @@ -37731,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, @@ -37778,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) @@ -37823,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 @@ -37859,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 @@ -37885,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; } @@ -37945,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, @@ -37962,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; @@ -38206,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"; @@ -38322,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); @@ -38361,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"; @@ -38580,6 +39837,10 @@ 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); @@ -38702,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); @@ -38723,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; @@ -38814,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; @@ -38920,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: @@ -38936,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; @@ -39376,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; @@ -39456,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; @@ -39468,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)) @@ -40040,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: @@ -40054,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) { @@ -40065,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; @@ -40089,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); @@ -40522,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: @@ -40770,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 */ @@ -40792,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 @@ -40812,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) @@ -40831,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, @@ -40878,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); } @@ -40893,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); @@ -40905,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); } @@ -41036,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; @@ -41054,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) @@ -41116,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); @@ -41148,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 */ @@ -41165,7 +42662,8 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p) | (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_DETACH)) + | (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) @@ -41177,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); @@ -41286,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) { @@ -41308,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) @@ -41320,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, @@ -41328,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: @@ -41623,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) { @@ -41643,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) @@ -41652,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 @@ -41692,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: @@ -41713,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) { @@ -41733,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) @@ -41742,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 @@ -41784,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: @@ -41815,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 @@ -41827,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); @@ -41835,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: @@ -41852,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 @@ -41966,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); @@ -41987,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) { @@ -42013,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); @@ -42635,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; @@ -43130,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)) @@ -43202,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); @@ -43216,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; } @@ -43247,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); @@ -43260,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)) @@ -43342,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; @@ -43372,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 @@ -43426,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)) { @@ -43860,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; @@ -43907,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); @@ -43992,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 @@ -44105,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 @@ -44414,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, @@ -44424,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); @@ -44853,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); @@ -44878,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; @@ -44893,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; @@ -44908,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; @@ -44924,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; @@ -44940,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; @@ -44956,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; @@ -44963,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); @@ -44983,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) @@ -44996,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) @@ -45008,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); @@ -45019,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) @@ -45032,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) @@ -45054,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: @@ -45076,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; @@ -45188,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. */ |