aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2020-04-28 22:30:44 -0400
committerMarek Polacek <polacek@redhat.com>2020-05-05 10:19:09 -0400
commitef3479afc5ab415f00a53fc6f6a990df7f6a0747 (patch)
treead74c7f5b8dac79c2b0797de6dfecd77b510e74f /gcc
parent811b7636cb8c10f1a550a76242b5666c7ae36da2 (diff)
downloadgcc-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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog12
-rw-r--r--gcc/cp/parser.c26
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/g++.dg/lookup/this1.C2
-rw-r--r--gcc/testsuite/g++.dg/template/lookup12.C26
-rw-r--r--gcc/testsuite/g++.dg/template/lookup13.C28
-rw-r--r--gcc/testsuite/g++.dg/template/lookup14.C11
-rw-r--r--gcc/testsuite/g++.dg/template/lookup15.C24
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();
+}