I'm not 100% sure I've handled this properly, any feedback welcome. In particular, maybe should I use `DECL_IMPLICIT_TYPEDEF_P` in the mangling logic instead of `!TYPE_DECL_ALIAS_P`? They both seem to work in this case but not sure which would be clearer.
I also looked into trying do a limited form of 'start_decl' before parsing the type but there were too many circular dependencies for me to work through, so I think any such changes would have to wait till GCC16 (if they're even possible at all). -- >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. This change also requires a slight adjustment to the late-ret-3 testcase, as changing the order of creating the node for the alias adjusted the tiebreak sorting of cluster members when logging. 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). * g++.dg/modules/late-ret-3_a.H: Adjust cluster order. 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 ++++++++++++------- gcc/testsuite/g++.dg/modules/late-ret-3_a.H | 2 +- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 170dafd52c1..9d457e2a2f3 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -292,7 +292,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. */ @@ -305,7 +305,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); @@ -402,8 +402,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 @@ -1044,6 +1044,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)); @@ -1588,7 +1589,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 cb234b53a55..cba7b97ef70 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -15753,6 +15753,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)) @@ -15766,19 +15767,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; @@ -22536,8 +22535,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); @@ -22568,8 +22566,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 *-*-* } } } diff --git a/gcc/testsuite/g++.dg/modules/late-ret-3_a.H b/gcc/testsuite/g++.dg/modules/late-ret-3_a.H index 54f95db0456..e64a6f340c0 100644 --- a/gcc/testsuite/g++.dg/modules/late-ret-3_a.H +++ b/gcc/testsuite/g++.dg/modules/late-ret-3_a.H @@ -17,4 +17,4 @@ auto Bar (const A& arg) -> TPL_3<typename TPL_1<decltype(arg)>::type> {return 3;} -// { dg-final { scan-lang-dump { Cluster members:\n \[0\]=decl definition '::template Foo'\n \[1\]=specialization declaration '::TPL_1<#null#>'\n \[2\]=specialization declaration '::TPL_3<::TPL_1<#null#>::type>'\n \[3\]=specialization declaration '::TPL_2<::TPL_1<#null#>::type>'\n \[4\]=binding '::Foo'\n} module } } +// { dg-final { scan-lang-dump { Cluster members:\n \[0\]=decl definition '::template Foo'\n \[1\]=specialization declaration '::TPL_3<::TPL_1<#null#>::type>'\n \[2\]=specialization declaration '::TPL_1<#null#>'\n \[3\]=specialization declaration '::TPL_2<::TPL_1<#null#>::type>'\n \[4\]=binding '::Foo'\n} module } } -- 2.47.0