[cxx-abi-dev] N4198 and mangling for member pointer template arguments

John McCall rjmccall at apple.com
Wed Dec 3 00:34:30 UTC 2014


> On Dec 2, 2014, at 3:51 PM, Richard Smith <richardsmith at google.com> wrote:
> On 2 December 2014 at 13:58, John McCall <rjmccall at apple.com <mailto:rjmccall at apple.com>> wrote:
> Hmm.  I’d prefer not to hard-code an order dependence, because I think it’s likely that the committee will eventually weaken the rules about where packs can appear in parameter lists (e.g. to allow templates to pull arguments off the end instead of the beginning).
> So I think we either need to do what EDG does and heroically match later arguments which have to be part of the pack — which may or may not work equally well with future pack-placement rules — or pull back and say we’re completely blocked by the existence of dependent pack expansions.
> 
> EDG's approach is impossible to follow in some cases, such as:
> 
>   template<int A, short B, int C = 0> struct X {};
>   template<int ...N> void f(X<N..., 5>) {}
>   template void f<0>(X<0, 5>);
>   template void f<0, 1>(X<0, 1, 5>);
> 
> (EDG rejects this, which I suspect is related to their eager analysis of template arguments.)

Okay.  So are we comfortable with a simple rule that dependent pack expansions always make a template argument “dependent” in the sense I described?

> I think the ABI rule we’re looking at is something like this:  there are two kinds of template argument, dependent and non-dependent.  A template argument is dependent if:
>   - it is itself instantiation-dependent,
>   - the template name is dependent, or
>   - <some rule about dependent pack expansions?>.
> 
> ... or its corresponding template parameter is a non-type template parameter with a dependent type (or perhaps is an instantiation-dependent template template parameter).

Ah, right.

> A dependent template argument should be mangled using its original value/type/template-name expression.  A non-dependent non-type template argument can always be matched with a corresponding template parameter type and should be mangled as a (possibly coerced) literal value.
> 
> Right now, coercion only applies to non-type template arguments, but it’s also possible for it to apply to template template arguments in the future — I was just thinking of passing
>   template <class T, class U=int> class A;
> to a parameter typed as:
>   template<class> class
> but Doug points out that you could also pass variadic templates, e.g.
>   template <class… T> class A;
> 
> The template template argument issue is not an "in the future" issue; we get this wrong today:

Oh, I didn’t realize this was something you could currently do; I assumed that template template arguments had to be well-kinded.  Silly me.

I guess we need a contorting mangling here when the kind of a template doesn’t match the kind of a template template parameter, but… it’s probably not the most urgent thing we could be doing. :)  Especially given that you can contort the parameters of a template template parameter in a recursive position...

>   template<typename> struct X {};
>   template<template<typename> class> void f();
>   template<template<typename...> class> void f();
> 
> Both f<X>s have the same mangling.
> 
> This might be a somewhat unhelpful observation, but the root cause of the problem seems to be that our mangling of a function template misses out part of the signature (the template parameter list); consequently, if the name of a function template specialization is not dependent, we must put sufficient information in the template arguments to allow us to recover the template parameter list (at least to the point that we can distinguish between overloads).

I agree that the original sin here is not directly mangling anything about template parameter lists.  That’s not fixable, though, without completely breaking function-template compatibility.  The approach of mangling the final type/kind of template arguments works well enough, especially given that type/kind mismatches are uncommon and, in many cases, were previously forbidden.

> It looks like the template template parameter / template type parameter duality for injected-class-names can also theoretically cause problems, but you need to be a terrible person to observe it:
> 
>   template<template<typename T> class> int f() {}
>   template<class> int g() {}
>   template<typename> struct A {
>     template<typename T> friend void h(decltype(T() + f<A>()) *, decltype(T() + g<A>()) *, T) {}
>     void x() { h(0, 0, this); }
>   };
>   void j() { A<int>().x(); }
> 
> Here, GCC mangles f<A> and g<A> the same, even though one of them refers to A as a class template, and the other refers to A as a non-template injected-class-name. That might just be a GCC bug, though; its diagnostics suggest that it thinks the template argument for f is A<int> rather than A.

Definitely seems like a GCC bug.  I hope Clang mangles the first as a reference to A and the second as the type A<int>?

John.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://sourcerytools.com/pipermail/cxx-abi-dev/attachments/20141202/a86f91fb/attachment.html>


More information about the cxx-abi-dev mailing list