-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mangling updates for lambdas with explicit template parameter lists #31
Comments
On Aug 28, 2017, at 5:09 PM, Richard Smith ***@***.***> wrote:
Under p0428r2 <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0428r2.pdf>[*] (part of C++2a), lambda-expressions can have explicit template parameters:
inline auto f() {
return []<typename T>(T t) {
static T thing;
return &thing;
}(0);
}
Our lambda mangling forms a from the type of the lambda call operator, whose function parameter types may now contain references to template parameters that we do not encode into the mangling.
Should we include the explicit template parameters in the in some way? Or should we allow lambdas with distinct template parameter lists to result in the same and distinguish them via the discriminator?
I have a slight preference for including the template parameters in the mangled name. That gives more options to the demangler.
Daveed
… [*] open-std.org is down right now; this document can be viewed on the author's github page <https://github.com/ldionne/wg21/blob/master/generated/p0428r2.pdf> instead
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub <#31>, or mute the thread <https://github.com/notifications/unsubscribe-auth/AA8ZT7THuBVO3bph6pGYf3iQ-6VwAAF4ks5scyySgaJpZM4PFEsC>.
|
It's pretty unfortunate that we have independent discriminator sequences for different I feel like we should at least mangle how many explicit template parameters there are. Do we need anything else? We don't otherwise mangle template parameter lists, I think. |
I don't think we need anything at all; I think this is largely a question of readability of mangled and demangled names. Is a count of template parameters useful to a demangler? I have a (very) slight preference for mangling the template parameters, for consistency between |
I share this preference. I recently had to explore mangling for template parameters so that we could generate unique names for function template definitions (not their specializations). I ended up with the following extensions (using the recently added '$' to indicate vendor extensions)
With the above,
|
The only reason I can think of that knowing the template parameters would be useful to a demangler is that it would let the demangler reject some ill-formed mangled names, e.g. if they referred to a non-existent or incorrectly-kinded template parameter. So, not really. I'm fine with inventing a mangling for template parameters. It'll make some pretty long symbols even longer, but these are symbols that can almost always be stripped anyway. And yeah, it'll be useful for some other tools, as well as for any potential use cases that come up down the road (maybe with concepts?). |
Edit: consistently call the new production <template-param-decl> instead of sometimes using the (already-existing) production name <template-param> Based somewhat on @tahonermann's approach, how about:
Issue #24 would add
and extends
Issue #47 would add
... for cases where it's permissible to overload on the <template-param-decl>, and where the <template-param-decl> is not obvious from the form of the <template-arg>. Specifically, we'd use this when
(Per discussion on issue #20, we may want to defer the non-concepts part of this to ABI v2. But we've made bigger changes already to fix mangling collisions, so I don't think we should.) For a type difference between a non-type template parameter and its <template-arg> (particularly for the pointer-to-member case), I think we previously agreed to use a "cv" mangling to describe the conversion. A <template-param-decl> is not sufficient there; we need to know the conversion path, not just the final type, in some cases. |
I see both I would prefer a different name than to extend the meaning of The reason I extended
|
@tahonermann Thanks, I've edited my comment to fix the <template-param> typo to <template-param-decl> throughout. This is intended to be a new production unrelated to the existing <template-param>. I don't think I like attaching the <template-param-decl> to a use of a <template-param>, and I expect that will lead to ambiguities down the road in templates that do not use all of their parameters; I would prefer that we give the template parameter declarations up-front (in the <template-args> list of the template, for a use of an overloadable template). Your example demonstrates that my proposed scheme is missing something: in
... we need a way to reference both |
It feels weird to me too. The way we used it (well, intend to, we haven't actually rolled this out yet) is in the <template-args> list for a function template (only). The <template-arg> addition I described allowed including the <template-param-decl> encoding for overload disambiguation purposes and the <template-param> encoding to register a substitution candidate for resolution across template parameter scopes. For these functions:
mangled names like the following are generated. This is using your proposed <template-param-decl> additions and my <template-arg> addition. I probably have other errors in here; the point is the use of 'S0_' in the first (to reference 'T') where 'T_' is used in the second (to reference 'U'):
|
Interesting. It looks like you're relying on all references to a template parameter other than the first being mangled as a <substitution>. That appears to almost be true; I think there are precisely three contexts where a <template-param> can appear that do not support a <substitution>:
Presumably your scheme doesn't work in those cases? (It's incidentally unnerving to observe how much we're polluting the substitution space with template parameters that already have names that are as short as the substitution or shorter.) The idea of using substitutions to express something that could not be expressed without them seems odd to me; my mental model of a substitution is that it refers to some earlier substring of the mangling, and you should be able to first replace all substitutions with their corresponding substrings and then demangle and get the same result. (In fact, I have an idea for a multi-pass in-place constant-storage demangler that relies on this property, but this margin is too small to contain it etc.) Is there a problem with the lexical numbering of visible parameters approach? FWIW, I think I would mangle a function template as if its <template-args> contained a list of <template-param-decl>s alone. So your two
|
Yes, I have been relying on all template parameter references being mangled as substitutions; I wasn't aware of the exceptions you mentioned, but yes, I agree it looks like my approach does fail those cases. My approach also looks to fail for <expression> as well; I suspect cases like this would result in name collisions:
When coming up with this scheme, I do recall having distinct is-this-really-a-valid-use-of-substitutions thoughts :)
I think there may be at the implementation level. I've only looked at EDG's implementation and I'm not strongly familiar with it. Perhaps Daveed could chime in. From what I recall, EDG uses a coordinate system to identify a template parameter declaration scope and position and uses that to generate the parameter index value for <template-param>. I'm not sure how difficult it would be to support a lexical numbering system.
Yeah, I think I'll have to revisit this. I only introduced the <template-param> uses to resolve ambiguities that arose with the naming that was already in place and never felt really satisfied with that approach. Thanks for sharing your suggestions. |
And, of course, that is what you meant when you stated
(I apparently struggle with reading comprehension...) |
We do the same in Clang, identifying a template parameter by depth and index. I think lexical numbering of in-scope parameters in such a model should be fairly simple: when you start mangling a template template parameter, track its lexical index, and add that to the index of parameters within it to form their index. (That is, store an array mapping from depth to offset, populated when you enter a template template parameter; the lexical index of a template parameter is then "offset[depth] + index".) Or we could directly invent a <template-param> mangling that specifies both a depth and an index for the depth != 0 cases, or even encode the complete path of indexes from the outermost template to the parameter (the lexical index can be viewed as a compressed form of the latter approach: the lexical index is simply the sum of those indexes). Among these, the lexical index has the advantage of being the shortest, but I'd be fine with the other options. |
Both of those approaches sound reasonable. I'm assuming depth == 0 means the outermost list. Would a relative depth approach for referencing a parameter from an enclosing template parameter list be reasonable? That would avoid the need to specify a depth for reference to a parameter in the same parameter list which, I assume, is the common case. For example, if we changed <template-param> to the following (where 'U' stands for "up"):
then the following function templates:
would mangle to:
Presumably, these references would be substitution candidates. If so, that would again break with your model of substitutions representing substrings since the context of the reference would affect the mangling. |
On Oct 4, 2017, at 5:38 PM, Richard Smith ***@***.***> wrote:
From what I recall, EDG uses a coordinate system to identify a template parameter declaration scope and position and uses that to generate the parameter index value for <template-param>. I'm not sure how difficult it would be to support a lexical numbering system.
We do the same in Clang, identifying a template parameter by depth and index. I think lexical numbering of in-scope parameters in such a model should be fairly simple: when you start mangling a template template parameter, track its lexical index, and add that to the index of parameters within it to form their index. (That is, store an array mapping from depth to offset, populated when you enter a template template parameter; the lexical index of a template parameter is then "offset[depth] + index".)
Or we could directly invent a <template-param> mangling that specifies both a depth and an index for the depth != 0 cases, or even encode the complete path of indexes from the outermost template to the parameter (the lexical index can be viewed as a compressed form of the latter approach: the lexical index is simply the sum of those indexes). Among these, the lexical index has the advantage of being the shortest, but I'd be fine with the other options.
We use a depth and index system too.
I think either of the proposed mechanisms would be fine for us.
John.
|
I think in the name of consistency we should follow what we do for function parameters (and what implementations do in practice) and number based on depth and index within that depth. Specifically:
(where L is the level number excluding any levels of template parameters that have already been substituted; for example, the template parameters of a function template that is a member of a class template would get mangled with L = 0, because the class template's arguments get substituted before mangling). This seems straightforward for compilers and for demanglers, and has the advantage for human readers that the name for a template parameter doesn't change in different scopes in the same mangling. |
That sounds fine to me. The text should indicate what order levels are numbered in (presumably outside-in). Do you want to write up a patch? |
Yes, I'll assemble a patch. One more question: should we mangle template parameter packs differently from non-pack parameters? The <template-param-decl> approach described above (and implemented in Clang) does not do so. I would note that the mangling for these two have conflicted since C++11:
... so I think using distinct manglings for pack parameters would be appropriate. Suggestion:
(by analogy to the use of |
That seems like a template-template-argument example of the general problem that we neither mangle template parameter lists nor reflect coercions in template arguments, right? I still feel like if we're interested in solving that problem, we should solve it in general rather than poking around the edges. |
template parameters. This finishes the implementation of the proposal described in itanium-cxx-abi/cxx-abi#31. (We already implemented the <lambda-sig> extensions, but didn't take them into account when computing mangling numbers, and didn't deal properly with expanded parameter packs, and didn't disambiguate between different levels of template parameters in manglings.) llvm-svn: 371004
template parameters. This finishes the implementation of the proposal described in itanium-cxx-abi/cxx-abi#31. (We already implemented the <lambda-sig> extensions, but didn't take them into account when computing mangling numbers, and didn't deal properly with expanded parameter packs, and didn't disambiguate between different levels of template parameters in manglings.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@371004 91177308-0d34-0410-b5e6-96231b3b80d8
template parameters. This finishes the implementation of the proposal described in itanium-cxx-abi/cxx-abi#31. (We already implemented the <lambda-sig> extensions, but didn't take them into account when computing mangling numbers, and didn't deal properly with expanded parameter packs, and didn't disambiguate between different levels of template parameters in manglings.) git-svn-id: http://llvm.org/svn/llvm-project/cfe/trunk@371004 91177308-0d34-0410-b5e6-96231b3b80d8
Quite coincidentally, I proposed the same extension to I'm also in favor of the |
* 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 itanium-cxx-abi#31.
* 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 itanium-cxx-abi#31.
P0315R4 means that lambdas can appear in the signature of a function template, so we need a mangling for lambda-expressions too. I think the obvious mangling is the following (and I've incorporated it into pull request #85 with the other changes from this issue):
I've implemented all of this other than lambda literals (and P0315R4 more broadly) in Clang and libc++abi, and it seems to work well enough. |
Do you think that leaves adequate room for the 100% inevitable extension of SFINAE to lambda bodies? |
Less snarkily:
|
CWG is pretty solidly opposed to permitting SFINAE of lambda bodies; at this point it would be a complete reversal of direction. Of course, that doesn't mean it won't happen, but I don't think it's all that likely. That said, I don't think this approach actually precludes such an extension. The contexts in which we will mangle lambda expressions with this proposal are the contexts in which you couldn't overload on a SFINAE constraint in the closure type anyway. (This proposal only covers member functions, members of local classes, and other similar things that appear within some larger ODR context. If a lambda-expression is part of the signature of a non-member function template, the symbols for specializations of that function template should not have external linkage, modulo the wrinkle with modules.) If we changed our minds and started allowing SFINAE on lambda bodies in the future, we would need to mangle the lambdas' bodies in the cases where we would currently give function template specializations internal linkage. So we'd end up with inconsistent rules (sometimes mangling bodies, sometimes not), but no ABI break. Onto the questions:
|
Oh, there's one other context in which a lambda can appear where we will need to give it a context and a numbering: in the type of an inline variable or variable template:
This one seems hard to deal with, since we don't find out the mangling context until after we have already finished processing the lambda. Ouch. I'm going to take that case back to CWG to see if we can disallow that. |
Having thought about this a bit, I think it's preferable to use
Pull request updated to match. So far, CWG seems to agree with the direction of disallowing lambdas in the types of inline variables and variable templates. |
Can we also say that there's never a discriminator so that we can completely bypass the context problem? I was asking about modules because, if something with formally internal linkage in the module interface has to be usable across translation units, we basically have to solve that set of problems anyway, so there's no point in including a statement like "implementations should make sure they use internal linkage for these". Lambdas that are used in e.g. template arguments can still have their members used, right? So we still need a mangling for the type and its |
The For a lambda in a module, we will have a module name (or module partition name) to number within; I think we will still need to say something about the case where we don't have such a name. Yes, lambdas used in template arguments or
... and the ODR says that's the same lambda and the same static local variable across all translation units. |
Okay. So, I'm extremely uncomfortable about making the ABI of a declaration depend on the exact set of declarations that have come before it in its class / namespace / module. If it was local to a translation unit, that would be bad enough, but already it's not because of modules, and I wouldn't really believe that it would stay restricted anyway. If we can ask the committee to reconsider anything, can we ask them to reconsider whether cases like your |
Asked; for those with C++ committee reflector access, this is being discussed in this thread. |
@zygoloid, in your specification for:
Should that be
|
@tahonermann, my intention was to be consistent with the directly analogous mangling for function parameters, which use I would have no objection to switching to the scheme you mention if we think the complexity is worthwhile. |
Thanks @zygoloid. Mostly i just wanted to confirm the intent. I wasn't aware that the function parameter mangling didn't omit the number for |
template parameters. This finishes the implementation of the proposal described in itanium-cxx-abi/cxx-abi#31. (We already implemented the <lambda-sig> extensions, but didn't take them into account when computing mangling numbers, and didn't deal properly with expanded parameter packs, and didn't disambiguate between different levels of template parameters in manglings.) llvm-svn: 371004
Is any additional followup still needed for this issue? The associated PR is still open (and now has conflicts that will need to be resolved). |
Well, we were blocked on the CWG discussion about numbering lambdas, and as someone who doesn't pour over mailings, it wasn't really clear to me how that was resolved. The idea of making these lambdas internal linkage seemed appealing, but I'm not sure if the CWG actually went for that in the end. It would be good to get some resolution there. |
I'm not sure there is a CWG issue with respect to numbering. My impression of the above is that either a lexical or depth mechanism would would work but there was a preference for the depth/position mechanism. I'm not clear on the difference between this issue and #85. This seems mostly like a subset of that one. CWG did make some changes to make it ill-formed to use a TU-local closure type from another TU via modules, but I think that is orthogonal to this issue. |
Any progress on merging this in? |
(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 itanium-cxx-abi/cxx-abi#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.
(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 itanium-cxx-abi/cxx-abi#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.
This implements proposals from: - itanium-cxx-abi/cxx-abi#24: mangling for constraints, requires-clauses, requires-expressions. - itanium-cxx-abi/cxx-abi#31: requires-clauses and template parameters in a lambda expression are mangled into the <lambda-sig>. - itanium-cxx-abi/cxx-abi#47 (STEP 3): mangling for template argument is prefixed by mangling of template parameter declaration if it's not "obvious", for example because the template parameter is constrained (we already implemented STEP 1 and STEP 2). This changes the manglings for a few cases: - Functions and function templates with constraints. - Function templates with template parameters with deduced types: `typename<auto N> void f();` - Function templates with template template parameters where the argument has a different template-head: `template<template<typename...T>> void f(); f<std::vector>();` In each case where a mangling changed, the change fixes a mangling collision. Note that only function templates are affected, not class templates or variable templates, and only new constructs (template parameters with deduced types, constrained templates) and esoteric constructs (templates with template template parameters with non-matching template template arguments, most of which Clang still does not accept by default due to `-frelaxed-template-template-args` not being enabled by default), so the risk to ABI stability from this change is relatively low. Nonetheless, `-fclang-abi-compat=17` can be used to restore the old manglings for cases which we could successfully but incorrectly mangle before. Fixes #48216, #49884, #61273 Reviewed By: erichkeane, #libc_abi Differential Revision: https://reviews.llvm.org/D147655
Under p0428r2[*] (part of C++2a), lambda-expressions can have explicit template parameters:
Our lambda mangling forms a
<lambda-sig>
from the type of the lambda call operator, whose function parameter types may now contain references to template parameters that we do not encode into the mangling.Should we include the explicit template parameters in the
<lambda-sig>
in some way? Or should we allow lambdas with distinct template parameter lists to result in the same<lambda-sig>
and distinguish them via the discriminator?[*] open-std.org is down right now; this document can be viewed on the author's github page instead
The text was updated successfully, but these errors were encountered: