Message ID | 20201020005202.64863-1-polacek@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: Member template function lookup failure [PR94799] | expand |
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 >
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>()); +}