From 8f0104ff80f5fb9912b841855c4f9122d95b4c84 Mon Sep 17 00:00:00 2001 From: dodji Date: Fri, 7 Dec 2012 17:05:19 +0000 Subject: [PATCH] PR c++/54401 - Confusing diagnostics about type-alias at class scope MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Consider this invalid example given in the PR, where T is not defined: 1 template 2 struct X { 3 using type = T; 4 }; g++ yields the confusing diagnostics: test.cc:3:10: error: expected nested-name-specifier before 'type' using type = T; ^ test.cc:3:10: error: using-declaration for non-member at class scope test.cc:3:15: error: expected ';' before '=' token using type = T; ^ test.cc:3:15: error: expected unqualified-id before '=' token I think this is because in cp_parser_member_declaration we tentatively parse an alias declaration; we then have a somewhat meaningful diagnostic which alas is not emitted because we are parsing tentatively. As the parsing didn't succeed (because the input is invalid) we try to parse a using declaration, which fails as well; but then the diagnostic emitted is the one for the failed attempt at parsing a using declaration, not an alias declaration. Oops. The idea of this patch is to commit the tentative parse when we see the '=' token in the alias-declaration. That way any error encounter after that token is reported to the user. We are now getting the following output: test.cc:3:18: erreur: expected type-specifier before ‘T’ using type = T; ^ test.cc:3:18: erreur: ‘T’ does not name a type I don't really like the "before 'T'" there, but I think we maybe could revisit the format of what cp_parser_error emits in general, now that we have caret diagnostics; We could maybe do away with the "before T" altogether? In the mean time, it seems to me that this patch brings an improvement over what we already have in trunk, and the issue above could be addressed separately. Tested on x86_64-unknown-linux-gnu against trunk. gcc/cp/ * parser.c (cp_parser_alias_declaration): Commit to tentative parse when see the '=' token. Get out if the type-id is invalid. Update function comment. (cp_parser_member_declaration): Don't try to parse a using declaration if we know that we expected an alias declaration; that is, if we see the '=' token after the identifier. gcc/testsuite/ * g++.dg/cpp0x/alias-decl-28.C: New test. * g++.dg/cpp0x/alias-decl-16.C: Update. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@194306 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 10 ++++++++++ gcc/cp/parser.c | 25 +++++++++++++++++++++++-- gcc/testsuite/ChangeLog | 6 ++++++ gcc/testsuite/g++.dg/cpp0x/alias-decl-16.C | 2 +- gcc/testsuite/g++.dg/cpp0x/alias-decl-28.C | 7 +++++++ 5 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-28.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7bec9ca..81c2048 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2012-12-07 Dodji Seketeli + + PR c++/54401 + * parser.c (cp_parser_alias_declaration): Commit to tentative + parse when see the '=' token. Get out if the type-id is invalid. + Update function comment. + (cp_parser_member_declaration): Don't try to parse a using + declaration if we know that we expected an alias declaration; that + is, if we see the '=' token after the identifier. + 2012-12-06 Jason Merrill PR c++/54325 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 3566d74..3dc2ec6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -15295,6 +15295,8 @@ cp_parser_alias_declaration (cp_parser* parser) if (cp_parser_error_occurred (parser)) return error_mark_node; + cp_parser_commit_to_tentative_parse (parser); + /* Now we are going to parse the type-id of the declaration. */ /* @@ -15324,10 +15326,19 @@ cp_parser_alias_declaration (cp_parser* parser) if (parser->num_template_parameter_lists) parser->type_definition_forbidden_message = saved_message; + if (type == error_mark_node) + { + cp_parser_skip_to_end_of_block_or_statement (parser); + return error_mark_node; + } + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); if (cp_parser_error_occurred (parser)) - return error_mark_node; + { + cp_parser_skip_to_end_of_block_or_statement (parser); + return error_mark_node; + } /* A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name. It has @@ -19063,9 +19074,19 @@ cp_parser_member_declaration (cp_parser* parser) else { tree decl; + bool alias_decl_expected; cp_parser_parse_tentatively (parser); decl = cp_parser_alias_declaration (parser); - if (cp_parser_parse_definitely (parser)) + /* Note that if we actually see the '=' token after the + identifier, cp_parser_alias_declaration commits the + tentative parse. In that case, we really expects an + alias-declaration. Otherwise, we expect a using + declaration. */ + alias_decl_expected = + !cp_parser_uncommitted_to_tentative_parse_p (parser); + cp_parser_parse_definitely (parser); + + if (alias_decl_expected) finish_member_declaration (decl); else cp_parser_using_declaration (parser, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d50d73b..1fd69fa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2012-12-07 Dodji Seketeli + + PR c++/54401 + * g++.dg/cpp0x/alias-decl-28.C: New test. + * g++.dg/cpp0x/alias-decl-16.C: Update. + 2012-12-07 Martin Jambor PR tree-optimization/55590 diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-16.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-16.C index d66660a..ce6ad0a 100644 --- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-16.C +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-16.C @@ -23,6 +23,6 @@ template using A3 = enum B3 {b = 0;}; //{ dg-error "types may not be defined in alias template" } -A3 a3; +A3 a3; // { dg-error "'A3' does not name a type" } int main() { } diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-28.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-28.C new file mode 100644 index 0000000..086b5e5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-28.C @@ -0,0 +1,7 @@ +// Origin: PR c++/54401 +// { dg-do compile { target c++11 } } + +template +struct X { + using type = T; // { dg-error "expected type-specifier|does not name a type" } +}; -- 2.7.4