From 50dc52e853ff267ad1f4c98571c262017b0536f8 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 13 Apr 2023 16:02:21 -0400 Subject: [PATCH] c++: 'typename T::X' vs 'struct T::X' lookup [PR109420] 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', since in that case we're dealing with an elaborated-type-specifier and so [basic.lookup.elab] applies. This patch implements this additional exception. 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) : Pass class_type or enum_type as tag_type to make_typename_type accordingly 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 5369714..772c059 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 4429ae6..fcc8e0d 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 'class' vs 'struct' vs 'union' + tags. TYPENAME_TYPE should probably remember the exact tag that + was written. */ + enum tag_types tag_type + = 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_type, 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 0000000..61b3efd --- /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 +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(); -- 2.7.4