]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: self-dependent alias template [PR117530]
authorJason Merrill <jason@redhat.com>
Mon, 7 Apr 2025 18:35:14 +0000 (14:35 -0400)
committerJason Merrill <jason@redhat.com>
Tue, 8 Apr 2025 11:43:37 +0000 (07:43 -0400)
Here, instantiating B<short> means instantiating A<short>, which means
instantiating B<short>.  And then when we go to register the initial
instantiation, it conflicts with the inner one.  Fixed by checking after
tsubst whether there's already something in the hash table.  We already did
something much like this in tsubst_decl, but that doesn't handle this case.

While I was here, I noticed that we had a pop_deferring_access_checks on one
early exit but not another, and since I wanted to add yet another I switched
to using deferring_access_check_sentinel.

PR c++/117530

gcc/cp/ChangeLog:

* pt.cc (instantiate_template): Check retrieve_specialization after
tsubst.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/lambda-uneval27.C: New test.

gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp2a/lambda-uneval27.C [new file with mode: 0644]

index 95b89f1281ba0a10223084cd53921188256e8763..8f35fa702a211f376f59f945e3f616fa8570ea6a 100644 (file)
@@ -22675,7 +22675,7 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain)
      FUNCTION_DECL which is the desired context for access checking
      is not built yet.  We solve this chicken-and-egg problem by
      deferring all checks until we have the FUNCTION_DECL.  */
-  push_deferring_access_checks (dk_deferred);
+  deferring_access_check_sentinel dacs (dk_deferred);
 
   /* Instantiation of the function happens in the context of the function
      template, not the context of the overload resolution we're doing.  */
@@ -22733,10 +22733,13 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain)
   pop_from_top_level ();
 
   if (fndecl == error_mark_node)
-    {
-      pop_deferring_access_checks ();
-      return error_mark_node;
-    }
+    return error_mark_node;
+
+  /* Substituting the type might have recursively instantiated this
+     same alias (c++/117530).  */
+  if (DECL_ALIAS_TEMPLATE_P (gen_tmpl)
+      && (spec = retrieve_specialization (gen_tmpl, targ_ptr, hash)))
+    return spec;
 
   /* The DECL_TI_TEMPLATE should always be the immediate parent
      template, not the most general template.  */
@@ -22771,7 +22774,6 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain)
        access_ok = false;
       pop_access_scope (fndecl);
     }
-  pop_deferring_access_checks ();
 
   /* If we've just instantiated the main entry point for a function,
      instantiate all the alternate entry points as well.  We do this
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval27.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval27.C
new file mode 100644 (file)
index 0000000..941fe63
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/117530
+// { dg-do compile { target c++20 } }
+
+template <class> struct A;
+template <class T> using B = decltype([]() -> A<T>::X { return 0; });
+template <class T> struct A {
+  typedef int X;
+  typedef B<T> U;
+};
+B<short> b;