diff options
author | Marek Polacek <polacek@redhat.com> | 2020-04-28 22:30:44 -0400 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2020-05-05 10:19:09 -0400 |
commit | ef3479afc5ab415f00a53fc6f6a990df7f6a0747 (patch) | |
tree | ad74c7f5b8dac79c2b0797de6dfecd77b510e74f | |
parent | 811b7636cb8c10f1a550a76242b5666c7ae36da2 (diff) | |
download | gcc-ef3479afc5ab415f00a53fc6f6a990df7f6a0747.zip gcc-ef3479afc5ab415f00a53fc6f6a990df7f6a0747.tar.gz gcc-ef3479afc5ab415f00a53fc6f6a990df7f6a0747.tar.bz2 |
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.
-rw-r--r-- | gcc/cp/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/cp/parser.c | 26 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/this1.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/lookup12.C | 26 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/lookup13.C | 28 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/lookup14.C | 11 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/lookup15.C | 24 |
8 files changed, 128 insertions, 10 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a3ae5ef..ef82d93 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2020-05-05 Marek Polacek <polacek@redhat.com> + Jason Merrill <jason@redhat.com> + + 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. + 2020-05-04 Patrick Palka <ppalka@redhat.com> PR c++/94038 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 337f22d..5832025 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7754,9 +7754,14 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, } if (dependent_p) - /* Tell cp_parser_lookup_name that there was an object, even though it's - type-dependent. */ - parser->context->object_type = unknown_type_node; + { + tree type = TREE_TYPE (postfix_expression); + /* If we don't have a (type-dependent) object of class type, use + typeof to figure out the type of the object. */ + if (type == NULL_TREE) + type = finish_typeof (postfix_expression); + parser->context->object_type = type; + } /* Assume this expression is not a pseudo-destructor access. */ pseudo_destructor_p = false; @@ -23625,8 +23630,15 @@ cp_parser_class_name (cp_parser *parser, } /* PARSER->SCOPE can be cleared when parsing the template-arguments - to a template-id, so we save it here. */ - scope = 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<T>::a() + + where we first want to look up A<T>::a in the class of the object + expression, as per [basic.lookup.classref]. */ + scope = parser->scope ? parser->scope : parser->context->object_type; if (scope == error_mark_node) return error_mark_node; @@ -28340,10 +28352,6 @@ cp_parser_lookup_name (cp_parser *parser, tree name, decl = lookup_name_real (name, prefer_type_arg (tag_type, is_template), /*nonclass=*/0, /*block_p=*/true, is_namespace, 0); - if (object_type == unknown_type_node) - /* The object is type-dependent, so we can't look anything up; we used - this to get the DR 141 behavior. */ - object_type = NULL_TREE; parser->object_scope = object_type; parser->qualifying_scope = NULL_TREE; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 88f8d06..c23213a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2020-05-05 Marek Polacek <polacek@redhat.com> + + PR c++/94799 + * 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. + 2020-05-05 Martin Liska <mliska@suse.cz> * gcc.dg/spellcheck-options-22.c: New test. diff --git a/gcc/testsuite/g++.dg/lookup/this1.C b/gcc/testsuite/g++.dg/lookup/this1.C index 20051bf..6b85cef 100644 --- a/gcc/testsuite/g++.dg/lookup/this1.C +++ b/gcc/testsuite/g++.dg/lookup/this1.C @@ -4,5 +4,5 @@ struct A { template<int> static void foo(); - static void bar() { this->A::foo<0>(); } // { dg-error "unavailable" } + static void bar() { this->A::foo<0>(); } // { dg-error "unavailable|not a class|expected" } }; diff --git a/gcc/testsuite/g++.dg/template/lookup12.C b/gcc/testsuite/g++.dg/template/lookup12.C new file mode 100644 index 0000000..fc5939a --- /dev/null +++ b/gcc/testsuite/g++.dg/template/lookup12.C @@ -0,0 +1,26 @@ +// PR c++/94799 - member template function lookup fails. + +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; + D<T>().template B<T>::foo (); + d.template D<T>::template B<T>::foo (); + d.template D<T>::template B<T>::i = 10; +} + +int +main () +{ + D<int> d; + fn(d); +} diff --git a/gcc/testsuite/g++.dg/template/lookup13.C b/gcc/testsuite/g++.dg/template/lookup13.C new file mode 100644 index 0000000..a8c7e18 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/lookup13.C @@ -0,0 +1,28 @@ +// PR c++/94799 - member template function lookup fails. + +template <typename T> +struct A { + int a() { + return 42; + } + + template<typename> struct X { typedef int type; }; +}; + +template <typename T> +struct B { + int b(A<T> *p) { + int i = 0; + i += p->a(); + i += p->template A<T>::a(); + i += p->template A<T>::template A<T>::a(); + i += A<T>().template A<T>::a(); + return i; + } +}; + +int main() { + A<int> a; + B<int> b; + return b.b(&a); +} diff --git a/gcc/testsuite/g++.dg/template/lookup14.C b/gcc/testsuite/g++.dg/template/lookup14.C new file mode 100644 index 0000000..e1c945a --- /dev/null +++ b/gcc/testsuite/g++.dg/template/lookup14.C @@ -0,0 +1,11 @@ +// PR c++/94799 - member template function lookup fails. + +template<typename T> +struct A { }; + +template<typename T> +void fn (A<T> a) +{ + // Don't perform name lookup of foo when parsing this template. + a.template A<T>::foo (); +} diff --git a/gcc/testsuite/g++.dg/template/lookup15.C b/gcc/testsuite/g++.dg/template/lookup15.C new file mode 100644 index 0000000..c7f3ba0 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/lookup15.C @@ -0,0 +1,24 @@ +// PR c++/94799 - member template function lookup fails. + +template<typename> +struct M { void fn() { } }; + +M<int>* bar (int); +M<int> bar2 (int); + +template<typename T> +struct X : M<T> { + void xfn () + { + this->template M<T>::fn (); + bar((T)1)->template M<T>::fn (); + bar2((T)1).template M<T>::fn (); + } +}; + +int +main () +{ + X<int> x; + x.xfn(); +} |