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>();

Reply via email to