On 9/11/24 4:36 PM, Marek Polacek wrote:
On Wed, Sep 11, 2024 at 11:26:56AM -0400, Jason Merrill wrote:
On 9/11/24 10:53 AM, Patrick Palka wrote:
On Wed, 11 Sep 2024, Patrick Palka wrote:
On Wed, 11 Sep 2024, Patrick Palka wrote:
On Wed, 4 Sep 2024, Marek Polacek wrote:
On Wed, Sep 04, 2024 at 10:58:25AM -0400, Jason Merrill wrote:
On 9/3/24 6:12 PM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/14?
The change to return bool seems like unrelated cleanup; please push that
separately on trunk only.
Done.
+ /* We can also have:
+
+ template <template <typename T, typename T::type TT> typename X>
+ void func() {}
+ template <typename U, int I>
+ struct Y {};
+ void g() { func<Y>(); }
+
+ where we are not in a template, but the type of PARM is T::type
+ and dependent_type_p doesn't want to see a TEMPLATE_TYPE_PARM
+ outside a template. */
... so the patch LGTM, except I'd prefer to not have this comment
containing an embedded specific testcase. IMHO it's "understood" that
processing_template_decl needs to be set when substituting using an
incomplete set of arguments since in that case the result must be
templated.
... and the comment might make this instance of the pattern seem more
like an exceptional case rather than a general rule, which paradoxically
could make the code seem more complex than it is at first glance.
Makes sense to me.
Thank you both. Here's a version without the cleanups and the comment.
Ran dg.exp on x86_64-pc-linux-gnu, OK for trunk?
OK.
-- >8 --
We crash when dependent_type_p gets a TEMPLATE_TYPE_PARM outside
a template. That happens here because in
template <template <typename T, typename T::type TT> typename X>
void func() {}
template <typename U, int I>
struct Y {};
void g() { func<Y>(); }
when performing overload resolution for func<Y>() we have to check
if U matches T and I matches TT. So we wind up in
coerce_template_template_parm/PARM_DECL. TREE_TYPE (arg) is int
so we try to substitute TT's type, which is T::type. But we have
nothing to substitute T with. And we call make_typename_type where
ctx is still T, which checks dependent_scope_p and we trip the assert.
It should work to always perform the substitution in a template context.
If the result still contains template parameters, we cannot say if they
match.
PR c++/96097
gcc/cp/ChangeLog:
* pt.cc (coerce_template_template_parm): Increment
processing_template_decl before calling tsubst.
gcc/testsuite/ChangeLog:
* g++.dg/template/ttp44.C: New test.
---
gcc/cp/pt.cc | 2 ++
gcc/testsuite/g++.dg/template/ttp44.C | 13 +++++++++++++
2 files changed, 15 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/template/ttp44.C
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 310e5dfff03..e4de5451f19 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -7951,7 +7951,9 @@ coerce_template_template_parm (tree parm, tree arg,
tsubst_flags_t complain,
i.e. the parameter list of TT depends on earlier parameters. */
if (!uses_template_parms (TREE_TYPE (arg)))
{
+ ++processing_template_decl;
tree t = tsubst (TREE_TYPE (parm), outer_args, complain, in_decl);
+ --processing_template_decl;
if (!uses_template_parms (t)
&& !same_type_p (t, TREE_TYPE (arg)))
return false;
diff --git a/gcc/testsuite/g++.dg/template/ttp44.C
b/gcc/testsuite/g++.dg/template/ttp44.C
new file mode 100644
index 00000000000..2a412975243
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp44.C
@@ -0,0 +1,13 @@
+// PR c++/96097
+// { dg-do compile }
+
+template <template <typename T, typename T::type TT> class X>
+void func() {}
+
+template <typename U, int I>
+struct Y {};
+
+void test()
+{
+ func<Y>();
+}
base-commit: 670cfd5fe6433ee8f2e86eedb197d2523dbb033b