FWIW, here's my WIP patch to fix the lambda in type alias case
"properly".  I've gotten stuck with trying to work out how to set
LAMBDA_EXPR_EXTRA_CONTEXT on the uninstantiated declaration; any
thoughts or suggestions here?

I also found that the hunk 

-           /* Substituting the type might have recursively instantiated this
-              same alias (c++/86171).  */
-           if (use_spec_table && gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl)
-               && (spec = retrieve_specialization (gen_tmpl, argvec, hash)))
-             {
-               r = spec;
-               break;
-             }

is no longer needed for the original testcase and doesn't appear to be
used anymore, but I imagine we might need something similar in a
different way to handle this testcase (which errors since GCC14 but
succeeds before then):

  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;

I wasn't able to find an exact dup for this so I've created a new issue
for it (PR117530).

-- >8 --

This adds mangling support for lambdas with a mangling context of an
alias template, and gives that context when instantiating such a lambda.

This only currently works for class-scope alias templates, however, due
to the

  if (LAMBDA_EXPR_EXTRA_SCOPE (t))
    record_lambda_scope (r);

condition in 'tsubst_lambda_scope'.

For namespace-scope alias templates, we can't easily add the mangling
context: we can't build the TYPE_DECL to record against until after
we've parsed the type (and already recorded lambda scope), as
`start_decl` relies on the type being passed in correctly, and setting
the mangling scope after parsing is too late because e.g.
'template_class_depth' (called from grokfndecl when building the lambda
functions while parsing the type) relies on the LAMBDA_EXPR_EXTRA_SCOPE
already being properly set.  This will also likely matter for
'determine_visibility'.  I'm not sure what a good way to break this
recursive dependency is.

        PR c++/116568

gcc/cp/ChangeLog:

        * mangle.cc (maybe_template_info): Support getting template info
        of alias templates.
        (canonicalize_for_substitution): Don't canonicalise aliases.
        (decl_mangling_context): Don't treat aliases as lambda closure
        types.
        (write_unqualified_name): Likewise.
        * pt.cc (tsubst_decl): Start lambda scope for alias templates.
        (instantiate_template): No longer need to special case alias
        templates here.

gcc/testsuite/ChangeLog:

        * g++.dg/abi/lambda-ctx4.C: Adjust mangling, include namespace
        scope alias templates (XFAILed for now).

Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
---
 gcc/cp/mangle.cc                       | 13 ++++++++-----
 gcc/cp/pt.cc                           | 23 ++++++++++-------------
 gcc/testsuite/g++.dg/abi/lambda-ctx4.C | 21 ++++++++++++++-------
 3 files changed, 32 insertions(+), 25 deletions(-)

diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 42fcdc34353..a6d1830397c 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -293,7 +293,7 @@ abi_check (int ver)
 static tree
 maybe_template_info (const tree decl)
 {
-  if (TREE_CODE (decl) == TYPE_DECL)
+  if (TREE_CODE (decl) == TYPE_DECL && !TYPE_DECL_ALIAS_P (decl))
     {
       /* TYPE_DECLs are handled specially.  Look at its type to decide
         if this is a template instantiation.  */
@@ -306,7 +306,7 @@ maybe_template_info (const tree decl)
     {
       /* Check if the template is a primary template.  */
       if (DECL_LANG_SPECIFIC (decl) != NULL
-         && VAR_OR_FUNCTION_DECL_P (decl)
+         && (VAR_OR_FUNCTION_DECL_P (decl) || TREE_CODE (decl) == TYPE_DECL)
          && DECL_TEMPLATE_INFO (decl)
          && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)))
        return DECL_TEMPLATE_INFO (decl);
@@ -403,8 +403,8 @@ write_exception_spec (tree spec)
 static inline tree
 canonicalize_for_substitution (tree node)
 {
-  /* For a TYPE_DECL, use the type instead.  */
-  if (TREE_CODE (node) == TYPE_DECL)
+  /* For a non-alias TYPE_DECL, use the type instead.  */
+  if (TREE_CODE (node) == TYPE_DECL && !TYPE_DECL_ALIAS_P (node))
     node = TREE_TYPE (node);
   if (TYPE_P (node)
       && TYPE_CANONICAL (node) != node
@@ -1045,6 +1045,7 @@ decl_mangling_context (tree decl)
     decl = DECL_TEMPLATE_RESULT (decl);
 
   if (TREE_CODE (decl) == TYPE_DECL
+      && !TYPE_DECL_ALIAS_P (decl)
       && LAMBDA_TYPE_P (TREE_TYPE (decl)))
     {
       tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl));
@@ -1589,7 +1590,9 @@ write_unqualified_name (tree decl)
       if (TREE_CODE (decl) == TYPE_DECL
           && TYPE_UNNAMED_P (type))
         write_unnamed_type_name (type);
-      else if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (type))
+      else if (TREE_CODE (decl) == TYPE_DECL
+              && !TYPE_DECL_ALIAS_P (decl)
+              && LAMBDA_TYPE_P (type))
         write_closure_type_name (type);
       else
         write_source_name (DECL_NAME (decl));
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 06d13fda872..686f7246057 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -15627,6 +15627,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
          }
 
        /* Create a new node for the specialization we need.  */
