From: Patrick Palka Date: Fri, 11 Aug 2023 17:26:02 +0000 (-0400) Subject: c++: dependently scoped template-id in type-req [PR110927] X-Git-Tag: basepoints/gcc-15~6978 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=63bd36be990f3b08fcee5b69718ef97c055fbb31;p=thirdparty%2Fgcc.git c++: dependently scoped template-id in type-req [PR110927] 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. --- 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);