This patch makes the parser more robust in determining whether an 'auto' specifier that appears in a parameter declaration corresponds to a placeholder for a late return type, or corresponds to an implicit template parameter as for an abbreviated function template.
Bootstrap + regtest in progress on x86_64-pc-linux-gnu, will also test this change against Boost. OK to commit if testing succeeds? What about for GCC 4.9/5? gcc/cp/ChangeLog: PR c++/69139 * parser.c (cp_parser_simple_type_specifier): Make the check for disambiguating between an 'auto' placeholder and an implicit template parameter more robust. gcc/testsuite/ChangeLog: PR c++/69139 * g++.dg/cpp0x/auto47.C: New test. --- gcc/cp/parser.c | 33 +++++++++++++++++++++++---------- gcc/testsuite/g++.dg/cpp0x/auto47.C | 20 ++++++++++++++++++++ 2 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/auto47.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d03b0c9..56c834f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16032,20 +16032,33 @@ cp_parser_simple_type_specifier (cp_parser* parser, /* The 'auto' might be the placeholder return type for a function decl with trailing return type. */ bool have_trailing_return_fn_decl = false; - if (cp_lexer_peek_nth_token (parser->lexer, 2)->type - == CPP_OPEN_PAREN) + + cp_parser_parse_tentatively (parser); + cp_lexer_consume_token (parser->lexer); + while (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ) + && cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA) + && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN) + && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) { - cp_parser_parse_tentatively (parser); - cp_lexer_consume_token (parser->lexer); - cp_lexer_consume_token (parser->lexer); - if (cp_parser_skip_to_closing_parenthesis (parser, + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_skip_to_closing_parenthesis (parser, /*recovering*/false, /*or_comma*/false, - /*consume_paren*/true)) - have_trailing_return_fn_decl - = cp_lexer_next_token_is (parser->lexer, CPP_DEREF); - cp_parser_abort_tentative_parse (parser); + /*consume_paren*/true); + continue; + } + + if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) + { + have_trailing_return_fn_decl = true; + break; + } + + cp_lexer_consume_token (parser->lexer); } + cp_parser_abort_tentative_parse (parser); if (have_trailing_return_fn_decl) { diff --git a/gcc/testsuite/g++.dg/cpp0x/auto47.C b/gcc/testsuite/g++.dg/cpp0x/auto47.C new file mode 100644 index 0000000..08adf31 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/auto47.C @@ -0,0 +1,20 @@ +// PR c++/69139 +// { dg-do compile { target c++11 } } + +auto get(int) -> int { return {}; } +template <class R> int f(auto (*)(int) -> R) { return {}; } +int i = f(get); + +int foo1 (auto (int) -> char); + +int foo2 (auto f(int) -> char); + +int foo2 (auto (f)(int) -> char); + +int foo3 (auto (*f)(int) -> char); + +int foo4 (auto (*const **&f)(int) -> char); + +int foo5 (auto (*const **&f)(int, int *) -> char); + +int foo6 (auto (int) const -> char); // { dg-error "const" } -- 2.7.0.134.gf5046bd.dirty