From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.81]) by sourceware.org (Postfix) with ESMTP id 9D0C1385DC0A for ; Wed, 29 Apr 2020 03:55:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 9D0C1385DC0A Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-203-cMW3CT_sOiStvcRqa68Jjg-1; Tue, 28 Apr 2020 23:55:57 -0400 X-MC-Unique: cMW3CT_sOiStvcRqa68Jjg-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 372081005510 for ; Wed, 29 Apr 2020 03:55:56 +0000 (UTC) Received: from pdp-11.redhat.com (ovpn-119-124.rdu2.redhat.com [10.10.119.124]) by smtp.corp.redhat.com (Postfix) with ESMTP id BACA55D9E5; Wed, 29 Apr 2020 03:55:55 +0000 (UTC) From: Marek Polacek To: Jason Merrill , GCC Patches Subject: [PATCH] c++: Member template function lookup failure [PR94799] Date: Tue, 28 Apr 2020 23:55:49 -0400 Message-Id: <20200429035549.1981957-1-polacek@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-28.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 29 Apr 2020 03:56:01 -0000 Whew, this took a while. We fail to parse "p->template A::a()" (where p is of type A *) 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 thou= gh it's 7758 type-dependent. */ 7759 parser->context->object_type =3D unknown_type_node; with which cp_parser_template_name returns identifier 'A', cp_parser_class_= name then creates a TEMPLATE_ID_EXPR A, but then 23735 decl =3D 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. The "&& scope !=3D unknown_type_node" line in cp_parser_class_name is there for diagnostic purposes only (to avoid issuing a confusing error). Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? (Happy to defer to GCC 11 if this doesn't seem very safe.) =09PR c++/94799 =09* parser.c (cp_parser_postfix_dot_deref_expression): If we have =09a type-dependent object of class type, stash it to =09parser->context->object_type. =09(cp_parser_class_name): Consider object scope too. Don't call =09make_typename_type when the scope is unknown_type_node. =09* g++.dg/lookup/this1.C: Adjust dg-error. =09* g++.dg/template/lookup12.C: New test. =09* g++.dg/template/lookup13.C: New test. =09* g++.dg/template/lookup14.C: New test. --- gcc/cp/parser.c | 28 ++++++++++++++++++------ gcc/testsuite/g++.dg/lookup/this1.C | 2 +- gcc/testsuite/g++.dg/template/lookup12.C | 26 ++++++++++++++++++++++ gcc/testsuite/g++.dg/template/lookup13.C | 28 ++++++++++++++++++++++++ gcc/testsuite/g++.dg/template/lookup14.C | 11 ++++++++++ 5 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/lookup12.C create mode 100644 gcc/testsuite/g++.dg/template/lookup13.C create mode 100644 gcc/testsuite/g++.dg/template/lookup14.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e1f9786893a..b344721fb60 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7694,11 +7694,16 @@ cp_parser_postfix_dot_deref_expression (cp_parser *= parser, bool pseudo_destructor_p; tree scope =3D NULL_TREE; location_t start_loc =3D postfix_expression.get_start (); + tree type =3D TREE_TYPE (postfix_expression); =20 /* If this is a `->' operator, dereference the pointer. */ if (token_type =3D=3D CPP_DEREF) - postfix_expression =3D build_x_arrow (location, postfix_expression, -=09=09=09=09=09tf_warning_or_error); + { + if (type && POINTER_TYPE_P (type)) +=09type =3D TREE_TYPE (type); + postfix_expression =3D build_x_arrow (location, postfix_expression, +=09=09=09=09=09 tf_warning_or_error); + } /* Check to see whether or not the expression is type-dependent and not the current instantiation. */ dependent_p =3D type_dependent_object_expression_p (postfix_expression); @@ -7754,9 +7759,10 @@ cp_parser_postfix_dot_deref_expression (cp_parser *p= arser, } =20 if (dependent_p) - /* Tell cp_parser_lookup_name that there was an object, even though it= 's - type-dependent. */ - parser->context->object_type =3D unknown_type_node; + /* If we don't have a (type-dependent) object of class type, use + unknown_type_node to signal that there was an object. */ + parser->context->object_type =3D (type && CLASS_TYPE_P (type) +=09=09=09=09 ? type : unknown_type_node); =20 /* Assume this expression is not a pseudo-destructor access. */ pseudo_destructor_p =3D false; @@ -23625,8 +23631,15 @@ cp_parser_class_name (cp_parser *parser, } =20 /* PARSER->SCOPE can be cleared when parsing the template-arguments - to a template-id, so we save it here. */ - scope =3D parser->scope; + to a template-id, so we save it here. Consider object scope too, + so that make_typename_type below can use it (cp_parser_template_name + considers object scope also). This may happen with code like + + p->template A::a() + + where we first want to look up A::a in the class of the object + expression, as per [basic.lookup.classref]. */ + scope =3D parser->scope ? parser->scope : parser->context->object_type; if (scope =3D=3D error_mark_node) return error_mark_node; =20 @@ -23720,6 +23733,7 @@ cp_parser_class_name (cp_parser *parser, /* Check to see that it is really the name of a class. */ if (TREE_CODE (decl) =3D=3D TEMPLATE_ID_EXPR && identifier_p (TREE_OPERAND (decl, 0)) + && scope !=3D unknown_type_node && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) /* Situations like this: =20 diff --git a/gcc/testsuite/g++.dg/lookup/this1.C b/gcc/testsuite/g++.dg/loo= kup/this1.C index 20051bf7515..6b85cefcd37 100644 --- a/gcc/testsuite/g++.dg/lookup/this1.C +++ b/gcc/testsuite/g++.dg/lookup/this1.C @@ -4,5 +4,5 @@ struct A { template static void foo(); - static void bar() { this->A::foo<0>(); } // { dg-error "unavailable" } + static void bar() { this->A::foo<0>(); } // { dg-error "unavailable|no= t a class|expected" } }; diff --git a/gcc/testsuite/g++.dg/template/lookup12.C b/gcc/testsuite/g++.d= g/template/lookup12.C new file mode 100644 index 00000000000..fc5939ab0f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/lookup12.C @@ -0,0 +1,26 @@ +// PR c++/94799 - member template function lookup fails. + +template struct B { + void foo (); + int i; +}; + +template +struct D : public B { }; + +template +void fn (D d) +{ + d.template B::foo (); + d.template B::i =3D 42; + D().template B::foo (); + d.template D::template B::foo (); + d.template D::template B::i =3D 10; +} + +int +main () +{ + D d; + fn(d); +} diff --git a/gcc/testsuite/g++.dg/template/lookup13.C b/gcc/testsuite/g++.d= g/template/lookup13.C new file mode 100644 index 00000000000..a8c7e18a707 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/lookup13.C @@ -0,0 +1,28 @@ +// PR c++/94799 - member template function lookup fails. + +template +struct A { + int a() { + return 42; + } + + template struct X { typedef int type; }; +}; + +template +struct B { + int b(A *p) { +=09int i =3D 0; + i +=3D p->a(); + i +=3D p->template A::a(); + i +=3D p->template A::template A::a(); +=09i +=3D A().template A::a(); +=09return i; + } +}; + +int main() { + A a; + B b; + return b.b(&a); +} diff --git a/gcc/testsuite/g++.dg/template/lookup14.C b/gcc/testsuite/g++.d= g/template/lookup14.C new file mode 100644 index 00000000000..e1c945a6dca --- /dev/null +++ b/gcc/testsuite/g++.dg/template/lookup14.C @@ -0,0 +1,11 @@ +// PR c++/94799 - member template function lookup fails. + +template +struct A { }; + +template +void fn (A a) +{ + // Don't perform name lookup of foo when parsing this template. + a.template A::foo (); +} base-commit: 19667c82e479dc2bf8351588ed57aff90220b748 --=20 Marek Polacek =E2=80=A2 Red Hat, Inc. =E2=80=A2 300 A St, Boston, MA