From: Marek Polacek Date: Mon, 19 Oct 2020 22:13:42 +0000 (-0400) Subject: c++: Member template function lookup failure [PR94799] X-Git-Tag: upstream/12.2.0~12455 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=323dd4255203479d8c456b85513db4f8e0041d04;p=platform%2Fupstream%2Fgcc.git c++: Member template function lookup failure [PR94799] My earlier patch for this PR, r11-86, broke pybind11. That patch changed cp_parser_class_name to also consider the object expression scope (parser->context->object_type) to fix parsing of p->template A::foo(); // consider p's scope too Here we reject b.operator typename B::type(); because 'typename_p' in cp_parser_class_name uses 'scope', which means that 'typename_p' will be true for the example above. Then we create a TYPENAME_TYPE via make_typename_type, which fails when tsubsting it; the code basically created 'typename B::B' and then we complain that there is no member named 'B' in 'A'. So, when deciding if we should create a TYPENAME_TYPE, don't consider the object_type scope, like we did pre-r11-86. gcc/cp/ChangeLog: PR c++/94799 * parser.c (cp_parser_class_name): Use parser->scope when setting typename_p. gcc/testsuite/ChangeLog: PR c++/94799 * g++.dg/template/lookup16.C: New test. --- diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 80d903c..2340795 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -23794,13 +23794,10 @@ cp_parser_class_name (cp_parser *parser, bool enum_ok) { tree decl; - tree scope; - bool typename_p; - cp_token *token; tree identifier = NULL_TREE; /* All class-names start with an identifier. */ - token = cp_lexer_peek_token (parser->lexer); + cp_token *token = cp_lexer_peek_token (parser->lexer); if (token->type != CPP_NAME && token->type != CPP_TEMPLATE_ID) { cp_parser_error (parser, "expected class-name"); @@ -23816,14 +23813,16 @@ cp_parser_class_name (cp_parser *parser, where we first want to look up A::a in the class of the object expression, as per [basic.lookup.classref]. */ - scope = parser->scope ? parser->scope : parser->context->object_type; + tree scope = parser->scope ? parser->scope : parser->context->object_type; if (scope == error_mark_node) return error_mark_node; /* Any name names a type if we're following the `typename' keyword in a qualified name where the enclosing scope is type-dependent. */ - typename_p = (typename_keyword_p && scope && TYPE_P (scope) - && dependent_type_p (scope)); + const bool typename_p = (typename_keyword_p + && parser->scope + && TYPE_P (parser->scope) + && dependent_type_p (parser->scope)); /* Handle the common case (an identifier, but not a template-id) efficiently. */ if (token->type == CPP_NAME diff --git a/gcc/testsuite/g++.dg/template/lookup16.C b/gcc/testsuite/g++.dg/template/lookup16.C new file mode 100644 index 0000000..5b34c08 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/lookup16.C @@ -0,0 +1,23 @@ +// PR c++/94799 +// { dg-do compile { target c++11 } } + +template struct A { + typedef int type; + operator int(); +}; + +template using B = A; + +template typename B::type foo(B b) +{ + auto r1 = b.operator typename A::type(); + auto r2 = b.operator typename A::template A::type(); + auto r3 = b.operator typename B::type(); + auto r4 = b.operator typename B::template A::type(); + return r1 + r2 + r3 + r4; +} + +void bar() +{ + foo(A()); +}