@@ -1,3 +1,16 @@
+2020-04-07 Jakub Jelinek <jakub@redhat.com>
+
+ Backported from mainline
+ 2020-03-17 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/90995
+ * parser.c (cp_parser_enum_specifier): Use temp_override for
+ parser->colon_corrects_to_scope_p, replace goto out with return.
+ If scoped enum or enum with underlying type is not followed by
+ { or ;, call cp_parser_commit_to_tentative_parse before calling
+ cp_parser_error and make sure to return error_mark_node instead of
+ NULL_TREE. Formatting fixes.
+
2020-04-05 Marek Polacek <polacek@redhat.com>
2020-02-06 Marek Polacek <polacek@redhat.com>
@@ -18705,9 +18705,7 @@ cp_parser_enum_specifier (cp_parser* parser)
bool is_unnamed = false;
tree underlying_type = NULL_TREE;
cp_token *type_start_token = NULL;
- bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
-
- parser->colon_corrects_to_scope_p = false;
+ temp_override<bool> cleanup (parser->colon_corrects_to_scope_p, false);
/* Parse tentatively so that we can back up if we don't find a
enum-specifier. */
@@ -18747,24 +18745,24 @@ cp_parser_enum_specifier (cp_parser* parser)
push_deferring_access_checks (dk_no_check);
nested_name_specifier
- = cp_parser_nested_name_specifier_opt (parser,
- /*typename_keyword_p=*/true,
- /*check_dependency_p=*/false,
- /*type_p=*/false,
- /*is_declaration=*/false);
+ = cp_parser_nested_name_specifier_opt (parser,
+ /*typename_keyword_p=*/true,
+ /*check_dependency_p=*/false,
+ /*type_p=*/false,
+ /*is_declaration=*/false);
if (nested_name_specifier)
{
tree name;
identifier = cp_parser_identifier (parser);
- name = cp_parser_lookup_name (parser, identifier,
- enum_type,
- /*is_template=*/false,
- /*is_namespace=*/false,
- /*check_dependency=*/true,
- /*ambiguous_decls=*/NULL,
- input_location);
+ name = cp_parser_lookup_name (parser, identifier,
+ enum_type,
+ /*is_template=*/false,
+ /*is_namespace=*/false,
+ /*check_dependency=*/true,
+ /*ambiguous_decls=*/NULL,
+ input_location);
if (name && name != error_mark_node)
{
type = TREE_TYPE (name);
@@ -18844,23 +18842,21 @@ cp_parser_enum_specifier (cp_parser* parser)
{
if (cxx_dialect < cxx11 || (!scoped_enum_p && !underlying_type))
{
+ if (has_underlying_type)
+ cp_parser_commit_to_tentative_parse (parser);
cp_parser_error (parser, "expected %<{%>");
if (has_underlying_type)
- {
- type = NULL_TREE;
- goto out;
- }
+ return error_mark_node;
}
/* An opaque-enum-specifier must have a ';' here. */
if ((scoped_enum_p || underlying_type)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
+ if (has_underlying_type)
+ cp_parser_commit_to_tentative_parse (parser);
cp_parser_error (parser, "expected %<;%> or %<{%>");
if (has_underlying_type)
- {
- type = NULL_TREE;
- goto out;
- }
+ return error_mark_node;
}
}
@@ -18876,9 +18872,7 @@ cp_parser_enum_specifier (cp_parser* parser)
push_scope (nested_name_specifier);
}
else if (TREE_CODE (nested_name_specifier) == NAMESPACE_DECL)
- {
- push_nested_namespace (nested_name_specifier);
- }
+ push_nested_namespace (nested_name_specifier);
}
/* Issue an error message if type-definitions are forbidden here. */
@@ -19038,12 +19032,8 @@ cp_parser_enum_specifier (cp_parser* parser)
pop_scope (nested_name_specifier);
}
else if (TREE_CODE (nested_name_specifier) == NAMESPACE_DECL)
- {
- pop_nested_namespace (nested_name_specifier);
- }
+ pop_nested_namespace (nested_name_specifier);
}
- out:
- parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
return type;
}
@@ -1,3 +1,11 @@
+2020-04-07 Jakub Jelinek <jakub@redhat.com>
+
+ Backported from mainline
+ 2020-03-17 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/90995
+ * g++.dg/cpp0x/enum40.C: New test.
+
2020-04-07 Jakub Jelinek <jakub@redhat.com>
PR target/94500
new file mode 100644
@@ -0,0 +1,26 @@
+// PR c++/90995
+// { dg-do compile { target c++11 } }
+
+void
+foo ()
+{
+ enum : int a alignas; // { dg-error "expected" }
+}
+
+void
+bar ()
+{
+ enum : int a; // { dg-error "expected" }
+}
+
+void
+baz ()
+{
+ enum class a : int b alignas; // { dg-error "expected" }
+}
+
+void
+qux ()
+{
+ enum class a : int b; // { dg-error "expected" }
+}
Hi! I've backported following 21 commits from trunk to 9.4, bootstrapped/regtested on x86_64-linux and i686-linux and committed to 9 branch. Jakub From 980a7a0be5a114e285c49ab05ac70881e4f27fc3 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek <jakub@redhat.com> Date: Tue, 17 Mar 2020 21:21:16 +0100 Subject: [PATCH] c++: Fix parsing of invalid enum specifiers [PR90995] The testcase shows some accepts-invalid (the ones without alignas) and ice-on-invalid-code (the ones with alignas) cases. If the enum doesn't have an underlying type and is not a definition, the caller retries to parse it as elaborated type specifier. E.g. for enum struct S s it will then pedwarn that elaborated type specifier shouldn't have the struct/class keywords. The problem is if the enum specifier is not followed by { when it has underlying type. In that case we have already called cp_parser_parse_definitely to end the tentative parsing started at the beginning of cp_parser_enum_specifier. But the cp_parser_error (parser, "expected %<;%> or %<{%>"); doesn't emit any error because the whole function is called from yet another tentative parse and the caller starts parsing the elaborated type specifier where the cp_parser_enum_specifier stopped (i.e. after the underlying type token(s)). The ultimate caller than commits the tentative parsing (and even if it wouldn't, it wouldn't know what kind of error to report). I think after seeing enum {,struct,class} : type not being followed by { or ;, there is no reason not to report it right away, as it can't be valid C++, which is what the patch does. Not sure if we shouldn't also return error_mark_node instead of NULL_TREE, so that the caller doesn't try to parse it as elaborated type specifier (the patch doesn't do that right now). Furthermore, while reading the code, I've noticed that parser->colon_corrects_to_scope_p is saved and set to false at the start of the function, but not restored back in some cases. Don't have a testcase where this would be a problem, but it just seems wrong. Either we can in the two spots replace return NULL_TREE; with { type = NULL_TREE; goto out; } or we could perhaps abuse warning_sentinel or create a special class with dtor to clean the flag up. And lastly, I've fixed some formatting issues in the function while reading it. 2020-03-17 Jakub Jelinek <jakub@redhat.com> PR c++/90995 * parser.c (cp_parser_enum_specifier): Use temp_override for parser->colon_corrects_to_scope_p, replace goto out with return. If scoped enum or enum with underlying type is not followed by { or ;, call cp_parser_commit_to_tentative_parse before calling cp_parser_error and make sure to return error_mark_node instead of NULL_TREE. Formatting fixes. * g++.dg/cpp0x/enum40.C: New test. --- gcc/cp/ChangeLog | 13 ++++++++ gcc/cp/parser.c | 52 ++++++++++++----------------- gcc/testsuite/ChangeLog | 8 +++++ gcc/testsuite/g++.dg/cpp0x/enum40.C | 26 +++++++++++++++ 4 files changed, 68 insertions(+), 31 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/enum40.C