Message ID | 20231214210227.1190177-1-polacek@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: fix parsing with auto(x) at block scope [PR112482] | expand |
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
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" } +}