+       r = copy_decl (t);
        if (type == NULL_TREE)
          {
            if (is_typedef_decl (t))
@@ -15640,19 +15641,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain,
            tsubst_flags_t tcomplain = complain;
            if (VAR_P (t))
              tcomplain |= tf_tst_ok;
+           bool is_alias
+             = (is_typedef_decl (t)
+                && alias_template_specialization_p (TREE_TYPE (t), nt_opaque));
+           if (is_alias)
+             start_lambda_scope (r);
            type = tsubst (type, args, tcomplain, in_decl);
-           /* Substituting the type might have recursively instantiated this
-              same alias (c++/86171).  */
-           if (use_spec_table && gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl)
-               && (spec = retrieve_specialization (gen_tmpl, argvec, hash)))
-             {
-               r = spec;
-               break;
-             }
+           if (is_alias)
+             finish_lambda_scope ();
          }
        if (type == error_mark_node && !(complain & tf_error))
          RETURN (error_mark_node);
-       r = copy_decl (t);
        if (VAR_P (r))
          {
            DECL_INITIALIZED_P (r) = 0;
@@ -22281,8 +22280,7 @@ instantiate_template (tree tmpl, tree orig_args, 
tsubst_flags_t complain)
        ctx = tsubst_entering_scope (DECL_CONTEXT (gen_tmpl), targ_ptr,
                                     complain, gen_tmpl);
       push_nested_class (ctx);
-      if (!DECL_ALIAS_TEMPLATE_P (gen_tmpl))
-       start_lambda_scope (TYPE_NAME (ctx));
+      start_lambda_scope (TYPE_NAME (ctx));
     }
 
   tree pattern = DECL_TEMPLATE_RESULT (gen_tmpl);
@@ -22313,8 +22311,7 @@ instantiate_template (tree tmpl, tree orig_args, 
tsubst_flags_t complain)
     fndecl = tsubst_decl (pattern, targ_ptr, complain, 
/*use_spec_table=*/false);
   if (DECL_CLASS_SCOPE_P (gen_tmpl))
     {
-      if (!DECL_ALIAS_TEMPLATE_P (gen_tmpl))
-       finish_lambda_scope ();
+      finish_lambda_scope ();
       pop_nested_class ();
     }
   pop_from_top_level ();
diff --git a/gcc/testsuite/g++.dg/abi/lambda-ctx4.C 
b/gcc/testsuite/g++.dg/abi/lambda-ctx4.C
index d6544a84652..809cace8574 100644
--- a/gcc/testsuite/g++.dg/abi/lambda-ctx4.C
+++ b/gcc/testsuite/g++.dg/abi/lambda-ctx4.C
@@ -1,5 +1,4 @@
 // { dg-do compile { target c++20 } }
-// { dg-additional-options "-fkeep-inline-functions" }
 
 struct S {
   template <int I>
@@ -9,14 +8,22 @@ struct S {
 S::T<0> a;
 S::T<1> b;
 
+template <int I>
+using L = decltype([]{ return I; });
+
+L<0> c;
+L<1> d;
+
 int main() {
   a();
   b();
+  c();
+  d();
 }
 
-// Currently we don't implement any special mangling rules for template aliases
-// (though we probably should; an alias template is a definable item by
-// [basic.def.odr] p1.5 and as such contained lambdas in different TUs should 
have
-// the same type, see [basic.def.odr] p15.6)
-// { scan_assembler {_ZNK1SUlvE_clEv:} }
-// { scan_assembler {_ZNK1SUlvE0_clEv:} }
+// { dg-final { scan-assembler {_ZNK1S1TILi0EEUlvE_clEv:} } }
+// { dg-final { scan-assembler {_ZNK1S1TILi1EEUlvE_clEv:} } }
+
+// namespace-scope aliases don't have LAMBDA_EXPR_EXTRA_CONTEXT properly set
+// { dg-final { scan-assembler {_ZNK1LILi0EEUlvE_clEv:} { xfail *-*-* } } }
+// { dg-final { scan-assembler {_ZNK1LILi1EEUlvE_clEv:} { xfail *-*-* } } }
-- 
2.47.0

Reply via email to