On 1/30/25 5:24 PM, Marek Polacek wrote:
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);
This looks like it will wrongly allow declaring an implicit template
within a function; you need a testcase with local extern declarations.
Incidentally, it seems odd that the override in
cp_parser_parameter_declaration is before an error early exit a few
lines below, moving it after that would avoid needing to clean it up on
that path.
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