-
Notifications
You must be signed in to change notification settings - Fork 100
Description
The ABI document doesn't appear to give any guidance as to how to mangle partially-substituted portions of templates. For example, in:
template<typename ...T> struct A {
template<typename ...U> void f(void (*...f)(T, U)) {}
};
void x(int, int);
void g() { A<int>().f(x); }
how should A<int>::f
be mangled?
EDG says: _ZN1AIJiEE1fIJiEEEvDpPFvT_T_E
GCC produces the same (but needs the template argument to be explicitly specified).
Clang gives: _ZN1AIJiEE1fIJiEEEvDpPFv_SUBSTPACK_T_E
Neither mangling preserves enough information to uniquely identify the target function.
The immediate context for this question is issues #47 and #63: after substituting in template arguments from an outer template, how do we mangle the signature of an inner template?
For example:
struct A { int x; };
template<A a> struct B {
template<typename T> void f(decltype(T(a.x))) {}
};
void g() { B<A{0}>().f<int>(0); }
GCC mangles this as _ZN1BIXtl1AEEE1fIiEEvDTcvT_dtL_Z11_ZTAXtl1AEEE1xE
(note the reference to the template parameter object in the middle, not just dttl1AE1x
or similar); I think that's the right mangling here.
Another example:
class C {
char buf[32];
public:
constexpr const char *data() const { return buf; }
};
C c;
template<const char *p> struct X {};
void f(X<c.data()>) {}
template<const char *p> struct Y { template<typename T> void g(X<T(p)>); };
void h() { Y<c.data()>().g<const char*>({}); }
As I argued in #47, I don't think it's acceptable for us to include the private member name buf
in the mangling of f
. So similarly it doesn't seem acceptable for us to include the private member name buf
in the mangling of Y<c.data()>::g
. That suggests to me that the correct mangling to use for a substituted non-type template argument in general is the mangling of the <expression> or <expr-primary> that would appear in the corresponding <template-arg>.
The extension to more general substitution situations seems mostly straightforward: when a type is substituted, you mangle it as you would mangle the <type> in the corresponding <template-arg> (and indeed, presumably this mangling will almost always be a substitution referring back to that <template-arg>). And it would then presumably be appropriate to mangle a substituted pack as J <template-arg>* E
.
So:
The first example is mangled as _ZN1AIJiEE1fIJiEEEvDpPFvJiET_E
In the second example, we produce the manglings:
_Z1f1XIXadsoKcL_Z1cEEEE
(that is, f(X<&{c subobject of type 'const char' at offset 0}>)
)
_ZN1YIXadsoKcL_Z1cEEEE1gIPKcEEv1XIXcvT_adsoKcL_Z1cEEEE
Does that seem reasonable? (Note that I'm not suggesting adding any substitution candidates for the new manglings -- and in practice we'll see outer non-type and pack template arguments appearing multiple times in the same mangling. I don't think that we can do much about that, unless we support substitutions of expressions in general (ouch) or ask implementations to keep track of where they substituted into a signature (perhaps also ouch?) -- and in any case changes of that kind would be an ABI break.)