diff options
author | Nathan Sidwell <nathan@acm.org> | 2022-10-24 17:39:55 -0400 |
---|---|---|
committer | Nathan Sidwell <nathan@acm.org> | 2022-10-27 11:56:11 -0400 |
commit | f7d1d7777bb86ad049f88214109fb561a741aa2c (patch) | |
tree | 82ece2eeb0a792f358dd7a0a57be1d4e85c90a57 /gcc | |
parent | f95d3d5de72a1c43e8d529bad3ef59afc3214705 (diff) | |
download | gcc-f7d1d7777bb86ad049f88214109fb561a741aa2c.zip gcc-f7d1d7777bb86ad049f88214109fb561a741aa2c.tar.gz gcc-f7d1d7777bb86ad049f88214109fb561a741aa2c.tar.bz2 |
c++: Templated lambda mangling
(Explicitly) Templated lambdas have a different signature to
implicitly templated lambdas -- '[]<template T> (T) {}' is not the
same as '[](auto) {}'. This should be reflected in the mangling. The
ABI captures this as
https://github.com/itanium-cxx-abi/cxx-abi/issues/31, and clang has
implemented such additions.
It's relatively straight forwards to write out the non-synthetic
template parms, and note if we need to issue an ABI warning.
gcc/cp/
* mangle.cc (write_closure_template_head): New.
(write_closure_type_name): Call it.
gcc/testsuite/
* g++.dg/abi/lambda-ctx1-18.C: Adjust.
* g++.dg/abi/lambda-ctx1-18vs17.C: Adjust.
* g++.dg/abi/lambda-tpl1-17.C: New.
* g++.dg/abi/lambda-tpl1-18.C: New.
* g++.dg/abi/lambda-tpl1-18vs17.C: New.
* g++.dg/abi/lambda-tpl1.h: New.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/mangle.cc | 68 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/lambda-ctx1-18.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/lambda-ctx1-18vs17.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/lambda-tpl1-17.C | 20 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/lambda-tpl1-18.C | 25 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/lambda-tpl1-18vs17.C | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/lambda-tpl1.h | 59 |
7 files changed, 192 insertions, 4 deletions
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 1215463..e396218 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -1727,6 +1727,66 @@ write_unnamed_type_name (const tree type) write_compact_number (discriminator); } +// A template head, for templated lambdas. +// <template-head> ::= Tp* Ty +// Tp* Tn <type> +// Tp* Tt <template-head> E +// New in ABI=18. Returns true iff we emitted anything -- used for ABI +// version warning. + +static bool +write_closure_template_head (tree tmpl) +{ + bool any = false; + + // We only need one level of template parms + tree inner = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl)); + + for (int ix = 0, len = TREE_VEC_LENGTH (inner); ix != len; ix++) + { + tree parm = TREE_VEC_ELT (inner, ix); + if (parm == error_mark_node) + continue; + parm = TREE_VALUE (parm); + + if (DECL_VIRTUAL_P (parm)) + // A synthetic parm, we're done. + break; + + any = true; + if (abi_version_at_least (18)) + { + if (TREE_CODE (parm) == PARM_DECL + ? TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) + : TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm))) + write_string ("Tp"); + + switch (TREE_CODE (parm)) + { + default: + gcc_unreachable (); + + case TYPE_DECL: + write_string ("Ty"); + break; + + case PARM_DECL: + write_string ("Tn"); + write_type (TREE_TYPE (parm)); + break; + + case TEMPLATE_DECL: + write_string ("Tt"); + write_closure_template_head (parm); + write_string ("E"); + break; + } + } + } + + return any; +} + /* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters */ @@ -1740,6 +1800,14 @@ write_closure_type_name (const tree type) MANGLE_TRACE_TREE ("closure-type-name", type); write_string ("Ul"); + + if (auto ti = maybe_template_info (fn)) + if (write_closure_template_head (TI_TEMPLATE (ti))) + // If there were any explicit template parms, we may need to + // issue a mangling diagnostic. + if (abi_warn_or_compat_version_crosses (18)) + G.need_abi_warning = true; + write_method_parms (parms, /*method_p=*/1, fn); write_char ('E'); write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda)); diff --git a/gcc/testsuite/g++.dg/abi/lambda-ctx1-18.C b/gcc/testsuite/g++.dg/abi/lambda-ctx1-18.C index c1c9e27..3dd68a4 100644 --- a/gcc/testsuite/g++.dg/abi/lambda-ctx1-18.C +++ b/gcc/testsuite/g++.dg/abi/lambda-ctx1-18.C @@ -6,6 +6,6 @@ // These correctly include the lambda's extra context as a // substitution candidate, and thus demangle as expected // { dg-final { scan-assembler {_ZNK1C1fMUlT_E_clIMS_iEEDaS1_:} } } -// { dg-final { scan-assembler {_ZNK2L2MUlT_T0_E_clIifEEvS0_S1_:} } } -// { dg-final { scan-assembler {_ZNK1B2L3MUlT_T0_E_clIjdEEvS1_S2_:} } } +// { dg-final { scan-assembler {_ZNK2L2MUlTyTyT_T0_E_clIifEEvS0_S1_:} } } +// { dg-final { scan-assembler {_ZNK1B2L3MUlTyTyT_T0_E_clIjdEEvS1_S2_:} } } // { dg-final { scan-assembler {_Z3fooIN1qMUlvE_ENS0_UlvE0_EEiOT_OT0_:} } } diff --git a/gcc/testsuite/g++.dg/abi/lambda-ctx1-18vs17.C b/gcc/testsuite/g++.dg/abi/lambda-ctx1-18vs17.C index f5ec905..ec6709a 100644 --- a/gcc/testsuite/g++.dg/abi/lambda-ctx1-18vs17.C +++ b/gcc/testsuite/g++.dg/abi/lambda-ctx1-18vs17.C @@ -3,7 +3,7 @@ #include "lambda-ctx1.h" -// { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK1B2L3MUlT_T0_E_clIjdEEvS0_S1_'\) and '-fabi-version=18' \('_ZNK1B2L3MUlT_T0_E_clIjdEEvS1_S2_'\) [^\n]*\n} } -// { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK2L2MUlT_T0_E_clIifEEvS_S0_'\) and '-fabi-version=18' \('_ZNK2L2MUlT_T0_E_clIifEEvS0_S1_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK1B2L3MUlT_T0_E_clIjdEEvS0_S1_'\) and '-fabi-version=18' \('_ZNK1B2L3MUlTyTyT_T0_E_clIjdEEvS1_S2_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK2L2MUlT_T0_E_clIifEEvS_S0_'\) and '-fabi-version=18' \('_ZNK2L2MUlTyTyT_T0_E_clIifEEvS0_S1_'\) [^\n]*\n} } // { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK1C1fMUlT_E_clIMS_iEEDaS0_'\) and '-fabi-version=18' \('_ZNK1C1fMUlT_E_clIMS_iEEDaS1_'\) [^\n]*\n} } // { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_Z3fooIN1qMUlvE_EN1qMUlvE0_EEiOT_OT0_'\) and '-fabi-version=18' \('_Z3fooIN1qMUlvE_ENS0_UlvE0_EEiOT_OT0_'\) [^\n]*\n} } diff --git a/gcc/testsuite/g++.dg/abi/lambda-tpl1-17.C b/gcc/testsuite/g++.dg/abi/lambda-tpl1-17.C new file mode 100644 index 0000000..b61aaf9 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-tpl1-17.C @@ -0,0 +1,20 @@ +// { dg-do compile { target c++20 } } +// { dg-options -fabi-version=17 } + +#include "lambda-tpl1.h" + +// { dg-final { scan-assembler {_ZNK6l_autoMUlT_E_clIiEEDaS_:} } } +// { dg-final { scan-assembler {_ZNK5l_tplMUlT_E_clIiEEDaS_:} } } +// { dg-final { scan-assembler {_ZNK10l_tpl_autoMUlT_T0_E_clIiiEEDaS_S0_:} } } +// { dg-final { scan-assembler {_ZNK12l_tpl_nt_aryMUlRAT__iE_clILi2EEEDaS0_:} } } +// { dg-final { scan-assembler {_ZNK13l_tpl_nt_autoMUlvE_clILi0EEEDav:} } } +// { dg-final { scan-assembler {_ZNK9l_tpl_tplMUlR3TPLIT_EE_clI1UEEDaS2_:} } } +// { dg-final { scan-assembler {_ZNK13l_tpl_tpl_tplMUlR6TPLTPLIT_EE_clI3TPLEEDaS2_:} } } +// { dg-final { scan-assembler {_ZNK5l_varMUlDpT_E_clIJiiiEEEDaS0_:} } } + +// This mangling might not be correct, it is my best guess: +// { FIXMEdg-final { scan-assembler {_ZNK6l_var2MUlDpRAT__iE_clIJLi2ELi2EEEEDaS1_:} } } + +// { dg-final { scan-assembler {_ZNK6l_var3MUlRT_IJXspT0_EEEE_clI1XJLi1ELi2ELi3EEEEDaS1_:} } } +// { dg-final { scan-assembler {_ZNK6l_var4MUlR1YIJDpT_EEE_clIJ1US6_EEEDaS3_:} } } +// { dg-final { scan-assembler {_ZZ2FnILi1EEvvENKUlT_E_clIiEEDaS0_:} } } diff --git a/gcc/testsuite/g++.dg/abi/lambda-tpl1-18.C b/gcc/testsuite/g++.dg/abi/lambda-tpl1-18.C new file mode 100644 index 0000000..dbeea40 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-tpl1-18.C @@ -0,0 +1,25 @@ +// { dg-do compile { target c++20 } } + +#include "lambda-tpl1.h" + +// { dg-final { scan-assembler {_ZNK6l_autoMUlT_E_clIiEEDaS0_:} } } +// { dg-final { scan-assembler {_ZNK5l_tplMUlTyT_E_clIiEEDaS0_:} } } +// { dg-final { scan-assembler {_ZNK10l_tpl_autoMUlTyT_T0_E_clIiiEEDaS0_S1_:} } } +// { dg-final { scan-assembler {_ZNK12l_tpl_nt_aryMUlTniRAT__iE_clILi2EEEDaS1_:} } } +// { dg-final { scan-assembler {_ZNK13l_tpl_nt_autoMUlTnDavE_clILi0EEEDav:} } } +// { dg-final { scan-assembler {_ZNK9l_tpl_tplMUlTtTyTnjER3TPLIT_EE_clI1UEEDaS3_:} } } +// { dg-final { scan-assembler {_ZNK13l_tpl_tpl_tplMUlTtTtTyTnjEER6TPLTPLIT_EE_clI3TPLEEDaS3_:} } } +// { dg-final { scan-assembler {_ZNK5l_varMUlTpTyDpT_E_clIJiiiEEEDaS1_:} } } + +// { FIXMEdg-final { scan-assembler {_ZNK6l_var2MUlTpTniDpRAT__iE_clIJLi2ELi2EEEEDaS2_:} } } + +// { dg-final { scan-assembler {_ZNK6l_var3MUlTtTpTniETpTniRT_IJXspT0_EEEE_clI1XJLi1ELi2ELi3EEEEDaS2_:} } } + +// { dg-final { scan-assembler {_ZNK6l_var4MUlTpTtTyTnjER1YIJDpT_EEE_clIJ1US7_EEEDaS4_:} } } +// This is a different mangling to clang, which gets +// _ZNK6l_var4MUlTpTtTyTnjER1YIJDpT_EEE_clIJ1US6_EEEDaS3_ +// However, I think that is incorrect -- it doesn't demangle as +// expected (using the llvm demangler). +// https://github.com/llvm/llvm-project/issues/58631 + +// { dg-final { scan-assembler {_ZZ2FnILi1EEvvENKUlTyT_E_clIiEEDaS0_:} } } diff --git a/gcc/testsuite/g++.dg/abi/lambda-tpl1-18vs17.C b/gcc/testsuite/g++.dg/abi/lambda-tpl1-18vs17.C new file mode 100644 index 0000000..8bead73 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-tpl1-18vs17.C @@ -0,0 +1,16 @@ +// { dg-do compile { target c++20 } } +// { dg-options {-fabi-version=18 -Wabi=17} } + +#include "lambda-tpl1.h" + +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZ2FnILi1EEvvENKUlT_E_clIiEEDaS0_'\) and '-fabi-version=18' \('_ZZ2FnILi1EEvvENKUlTyT_E_clIiEEDaS0_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK6l_var4MUlR1YIJDpT_EEE_clIJ1US6_EEEDaS3_'\) and '-fabi-version=18' \('_ZNK6l_var4MUlTpTtTyTnjER1YIJDpT_EEE_clIJ1US7_EEEDaS4_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK6l_var3MUlRT_IJXspT0_EEEE_clI1XJLi1ELi2ELi3EEEEDaS1_'\) and '-fabi-version=18' \('_ZNK6l_var3MUlTtTpTniETpTniRT_IJXspT0_EEEE_clI1XJLi1ELi2ELi3EEEEDaS2_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK5l_varMUlDpT_E_clIJiiiEEEDaS0_'\) and '-fabi-version=18' \('_ZNK5l_varMUlTpTyDpT_E_clIJiiiEEEDaS1_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK13l_tpl_tpl_tplMUlR6TPLTPLIT_EE_clI3TPLEEDaS2_'\) and '-fabi-version=18' \('_ZNK13l_tpl_tpl_tplMUlTtTtTyTnjEER6TPLTPLIT_EE_clI3TPLEEDaS3_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK9l_tpl_tplMUlR3TPLIT_EE_clI1UEEDaS2_'\) and '-fabi-version=18' \('_ZNK9l_tpl_tplMUlTtTyTnjER3TPLIT_EE_clI1UEEDaS3_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK13l_tpl_nt_autoMUlvE_clILi0EEEDav'\) and '-fabi-version=18' \('_ZNK13l_tpl_nt_autoMUlTnDavE_clILi0EEEDav'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK12l_tpl_nt_aryMUlRAT__iE_clILi2EEEDaS0_'\) and '-fabi-version=18' \('_ZNK12l_tpl_nt_aryMUlTniRAT__iE_clILi2EEEDaS1_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK10l_tpl_autoMUlT_T0_E_clIiiEEDaS_S0_'\) and '-fabi-version=18' \('_ZNK10l_tpl_autoMUlTyT_T0_E_clIiiEEDaS0_S1_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK5l_tplMUlT_E_clIiEEDaS_'\) and '-fabi-version=18' \('_ZNK5l_tplMUlTyT_E_clIiEEDaS0_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK6l_autoMUlT_E_clIiEEDaS_'\) and '-fabi-version=18' \('_ZNK6l_autoMUlT_E_clIiEEDaS0_'\) [^\n]*\n} } diff --git a/gcc/testsuite/g++.dg/abi/lambda-tpl1.h b/gcc/testsuite/g++.dg/abi/lambda-tpl1.h new file mode 100644 index 0000000..5d6fe5e --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-tpl1.h @@ -0,0 +1,59 @@ +inline auto l_auto = [] (auto) {}; + +inline auto l_tpl = [] <typename T> (T) {}; + +inline auto l_tpl_auto = [] <typename T> (T, auto) {}; + +inline auto l_tpl_nt_ary = [] <int I> (int (&)[I]) {}; + +inline auto l_tpl_nt_auto = [] <auto I = 0> () {}; + +template<typename T, unsigned I> class U; + +template<template<typename, unsigned> typename> class TPL {}; +inline auto l_tpl_tpl = [] <template<typename, unsigned> typename T> (TPL<T> &) {}; + +template<template<template<typename, unsigned> typename> typename> class TPLTPL {}; +inline auto l_tpl_tpl_tpl = []<template<template<typename, unsigned> typename> typename T> (TPLTPL<T> &) {}; + +inline auto l_var = []<typename... Args> (Args...) {}; + +#if FIXME // we fail to parse (&...) correctly +inline auto l_var2 = []<int... I> (int (&...)[I]) {}; +#endif + +template<int...I> class X {}; +inline auto l_var3 = []<template<int...> typename T, int...I> (T<I...> &a) {}; + +template<template<typename, unsigned> typename...T> class Y{}; +inline auto l_var4 = []<template<typename, unsigned> typename... T> (Y<T...> &a) {}; + +template<int I> inline void Fn () +{ + auto l = []<typename T> (T) {}; + l (1); +} + +void f () +{ + l_auto (1); + l_tpl (1); + l_tpl_auto (1, 1); + int ary[2]; + l_tpl_nt_ary (ary); + l_tpl_nt_auto (); + TPL<U> v; + l_tpl_tpl (v); + TPLTPL<TPL> u; + l_tpl_tpl_tpl (u); + l_var (1, 2, 3); +#if FIXME + l_var2 (ary, ary); +#endif + X<1,2,3> x; + l_var3 (x); + Y<U,U> y; + l_var4 (y); + + Fn<1> (); +} |