public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* c++: Templated lambda mangling
@ 2022-10-27 16:00 Nathan Sidwell
  0 siblings, 0 replies; only message in thread
From: Nathan Sidwell @ 2022-10-27 16:00 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 877 bytes --]

(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.

I did find a couple of bugs on the way -- one is a failure to parse thhe pack 
expansion in :
   inline auto l_var2 = []<int... I> (int (&...)[I]) {}

the other was clang miscounting substitutions, 
https://github.com/llvm/llvm-project/issues/58631, always a good idea to have 
multiple implementations :)

the remaining change to do is lambda sequence numbering, as that is affected by 
lambda signature.

nathan

-- 
Nathan Sidwell

[-- Attachment #2: 0001-c-Templated-lambda-mangling.patch --]
[-- Type: text/x-patch, Size: 13790 bytes --]

From bf6e972b65c56c615682f712f785d0f0541ac77b Mon Sep 17 00:00:00 2001
From: Nathan Sidwell <nathan@acm.org>
Date: Mon, 24 Oct 2022 17:39:55 -0400
Subject: [PATCH] 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.
---
 gcc/cp/mangle.cc                              | 68 +++++++++++++++++++
 gcc/testsuite/g++.dg/abi/lambda-ctx1-18.C     |  4 +-
 gcc/testsuite/g++.dg/abi/lambda-ctx1-18vs17.C |  4 +-
 gcc/testsuite/g++.dg/abi/lambda-tpl1-17.C     | 20 ++++++
 gcc/testsuite/g++.dg/abi/lambda-tpl1-18.C     | 25 +++++++
 gcc/testsuite/g++.dg/abi/lambda-tpl1-18vs17.C | 16 +++++
 gcc/testsuite/g++.dg/abi/lambda-tpl1.h        | 59 ++++++++++++++++
 7 files changed, 192 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/abi/lambda-tpl1-17.C
 create mode 100644 gcc/testsuite/g++.dg/abi/lambda-tpl1-18.C
 create mode 100644 gcc/testsuite/g++.dg/abi/lambda-tpl1-18vs17.C
 create mode 100644 gcc/testsuite/g++.dg/abi/lambda-tpl1.h

diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 1215463089b..e39621876ef 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 c1c9e274d7f..3dd68a4bed2 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 f5ec905dec3..ec6709a1df0 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 00000000000..b61aaf98cd0
--- /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 00000000000..dbeea407651
--- /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 00000000000..8bead7393c7
--- /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 00000000000..5d6fe5e1d0a
--- /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> ();
+}
-- 
2.37.3


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-27 16:00 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-27 16:00 c++: Templated lambda mangling Nathan Sidwell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).