diff options
Diffstat (limited to 'gcc/cp/parser.cc')
-rw-r--r-- | gcc/cp/parser.cc | 435 |
1 files changed, 343 insertions, 92 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index b1626ac..860f3f0 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2519,7 +2519,7 @@ static cp_expr cp_parser_id_expression static cp_expr cp_parser_unqualified_id (cp_parser *, bool, bool, bool, bool); static tree cp_parser_nested_name_specifier_opt - (cp_parser *, bool, bool, bool, bool, bool = false); + (cp_parser *, bool, bool, bool, bool, bool = false, bool = false); static tree cp_parser_nested_name_specifier (cp_parser *, bool, bool, bool, bool); static tree cp_parser_qualifying_entity @@ -2576,11 +2576,11 @@ static cp_expr cp_parser_constant_expression static cp_expr cp_parser_builtin_offsetof (cp_parser *); static cp_expr cp_parser_lambda_expression - (cp_parser *); + (cp_parser *, bool = false); static void cp_parser_lambda_introducer (cp_parser *, tree); static bool cp_parser_lambda_declarator_opt - (cp_parser *, tree); + (cp_parser *, tree, bool = false); static void cp_parser_lambda_body (cp_parser *, tree); @@ -2921,7 +2921,7 @@ static size_t cp_parser_skip_std_attribute_spec_seq static size_t cp_parser_skip_attributes_opt (cp_parser *, size_t); static bool cp_parser_extension_opt - (cp_parser *, int *); + (cp_parser *, int *, int *); static void cp_parser_label_declaration (cp_parser *); @@ -3091,8 +3091,8 @@ static cp_token *cp_parser_require_keyword (cp_parser *, enum rid, required_token); static bool cp_parser_token_starts_function_definition_p (cp_token *); -static bool cp_parser_next_token_starts_class_definition_p - (cp_parser *); +static bool cp_parser_nth_token_starts_class_definition_p + (cp_parser *, size_t); static bool cp_parser_next_token_ends_template_argument_p (cp_parser *); static bool cp_parser_nth_token_starts_template_argument_list_p @@ -5266,7 +5266,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) && (id_equal (suffix_id, "i") || id_equal (suffix_id, "if") || id_equal (suffix_id, "il"))); - diagnostic_t kind = DK_ERROR; + enum diagnostics::kind kind = diagnostics::kind::error; int opt = 0; if (i14 && ext) @@ -5276,7 +5276,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) if (cxlit == error_mark_node) { /* No <complex>, so pedwarn and use GNU semantics. */ - kind = DK_PEDWARN; + kind = diagnostics::kind::pedwarn; opt = OPT_Wpedantic; } } @@ -5303,7 +5303,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) "to enable more built-in suffixes"); } - if (kind == DK_ERROR) + if (kind == diagnostics::kind::error) value = error_mark_node; else { @@ -6307,7 +6307,10 @@ cp_parser_primary_expression (cp_parser *parser, /* Recognize the `this' keyword. */ case RID_THIS: cp_lexer_consume_token (parser->lexer); - if (parser->local_variables_forbidden_p & THIS_FORBIDDEN) + if ((parser->local_variables_forbidden_p & THIS_FORBIDDEN) + /* It's OK to refer to 'this' in an unevaluated operand in a + lambda default argument (lambda-targ16.C). */ + && !cp_unevaluated_operand) { error_at (token->location, "%<this%> may not be used in this context"); @@ -6644,7 +6647,8 @@ cp_parser_primary_expression (cp_parser *parser, member template. */ static void -missing_template_diag (location_t loc, diagnostic_t diag_kind = DK_WARNING) +missing_template_diag (location_t loc, + enum diagnostics::kind diag_kind = diagnostics::kind::warning) { if (warning_suppressed_at (loc, OPT_Wmissing_template_keyword)) return; @@ -7239,18 +7243,22 @@ check_template_keyword_in_nested_name_spec (tree name) nested-name-specifier template [opt] simple-template-id :: PARSER->SCOPE should be set appropriately before this function is - called. TYPENAME_KEYWORD_P is TRUE if the `typename' keyword is in - effect. TYPE_P is TRUE if we non-type bindings should be ignored - in name lookups. + called. TYPENAME_KEYWORD_P is true if the `typename' keyword is in + effect. TYPE_P is true if we non-type bindings should be ignored + in name lookups. TEMPLATE_KEYWORD_P is true if the `template' keyword + was seen. GLOBAL_P is true if `::' has already been parsed. + TODO: This function doesn't handle the C++14 change to make `::' + a nested-name-specifier by itself. If it did, GLOBAL_P could probably + go. Sets PARSER->SCOPE to the class (TYPE) or namespace (NAMESPACE_DECL) specified by the nested-name-specifier, or leaves it unchanged if there is no nested-name-specifier. Returns the new scope iff there is a nested-name-specifier, or NULL_TREE otherwise. - If CHECK_DEPENDENCY_P is FALSE, names are looked up in dependent scopes. + If CHECK_DEPENDENCY_P is false, names are looked up in dependent scopes. - If IS_DECLARATION is TRUE, the nested-name-specifier is known to be + If IS_DECLARATION is true, the nested-name-specifier is known to be part of a declaration and/or decl-specifier. */ static tree @@ -7259,7 +7267,8 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, bool check_dependency_p, bool type_p, bool is_declaration, - bool template_keyword_p /* = false */) + bool template_keyword_p /* = false */, + bool global_p /* = false */) { bool success = false; cp_token_position start = 0; @@ -7307,8 +7316,9 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, /* Spot cases that cannot be the beginning of a nested-name-specifier. On the second and subsequent times - through the loop, we look for the `template' keyword. */ - if (success && token->keyword == RID_TEMPLATE) + (or the first, if '::' has already been parsed) through the + loop, we look for the `template' keyword. */ + if ((success || global_p) && token->keyword == RID_TEMPLATE) ; /* A template-id can start a nested-name-specifier. */ else if (token->type == CPP_TEMPLATE_ID) @@ -7356,8 +7366,11 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, cp_parser_parse_tentatively (parser); /* Look for the optional `template' keyword, if this isn't the - first time through the loop. */ - if (success) + first time through the loop, or if we've already parsed '::'; + this is then the + nested-name-specifier template [opt] simple-template-id :: + production. */ + if (success || global_p) { template_keyword_p = cp_parser_optional_template_keyword (parser); /* DR1710: "In a qualified-id used as the name in @@ -8842,8 +8855,10 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression, { /* In a template, be permissive by treating an object expression of incomplete type as dependent (after a pedwarn). */ - diagnostic_t kind = (processing_template_decl - && MAYBE_CLASS_TYPE_P (*scope) ? DK_PEDWARN : DK_ERROR); + enum diagnostics::kind kind = ((processing_template_decl + && MAYBE_CLASS_TYPE_P (*scope)) + ? diagnostics::kind::pedwarn + : diagnostics::kind::error); switch (TREE_CODE (*postfix_expression)) { @@ -8855,27 +8870,27 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression, case IMPLICIT_CONV_EXPR: case VIEW_CONVERT_EXPR: case NON_LVALUE_EXPR: - kind = DK_ERROR; + kind = diagnostics::kind::error; break; case OVERLOAD: /* Don't emit any diagnostic for OVERLOADs. */ - kind = DK_IGNORED; + kind = diagnostics::kind::ignored; break; default: /* Avoid clobbering e.g. DECLs. */ if (!EXPR_P (*postfix_expression)) - kind = DK_ERROR; + kind = diagnostics::kind::error; break; } - if (kind == DK_IGNORED) + if (kind == diagnostics::kind::ignored) return false; location_t exploc = location_of (*postfix_expression); cxx_incomplete_type_diagnostic (exploc, *postfix_expression, *scope, kind); if (!MAYBE_CLASS_TYPE_P (*scope)) return true; - if (kind == DK_ERROR) + if (kind == diagnostics::kind::error) *scope = *postfix_expression = error_mark_node; else if (processing_template_decl) { @@ -9489,21 +9504,23 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, case RID_EXTENSION: { /* The saved value of the PEDANTIC flag. */ - int saved_pedantic; + int saved_pedantic, saved_long_long; tree expr; /* Save away the PEDANTIC flag. */ - cp_parser_extension_opt (parser, &saved_pedantic); + cp_parser_extension_opt (parser, &saved_pedantic, + &saved_long_long); /* Also suppress -Wconditionally-supported. */ diagnostic_push_diagnostics (global_dc, input_location); diagnostic_classify_diagnostic (global_dc, OPT_Wconditionally_supported, - DK_IGNORED, input_location); + diagnostics::kind::ignored, input_location); /* Parse the cast-expression. */ expr = cp_parser_simple_cast_expression (parser); /* Restore the PEDANTIC flag. */ diagnostic_pop_diagnostics (global_dc, input_location); pedantic = saved_pedantic; + warn_long_long = saved_long_long; return expr; } @@ -11727,10 +11744,14 @@ cp_parser_trait (cp_parser* parser, const cp_trait* trait) lambda-introducer < template-parameter-list > requires-clause [opt] lambda-declarator [opt] compound-statement + If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which + is syntactic sugar for a consteval lambda. + Returns a representation of the expression. */ static cp_expr -cp_parser_lambda_expression (cp_parser* parser) +cp_parser_lambda_expression (cp_parser* parser, + bool consteval_block_p/*=false*/) { tree lambda_expr = build_lambda_expr (); tree type; @@ -11739,6 +11760,7 @@ cp_parser_lambda_expression (cp_parser* parser) cp_token_position start = 0; LAMBDA_EXPR_LOCATION (lambda_expr) = token->location; + LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lambda_expr) = consteval_block_p; if (cxx_dialect >= cxx20) { @@ -11782,9 +11804,12 @@ cp_parser_lambda_expression (cp_parser* parser) it now. */ push_deferring_access_checks (dk_no_deferred); - cp_parser_lambda_introducer (parser, lambda_expr); - if (cp_parser_error_occurred (parser)) - return error_mark_node; + if (!consteval_block_p) + { + cp_parser_lambda_introducer (parser, lambda_expr); + if (cp_parser_error_occurred (parser)) + return error_mark_node; + } { /* OK, this is a bit tricksy. cp_parser_requires_expression sets @@ -11826,6 +11851,7 @@ cp_parser_lambda_expression (cp_parser* parser) bool auto_is_implicit_function_template_parm_p = parser->auto_is_implicit_function_template_parm_p; bool saved_omp_array_section_p = parser->omp_array_section_p; + bool saved_in_targ = parser->in_template_argument_list_p; parser->num_template_parameter_lists = 0; parser->in_statement = 0; @@ -11835,6 +11861,7 @@ cp_parser_lambda_expression (cp_parser* parser) parser->implicit_template_scope = 0; parser->auto_is_implicit_function_template_parm_p = false; parser->omp_array_section_p = false; + parser->in_template_argument_list_p = false; /* Inside the lambda, outside unevaluated context do not apply. */ cp_evaluated ev; @@ -11854,7 +11881,8 @@ cp_parser_lambda_expression (cp_parser* parser) if (cp_parser_start_tentative_firewall (parser)) start = token; - ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr); + ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr, + consteval_block_p); if (ok && cp_parser_error_occurred (parser)) ok = false; @@ -11889,6 +11917,7 @@ cp_parser_lambda_expression (cp_parser* parser) parser->auto_is_implicit_function_template_parm_p = auto_is_implicit_function_template_parm_p; parser->omp_array_section_p = saved_omp_array_section_p; + parser->in_template_argument_list_p = saved_in_targ; } /* This lambda shouldn't have any proxies left at this point. */ @@ -12236,10 +12265,13 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) decl-specifier-seq [opt] noexcept-specifier [opt] attribute-specifier-seq [opt] trailing-return-type [opt] - LAMBDA_EXPR is the current representation of the lambda expression. */ + LAMBDA_EXPR is the current representation of the lambda expression. + If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which + is syntactic sugar for a consteval lambda. */ static bool -cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) +cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr, + bool consteval_block_p/*=false*/) { /* 5.1.1.4 of the standard says: If a lambda-expression does not include a lambda-declarator, it is as if @@ -12342,6 +12374,18 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR, &lambda_specs, &declares_class_or_enum); + /* [dcl.pre] For a consteval-block-declaration D, the expression E + corresponding to D is: + [] -> void static consteval compound-statement () + Make it so. */ + if (consteval_block_p) + { + return_type = void_type_node; + lambda_specs.storage_class = sc_static; + set_and_check_decl_spec_loc (&lambda_specs, ds_consteval, + cp_lexer_peek_token (parser->lexer)); + } + if (omitted_parms_loc && lambda_specs.any_specifiers_p) { pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, @@ -16029,15 +16073,16 @@ cp_parser_declaration_seq_opt (cp_parser* parser) static void cp_parser_declaration (cp_parser* parser, tree prefix_attrs) { - int saved_pedantic; + int saved_pedantic, saved_long_long; /* Check for the `__extension__' keyword. */ - if (cp_parser_extension_opt (parser, &saved_pedantic)) + if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long)) { /* Parse the qualified declaration. */ cp_parser_declaration (parser, prefix_attrs); /* Restore the PEDANTIC flag. */ pedantic = saved_pedantic; + warn_long_long = saved_long_long; return; } @@ -16279,6 +16324,56 @@ cp_parser_toplevel_declaration (cp_parser* parser) cp_parser_declaration (parser, NULL_TREE); } +/* Build an empty string for static_assert. */ + +static tree +build_empty_string () +{ + tree message = build_string (1, ""); + TREE_TYPE (message) = char_array_type_node; + fix_string_type (message); + return message; +} + +/* Return true iff the next tokens start a C++26 consteval block. */ + +static bool +cp_parser_next_tokens_are_consteval_block_p (cp_parser *parser) +{ + return (cxx_dialect >= cxx26 + && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONSTEVAL) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_BRACE)); +} + +/* Parse a consteval-block-declaration. + + consteval-block-declaration: + consteval compound-statement + + If MEMBER_P, this consteval block is a member declaration. */ + +static void +cp_parser_consteval_block (cp_parser *parser, bool member_p) +{ + const location_t loc = cp_lexer_peek_token (parser->lexer)->location; + /* Consume the 'consteval'. */ + cp_lexer_consume_token (parser->lexer); + + /* We know the next token is '{'. Let cp_parser_lambda_body handle it. */ + cp_expr lam = cp_parser_lambda_expression (parser, + /*consteval_block_p=*/true); + if (!cp_parser_error_occurred (parser)) + { + releasing_vec args; + tree call = finish_call_expr (lam, &args, + /*disallow_virtual=*/false, + /*koenig_p=*/false, + tf_warning_or_error); + finish_static_assert (call, build_empty_string (), loc, member_p, + /*show_expr_p=*/false, /*consteval_block_p=*/true); + } +} + /* Parse a block-declaration. block-declaration: @@ -16286,18 +16381,18 @@ cp_parser_toplevel_declaration (cp_parser* parser) asm-definition namespace-alias-definition using-declaration + using-enum-declaration using-directive + static_assert-declaration + consteval-block-declaration + alias-declaration + opaque-enum-declaration GNU Extension: block-declaration: __extension__ block-declaration - C++0x Extension: - - block-declaration: - static_assert-declaration - If STATEMENT_P is TRUE, then this block-declaration is occurring as part of a declaration-statement. */ @@ -16305,15 +16400,16 @@ static void cp_parser_block_declaration (cp_parser *parser, bool statement_p) { - int saved_pedantic; + int saved_pedantic, saved_long_long; /* Check for the `__extension__' keyword. */ - if (cp_parser_extension_opt (parser, &saved_pedantic)) + if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long)) { /* Parse the qualified declaration. */ cp_parser_block_declaration (parser, statement_p); /* Restore the PEDANTIC flag. */ pedantic = saved_pedantic; + warn_long_long = saved_long_long; return; } @@ -16374,6 +16470,8 @@ cp_parser_block_declaration (cp_parser *parser, /* If the next token is `static_assert' we have a static assertion. */ else if (token1->keyword == RID_STATIC_ASSERT) cp_parser_static_assert (parser, /*member_p=*/false); + else if (cp_parser_next_tokens_are_consteval_block_p (parser)) + cp_parser_consteval_block (parser, /*member_p=*/false); else { size_t attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1); @@ -16867,7 +16965,11 @@ cp_parser_decomposition_declaration (cp_parser *parser, decl = error_mark_node; } else - prev = decl2; + { + prev = decl2; + DECL_DECLARED_CONSTEXPR_P (decl2) = DECL_DECLARED_CONSTEXPR_P (decl); + DECL_DECLARED_CONSTINIT_P (decl2) = DECL_DECLARED_CONSTINIT_P (decl); + } if (elt_pushed_scope) pop_scope (elt_pushed_scope); } @@ -16916,6 +17018,15 @@ cp_parser_decomposition_declaration (cp_parser *parser, /* Ensure DECL_VALUE_EXPR is created for all the decls but the underlying DECL. */ cp_finish_decomp (decl, &decomp); + if (decl_spec_seq_has_spec_p (decl_specifiers, ds_thread)) + pedwarn (decl_specifiers->locations[ds_thread], + 0, "for-range-declaration cannot be %qs", + decl_specifiers->gnu_thread_keyword_p + ? "__thread" : "thread_local"); + else if (decl_specifiers->storage_class == sc_static) + pedwarn (decl_specifiers->locations[ds_storage_class], + 0, "for-range-declaration cannot be %qs", + "static"); } if (pushed_scope) @@ -17664,9 +17775,7 @@ cp_parser_static_assert (cp_parser *parser, bool member_p) "only available with %<-std=c++17%> or %<-std=gnu++17%>"); /* Eat the ')' */ cp_lexer_consume_token (parser->lexer); - message = build_string (1, ""); - TREE_TYPE (message) = char_array_type_node; - fix_string_type (message); + message = build_empty_string (); } else { @@ -21009,9 +21118,6 @@ cp_parser_simple_type_specifier (cp_parser* parser, "only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); } - else if (parser->in_template_argument_list_p) - error_at (token->location, - "use of %<auto%> in template argument"); else if (!flag_concepts) pedwarn (token->location, OPT_Wc__20_extensions, "use of %<auto%> in parameter declaration " @@ -21021,6 +21127,11 @@ cp_parser_simple_type_specifier (cp_parser* parser, "use of %<auto%> in parameter declaration " "only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); + + if (parser->in_template_argument_list_p) + permerror_opt (token->location, + OPT_Wabbreviated_auto_in_template_arg, + "use of %<auto%> in template argument"); } else type = make_auto (); @@ -21149,7 +21260,9 @@ cp_parser_simple_type_specifier (cp_parser* parser, /*typename_keyword_p=*/false, /*check_dependency_p=*/true, /*type_p=*/false, - /*is_declaration=*/false) + /*is_declaration=*/false, + /*template_keyword_p=*/false, + global_p) != NULL_TREE); /* If we have seen a nested-name-specifier, and the next token is `template', then we are using the template-id production. */ @@ -21467,6 +21580,10 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc, error_at (loc, "cannot declare a parameter with %<decltype(auto)%>"); return error_mark_node; } + if (parser->in_template_argument_list_p) + permerror_opt (placeholder->location, + OPT_Wabbreviated_auto_in_template_arg, + "use of %<auto%> in template argument"); tree parm = build_constrained_parameter (con, proto, args); return synthesize_implicit_template_parm (parser, parm); } @@ -21995,7 +22112,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, bool template_p = (template_parm_lists_apply - && (cp_parser_next_token_starts_class_definition_p (parser) + && (cp_parser_nth_token_starts_class_definition_p (parser, 1) || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))); /* An unqualified name was used to reference this type, so there were no qualifying templates. */ @@ -24159,7 +24276,26 @@ cp_parser_init_declarator (cp_parser* parser, && token->type != CPP_SEMICOLON) { if (maybe_range_for_decl && *maybe_range_for_decl != error_mark_node) - range_for_decl_p = true; + { + range_for_decl_p = true; + if (decl_spec_seq_has_spec_p (decl_specifiers, ds_thread)) + pedwarn (decl_specifiers->locations[ds_thread], + 0, "for-range-declaration cannot be %qs", + decl_specifiers->gnu_thread_keyword_p + ? "__thread" : "thread_local"); + else if (decl_specifiers->storage_class == sc_static) + pedwarn (decl_specifiers->locations[ds_storage_class], + 0, "for-range-declaration cannot be %qs", + "static"); + else if (decl_specifiers->storage_class == sc_extern) + pedwarn (decl_specifiers->locations[ds_storage_class], + 0, "for-range-declaration cannot be %qs", + "extern"); + else if (decl_specifiers->storage_class == sc_register) + pedwarn (decl_specifiers->locations[ds_storage_class], + 0, "for-range-declaration cannot be %qs", + "register"); + } else { if (!maybe_range_for_decl) @@ -28013,6 +28149,98 @@ cp_parser_class_specifier (cp_parser* parser) return type; } +/* Parse an (optional) class-property-specifier-seq. + + class-property-specifier-seq: + class-property-specifier class-property-specifier-seq [opt] + + class-property-specifier: + final + trivially_relocatable_if_eligible (C++26) + replaceable_if_eligible (C++26) + + Returns a bitmask representing the class-property-specifiers. */ + +static cp_virt_specifiers +cp_parser_class_property_specifier_seq_opt (cp_parser *parser) +{ + cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED; + + while (true) + { + cp_token *token; + cp_virt_specifiers virt_specifier; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* See if it's a class-property-specifier. */ + if (token->type != CPP_NAME) + break; + if (id_equal (token->u.value, "final")) + { + /* For C++98, quietly ignore final in e.g. + struct S final = 24; */ + if (cxx_dialect == cxx98 + && virt_specifiers == VIRT_SPEC_UNSPECIFIED + && !cp_parser_nth_token_starts_class_definition_p (parser, 2) + && !cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + break; + maybe_warn_cpp0x (CPP0X_OVERRIDE_CONTROLS); + virt_specifier = VIRT_SPEC_FINAL; + } + else if (id_equal (token->u.value, "__final")) + virt_specifier = VIRT_SPEC_FINAL; + else if (id_equal (token->u.value, "trivially_relocatable_if_eligible")) + { + if (cxx_dialect < cxx26) + { + /* Warn about the C++26 conditional keyword (but don't parse + it). */ + warning_at (token->location, OPT_Wc__26_compat, + "identifier %qE is a conditional keyword in C++26", + token->u.value); + break; + } + virt_specifier = VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE; + } + else if (id_equal (token->u.value, + "__trivially_relocatable_if_eligible")) + virt_specifier = VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE; + else if (id_equal (token->u.value, "replaceable_if_eligible")) + { + if (cxx_dialect < cxx26) + { + /* Warn about the C++26 conditional keyword (but don't parse + it). */ + warning_at (token->location, OPT_Wc__26_compat, + "identifier %qE is a conditional keyword in C++26", + token->u.value); + break; + } + virt_specifier = VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE; + } + else if (id_equal (token->u.value, + "__replaceable_if_eligible")) + virt_specifier = VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE; + else + break; + + if (virt_specifiers & virt_specifier) + { + gcc_rich_location richloc (token->location); + richloc.add_fixit_remove (); + error_at (&richloc, "duplicate %qD specifier", token->u.value); + cp_lexer_purge_token (parser->lexer); + } + else + { + cp_lexer_consume_token (parser->lexer); + virt_specifiers |= virt_specifier; + } + } + return virt_specifiers; +} + /* Parse a class-head. class-head: @@ -28203,18 +28431,16 @@ cp_parser_class_head (cp_parser* parser, pop_deferring_access_checks (); if (id) - { - cp_parser_check_for_invalid_template_id (parser, id, - class_key, - type_start_token->location); - } - virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); + cp_parser_check_for_invalid_template_id (parser, id, + class_key, + type_start_token->location); + virt_specifiers = cp_parser_class_property_specifier_seq_opt (parser); /* If it's not a `:' or a `{' then we can't really be looking at a class-head, since a class-head only appears as part of a class-specifier. We have to detect this situation before calling xref_tag, since that has irreversible side-effects. */ - if (!cp_parser_next_token_starts_class_definition_p (parser)) + if (!cp_parser_nth_token_starts_class_definition_p (parser, 1)) { cp_parser_error (parser, "expected %<{%> or %<:%>"); type = error_mark_node; @@ -28224,13 +28450,6 @@ cp_parser_class_head (cp_parser* parser, /* At this point, we're going ahead with the class-specifier, even if some other problem occurs. */ cp_parser_commit_to_tentative_parse (parser); - if (virt_specifiers & VIRT_SPEC_OVERRIDE) - { - cp_parser_error (parser, - "cannot specify %<override%> for a class"); - type = error_mark_node; - goto out; - } /* Issue the error about the overly-qualified name now. */ if (qualified_p) { @@ -28558,6 +28777,16 @@ cp_parser_class_head (cp_parser* parser, DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location; if (type && (virt_specifiers & VIRT_SPEC_FINAL)) CLASSTYPE_FINAL (type) = 1; + if (type && (virt_specifiers & VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE)) + { + gcc_assert (!CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (type)); + CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (type) = 1; + } + if (type && (virt_specifiers & VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE)) + { + gcc_assert (!CLASSTYPE_REPLACEABLE_COMPUTED (type)); + CLASSTYPE_REPLACEABLE_BIT (type) = 1; + } out: parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; return type; @@ -28676,12 +28905,20 @@ cp_parser_member_specification_opt (cp_parser* parser) /* Parse a member-declaration. member-declaration: - decl-specifier-seq [opt] member-declarator-list [opt] ; - function-definition ; [opt] - :: [opt] nested-name-specifier template [opt] unqualified-id ; + attribute-specifier-seq [opt] decl-specifier-seq [opt] + member-declarator-list [opt] ; + function-definition + friend-type-declaration using-declaration + using-enum-declaration + static_assert-declaration + consteval-block-declaration template-declaration + explicit-specialization + deduction-guide alias-declaration + opaque-enum-declaration + empty-declaration member-declarator-list: member-declarator @@ -28700,12 +28937,7 @@ cp_parser_member_specification_opt (cp_parser* parser) member-declarator: declarator attributes [opt] pure-specifier [opt] declarator attributes [opt] constant-initializer [opt] - identifier [opt] attributes [opt] : constant-expression - - C++0x Extensions: - - member-declaration: - static_assert-declaration */ + identifier [opt] attributes [opt] : constant-expression */ static void cp_parser_member_declaration (cp_parser* parser) @@ -28718,16 +28950,17 @@ cp_parser_member_declaration (cp_parser* parser) cp_token *token = NULL; cp_token *decl_spec_token_start = NULL; cp_token *initializer_token_start = NULL; - int saved_pedantic; + int saved_pedantic, saved_long_long; bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; /* Check for the `__extension__' keyword. */ - if (cp_parser_extension_opt (parser, &saved_pedantic)) + if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long)) { /* Recurse. */ cp_parser_member_declaration (parser); /* Restore the old value of the PEDANTIC flag. */ pedantic = saved_pedantic; + warn_long_long = saved_long_long; return; } @@ -28804,6 +29037,12 @@ cp_parser_member_declaration (cp_parser* parser) return; } + if (cp_parser_next_tokens_are_consteval_block_p (parser)) + { + cp_parser_consteval_block (parser, /*member_p=*/true); + return; + } + parser->colon_corrects_to_scope_p = false; cp_omp_declare_simd_data odsd; @@ -31869,13 +32108,16 @@ cp_parser_skip_attributes_opt (cp_parser *parser, size_t n) present, and FALSE otherwise. *SAVED_PEDANTIC is set to the current value of the PEDANTIC flag, regardless of whether or not the `__extension__' keyword is present. The caller is responsible - for restoring the value of the PEDANTIC flag. */ + for restoring the value of the PEDANTIC flag. Similarly *SAVED_LONG_LONG + for warn_long_long flag. */ static bool -cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic) +cp_parser_extension_opt (cp_parser *parser, int *saved_pedantic, + int *saved_long_long) { /* Save the old value of the PEDANTIC flag. */ *saved_pedantic = pedantic; + *saved_long_long = warn_long_long; if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTENSION)) { @@ -31884,6 +32126,8 @@ cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic) /* We're not being pedantic while the `__extension__' keyword is in effect. */ pedantic = 0; + /* And we don't want -Wlong-long warning. */ + warn_long_long = 0; return true; } @@ -33558,7 +33802,9 @@ cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags, && cp_lexer_peek_token (parser->lexer)->type == CPP_TEMPLATE_ID) { auto_diagnostic_group d; - if (emit_diagnostic (cxx_dialect >= cxx20 ? DK_PEDWARN : DK_WARNING, + if (emit_diagnostic ((cxx_dialect >= cxx20 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning), input_location, OPT_Wtemplate_id_cdtor, "template-id not allowed for constructor in C++20")) inform (input_location, "remove the %qs", "< >"); @@ -35599,15 +35845,15 @@ cp_parser_token_starts_function_definition_p (cp_token* token) || token->keyword == RID_RETURN); } -/* Returns TRUE iff the next token is the ":" or "{" beginning a class +/* Returns TRUE iff the Nth token is the ":" or "{" beginning a class definition. */ static bool -cp_parser_next_token_starts_class_definition_p (cp_parser *parser) +cp_parser_nth_token_starts_class_definition_p (cp_parser *parser, size_t n) { cp_token *token; - token = cp_lexer_peek_token (parser->lexer); + token = cp_lexer_peek_nth_token (parser->lexer, n); return (token->type == CPP_OPEN_BRACE || (token->type == CPP_COLON && !parser->colon_doesnt_start_class_def_p)); @@ -35887,7 +36133,9 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc, return; bool seen_as_union = TREE_CODE (type) == UNION_TYPE; - if (seen_as_union != (class_key == union_type)) + if (class_key != typename_type + && TREE_CODE (type) != TYPENAME_TYPE + && seen_as_union != (class_key == union_type)) { auto_diagnostic_group d; if (permerror (input_location, "%qs tag used in naming %q#T", @@ -36661,7 +36909,7 @@ static void cp_parser_abort_tentative_parse (cp_parser* parser) { gcc_assert (parser->context->status != CP_PARSER_STATUS_KIND_COMMITTED - || errorcount > 0); + || seen_error ()); cp_parser_simulate_error (parser); /* Now, pretend that we want to see if the construct was successfully parsed. */ @@ -52898,11 +53146,14 @@ cp_parser_omp_error (cp_parser *parser, cp_token *pragma_tok, if (msg == NULL) msg = _("<message unknown at compile time>"); } + const enum diagnostics::kind diag_kind = (severity_fatal + ? diagnostics::kind::error + : diagnostics::kind::warning); if (msg) - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + emit_diagnostic (diag_kind, loc, 0, "%<pragma omp error%> encountered: %s", msg); else - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + emit_diagnostic (diag_kind, loc, 0, "%<pragma omp error%> encountered"); return false; } |