Hello, Consider this invalid example given in the PR, where T is not defined:
1 template<typename> 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 detect in advance that we want to parse an alias declaration, parse it non-tentatively, and then if an error arises, emit it. I also changed cp_parser_alias_declaration to get out directly when it detects that the type-id is invalid, rather than going on nonetheless and emitting more (irrelevant) error diagnostics. 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_expecting_alias_declaration_p): New static function. (cp_parser_block_declaration): Use it. (cp_parser_member_declaration): Likewise. Don't parse the using declaration tentatively. (cp_parser_alias_declaration): Get out if the type-id is invalid. gcc/testsuite/ * g++.dg/cpp0x/alias-decl-23.C: New test. --- gcc/cp/parser.c | 38 +++++++++++++++++++++++------- gcc/testsuite/g++.dg/cpp0x/alias-decl-23.C | 7 ++++++ 2 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-23.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e8c0378..cab2d09 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1937,6 +1937,8 @@ static bool cp_parser_using_declaration (cp_parser *, bool); static void cp_parser_using_directive (cp_parser *); +static bool cp_parser_expecting_alias_declaration_p + (cp_parser*); static tree cp_parser_alias_declaration (cp_parser *); static void cp_parser_asm_definition @@ -10292,11 +10294,7 @@ cp_parser_block_declaration (cp_parser *parser, cp_parser_using_directive (parser); /* If the second token after 'using' is '=', then we have an alias-declaration. */ - else if (cxx_dialect >= cxx0x - && token2->type == CPP_NAME - && ((cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ) - || (cp_lexer_peek_nth_token (parser->lexer, 3)->keyword - == RID_ATTRIBUTE))) + else if (cp_parser_expecting_alias_declaration_p (parser)) cp_parser_alias_declaration (parser); /* Otherwise, it's a using-declaration. */ else @@ -15079,6 +15077,24 @@ cp_parser_using_declaration (cp_parser* parser, return true; } +/* Return TRUE if the coming tokens reasonably denote the beginning of + an alias declaration. */ + +static bool +cp_parser_expecting_alias_declaration_p (cp_parser* parser) +{ + if (cxx_dialect < cxx0x) + return false; + cp_parser_parse_tentatively (parser); + cp_parser_require_keyword (parser, RID_USING, RT_USING); + cp_parser_identifier (parser); + cp_parser_attributes_opt (parser); + cp_parser_require (parser, CPP_EQ, RT_EQ); + bool is_ok = !cp_parser_error_occurred (parser); + cp_parser_abort_tentative_parse (parser); + return is_ok; +} + /* Parse an alias-declaration. alias-declaration: @@ -15141,6 +15157,9 @@ 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) + return error_mark_node; + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); if (cp_parser_error_occurred (parser)) @@ -18849,10 +18868,11 @@ cp_parser_member_declaration (cp_parser* parser) else { tree decl; - cp_parser_parse_tentatively (parser); - decl = cp_parser_alias_declaration (parser); - if (cp_parser_parse_definitely (parser)) - finish_member_declaration (decl); + if (cp_parser_expecting_alias_declaration_p (parser)) + { + decl = cp_parser_alias_declaration (parser); + finish_member_declaration (decl); + } else cp_parser_using_declaration (parser, /*access_declaration_p=*/false); diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-23.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-23.C new file mode 100644 index 0000000..086b5e5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-23.C @@ -0,0 +1,7 @@ +// Origin: PR c++/54401 +// { dg-do compile { target c++11 } } + +template<typename> +struct X { + using type = T; // { dg-error "expected type-specifier|does not name a type" } +}; -- 1.7.11.4 -- Dodji