On 4/28/23 08:54, Patrick Palka wrote:
On Thu, 27 Apr 2023, Patrick Palka wrote:

On Thu, Apr 27, 2023 at 4:46 PM Patrick Palka <ppa...@redhat.com> wrote:

Now that with r14-11-g2245459c85a3f4 made us coerce the template
arguments of a bound ttp again after level-lowering, this unfortunately
causes a crash from coerce_template_args_for_ttp in the below testcase.

During the level-lowering substitution T=int into the bound ttp TT<int>
as part of substitution into the lambda signature, current_template_parms
is just U=U rather than the ideal TT=TT, U=U.  And because we don't
consistently set DECL_CONTEXT for level-lowered ttps (it's kind of a
chicken of the egg problem in this case), we attempt to use
current_template_parms to obtain the outer arguments during
coerce_template_args_for_ttp.  But the depth 1 of c_t_p
current_template_parms is less than the depth 2 of the level-lowered TT,
and we end up segfaulting from there.

So for level-lowered ttps it seems we need to get the outer arguments a
different way -- namely, we can look at the trailing parms of its
DECL_TEMPLATE_PARMS.

Note this is not an ideal solution because TREE_CHAIN of
DECL_TEMPLATE_PARMS in this case is just "2 <empty>, 1 U", so we're
missing tparm information for the level that the ttp belongs to :/ So
the only difference compared to using current_template_parms in this
case is the extra empty level of args corresponding to the ttp's
level.

And on the other hand, this issue seems specific to lambdas because
it's in tsubst_lambda_expr that we substitute the function type _before_
substituting and installing the template parameters, which is opposite
to the typical order that tsubst_template_decl does things in.  And
that's ultimately the reason the current_template_parms fallback in
coerce_template_args_for_ttp misbehaves in this testcase.

So the following seems to be a better fix.  With it, current_template_parms
is correctly 2 TT, 1 U during substitution the lambda's function type,
which makes coerce_template_args_for_ttp happy when level lowering
the bound ttp within the function type.

OK.

-- >8 --

Subject: [PATCH] c++: bound ttp in lambda function type [PR109651]

        PR c++/109651

gcc/cp/ChangeLog:

        * pt.cc (tsubst_template_decl): Add default argument to
        lambda_fntype parameter.  Add defaulted lambda_tparms parameter.
        Prefer to use lambda_tparms instead of substituting
        DECL_TEMPLATE_PARMS.
        (tsubst_decl) <case TEMPLATE_DECL>: Adjust tsubst_template_decl
        call.
        (tsubst_lambda_expr): For a generic lambda, substitute
        DECL_TEMPLATE_PARMS and update current_template_parms
        before substituting the function type.  Pass the substituted
        DECL_TEMPLATE_PARMS to tsubst_template_decl.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/lambda-generic-ttp1.C: New test.
        * g++.dg/cpp2a/lambda-generic-ttp2.C: New test.
---
  gcc/cp/pt.cc                                  | 30 ++++++++++++++-----
  .../g++.dg/cpp2a/lambda-generic-ttp1.C        | 11 +++++++
  .../g++.dg/cpp2a/lambda-generic-ttp2.C        | 13 ++++++++
  3 files changed, 47 insertions(+), 7 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-generic-ttp1.C
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-generic-ttp2.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 678cb7930e3..43713d9ab72 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -14629,7 +14629,8 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t 
complain,
static tree
  tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
-                     tree lambda_fntype)
+                     tree lambda_fntype = NULL_TREE,
+                     tree lambda_tparms = NULL_TREE)
  {
    /* We can get here when processing a member function template,
       member class template, or template template parameter.  */
@@ -14719,8 +14720,10 @@ tsubst_template_decl (tree t, tree args, 
tsubst_flags_t complain,
    auto tparm_guard = make_temp_override (current_template_parms);
    DECL_TEMPLATE_PARMS (r)
      = current_template_parms
-    = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
-                            complain);
+    = (lambda_tparms
+       ? lambda_tparms
+       : tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
+                               complain));
bool class_p = false;
    tree inner = decl;
@@ -14888,7 +14891,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
    switch (TREE_CODE (t))
      {
      case TEMPLATE_DECL:
-      r = tsubst_template_decl (t, args, complain, /*lambda*/NULL_TREE);
+      r = tsubst_template_decl (t, args, complain);
        break;
case FUNCTION_DECL:
@@ -20130,12 +20133,24 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
                  ? DECL_TI_TEMPLATE (oldfn)
                  : NULL_TREE);
+ tree tparms = NULL_TREE;
+  if (oldtmpl)
+    tparms = tsubst_template_parms (DECL_TEMPLATE_PARMS (oldtmpl), args, 
complain);
+
    tree fntype = static_fn_type (oldfn);
+
+  tree saved_ctp = current_template_parms;
    if (oldtmpl)
-    ++processing_template_decl;
+    {
+      ++processing_template_decl;
+      current_template_parms = tparms;
+    }
    fntype = tsubst (fntype, args, complain, in_decl);
    if (oldtmpl)
-    --processing_template_decl;
+    {
+      current_template_parms = saved_ctp;
+      --processing_template_decl;
+    }
if (fntype == error_mark_node)
      r = error_mark_node;
@@ -20151,7 +20166,8 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
                                 type_memfn_quals (fntype),
                                 type_memfn_rqual (fntype));
        tree inst = (oldtmpl
-                  ? tsubst_template_decl (oldtmpl, args, complain, fntype)
+                  ? tsubst_template_decl (oldtmpl, args, complain,
+                                          fntype, tparms)
                   : tsubst_function_decl (oldfn, args, complain, fntype));
        if (inst == error_mark_node)
        {
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-generic-ttp1.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-generic-ttp1.C
new file mode 100644
index 00000000000..876e5b6232a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-generic-ttp1.C
@@ -0,0 +1,11 @@
+// PR c++/109651
+// { dg-do compile { target c++20 } }
+
+template<class T>
+void f() {
+  []<class U>() {
+    []<template<class> class TT>(TT<int>) { };
+  };
+}
+
+template void f<int>();
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-generic-ttp2.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-generic-ttp2.C
new file mode 100644
index 00000000000..dc2029d7227
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-generic-ttp2.C
@@ -0,0 +1,13 @@
+// PR c++/109651
+// { dg-do compile { target c++20 } }
+
+template<class T>
+auto f() {
+  return []<class U, template<class V, U, V> class TT>(U, TT<int, 1, 2>) { };
+}
+
+template<class T, int N, int M> struct A { };
+
+int main() {
+  f<int>()(0, A<int, 1, 2>{});
+}

Reply via email to