diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 1da881e295b4f88e6a2a18200a76228b824e05f4..9b8be084452e7fd1162995e26b44f239a5abd087 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -25518,6 +25518,26 @@ 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 && !current_function_decl)); + type = cp_parser_trailing_type_id (parser); } @@ -26283,15 +26303,6 @@ cp_parser_parameter_declaration (cp_parser *parser, &decl_specifiers, &declares_class_or_enum); - /* [dcl.spec.auto.general]: "A placeholder-type-specifier of the form - 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. */ - auto cleanup = make_temp_override - (parser->auto_is_implicit_function_template_parm_p, false); - /* Complain about missing 'typename' or other invalid type names. */ if (!decl_specifiers.any_type_specifiers_p && cp_parser_parse_and_diagnose_invalid_type_name (parser)) @@ -26305,6 +26316,16 @@ cp_parser_parameter_declaration (cp_parser *parser, return NULL; } + /* [dcl.spec.auto.general]: "A placeholder-type-specifier of the form + 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 (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); + /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); 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 0000000000000000000000000000000000000000..f377e3acc912a687dfe8ddc08f8960e6e16694ae --- /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 0000000000000000000000000000000000000000..902382651b893d0f3f943b22d9871babb7e89f90 --- /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 0000000000000000000000000000000000000000..865fc5cd10d0277da01a4fe59ee88f39d6d531bf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/abbrev-fn3.C @@ -0,0 +1,15 @@ +// 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" } + +void +g () +{ + extern int e1 (auto fp()); // { dg-error ".auto. parameter not permitted" } + extern int e2 (auto fp() -> auto); // { dg-error ".auto. parameter not permitted" } + extern int e3 (auto fp(auto fp2() -> auto) -> auto); // { dg-error ".auto. parameter not permitted" } +}