From 3ebf3e64c51b6c703621ebc39fc3af9e1f644557 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 5 Sep 2019 16:20:34 -0700 Subject: [PATCH 1/5] ABI updates for C++20 lambda-expression features: * include declarations for explicitly-specified template parameters in the lambda-sig mangling * add mangling for template parameters at different depths (possible via generic lambdas in unevaluated operands and via template template parameters in lambda-sigs) Fixes #31. --- abi.html | 68 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/abi.html b/abi.html index 700d3319..a9439ff3 100644 --- a/abi.html +++ b/abi.html @@ -4990,14 +4990,52 @@
5.1.5.8 Template parameters
that is the actual parameter.

+

+Let L be the number of template parameter scopes enclosing the +template parameter scope in which the parameter is declared, +excluding any template parameter scopes whose template arguments +have already been substituted into the type or expression being mangled. +Typically L will be zero, but can be nonzero when a generic lambda +occurs within the signature of a function template or when mangling +a template template parameter declaration. For example: + +


+	template<typename> struct A {
+	  // Type of a is TL0_0_, type of b is T_, type of c is TL0__, type of u is TL1__.
+	  template<typename T> void f(decltype([]<typename U, template<U u> typename>(auto a, T b, U c){})) {}
+	};
+
+

+

-  <template-param> ::= T_	# first template parameter
-		   ::= T <parameter-2 non-negative number> _
+  <template-param> ::= T_									# L == 0, first parameter
+		   ::= T <parameter-2 non-negative number> _					# L == 0, second and later parameters
+		   ::= TL <L-1 non-negative number> __						# L > 0, first parameter
+		   ::= TL <L-1 non-negative number> _ <parameter-2 non-negative number> _	# L > 0, second and later parameters
   <template-template-param> ::= <template-param>
 			    ::= <substitution>
+
+ +

+Within a <lambda-sig>, +explicit template parameter declarations are mangled. +

+ +

+  <template-param-decl> ::= Ty					# template type parameter
+			::= Tn <type>				# template non-type parameter
+			::= Tt <template-param-decl>* E		# template template parameter
+			::= Tp <non-pack template-param-decl>	# template parameter pack
 
+

+(Note: the intent is to eventually use these template parameter +manglings more broadly, to distinguish between function templates +that are overloaded on template parameters but that are otherwise +indistinguishable.) +

+
5.1.5.9 Function parameter references
@@ -5531,7 +5569,8 @@

5.1.8 Closure Types (Lambdas)

<closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ with -
  <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters
+
  <lambda-sig> ::= <explicit template-param-decl>*	# Excluding template parameters introduced for auto parameters
+                   <parameter type>+			# Parameter types or "v" if the lambda has no parameters
 
The number is omitted for the first closure type with a given <lambda-sig> in a given context; it is n-2 for the nth closure @@ -5611,13 +5650,22 @@

5.1.8 Closure Types (Lambdas)

In a generic lambda, uses of auto in the parameter list are mangled as the corresponding artificial template type parameter. -This is never ambiguous with a lambda parameter whose type is an -enclosing template type parameter, because lambdas are never mangled -in a dependent context (they are forbidden from appearing in function -signatures). A <template-param> in a <lambda-sig> can only ever refer to a -template parameter of a generic lambda. +If a generic lambda appears in a dependent context (for example, in +the signature of a function template), references to its template +parameters (including those introduced by uses of auto) +are encoded as <template-param>s +with a non-zero level. +

+ +

+<b>NOTE</b>: + +A non-member function template whose signature contains a lambda-expression can +never redeclare a function template declared in a different translation unit. +Implementations must ensure that such symbols are not linked together across +translation units, perhaps by giving affected symbols internal linkage. + +

From d87d707357d649d8a407fa289c6e95d6e18f6c8c Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 6 Sep 2019 15:24:00 -0700 Subject: [PATCH 2/5] Add a mangling for lambda-expressions (which can now appear in unevaluated operands and therefore in function signatures). --- abi.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/abi.html b/abi.html index a9439ff3..ea65b86f 100644 --- a/abi.html +++ b/abi.html @@ -5246,6 +5246,7 @@

5.1.6 Expressions

::= L <nullptr type> E # nullptr literal (i.e., "LDnE") ::= L <pointer type> 0 E # null pointer template argument ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) + ::= L <lambda closure-type-name> E # lambda expression ::= L _Z <encoding> E # external name <braced-expression> ::= <expression> @@ -5265,6 +5266,16 @@

5.1.6 Expressions

(e.g., ::x).

+

When a lambda expression appears in the type of a function template at namespace scope, +that function template cannot be redeclared in other translation units, +so this ABI does not constrain its mangling except that it cannot collide +with symbols in other translation units. +When a lambda expression appears in an instantiation-dependent expression +in other contexts (for example, in the signature of a function template at class scope), +it is mangled as a <closure-type-name>, +excluding any name prefix, but including its number within its context. +The context is implied by the remaining portion of the encoding.

