aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2025-04-07 14:35:14 -0400
committerJason Merrill <jason@redhat.com>2025-04-08 07:43:37 -0400
commitd034c78c7be613db3c25fddec1dd50222327117b (patch)
tree19a83b5d51c043db6eac75378f4a7d1a6b49c96c
parentf53c5cde64770d6c175737a444450fea81feba80 (diff)
downloadgcc-d034c78c7be613db3c25fddec1dd50222327117b.zip
gcc-d034c78c7be613db3c25fddec1dd50222327117b.tar.gz
gcc-d034c78c7be613db3c25fddec1dd50222327117b.tar.bz2
c++: self-dependent alias template [PR117530]
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.
-rw-r--r--gcc/cp/pt.cc14
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/lambda-uneval27.C10
2 files changed, 18 insertions, 6 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 95b89f12..8f35fa7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -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
index 0000000..941fe63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval27.C
@@ -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;