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