@@ -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));
@@ -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 ();
@@ -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 *-*-* } } }
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 <nathanieloshead@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(-)