The invalid test case in this PR highlights a bad interaction between the tentative_firewall and error recovery in cp_parser_decltype: the firewall makes cp_parser_skip_to_closing_parenthesis a no-op, and the parser does not make any progress, running "forever".
This patch calls cp_parser_commit_to_tentative_parse before initiating error recovery. Successfully tested on x86_64-pc-linux-gnu. PR c++/114858 gcc/cp/ChangeLog: * parser.cc (cp_parser_decltype): Commit tentative parse before initiating error recovery. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/decltype10.C: Adjust test expectation. * g++.dg/cpp2a/pr114858.C: New test. --- gcc/cp/parser.cc | 3 +++ gcc/testsuite/g++.dg/cpp0x/decltype10.C | 2 ++ gcc/testsuite/g++.dg/cpp2a/pr114858.C | 25 +++++++++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp2a/pr114858.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 4dd9474cf60..3a7c5ffe4c8 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -17508,6 +17508,9 @@ cp_parser_decltype (cp_parser *parser) /* Parse to the closing `)'. */ if (expr == error_mark_node || !parens.require_close (parser)) { + /* Commit to the tentative_firewall so we actually skip to the closing + parenthesis. */ + cp_parser_commit_to_tentative_parse (parser); cp_parser_skip_to_closing_parenthesis (parser, true, false, /*consume_paren=*/true); expr = error_mark_node; diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype10.C b/gcc/testsuite/g++.dg/cpp0x/decltype10.C index fe7247269f5..bd606e325d4 100644 --- a/gcc/testsuite/g++.dg/cpp0x/decltype10.C +++ b/gcc/testsuite/g++.dg/cpp0x/decltype10.C @@ -7,3 +7,5 @@ template<int> struct A }; template<int N> int A<N>::i(decltype (A::i; // { dg-error "expected" } + +// { dg-excess-errors "" } diff --git a/gcc/testsuite/g++.dg/cpp2a/pr114858.C b/gcc/testsuite/g++.dg/cpp2a/pr114858.C new file mode 100644 index 00000000000..6ffde4c3a2c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/pr114858.C @@ -0,0 +1,25 @@ +// PR c++/114858 +// { dg-do compile { target c++20 } } +// { dg-timeout 2 } + +template <class F> void g(F); +template <class... A> +auto h(A &&... a) -> decltype( + decltype(g< // { dg-error "expected primary-expression" } + decltype(g<decltype(g<decltype(g<decltype(g<decltype(g< + decltype(g<decltype(g<decltype(g<decltype(g<decltype(g<decltype(g< + decltype(g<decltype(g<decltype(g<decltype(g<decltype(g<decltype(g< + decltype(g<decltype(g<decltype(g<decltype(g<decltype(g<decltype(g< + decltype(g<decltype(g<decltype(g<decltype(g<decltype(g<decltype(g< + decltype(g<decltype(g< + decltype()>)(a)...) +{ + h([] {}); +} + +int main() { + h(); + return 0; +} + +// { dg-excess-errors "" } -- 2.44.0