From gcc version 7.2 and upwards this c++ code, using a member template function look-up, fails to compile: template <typename T> struct A { int a() { return 42; } }; template <typename T> struct B { int b(A<T> *p) { return p->template A<T>::a(); } }; int main() { A<int> a; B<int> b; return b.b(&a); } On gcc version 9.3.0 (Gentoo 9.3.0 p2), this output is generated: main.cc: In member function 'int B<T>::b(A<T>*)': main.cc:11:32: error: expected ';' before '::' token 11 | return p->template A<T>::a(); | ^~ | ; main.cc:11:34: error: '::a' has not been declared 11 | return p->template A<T>::a(); | ^ main.cc: In instantiation of 'int B<T>::b(A<T>*) [with T = int]': main.cc:18:18: required from here main.cc:11:28: error: 'A' is not a member template function 11 | return p->template A<T>::a(); | ~~~~~~~~~~~~^~~~ This code successfully compiles on new versions of clang, icc and msvc as well as gcc versions before 7.2.
Started with commit 1e5f79b61994f8ffccad62a58031f5937aa16ae3 Author: Jason Merrill <jason@redhat.com> Date: Wed Jun 28 15:41:36 2017 -0400 PR c++/54769 - wrong lookup of dependent template-name. * parser.c (cp_parser_template_name): Handle dependent object type. (cp_parser_nested_name_specifier_opt): Make template_keyword_p a parameter. (cp_parser_id_expression): Pass it. (cp_parser_diagnose_invalid_type_name): Handle TEMPLATE_ID_EXPR. From-SVN: r249752
Relevant threads: https://gcc.gnu.org/pipermail/gcc-patches/2017-June/478011.html https://gcc.gnu.org/pipermail/gcc-patches/2017-June/478247.html
Here we have "p->template A<T>::a()" but cp_parser_expression only parses the "p->template A<T>" part, so we complain that a ; isn't following. It's because cp_parser_template_name now considers the object scope: 16957 if (template_keyword_p) 16958 { 16959 tree scope = (parser->scope ? parser->scope 16960 : parser->context->object_type); 16961 if (scope && TYPE_P (scope) 16962 && (!CLASS_TYPE_P (scope) 16963 || (check_dependency_p && dependent_type_p (scope)))) 16964 { 16965 /* We're optimizing away the call to cp_parser_lookup_name, but 16966 we still need to do this. */ 16967 parser->context->object_type = NULL_TREE; 16968 return identifier; 16969 } 16970 } which here is unknown_type_node, signalling a type-dependent object: 7756 if (dependent_p) 7757 /* Tell cp_parser_lookup_name that there was an object, even though it's 7758 type-dependent. */ 7759 parser->context->object_type = unknown_type_node; so now cp_parser_template_name returns identifier 'A', cp_parser_class_name creates a TEMPLATE_ID_EXPR A<T>, but then 23735 decl = make_typename_type (scope, decl, tag_type, tf_error); fails because scope is NULL -- we've used the object scope instead. We probably have to look that up first.
Another test, where the name after . isn't an injected-class-name: template<typename T> struct B { void foo (); int i; }; template<typename T> struct D : public B<T> { }; template<typename T> void fn (D<T> d) { d.template B<T>::foo (); d.template B<T>::i = 42; }
Finally I have something that seems to work...
https://gcc.gnu.org/pipermail/gcc-patches/2020-April/544806.html
The master branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>: https://gcc.gnu.org/g:ef3479afc5ab415f00a53fc6f6a990df7f6a0747 commit r11-86-gef3479afc5ab415f00a53fc6f6a990df7f6a0747 Author: Marek Polacek <polacek@redhat.com> Date: Tue Apr 28 22:30:44 2020 -0400 c++: Member template function lookup failure [PR94799] Whew, this took a while. We fail to parse "p->template A<T>::a()" (where p is of type A<T> *) because since r249752 we treat the RHS of the -> as dependent and avoid a lookup in the enclosing context: since that rev cp_parser_template_name checks parser->context->object_type too, which here is unknown_type_node, signalling a type-dependent object: 7756 if (dependent_p) 7757 /* Tell cp_parser_lookup_name that there was an object, even though it's 7758 type-dependent. */ 7759 parser->context->object_type = unknown_type_node; with which cp_parser_template_name returns identifier 'A', cp_parser_class_name then creates a TEMPLATE_ID_EXPR A<T>, but then 23735 decl = make_typename_type (scope, decl, tag_type, tf_error); in cp_parser_class_name fails because scope is NULL. Then we return error_mark_node and parse errors ensue. I've tried various approaches, e.g. keeping TEMPLATE_ID_EXPR around instead of calling make_typename_type, which didn't work, whereupon I realized that since we don't want to perform name lookup if we've seen the template keyword and the scope is dependent, we can adjust parser->context->object_type and use the type of the object expression as the scope, even if it's type-dependent. This should be in line with [basic.lookup.classref]p4. If the postfix expression doesn't have a type, use typeof to carry its type. This typeof will be processed in tsubst/TYPENAME_TYPE. PR c++/94799 * parser.c (cp_parser_postfix_dot_deref_expression): If we have a type-dependent object of class type, stash it to parser->context->object_type. If the postfix expression doesn't have a type, use typeof. (cp_parser_class_name): Consider object scope too. (cp_parser_lookup_name): Remove code dealing with the case when object_type is unknown_type_node. * g++.dg/lookup/this1.C: Adjust dg-error. * g++.dg/template/lookup12.C: New test. * g++.dg/template/lookup13.C: New test. * g++.dg/template/lookup14.C: New test. * g++.dg/template/lookup15.C: New test.
Fixed on trunk so far. I plan to backport it to 10.2, maybe 9 too.
Hi Marek, your fix unfortunately breaks the following valid code (reduced from pybind11): ======================================================= template <typename> struct A { typedef int type; operator int(); }; template <typename T> using B = A<T>; template <typename T> typename B<T>::type foo(B<T> b) { return b.operator typename B<T>::type(); } void bar() { foo(A<int>()); } ======================================================= bug.cc: In instantiation of 'typename B<T>::type foo(B<T>) [with T = int; typename B<T>::type = int; B<T> = A<int>; B<T> = A<int>]': bug.cc:16:15: required from here bug.cc:11:36: error: no type named 'B' in 'struct A<int>' 11 | return b.operator typename B<T>::type(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
I see :(. I'll take a look, thanks for noticing.
Hi Marek, any news on this one? It's three months now... Or should I file a new bug for the regression on trunk?
(In reply to Volker Reichelt from comment #11) > Hi Marek, any news on this one? It's three months now... > Or should I file a new bug for the regression on trunk? No news yet. I've been largely away from upstream GCC for the past two months, but I should have more time now. I hope this will be fixed within the next couple of weeks. Sorry it's taking so long.
The fix may be as easy as this: --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -23812,8 +23812,8 @@ cp_parser_class_name (cp_parser *parser, /* 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)); + 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
Patch posted: https://gcc.gnu.org/pipermail/gcc-patches/2020-October/556517.html
*** Bug 97564 has been marked as a duplicate of this bug. ***
The master branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>: https://gcc.gnu.org/g:323dd4255203479d8c456b85513db4f8e0041d04 commit r11-4499-g323dd4255203479d8c456b85513db4f8e0041d04 Author: Marek Polacek <polacek@redhat.com> Date: Mon Oct 19 18:13:42 2020 -0400 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<T>::foo(); // consider p's scope too Here we reject b.operator typename B<T>::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<int>'. 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.
Should be fixed now. Sorry it took so long.