On 10/19/20 8:52 PM, Marek Polacek wrote:
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.
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
OK.
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.
---
gcc/cp/parser.c | 13 ++++++-------
gcc/testsuite/g++.dg/template/lookup16.C | 23 +++++++++++++++++++++++
2 files changed, 29 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/template/lookup16.C
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 7ec7d42773c..ecbd4b7d15a 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -23784,13 +23784,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");
@@ -23806,14 +23803,16 @@ cp_parser_class_name (cp_parser *parser,
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;
+ 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 00000000000..5b34c08282c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/lookup16.C
@@ -0,0 +1,23 @@
+// PR c++/94799
+// { dg-do compile { target c++11 } }
+
+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)
+{
+ auto r1 = b.operator typename A<T>::type();
+ auto r2 = b.operator typename A<T>::template A<T>::type();
+ auto r3 = b.operator typename B<T>::type();
+ auto r4 = b.operator typename B<T>::template A<T>::type();
+ return r1 + r2 + r3 + r4;
+}
+
+void bar()
+{
+ foo(A<int>());
+}
base-commit: 970d683f67777319990b30302a21a860990e2ec8