Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/14? -- >8 -- This PR describes a few issues, both ICE and rejects-valid, but ultimately the problem is that we don't properly synthesize the second auto in:
int g (auto fp() -> auto) { return fp (); } since r12-5860, which disabled auto_is_implicit_function_template_parm_p in cp_parser_parameter_declaration after parsing the decl-specifier-seq. If there is no trailing auto, there is no problem. So we have to make sure auto_is_implicit_function_template_parm_p is properly set when parsing the trailing auto. A complication is that one can write: auto f (auto fp(auto fp2() -> auto) -> auto) -> auto; ~~~~~~~ where only the underlined auto should be synthesized. So when we parse a parameter-declaration-clause inside another parameter-declaration-clause, we should not enable the flag. We have no flags to keep track of such nesting, but I think I can walk current_binding_level to see if we find ourselves in such an unlikely scenario. PR c++/117778 gcc/cp/ChangeLog: * parser.cc (cp_parser_late_return_type_opt): Maybe override auto_is_implicit_function_template_parm_p. (cp_parser_parameter_declaration): Update commentary. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/lambda-generic-117778.C: New test. * g++.dg/cpp2a/abbrev-fn2.C: New test. * g++.dg/cpp2a/abbrev-fn3.C: New test. --- gcc/cp/parser.cc | 24 ++++++++- .../g++.dg/cpp1y/lambda-generic-117778.C | 12 +++++ gcc/testsuite/g++.dg/cpp2a/abbrev-fn2.C | 49 +++++++++++++++++++ gcc/testsuite/g++.dg/cpp2a/abbrev-fn3.C | 7 +++ 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-117778.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/abbrev-fn2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/abbrev-fn3.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 44515bb9074..89c5c2721a7 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -25514,6 +25514,25 @@ cp_parser_late_return_type_opt (cp_parser *parser, cp_declarator *declarator, /* Consume the ->. */ cp_lexer_consume_token (parser->lexer); + /* We may be in the context of parsing a parameter declaration, + namely, its declarator. auto_is_implicit_function_template_parm_p + will be disabled in that case. But for code like + + int g (auto fp() -> auto); + + we have to re-enable the flag for the trailing auto. However, that + only applies for the outermost trailing auto in a parameter clause; in + + int f2 (auto fp(auto fp2() -> auto) -> auto); + + the inner -> auto should not be synthesized. */ + int i = 0; + for (cp_binding_level *b = current_binding_level; + b->kind == sk_function_parms; b = b->level_chain) + ++i; + auto cleanup = make_temp_override + (parser->auto_is_implicit_function_template_parm_p, i == 2); + type = cp_parser_trailing_type_id (parser); } @@ -26283,8 +26302,9 @@ cp_parser_parameter_declaration (cp_parser *parser, type-constraint opt auto can be used as a decl-specifier of the decl-specifier-seq of a parameter-declaration of a function declaration or lambda-expression..." but we must not synthesize an implicit template - type parameter in its declarator. That is, in "void f(auto[auto{10}]);" - we want to synthesize only the first auto. */ + type parameter in its declarator (except the trailing-return-type). + That is, in "void f(auto[auto{10}]);" we want to synthesize only the + first auto. */ auto cleanup = make_temp_override (parser->auto_is_implicit_function_template_parm_p, false); diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-117778.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-117778.C new file mode 100644 index 00000000000..f377e3acc91 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-117778.C @@ -0,0 +1,12 @@ +// PR c++/117778 +// { dg-do compile { target c++14 } } + +auto l1 = [](auto (*fp)() -> auto) { return fp; }; +auto l2 = [](auto fp() -> auto) { return fp; }; +auto l3 = [](auto fp()) { return fp; }; +auto l4 = [](auto (*fp)()) { return fp; }; +auto l5 = [](auto fp() -> auto) -> auto { return fp; }; +auto l6 = [](auto fp(auto fp2()) -> auto) -> auto { return fp; }; // { dg-error ".auto. parameter not permitted" } +auto l7 = [](auto fp(auto fp2() -> auto) -> auto) -> auto { return fp; }; // { dg-error ".auto. parameter not permitted" } +auto l8 = [](int fp(auto fp2())) { return fp; }; // { dg-error ".auto. parameter not permitted" } +auto l9 = [](auto fp(auto fp2() -> auto) -> auto) { return fp; }; // { dg-error ".auto. parameter not permitted" } diff --git a/gcc/testsuite/g++.dg/cpp2a/abbrev-fn2.C b/gcc/testsuite/g++.dg/cpp2a/abbrev-fn2.C new file mode 100644 index 00000000000..902382651b8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/abbrev-fn2.C @@ -0,0 +1,49 @@ +// PR c++/117778 +// { dg-do run { target c++20 } } + +int +f (auto fp()) +{ + return fp (); +} + +int +g (auto fp() -> auto) +{ + return fp (); +} + +int +h (auto (*fp)() -> auto) +{ + return fp (); +} + +auto +fa (auto fp()) -> auto +{ + return fp (); +} + +auto +ga (auto fp() -> auto) -> auto +{ + return fp (); +} + +auto +ha (auto (*fp)() -> auto) -> auto +{ + return fp (); +} + +int bar() { return 42; } + +int +main () +{ + if (f (bar) != 42 || g (bar) != 42 || h (bar) != 42) + __builtin_abort (); + if (fa (bar) != 42 || ga (bar) != 42 || ha (bar) != 42) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/abbrev-fn3.C b/gcc/testsuite/g++.dg/cpp2a/abbrev-fn3.C new file mode 100644 index 00000000000..b47abdef2f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/abbrev-fn3.C @@ -0,0 +1,7 @@ +// PR c++/117778 +// { dg-do compile { target c++20 } } + +int f1 (auto fp(auto fp2())); // { dg-error ".auto. parameter not permitted" } +int f2 (auto fp(auto fp2() -> auto)); // { dg-error ".auto. parameter not permitted" } +auto f3 (auto fp() -> auto) -> auto; +auto f3 (auto fp(auto fp2() -> auto) -> auto) -> auto; // { dg-error ".auto. parameter not permitted" } base-commit: 1e819a997dd5507e52cafc540656fc15160322fd -- 2.48.1