Here when parsing the class-scope auto constrained by a qualified concept-id, we first tentatively parse the overall member-declaration as a deprecated access-declaration, during which we parse C<int> as a standalone TEMPLATE_ID_EXPR (not part of the auto) and end up emitting the bogus error
concepts-placeholder11.C:9:6: error: wrong number of template arguments (1, should be 2) 9 | N::C<int> auto f() { return 0; } | ^~~~~~ concepts-placeholder11.C:5:34: note: provided for ‘template<class, class> concept N::C’ 5 | template<class, class> concept C = true; | ^ from build_concept_id called from cp_parser_template_id_expr. We could fix this by adding a complain parameter to build_concept_id and passing tf_none when parsing tentatively. However, it seems we can fix this in a more general way that might benefit non-concepts code: when tentatively parsing an access-declaration, abort the parse early if the qualifying scope isn't possibly a class type, so that we avoid parsing C<int> as a TEMPLATE_ID_EXPR in the first place. This patch takes this latter approach. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? PR c++/107188 gcc/cp/ChangeLog: * parser.cc (cp_parser_using_declaration): Abort the tentative parse early if the scope of an access-declaration isn't possibly a class type. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-placeholder11.C: New test. --- gcc/cp/parser.cc | 5 +++++ gcc/testsuite/g++.dg/cpp2a/concepts-placeholder11.C | 10 ++++++++++ 2 files changed, 15 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder11.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index e8a50904243..ccacf6d7dd0 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -21670,6 +21670,11 @@ cp_parser_using_declaration (cp_parser* parser, cp_warn_deprecated_use_scopes (qscope); + if (access_declaration_p && !MAYBE_CLASS_TYPE_P (qscope)) + /* If the qualifying scope of an access-declaration isn't possibly + a class type then it must be invalid. */ + cp_parser_simulate_error (parser); + if (access_declaration_p && cp_parser_error_occurred (parser)) /* Something has already gone wrong; there's no need to parse further. Since an error has occurred, the return value of diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder11.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder11.C new file mode 100644 index 00000000000..61eef743bae --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder11.C @@ -0,0 +1,10 @@ +// PR c++/107188 +// { dg-do compile { target c++20 } } + +namespace N { + template<class, class> concept C = true; +} + +struct X { + N::C<int> auto f() { return 0; } +}; -- 2.39.0.rc2