From 63bd36be990f3b08fcee5b69718ef97c055fbb31 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 11 Aug 2023 13:26:02 -0400 Subject: [PATCH] c++: dependently scoped template-id in type-req [PR110927] MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Here we're incorrectly rejecting the first type-requirement at parse time with concepts-requires35.C:14:56: error: ‘typename A::B’ is not a template [-fpermissive] We also incorrectly reject the second type-requirement at satisfaction time with concepts-requires35.C:17:34: error: ‘typename A::B’ names ‘template struct A::B’, which is not a type and similarly for the third type-requirement. This seems to happen only within a type-requirement; if we instead use e.g. an alias template then it works as expected. The difference ultimately seems to be that during parsing of a using-decl, we pass check_dependency_p=true to cp_parser_nested_name_specifier_opt whereas for a type-requirement we pass check_dependency_p=false. Passing =false causes cp_parser_template_id for the dependently-scoped template-id B to create a TYPE_DECL of TYPENAME_TYPE (with TYPENAME_IS_CLASS_P unexpectedly set in the last two cases) whereas passing =true causes it to return a TEMPLATE_ID_EXPR. We then call make_typename_type on this TYPE_DECL which does the wrong thing. Since there seems to be no justification for using check_dependency_p=false here, the simplest fix seems to be to pass check_dependency_p=true instead, matching the behavior of cp_parser_elaborated_type_specifier. PR c++/110927 gcc/cp/ChangeLog: * parser.cc (cp_parser_type_requirement): Pass check_dependency_p=true instead of =false. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-requires35.C: New test. --- gcc/cp/parser.cc | 4 +-- .../g++.dg/cpp2a/concepts-requires35.C | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 589ac879c6d3..2d27376d9882 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -30977,7 +30977,7 @@ cp_parser_type_requirement (cp_parser *parser) cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false); cp_parser_nested_name_specifier_opt (parser, /*typename_keyword_p=*/true, - /*check_dependency_p=*/false, + /*check_dependency_p=*/true, /*type_p=*/true, /*is_declaration=*/false); @@ -30987,7 +30987,7 @@ cp_parser_type_requirement (cp_parser *parser) cp_lexer_consume_token (parser->lexer); type = cp_parser_template_id (parser, /*template_keyword_p=*/true, - /*check_dependency=*/false, + /*check_dependency_p=*/true, /*tag_type=*/none_type, /*is_declaration=*/false); type = make_typename_type (parser->scope, type, typename_type, diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C new file mode 100644 index 000000000000..7023019ea418 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C @@ -0,0 +1,27 @@ +// PR c++/110927 +// { dg-do compile { target c++20 } } + +template +struct A { + template struct B { using type = B; }; + template using type = U; +}; + +template<> struct A { }; + +template +concept C1 = requires { typename A::template B::type; }; + +template +concept C2 = requires { typename A::template B; }; + +template +concept C3 = requires { typename A::template type; }; + +static_assert(C1); +static_assert(C2); +static_assert(C3); + +static_assert(!C1); +static_assert(!C2); +static_assert(!C3); -- 2.47.2