]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: nested typename type resolving to wildcard type [PR122752]
authorPatrick Palka <ppalka@redhat.com>
Mon, 15 Dec 2025 19:30:53 +0000 (14:30 -0500)
committerPatrick Palka <ppalka@redhat.com>
Mon, 15 Dec 2025 19:30:53 +0000 (14:30 -0500)
Here typename A<S>::VertexSet::size_type within the out-of-line
declaration is initially parsed at namespace scope, so the LHS
A<S>::VertexSet is treated as a dependent name and represented as a
TYPENAME_TYPE with tag_type as class_type.[1]

Once we realize we're parsing a member declarator we call
maybe_update_decl_type to reprocess the TYPENAME_TYPE relative to the
class template scope, during which make_typename_type succeeds in
resolving the lookup and returns the member typedef VertexSet (to the
TEMPLATE_TYPE_PARM S).  But then the caller tsubst complains that this
result isn't a class type as per the tag_type.

This patch just relaxes tsubst to allow TYPENAME_TYPE getting resolved
to a wildcard type regardless of the tag_type.  This does mean we lose
information about the tag_type during a subsequent tsubst, but that's
probably harmless (famous last words).

[1]: The tag_type should probably be scope_type.  Changing this seems
to be a matter of changing cp_parser_qualifying_entity to pass
scope_type instead of class_type, but I don't feel confident about that
and it seems risky.  I then got confused as to why that function passes
none_type in the !type_p case; to me it should use scope_type
unconditionally, but doing so breaks things.  This approach seems safer
to backport.

PR c++/122752

gcc/cp/ChangeLog:

* pt.cc (tsubst) <case TYPENAME_TYPE>: Allow TYPENAME_TYPE
resolving to another wildcard type.

gcc/testsuite/ChangeLog:

* g++.dg/template/dependent-name19.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/pt.cc
gcc/testsuite/g++.dg/template/dependent-name19.C [new file with mode: 0644]

index f13b3436eb3f072c7c903e4a003fe3ed509c8acc..a5d932ac9ea6900a3a10aab6d26e83686a0bc7ce 100644 (file)
@@ -17342,7 +17342,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
            f = TREE_TYPE (f);
          }
 
-       if (TREE_CODE (f) != TYPENAME_TYPE)
+       if (!WILDCARD_TYPE_P (f))
          {
            if (TYPENAME_IS_ENUM_P (t) && TREE_CODE (f) != ENUMERAL_TYPE)
              {
diff --git a/gcc/testsuite/g++.dg/template/dependent-name19.C b/gcc/testsuite/g++.dg/template/dependent-name19.C
new file mode 100644 (file)
index 0000000..87fe7c7
--- /dev/null
@@ -0,0 +1,22 @@
+// PR c++/122752
+
+struct set {
+  typedef unsigned size_type;
+  unsigned size() { return 42; }
+};
+
+template<class S>
+struct A {
+  typedef S VertexSet;
+  typename VertexSet::size_type size();
+  VertexSet vertices_;
+};
+
+template<class S>
+inline typename A<S>::VertexSet::size_type A<S>::size()
+{ return vertices_.size(); }
+
+int main() {
+  A<set> a;
+  a.size();
+}