c++: fix parsing with auto(x) at block scope [PR112482]
Checks
Commit Message
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
This is sort of like r14-5514, but at block scope. Consider
struct A { A(int, int); };
void
g (int a)
{
A bar(auto(a), 42); // not a fn decl
}
where we emit error: 'auto' parameter not permitted in this context
which is bogus -- bar doesn't declare a function, so the auto is OK,
but we don't know it till we've seen the second argument. The error
comes from grokdeclarator invoked just after we've parsed the auto(a).
A possible approach seems to be to delay the auto parameter checking
and only check once we know we are indeed dealing with a function
declaration. For tparms, we should still emit the error right away.
PR c++/112482
gcc/cp/ChangeLog:
* decl.cc (grokdeclarator): Do not issue the auto parameter error while
tentatively parsing a function parameter.
* parser.cc (cp_parser_parameter_declaration_clause): Check it here.
gcc/testsuite/ChangeLog:
* g++.dg/cpp23/auto-fncast15.C: New test.
---
gcc/cp/decl.cc | 13 +++++++++++--
gcc/cp/parser.cc | 17 +++++++++++++++--
gcc/testsuite/g++.dg/cpp23/auto-fncast15.C | 21 +++++++++++++++++++++
3 files changed, 47 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast15.C
base-commit: 767e2674875139ac8f354ceee655c1a9561b9779
Comments
On 12/14/23 16:02, Marek Polacek wrote:
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
OK.
> -- >8 --
> This is sort of like r14-5514, but at block scope. Consider
>
> struct A { A(int, int); };
> void
> g (int a)
> {
> A bar(auto(a), 42); // not a fn decl
> }
>
> where we emit error: 'auto' parameter not permitted in this context
> which is bogus -- bar doesn't declare a function, so the auto is OK,
> but we don't know it till we've seen the second argument. The error
> comes from grokdeclarator invoked just after we've parsed the auto(a).
>
> A possible approach seems to be to delay the auto parameter checking
> and only check once we know we are indeed dealing with a function
> declaration. For tparms, we should still emit the error right away.
>
> PR c++/112482
>
> gcc/cp/ChangeLog:
>
> * decl.cc (grokdeclarator): Do not issue the auto parameter error while
> tentatively parsing a function parameter.
> * parser.cc (cp_parser_parameter_declaration_clause): Check it here.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp23/auto-fncast15.C: New test.
> ---
> gcc/cp/decl.cc | 13 +++++++++++--
> gcc/cp/parser.cc | 17 +++++++++++++++--
> gcc/testsuite/g++.dg/cpp23/auto-fncast15.C | 21 +++++++++++++++++++++
> 3 files changed, 47 insertions(+), 4 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast15.C
>
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 4d17ead123a..1ffe4c82748 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -14203,6 +14203,7 @@ grokdeclarator (const cp_declarator *declarator,
> tree auto_node = type_uses_auto (type);
> if (auto_node && !(cxx_dialect >= cxx17 && template_parm_flag))
> {
> + bool err_p = true;
> if (cxx_dialect >= cxx14)
> {
> if (decl_context == PARM && AUTO_IS_DECLTYPE (auto_node))
> @@ -14221,13 +14222,21 @@ grokdeclarator (const cp_declarator *declarator,
> "abbreviated function template");
> inform (DECL_SOURCE_LOCATION (c), "%qD declared here", c);
> }
> - else
> + else if (decl_context == CATCHPARM || template_parm_flag)
> error_at (typespec_loc,
> "%<auto%> parameter not permitted in this context");
> + else
> + /* Do not issue an error while tentatively parsing a function
> + parameter: for T t(auto(a), 42);, when we just saw the 1st
> + parameter, we don't know yet that this construct won't be
> + a function declaration. Defer the checking to
> + cp_parser_parameter_declaration_clause. */
> + err_p = false;
> }
> else
> error_at (typespec_loc, "parameter declared %<auto%>");
> - type = error_mark_node;
> + if (err_p)
> + type = error_mark_node;
> }
>
> /* A parameter declared as an array of T is really a pointer to T.
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 58e910d64af..e4fbab1bab5 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -25102,8 +25102,21 @@ cp_parser_parameter_declaration_clause (cp_parser* parser,
> committed yet, nor should we. Pushing here will detect the error
> of redefining a parameter. */
> if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
> - for (tree p : pending_decls)
> - pushdecl (p);
> + {
> + for (tree p : pending_decls)
> + pushdecl (p);
> +
> + /* Delayed checking of auto parameters. */
> + if (!parser->auto_is_implicit_function_template_parm_p
> + && cxx_dialect >= cxx14)
> + for (tree p = parameters; p; p = TREE_CHAIN (p))
> + if (type_uses_auto (TREE_TYPE (TREE_VALUE (p))))
> + {
> + error_at (location_of (TREE_VALUE (p)),
> + "%<auto%> parameter not permitted in this context");
> + TREE_TYPE (TREE_VALUE (p)) = error_mark_node;
> + }
> + }
>
> /* Finish the parameter list. */
> if (!ellipsis_p)
> diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast15.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast15.C
> new file mode 100644
> index 00000000000..deb1efcc46c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast15.C
> @@ -0,0 +1,21 @@
> +// PR c++/112482
> +// { dg-do compile { target c++23 } }
> +// { dg-options "-Wno-vexing-parse" }
> +
> +void foo (auto i, auto j);
> +
> +struct A {
> + A(int,int);
> +};
> +
> +void
> +g (int a)
> +{
> + A b1(auto(42), auto(42));
> + A b2(auto(a), auto(42));
> + A b3(auto(42), auto(a));
> + A b4(auto(a), // { dg-error "13:'auto' parameter" }
> + auto(a2)); // { dg-error "13:'auto' parameter" }
> + int v1(auto(42));
> + int fn1(auto(a)); // { dg-error "16:'auto' parameter" }
> +}
>
> base-commit: 767e2674875139ac8f354ceee655c1a9561b9779
@@ -14203,6 +14203,7 @@ grokdeclarator (const cp_declarator *declarator,
tree auto_node = type_uses_auto (type);
if (auto_node && !(cxx_dialect >= cxx17 && template_parm_flag))
{
+ bool err_p = true;
if (cxx_dialect >= cxx14)
{
if (decl_context == PARM && AUTO_IS_DECLTYPE (auto_node))
@@ -14221,13 +14222,21 @@ grokdeclarator (const cp_declarator *declarator,
"abbreviated function template");
inform (DECL_SOURCE_LOCATION (c), "%qD declared here", c);
}
- else
+ else if (decl_context == CATCHPARM || template_parm_flag)
error_at (typespec_loc,
"%<auto%> parameter not permitted in this context");
+ else
+ /* Do not issue an error while tentatively parsing a function
+ parameter: for T t(auto(a), 42);, when we just saw the 1st
+ parameter, we don't know yet that this construct won't be
+ a function declaration. Defer the checking to
+ cp_parser_parameter_declaration_clause. */
+ err_p = false;
}
else
error_at (typespec_loc, "parameter declared %<auto%>");
- type = error_mark_node;
+ if (err_p)
+ type = error_mark_node;
}
/* A parameter declared as an array of T is really a pointer to T.
@@ -25102,8 +25102,21 @@ cp_parser_parameter_declaration_clause (cp_parser* parser,
committed yet, nor should we. Pushing here will detect the error
of redefining a parameter. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
- for (tree p : pending_decls)
- pushdecl (p);
+ {
+ for (tree p : pending_decls)
+ pushdecl (p);
+
+ /* Delayed checking of auto parameters. */
+ if (!parser->auto_is_implicit_function_template_parm_p
+ && cxx_dialect >= cxx14)
+ for (tree p = parameters; p; p = TREE_CHAIN (p))
+ if (type_uses_auto (TREE_TYPE (TREE_VALUE (p))))
+ {
+ error_at (location_of (TREE_VALUE (p)),
+ "%<auto%> parameter not permitted in this context");
+ TREE_TYPE (TREE_VALUE (p)) = error_mark_node;
+ }
+ }
/* Finish the parameter list. */
if (!ellipsis_p)
new file mode 100644
@@ -0,0 +1,21 @@
+// PR c++/112482
+// { dg-do compile { target c++23 } }
+// { dg-options "-Wno-vexing-parse" }
+
+void foo (auto i, auto j);
+
+struct A {
+ A(int,int);
+};
+
+void
+g (int a)
+{
+ A b1(auto(42), auto(42));
+ A b2(auto(a), auto(42));
+ A b3(auto(42), auto(a));
+ A b4(auto(a), // { dg-error "13:'auto' parameter" }
+ auto(a2)); // { dg-error "13:'auto' parameter" }
+ int v1(auto(42));
+ int fn1(auto(a)); // { dg-error "16:'auto' parameter" }
+}