Message ID | 20230405165927.1987914-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: 'typename T::X' vs 'struct T::X' lookup [PR109420] | expand |
On Wed, 5 Apr 2023, Patrick Palka wrote: > r13-6098-g46711ff8e60d64 made make_typename_type no longer ignore > non-types during the lookup, unless the TYPENAME_TYPE in question was > followed by the :: scope resolution operator. But there is another > exception to this rule: we need to ignore non-types during the lookup > also if the TYPENAME_TYPE was named with a tag other than 'typename', > such as 'struct' or 'enum', as per [dcl.type.elab]/5. > > This patch implements this additional exception. It occurred to me that > the tf_qualifying_scope flag is probably unnecessary if we'd use the > scope_type tag more thoroughly, but that requires parser changes that > are probably too risky at this stage. (I'm working on addressing the > FIXME/TODOs here for GCC 14.) > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk? > > PR c++/109420 > > gcc/cp/ChangeLog: > > * decl.cc (make_typename_type): Also ignore non-types during > the lookup if tag_type is something other than none_type or > typename_type. > * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or > enum_type as tag_type to make_typename_type as appropriate > instead of always passing typename_type. > > gcc/testsuite/ChangeLog: > > * g++.dg/template/typename27.C: New test. > --- > gcc/cp/decl.cc | 9 ++++++++- > gcc/cp/pt.cc | 9 ++++++++- > gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ > 3 files changed, 35 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/template/typename27.C > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > index 5369714f9b3..a0a20c5accc 100644 > --- a/gcc/cp/decl.cc > +++ b/gcc/cp/decl.cc > @@ -4307,7 +4307,14 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, > lookup will stop when we hit a dependent base. */ > if (!dependent_scope_p (context)) > { > - bool want_type = (complain & tf_qualifying_scope); > + /* As per [dcl.type.elab]/5 and [temp.res.general]/3, ignore non-types if > + the tag corresponds to a class-key or 'enum' (or is scope_type), or if > + this typename is followed by :: as per [basic.lookup.qual.general]/1. > + TODO: If we'd set the scope_type tag accurately on all TYPENAME_TYPEs > + that are followed by :: then we wouldn't need the tf_qualifying_scope > + flag. */ > + bool want_type = (tag_type != none_type && tag_type != typename_type) > + || (complain & tf_qualifying_scope); Here's v2 which just slightly improves this comment. I reckon [basic.lookup.elab] is a better reference than [dcl.type.elab]/5 for justifying why the lookup should be type-only for class-key and 'enum' TYPENAME_TYPEs. -- >8 -- PR c++/109420 gcc/cp/ChangeLog: * decl.cc (make_typename_type): Also ignore non-types during the lookup if tag_type corresponds to an elaborated-type-specifier. * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or enum_type as tag_type to make_typename_type as appropriate instead of always passing typename_type. gcc/testsuite/ChangeLog: * g++.dg/template/typename27.C: New test. --- gcc/cp/decl.cc | 12 +++++++++++- gcc/cp/pt.cc | 9 ++++++++- gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/typename27.C diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 5369714f9b3..772c059dc2c 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -4307,7 +4307,17 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, lookup will stop when we hit a dependent base. */ if (!dependent_scope_p (context)) { - bool want_type = (complain & tf_qualifying_scope); + /* We generally don't ignore non-types during TYPENAME_TYPE lookup + (as per [temp.res.general]/3), unless + - the tag corresponds to a class-key or 'enum' so + [basic.lookup.elab] applies, or + - the tag corresponds to scope_type or tf_qualifying_scope is + set so [basic.lookup.qual]/1 applies. + TODO: If we'd set/track the scope_type tag thoroughly on all + TYPENAME_TYPEs that are followed by :: then we wouldn't need the + tf_qualifying_scope flag. */ + bool want_type = (tag_type != none_type && tag_type != typename_type) + || (complain & tf_qualifying_scope); t = lookup_member (context, name, /*protect=*/2, want_type, complain); } else diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 821e0035c08..09559c88f29 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -16580,9 +16580,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) return error_mark_node; } + /* FIXME: TYPENAME_IS_CLASS_P conflates 'union' vs 'struct' vs 'class' + tags. TYPENAME_TYPE should probably remember the exact tag that + was written. */ + enum tag_types tag + = TYPENAME_IS_CLASS_P (t) ? class_type + : TYPENAME_IS_ENUM_P (t) ? enum_type + : typename_type; tsubst_flags_t tcomplain = complain | tf_keep_type_decl; tcomplain |= tst_ok_flag | qualifying_scope_flag; - f = make_typename_type (ctx, f, typename_type, tcomplain); + f = make_typename_type (ctx, f, tag, tcomplain); if (f == error_mark_node) return f; if (TREE_CODE (f) == TYPE_DECL) diff --git a/gcc/testsuite/g++.dg/template/typename27.C b/gcc/testsuite/g++.dg/template/typename27.C new file mode 100644 index 00000000000..61b3efd998e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typename27.C @@ -0,0 +1,19 @@ +// PR c++/109420 + +struct A { + struct X { }; + int X; +}; + +struct B { + enum E { }; + enum F { E }; +}; + +template<class T, class U> +void f() { + struct T::X x; // OK, lookup ignores the data member 'int A::X' + enum U::E e; // OK, lookup ignores the enumerator 'B::F::E' +} + +template void f<A, B>();
On Wed, Apr 5, 2023 at 10:32 AM Patrick Palka via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > On Wed, 5 Apr 2023, Patrick Palka wrote: > > > r13-6098-g46711ff8e60d64 made make_typename_type no longer ignore > > non-types during the lookup, unless the TYPENAME_TYPE in question was > > followed by the :: scope resolution operator. But there is another > > exception to this rule: we need to ignore non-types during the lookup > > also if the TYPENAME_TYPE was named with a tag other than 'typename', > > such as 'struct' or 'enum', as per [dcl.type.elab]/5. > > > > This patch implements this additional exception. It occurred to me that > > the tf_qualifying_scope flag is probably unnecessary if we'd use the > > scope_type tag more thoroughly, but that requires parser changes that > > are probably too risky at this stage. (I'm working on addressing the > > FIXME/TODOs here for GCC 14.) > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > > trunk? > > > > PR c++/109420 > > > > gcc/cp/ChangeLog: > > > > * decl.cc (make_typename_type): Also ignore non-types during > > the lookup if tag_type is something other than none_type or > > typename_type. > > * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or > > enum_type as tag_type to make_typename_type as appropriate > > instead of always passing typename_type. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/template/typename27.C: New test. > > --- > > gcc/cp/decl.cc | 9 ++++++++- > > gcc/cp/pt.cc | 9 ++++++++- > > gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ > > 3 files changed, 35 insertions(+), 2 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/template/typename27.C > > > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > > index 5369714f9b3..a0a20c5accc 100644 > > --- a/gcc/cp/decl.cc > > +++ b/gcc/cp/decl.cc > > @@ -4307,7 +4307,14 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, > > lookup will stop when we hit a dependent base. */ > > if (!dependent_scope_p (context)) > > { > > - bool want_type = (complain & tf_qualifying_scope); > > + /* As per [dcl.type.elab]/5 and [temp.res.general]/3, ignore non-types if > > + the tag corresponds to a class-key or 'enum' (or is scope_type), or if > > + this typename is followed by :: as per [basic.lookup.qual.general]/1. > > + TODO: If we'd set the scope_type tag accurately on all TYPENAME_TYPEs > > + that are followed by :: then we wouldn't need the tf_qualifying_scope > > + flag. */ > > + bool want_type = (tag_type != none_type && tag_type != typename_type) > > + || (complain & tf_qualifying_scope); > > Here's v2 which just slightly improves this comment. I reckon [basic.lookup.elab] > is a better reference than [dcl.type.elab]/5 for justifying why the > lookup should be type-only for class-key and 'enum' TYPENAME_TYPEs. > > -- >8 -- > > PR c++/109420 > > gcc/cp/ChangeLog: > > * decl.cc (make_typename_type): Also ignore non-types during the > lookup if tag_type corresponds to an elaborated-type-specifier. > * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or > enum_type as tag_type to make_typename_type as appropriate > instead of always passing typename_type. > > gcc/testsuite/ChangeLog: > > * g++.dg/template/typename27.C: New test. > --- > gcc/cp/decl.cc | 12 +++++++++++- > gcc/cp/pt.cc | 9 ++++++++- > gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ > 3 files changed, 38 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/template/typename27.C > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > index 5369714f9b3..772c059dc2c 100644 > --- a/gcc/cp/decl.cc > +++ b/gcc/cp/decl.cc > @@ -4307,7 +4307,17 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, > lookup will stop when we hit a dependent base. */ > if (!dependent_scope_p (context)) > { > - bool want_type = (complain & tf_qualifying_scope); > + /* We generally don't ignore non-types during TYPENAME_TYPE lookup > + (as per [temp.res.general]/3), unless > + - the tag corresponds to a class-key or 'enum' so > + [basic.lookup.elab] applies, or > + - the tag corresponds to scope_type or tf_qualifying_scope is > + set so [basic.lookup.qual]/1 applies. > + TODO: If we'd set/track the scope_type tag thoroughly on all > + TYPENAME_TYPEs that are followed by :: then we wouldn't need the > + tf_qualifying_scope flag. */ > + bool want_type = (tag_type != none_type && tag_type != typename_type) > + || (complain & tf_qualifying_scope); > t = lookup_member (context, name, /*protect=*/2, want_type, complain); > } > else > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index 821e0035c08..09559c88f29 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -16580,9 +16580,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) > return error_mark_node; > } > > + /* FIXME: TYPENAME_IS_CLASS_P conflates 'union' vs 'struct' vs 'class' > + tags. TYPENAME_TYPE should probably remember the exact tag that > + was written. */ Yes I had a patch for that but I submitted during stage 4 of GCC 12 and never updated again during stage 1 of GCC 13. I hope to submit it again with updated changes post this patch. Thanks, Andrew > + enum tag_types tag > + = TYPENAME_IS_CLASS_P (t) ? class_type > + : TYPENAME_IS_ENUM_P (t) ? enum_type > + : typename_type; > tsubst_flags_t tcomplain = complain | tf_keep_type_decl; > tcomplain |= tst_ok_flag | qualifying_scope_flag; > - f = make_typename_type (ctx, f, typename_type, tcomplain); > + f = make_typename_type (ctx, f, tag, tcomplain); > if (f == error_mark_node) > return f; > if (TREE_CODE (f) == TYPE_DECL) > diff --git a/gcc/testsuite/g++.dg/template/typename27.C b/gcc/testsuite/g++.dg/template/typename27.C > new file mode 100644 > index 00000000000..61b3efd998e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/typename27.C > @@ -0,0 +1,19 @@ > +// PR c++/109420 > + > +struct A { > + struct X { }; > + int X; > +}; > + > +struct B { > + enum E { }; > + enum F { E }; > +}; > + > +template<class T, class U> > +void f() { > + struct T::X x; // OK, lookup ignores the data member 'int A::X' > + enum U::E e; // OK, lookup ignores the enumerator 'B::F::E' > +} > + > +template void f<A, B>(); > -- > 2.40.0.153.g6369acd968 >
On 4/5/23 13:31, Patrick Palka wrote: > On Wed, 5 Apr 2023, Patrick Palka wrote: > >> r13-6098-g46711ff8e60d64 made make_typename_type no longer ignore >> non-types during the lookup, unless the TYPENAME_TYPE in question was >> followed by the :: scope resolution operator. But there is another >> exception to this rule: we need to ignore non-types during the lookup >> also if the TYPENAME_TYPE was named with a tag other than 'typename', >> such as 'struct' or 'enum', as per [dcl.type.elab]/5. >> >> This patch implements this additional exception. It occurred to me that >> the tf_qualifying_scope flag is probably unnecessary if we'd use the >> scope_type tag more thoroughly, but that requires parser changes that >> are probably too risky at this stage. (I'm working on addressing the >> FIXME/TODOs here for GCC 14.) >> >> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for >> trunk? >> >> PR c++/109420 >> >> gcc/cp/ChangeLog: >> >> * decl.cc (make_typename_type): Also ignore non-types during >> the lookup if tag_type is something other than none_type or >> typename_type. >> * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or >> enum_type as tag_type to make_typename_type as appropriate >> instead of always passing typename_type. >> >> gcc/testsuite/ChangeLog: >> >> * g++.dg/template/typename27.C: New test. >> --- >> gcc/cp/decl.cc | 9 ++++++++- >> gcc/cp/pt.cc | 9 ++++++++- >> gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ >> 3 files changed, 35 insertions(+), 2 deletions(-) >> create mode 100644 gcc/testsuite/g++.dg/template/typename27.C >> >> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc >> index 5369714f9b3..a0a20c5accc 100644 >> --- a/gcc/cp/decl.cc >> +++ b/gcc/cp/decl.cc >> @@ -4307,7 +4307,14 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, >> lookup will stop when we hit a dependent base. */ >> if (!dependent_scope_p (context)) >> { >> - bool want_type = (complain & tf_qualifying_scope); >> + /* As per [dcl.type.elab]/5 and [temp.res.general]/3, ignore non-types if >> + the tag corresponds to a class-key or 'enum' (or is scope_type), or if >> + this typename is followed by :: as per [basic.lookup.qual.general]/1. >> + TODO: If we'd set the scope_type tag accurately on all TYPENAME_TYPEs >> + that are followed by :: then we wouldn't need the tf_qualifying_scope >> + flag. */ >> + bool want_type = (tag_type != none_type && tag_type != typename_type) >> + || (complain & tf_qualifying_scope); > > Here's v2 which just slightly improves this comment. I reckon [basic.lookup.elab] > is a better reference than [dcl.type.elab]/5 for justifying why the > lookup should be type-only for class-key and 'enum' TYPENAME_TYPEs. OK, thanks. > -- >8 -- > > PR c++/109420 > > gcc/cp/ChangeLog: > > * decl.cc (make_typename_type): Also ignore non-types during the > lookup if tag_type corresponds to an elaborated-type-specifier. > * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or > enum_type as tag_type to make_typename_type as appropriate > instead of always passing typename_type. > > gcc/testsuite/ChangeLog: > > * g++.dg/template/typename27.C: New test. > --- > gcc/cp/decl.cc | 12 +++++++++++- > gcc/cp/pt.cc | 9 ++++++++- > gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ > 3 files changed, 38 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/template/typename27.C > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > index 5369714f9b3..772c059dc2c 100644 > --- a/gcc/cp/decl.cc > +++ b/gcc/cp/decl.cc > @@ -4307,7 +4307,17 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, > lookup will stop when we hit a dependent base. */ > if (!dependent_scope_p (context)) > { > - bool want_type = (complain & tf_qualifying_scope); > + /* We generally don't ignore non-types during TYPENAME_TYPE lookup > + (as per [temp.res.general]/3), unless > + - the tag corresponds to a class-key or 'enum' so > + [basic.lookup.elab] applies, or > + - the tag corresponds to scope_type or tf_qualifying_scope is > + set so [basic.lookup.qual]/1 applies. > + TODO: If we'd set/track the scope_type tag thoroughly on all > + TYPENAME_TYPEs that are followed by :: then we wouldn't need the > + tf_qualifying_scope flag. */ > + bool want_type = (tag_type != none_type && tag_type != typename_type) > + || (complain & tf_qualifying_scope); > t = lookup_member (context, name, /*protect=*/2, want_type, complain); > } > else > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index 821e0035c08..09559c88f29 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -16580,9 +16580,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) > return error_mark_node; > } > > + /* FIXME: TYPENAME_IS_CLASS_P conflates 'union' vs 'struct' vs 'class' > + tags. TYPENAME_TYPE should probably remember the exact tag that > + was written. */ > + enum tag_types tag > + = TYPENAME_IS_CLASS_P (t) ? class_type > + : TYPENAME_IS_ENUM_P (t) ? enum_type > + : typename_type; > tsubst_flags_t tcomplain = complain | tf_keep_type_decl; > tcomplain |= tst_ok_flag | qualifying_scope_flag; > - f = make_typename_type (ctx, f, typename_type, tcomplain); > + f = make_typename_type (ctx, f, tag, tcomplain); > if (f == error_mark_node) > return f; > if (TREE_CODE (f) == TYPE_DECL) > diff --git a/gcc/testsuite/g++.dg/template/typename27.C b/gcc/testsuite/g++.dg/template/typename27.C > new file mode 100644 > index 00000000000..61b3efd998e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/typename27.C > @@ -0,0 +1,19 @@ > +// PR c++/109420 > + > +struct A { > + struct X { }; > + int X; > +}; > + > +struct B { > + enum E { }; > + enum F { E }; > +}; > + > +template<class T, class U> > +void f() { > + struct T::X x; // OK, lookup ignores the data member 'int A::X' > + enum U::E e; // OK, lookup ignores the enumerator 'B::F::E' > +} > + > +template void f<A, B>();
On Wed, Apr 5, 2023 at 1:36 PM Andrew Pinski <pinskia@gmail.com> wrote: > > On Wed, Apr 5, 2023 at 10:32 AM Patrick Palka via Gcc-patches > <gcc-patches@gcc.gnu.org> wrote: > > > > On Wed, 5 Apr 2023, Patrick Palka wrote: > > > > > r13-6098-g46711ff8e60d64 made make_typename_type no longer ignore > > > non-types during the lookup, unless the TYPENAME_TYPE in question was > > > followed by the :: scope resolution operator. But there is another > > > exception to this rule: we need to ignore non-types during the lookup > > > also if the TYPENAME_TYPE was named with a tag other than 'typename', > > > such as 'struct' or 'enum', as per [dcl.type.elab]/5. > > > > > > This patch implements this additional exception. It occurred to me that > > > the tf_qualifying_scope flag is probably unnecessary if we'd use the > > > scope_type tag more thoroughly, but that requires parser changes that > > > are probably too risky at this stage. (I'm working on addressing the > > > FIXME/TODOs here for GCC 14.) > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > > > trunk? > > > > > > PR c++/109420 > > > > > > gcc/cp/ChangeLog: > > > > > > * decl.cc (make_typename_type): Also ignore non-types during > > > the lookup if tag_type is something other than none_type or > > > typename_type. > > > * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or > > > enum_type as tag_type to make_typename_type as appropriate > > > instead of always passing typename_type. > > > > > > gcc/testsuite/ChangeLog: > > > > > > * g++.dg/template/typename27.C: New test. > > > --- > > > gcc/cp/decl.cc | 9 ++++++++- > > > gcc/cp/pt.cc | 9 ++++++++- > > > gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ > > > 3 files changed, 35 insertions(+), 2 deletions(-) > > > create mode 100644 gcc/testsuite/g++.dg/template/typename27.C > > > > > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > > > index 5369714f9b3..a0a20c5accc 100644 > > > --- a/gcc/cp/decl.cc > > > +++ b/gcc/cp/decl.cc > > > @@ -4307,7 +4307,14 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, > > > lookup will stop when we hit a dependent base. */ > > > if (!dependent_scope_p (context)) > > > { > > > - bool want_type = (complain & tf_qualifying_scope); > > > + /* As per [dcl.type.elab]/5 and [temp.res.general]/3, ignore non-types if > > > + the tag corresponds to a class-key or 'enum' (or is scope_type), or if > > > + this typename is followed by :: as per [basic.lookup.qual.general]/1. > > > + TODO: If we'd set the scope_type tag accurately on all TYPENAME_TYPEs > > > + that are followed by :: then we wouldn't need the tf_qualifying_scope > > > + flag. */ > > > + bool want_type = (tag_type != none_type && tag_type != typename_type) > > > + || (complain & tf_qualifying_scope); > > > > Here's v2 which just slightly improves this comment. I reckon [basic.lookup.elab] > > is a better reference than [dcl.type.elab]/5 for justifying why the > > lookup should be type-only for class-key and 'enum' TYPENAME_TYPEs. > > > > -- >8 -- > > > > PR c++/109420 > > > > gcc/cp/ChangeLog: > > > > * decl.cc (make_typename_type): Also ignore non-types during the > > lookup if tag_type corresponds to an elaborated-type-specifier. > > * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or > > enum_type as tag_type to make_typename_type as appropriate > > instead of always passing typename_type. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/template/typename27.C: New test. > > --- > > gcc/cp/decl.cc | 12 +++++++++++- > > gcc/cp/pt.cc | 9 ++++++++- > > gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ > > 3 files changed, 38 insertions(+), 2 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/template/typename27.C > > > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > > index 5369714f9b3..772c059dc2c 100644 > > --- a/gcc/cp/decl.cc > > +++ b/gcc/cp/decl.cc > > @@ -4307,7 +4307,17 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, > > lookup will stop when we hit a dependent base. */ > > if (!dependent_scope_p (context)) > > { > > - bool want_type = (complain & tf_qualifying_scope); > > + /* We generally don't ignore non-types during TYPENAME_TYPE lookup > > + (as per [temp.res.general]/3), unless > > + - the tag corresponds to a class-key or 'enum' so > > + [basic.lookup.elab] applies, or > > + - the tag corresponds to scope_type or tf_qualifying_scope is > > + set so [basic.lookup.qual]/1 applies. > > + TODO: If we'd set/track the scope_type tag thoroughly on all > > + TYPENAME_TYPEs that are followed by :: then we wouldn't need the > > + tf_qualifying_scope flag. */ > > + bool want_type = (tag_type != none_type && tag_type != typename_type) > > + || (complain & tf_qualifying_scope); > > t = lookup_member (context, name, /*protect=*/2, want_type, complain); > > } > > else > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > > index 821e0035c08..09559c88f29 100644 > > --- a/gcc/cp/pt.cc > > +++ b/gcc/cp/pt.cc > > @@ -16580,9 +16580,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) > > return error_mark_node; > > } > > > > + /* FIXME: TYPENAME_IS_CLASS_P conflates 'union' vs 'struct' vs 'class' > > + tags. TYPENAME_TYPE should probably remember the exact tag that > > + was written. */ > > Yes I had a patch for that but I submitted during stage 4 of GCC 12 > and never updated again during stage 1 of GCC 13. I hope to submit it > again with updated changes post this patch. That'd be great. We could encode all possible tags using three adjacent TREE_LANG_FLAG bits I think (so just one more bit than what TYPENAME_TYPE currently uses). > > Thanks, > Andrew > > > > + enum tag_types tag > > + = TYPENAME_IS_CLASS_P (t) ? class_type > > + : TYPENAME_IS_ENUM_P (t) ? enum_type > > + : typename_type; > > tsubst_flags_t tcomplain = complain | tf_keep_type_decl; > > tcomplain |= tst_ok_flag | qualifying_scope_flag; > > - f = make_typename_type (ctx, f, typename_type, tcomplain); > > + f = make_typename_type (ctx, f, tag, tcomplain); > > if (f == error_mark_node) > > return f; > > if (TREE_CODE (f) == TYPE_DECL) > > diff --git a/gcc/testsuite/g++.dg/template/typename27.C b/gcc/testsuite/g++.dg/template/typename27.C > > new file mode 100644 > > index 00000000000..61b3efd998e > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/template/typename27.C > > @@ -0,0 +1,19 @@ > > +// PR c++/109420 > > + > > +struct A { > > + struct X { }; > > + int X; > > +}; > > + > > +struct B { > > + enum E { }; > > + enum F { E }; > > +}; > > + > > +template<class T, class U> > > +void f() { > > + struct T::X x; // OK, lookup ignores the data member 'int A::X' > > + enum U::E e; // OK, lookup ignores the enumerator 'B::F::E' > > +} > > + > > +template void f<A, B>(); > > -- > > 2.40.0.153.g6369acd968 > > >
Hey Andrew, On Wed, 5 Apr 2023, Andrew Pinski wrote: > On Wed, Apr 5, 2023 at 10:32 AM Patrick Palka via Gcc-patches > <gcc-patches@gcc.gnu.org> wrote: > > > > On Wed, 5 Apr 2023, Patrick Palka wrote: > > > > > r13-6098-g46711ff8e60d64 made make_typename_type no longer ignore > > > non-types during the lookup, unless the TYPENAME_TYPE in question was > > > followed by the :: scope resolution operator. But there is another > > > exception to this rule: we need to ignore non-types during the lookup > > > also if the TYPENAME_TYPE was named with a tag other than 'typename', > > > such as 'struct' or 'enum', as per [dcl.type.elab]/5. > > > > > > This patch implements this additional exception. It occurred to me that > > > the tf_qualifying_scope flag is probably unnecessary if we'd use the > > > scope_type tag more thoroughly, but that requires parser changes that > > > are probably too risky at this stage. (I'm working on addressing the > > > FIXME/TODOs here for GCC 14.) > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > > > trunk? > > > > > > PR c++/109420 > > > > > > gcc/cp/ChangeLog: > > > > > > * decl.cc (make_typename_type): Also ignore non-types during > > > the lookup if tag_type is something other than none_type or > > > typename_type. > > > * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or > > > enum_type as tag_type to make_typename_type as appropriate > > > instead of always passing typename_type. > > > > > > gcc/testsuite/ChangeLog: > > > > > > * g++.dg/template/typename27.C: New test. > > > --- > > > gcc/cp/decl.cc | 9 ++++++++- > > > gcc/cp/pt.cc | 9 ++++++++- > > > gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ > > > 3 files changed, 35 insertions(+), 2 deletions(-) > > > create mode 100644 gcc/testsuite/g++.dg/template/typename27.C > > > > > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > > > index 5369714f9b3..a0a20c5accc 100644 > > > --- a/gcc/cp/decl.cc > > > +++ b/gcc/cp/decl.cc > > > @@ -4307,7 +4307,14 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, > > > lookup will stop when we hit a dependent base. */ > > > if (!dependent_scope_p (context)) > > > { > > > - bool want_type = (complain & tf_qualifying_scope); > > > + /* As per [dcl.type.elab]/5 and [temp.res.general]/3, ignore non-types if > > > + the tag corresponds to a class-key or 'enum' (or is scope_type), or if > > > + this typename is followed by :: as per [basic.lookup.qual.general]/1. > > > + TODO: If we'd set the scope_type tag accurately on all TYPENAME_TYPEs > > > + that are followed by :: then we wouldn't need the tf_qualifying_scope > > > + flag. */ > > > + bool want_type = (tag_type != none_type && tag_type != typename_type) > > > + || (complain & tf_qualifying_scope); > > > > Here's v2 which just slightly improves this comment. I reckon [basic.lookup.elab] > > is a better reference than [dcl.type.elab]/5 for justifying why the > > lookup should be type-only for class-key and 'enum' TYPENAME_TYPEs. > > > > -- >8 -- > > > > PR c++/109420 > > > > gcc/cp/ChangeLog: > > > > * decl.cc (make_typename_type): Also ignore non-types during the > > lookup if tag_type corresponds to an elaborated-type-specifier. > > * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or > > enum_type as tag_type to make_typename_type as appropriate > > instead of always passing typename_type. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/template/typename27.C: New test. > > --- > > gcc/cp/decl.cc | 12 +++++++++++- > > gcc/cp/pt.cc | 9 ++++++++- > > gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ > > 3 files changed, 38 insertions(+), 2 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/template/typename27.C > > > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > > index 5369714f9b3..772c059dc2c 100644 > > --- a/gcc/cp/decl.cc > > +++ b/gcc/cp/decl.cc > > @@ -4307,7 +4307,17 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, > > lookup will stop when we hit a dependent base. */ > > if (!dependent_scope_p (context)) > > { > > - bool want_type = (complain & tf_qualifying_scope); > > + /* We generally don't ignore non-types during TYPENAME_TYPE lookup > > + (as per [temp.res.general]/3), unless > > + - the tag corresponds to a class-key or 'enum' so > > + [basic.lookup.elab] applies, or > > + - the tag corresponds to scope_type or tf_qualifying_scope is > > + set so [basic.lookup.qual]/1 applies. > > + TODO: If we'd set/track the scope_type tag thoroughly on all > > + TYPENAME_TYPEs that are followed by :: then we wouldn't need the > > + tf_qualifying_scope flag. */ > > + bool want_type = (tag_type != none_type && tag_type != typename_type) > > + || (complain & tf_qualifying_scope); > > t = lookup_member (context, name, /*protect=*/2, want_type, complain); > > } > > else > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > > index 821e0035c08..09559c88f29 100644 > > --- a/gcc/cp/pt.cc > > +++ b/gcc/cp/pt.cc > > @@ -16580,9 +16580,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) > > return error_mark_node; > > } > > > > + /* FIXME: TYPENAME_IS_CLASS_P conflates 'union' vs 'struct' vs 'class' > > + tags. TYPENAME_TYPE should probably remember the exact tag that > > + was written. */ > > Yes I had a patch for that but I submitted during stage 4 of GCC 12 > and never updated again during stage 1 of GCC 13. I hope to submit it > again with updated changes post this patch. Do you still plan on submitting a patch for this? It would be great to fix this for GCC 15 :) > > Thanks, > Andrew > > > > + enum tag_types tag > > + = TYPENAME_IS_CLASS_P (t) ? class_type > > + : TYPENAME_IS_ENUM_P (t) ? enum_type > > + : typename_type; > > tsubst_flags_t tcomplain = complain | tf_keep_type_decl; > > tcomplain |= tst_ok_flag | qualifying_scope_flag; > > - f = make_typename_type (ctx, f, typename_type, tcomplain); > > + f = make_typename_type (ctx, f, tag, tcomplain); > > if (f == error_mark_node) > > return f; > > if (TREE_CODE (f) == TYPE_DECL) > > diff --git a/gcc/testsuite/g++.dg/template/typename27.C b/gcc/testsuite/g++.dg/template/typename27.C > > new file mode 100644 > > index 00000000000..61b3efd998e > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/template/typename27.C > > @@ -0,0 +1,19 @@ > > +// PR c++/109420 > > + > > +struct A { > > + struct X { }; > > + int X; > > +}; > > + > > +struct B { > > + enum E { }; > > + enum F { E }; > > +}; > > + > > +template<class T, class U> > > +void f() { > > + struct T::X x; // OK, lookup ignores the data member 'int A::X' > > + enum U::E e; // OK, lookup ignores the enumerator 'B::F::E' > > +} > > + > > +template void f<A, B>(); > > -- > > 2.40.0.153.g6369acd968 > > > >
On Fri, May 3, 2024 at 8:08 AM Patrick Palka <ppalka@redhat.com> wrote: > > Hey Andrew, > > On Wed, 5 Apr 2023, Andrew Pinski wrote: > > > On Wed, Apr 5, 2023 at 10:32 AM Patrick Palka via Gcc-patches > > <gcc-patches@gcc.gnu.org> wrote: > > > > > > On Wed, 5 Apr 2023, Patrick Palka wrote: > > > > > > > r13-6098-g46711ff8e60d64 made make_typename_type no longer ignore > > > > non-types during the lookup, unless the TYPENAME_TYPE in question was > > > > followed by the :: scope resolution operator. But there is another > > > > exception to this rule: we need to ignore non-types during the lookup > > > > also if the TYPENAME_TYPE was named with a tag other than 'typename', > > > > such as 'struct' or 'enum', as per [dcl.type.elab]/5. > > > > > > > > This patch implements this additional exception. It occurred to me that > > > > the tf_qualifying_scope flag is probably unnecessary if we'd use the > > > > scope_type tag more thoroughly, but that requires parser changes that > > > > are probably too risky at this stage. (I'm working on addressing the > > > > FIXME/TODOs here for GCC 14.) > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > > > > trunk? > > > > > > > > PR c++/109420 > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > * decl.cc (make_typename_type): Also ignore non-types during > > > > the lookup if tag_type is something other than none_type or > > > > typename_type. > > > > * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or > > > > enum_type as tag_type to make_typename_type as appropriate > > > > instead of always passing typename_type. > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > * g++.dg/template/typename27.C: New test. > > > > --- > > > > gcc/cp/decl.cc | 9 ++++++++- > > > > gcc/cp/pt.cc | 9 ++++++++- > > > > gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ > > > > 3 files changed, 35 insertions(+), 2 deletions(-) > > > > create mode 100644 gcc/testsuite/g++.dg/template/typename27.C > > > > > > > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > > > > index 5369714f9b3..a0a20c5accc 100644 > > > > --- a/gcc/cp/decl.cc > > > > +++ b/gcc/cp/decl.cc > > > > @@ -4307,7 +4307,14 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, > > > > lookup will stop when we hit a dependent base. */ > > > > if (!dependent_scope_p (context)) > > > > { > > > > - bool want_type = (complain & tf_qualifying_scope); > > > > + /* As per [dcl.type.elab]/5 and [temp.res.general]/3, ignore non-types if > > > > + the tag corresponds to a class-key or 'enum' (or is scope_type), or if > > > > + this typename is followed by :: as per [basic.lookup.qual.general]/1. > > > > + TODO: If we'd set the scope_type tag accurately on all TYPENAME_TYPEs > > > > + that are followed by :: then we wouldn't need the tf_qualifying_scope > > > > + flag. */ > > > > + bool want_type = (tag_type != none_type && tag_type != typename_type) > > > > + || (complain & tf_qualifying_scope); > > > > > > Here's v2 which just slightly improves this comment. I reckon [basic.lookup.elab] > > > is a better reference than [dcl.type.elab]/5 for justifying why the > > > lookup should be type-only for class-key and 'enum' TYPENAME_TYPEs. > > > > > > -- >8 -- > > > > > > PR c++/109420 > > > > > > gcc/cp/ChangeLog: > > > > > > * decl.cc (make_typename_type): Also ignore non-types during the > > > lookup if tag_type corresponds to an elaborated-type-specifier. > > > * pt.cc (tsubst) <case TYPENAME_TYPE>: Pass class_type or > > > enum_type as tag_type to make_typename_type as appropriate > > > instead of always passing typename_type. > > > > > > gcc/testsuite/ChangeLog: > > > > > > * g++.dg/template/typename27.C: New test. > > > --- > > > gcc/cp/decl.cc | 12 +++++++++++- > > > gcc/cp/pt.cc | 9 ++++++++- > > > gcc/testsuite/g++.dg/template/typename27.C | 19 +++++++++++++++++++ > > > 3 files changed, 38 insertions(+), 2 deletions(-) > > > create mode 100644 gcc/testsuite/g++.dg/template/typename27.C > > > > > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > > > index 5369714f9b3..772c059dc2c 100644 > > > --- a/gcc/cp/decl.cc > > > +++ b/gcc/cp/decl.cc > > > @@ -4307,7 +4307,17 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, > > > lookup will stop when we hit a dependent base. */ > > > if (!dependent_scope_p (context)) > > > { > > > - bool want_type = (complain & tf_qualifying_scope); > > > + /* We generally don't ignore non-types during TYPENAME_TYPE lookup > > > + (as per [temp.res.general]/3), unless > > > + - the tag corresponds to a class-key or 'enum' so > > > + [basic.lookup.elab] applies, or > > > + - the tag corresponds to scope_type or tf_qualifying_scope is > > > + set so [basic.lookup.qual]/1 applies. > > > + TODO: If we'd set/track the scope_type tag thoroughly on all > > > + TYPENAME_TYPEs that are followed by :: then we wouldn't need the > > > + tf_qualifying_scope flag. */ > > > + bool want_type = (tag_type != none_type && tag_type != typename_type) > > > + || (complain & tf_qualifying_scope); > > > t = lookup_member (context, name, /*protect=*/2, want_type, complain); > > > } > > > else > > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > > > index 821e0035c08..09559c88f29 100644 > > > --- a/gcc/cp/pt.cc > > > +++ b/gcc/cp/pt.cc > > > @@ -16580,9 +16580,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) > > > return error_mark_node; > > > } > > > > > > + /* FIXME: TYPENAME_IS_CLASS_P conflates 'union' vs 'struct' vs 'class' > > > + tags. TYPENAME_TYPE should probably remember the exact tag that > > > + was written. */ > > > > Yes I had a patch for that but I submitted during stage 4 of GCC 12 > > and never updated again during stage 1 of GCC 13. I hope to submit it > > again with updated changes post this patch. > > Do you still plan on submitting a patch for this? It would be great to > fix this for GCC 15 :) I think I will be getting back to that patch the first week of June and submitting an updated version based on the previous review. I have a few other patches I am working on before I can start working on that one. Thanks, Andrew > > > > > Thanks, > > Andrew > > > > > > > + enum tag_types tag > > > + = TYPENAME_IS_CLASS_P (t) ? class_type > > > + : TYPENAME_IS_ENUM_P (t) ? enum_type > > > + : typename_type; > > > tsubst_flags_t tcomplain = complain | tf_keep_type_decl; > > > tcomplain |= tst_ok_flag | qualifying_scope_flag; > > > - f = make_typename_type (ctx, f, typename_type, tcomplain); > > > + f = make_typename_type (ctx, f, tag, tcomplain); > > > if (f == error_mark_node) > > > return f; > > > if (TREE_CODE (f) == TYPE_DECL) > > > diff --git a/gcc/testsuite/g++.dg/template/typename27.C b/gcc/testsuite/g++.dg/template/typename27.C > > > new file mode 100644 > > > index 00000000000..61b3efd998e > > > --- /dev/null > > > +++ b/gcc/testsuite/g++.dg/template/typename27.C > > > @@ -0,0 +1,19 @@ > > > +// PR c++/109420 > > > + > > > +struct A { > > > + struct X { }; > > > + int X; > > > +}; > > > + > > > +struct B { > > > + enum E { }; > > > + enum F { E }; > > > +}; > > > + > > > +template<class T, class U> > > > +void f() { > > > + struct T::X x; // OK, lookup ignores the data member 'int A::X' > > > + enum U::E e; // OK, lookup ignores the enumerator 'B::F::E' > > > +} > > > + > > > +template void f<A, B>(); > > > -- > > > 2.40.0.153.g6369acd968 > > > > > > >
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 5369714f9b3..a0a20c5accc 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -4307,7 +4307,14 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, lookup will stop when we hit a dependent base. */ if (!dependent_scope_p (context)) { - bool want_type = (complain & tf_qualifying_scope); + /* As per [dcl.type.elab]/5 and [temp.res.general]/3, ignore non-types if + the tag corresponds to a class-key or 'enum' (or is scope_type), or if + this typename is followed by :: as per [basic.lookup.qual.general]/1. + TODO: If we'd set the scope_type tag accurately on all TYPENAME_TYPEs + that are followed by :: then we wouldn't need the tf_qualifying_scope + flag. */ + bool want_type = (tag_type != none_type && tag_type != typename_type) + || (complain & tf_qualifying_scope); t = lookup_member (context, name, /*protect=*/2, want_type, complain); } else diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 821e0035c08..1e778e6e786 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -16580,9 +16580,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) return error_mark_node; } + /* FIXME: TYPENAME_IS_CLASS_P conflates 'union' vs 'struct' vs 'class' + tags. TYPENAME_TYPE should probably remember the exact tag that + was used. */ + enum tag_types tag + = TYPENAME_IS_CLASS_P (t) ? class_type + : TYPENAME_IS_ENUM_P (t) ? enum_type + : typename_type; tsubst_flags_t tcomplain = complain | tf_keep_type_decl; tcomplain |= tst_ok_flag | qualifying_scope_flag; - f = make_typename_type (ctx, f, typename_type, tcomplain); + f = make_typename_type (ctx, f, tag, tcomplain); if (f == error_mark_node) return f; if (TREE_CODE (f) == TYPE_DECL) diff --git a/gcc/testsuite/g++.dg/template/typename27.C b/gcc/testsuite/g++.dg/template/typename27.C new file mode 100644 index 00000000000..61b3efd998e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typename27.C @@ -0,0 +1,19 @@ +// PR c++/109420 + +struct A { + struct X { }; + int X; +}; + +struct B { + enum E { }; + enum F { E }; +}; + +template<class T, class U> +void f() { + struct T::X x; // OK, lookup ignores the data member 'int A::X' + enum U::E e; // OK, lookup ignores the enumerator 'B::F::E' +} + +template void f<A, B>();