+

tl is used for direct-list-initializations, where the type name is directly followed by a braced-init-list; e.g., MyArray{1,2,3} should be mangled tl7MyArrayLi1ELi2ELi3EE. If the braced-init-list is parenthesized, this is not a direct-list-initialization, and it should be mangled with cv and a nested il; for example, MyArray({1,2,3}) should be mangled cv7MyArrayilLi1ELi2ELi3EE.

If an implementation supports the full C99 designated initializer syntax (as an extension), a designator list comprising multiple designators results in From 9618b59f28475fa2959481ea5b44df39263f0dbd Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 6 Sep 2019 19:09:14 -0700 Subject: [PATCH 3/5] Add numbering rule for lambdas in class bodies outside of default arguments and default member initializers. --- abi.html | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/abi.html b/abi.html index ea65b86f..6a2922fd 100644 --- a/abi.html +++ b/abi.html @@ -5570,6 +5570,7 @@

5.1.8 Closure Types (Lambdas)

  • default member initializers
  • the bodies of inline or templated functions
  • the initializers of inline or templated variables
  • +
  • the remaining contexts in class definitions
  • In all these contexts, the encoding of the closure types builds on an @@ -5658,6 +5659,28 @@

    5.1.8 Closure Types (Lambdas)

    // Corresponding operator(): _ZNK1SIiE1xMUlvE_clEv
    +

    +If the context is within a class definition, +and not within one of the above more specific cases, +the closure class and its members are encoded as follows: +

      <local-name> ::= Z <class name> E <entity name>
    +
    +As above, the <entity name> will contain a +<closure-type-name>, +which is numbered within the class, counting only those closure types for which +this mangling rule applies. +For example: +
    +	struct S {
    +	  // Template argument is LZ1SEUlvE_E; f<true> is _ZN1S1fILb1EEEv1XILUlvE_EE
    +	  template<bool B> void f(X<[]{ return B; }()>) { ... }
    +	  int n = []{ return 0; }(); // not counted towards numbering in struct S
    +	  // Template argument is LZ1SEUlvE0_E; f<true> is _ZN1S1fILb1EEEv1XILUlvE0_EE
    +	  template<bool B> void f(X<[]{ return !B; }()>) { ... }
    +	};
    +
    + +

    In a generic lambda, uses of auto in the parameter list are mangled as the corresponding artificial template type parameter. From 36bc62b8479244981b51629770b4c6f4b1715f3d Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 28 Jun 2023 12:03:31 -0700 Subject: [PATCH 4/5] Use the name of a static data member in the mangling of a lambda appearing in its initializer. --- abi.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abi.html b/abi.html index 6a2922fd..8bf9f39a 100644 --- a/abi.html +++ b/abi.html @@ -5569,7 +5569,7 @@

    5.1.8 Closure Types (Lambdas)

  • default arguments appearing in class definitions
  • default member initializers
  • the bodies of inline or templated functions
  • -
  • the initializers of inline or templated variables
  • +
  • the initializers of inline or templated variables and static data members
  • the remaining contexts in class definitions
  • From 886d2c3bb579833eaacaea6c624290f9ac33d0fc Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 28 Jun 2023 13:17:19 -0700 Subject: [PATCH 5/5] Describe a mangling wrinkle that occurs when naming a lambda that appears in the signature of a function template. --- abi.html | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/abi.html b/abi.html index 7ec99f16..ba6903da 100644 --- a/abi.html +++ b/abi.html @@ -6136,6 +6136,34 @@

    5.1.8 Closure Types (Lambdas)

    template<bool B> void f(X<[]{ return !B; }()>) { ... } }; +

    + +

    +When a lambda appears in the declaration portion of a function template, +it is numbered within the enclosing context when determining +the mangling of the function template and its instantiations. +Similarly, when a lambda appears in the declaration portion +of a non-template variable or function, +it is numbered within the enclosing context. +However, when a function or variable template is instantiated, +all lambdas produced by that instantiation, +including those in the declaration portion, +are numbered within the resulting instantiated function or variable +as part of the same numbering sequence as lambdas appearing +in the function definition or variable initializer. +For example: +

    +	struct S {
    +	  // S::f<int, int> is _ZN1S1fIJiiEEEv1XIJXspLUlvE_EEEE
    +	  // The lambda call operators for the two lambdas are
    +	  // _ZZN1S1fIJiiEEEv1XIJXspLUlvE_EEEEENKUlvE_clEi and
    +	  // _ZZN1S1fIJiiEEEv1XIJXspLUlvE_EEEEENKUlvE0_clEi,
    +	  // and numbering of lambdas with a <lambda-sig> of v
    +	  // within the body starts at UlvE1_.
    +	  template<typename ...T> void f(X<[]{ static T n; return &n; }...>) { ... }
    +	};
    +
    +