dmd/test/compilable/cppmangle2.d
Geod24 b75c9f1107 Fix issue 16479: No namespace substitution for C++ mangling on POSIX
The C++ ABI used by POSIX is the Itanium C++ ABI.
Reference document available here: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling

One important (and tricky) part of the ABI is the substitutions being done,
in order to reduce the bloat introduced by long symbol names,
a typical issue when using templates heavily (of which D was not exempt).

There are 2 kinds of substitutions: component substitution and template parameter substitution.
Component substitution replaces repeated parts of the symbol with `S[X]_`,
template parameter substitution replaces occurences of template parameters with `T[X]_`.
`X` represents a base36 index into the array of components or
template parameters already encountered so far, respectively.

This substitution is done on an identity basis, which means that the templated function
`template<typename T> int foo()` instantiated with `int` will be mangled as `_Z3fooIiE*i*v`
(asterisks are emphasis and not part of the mangling) while it would be mangled as `_Z3fooIiE*T_*v`
if the definition was `template<typename T> T foo()`.

Moreover, experience with C++ compilers shows that component substitution is prefered over
template parameter substitution, such as `template<typename T> T foo(T)` is mangled as
`_Z3fooIiET_*S0_*` when instantiated with `int` and not `_Z3fooIiET_*T_*` as would be the case
if template substitution was prefered.

This is just brushing the surface of the problem, since only template type parameters have been
mentioned so far, but other kind (aliases, values) are also concerned.
Substitution also needs to happen if a template parameter is part of another type,
such as the `template<typename T> array<T>* foo (T, int)`, which, when instantiated with `int`,
is mangled as `_Z3fooIiEP5arrayIT_ES1_i`.

For more detailed test cases, see `test/compilable/cppmangle.d`.

The main issue encountered while implementing this in DMD is that there's no easy way to know
if a type (which is part of the function's type, e.g. parameters and return value)
was a template parameter or not, as DMD merges types, so in the previously mentioned
`template<typename T> int foo()` vs `template<typename T> T foo()` the template instantiation
will come with the same exact two pointer to the singleton `int` type.

Moreover, DMD does destructive semantic analysis, meaning that objects gets mutated,
pointers get replaced, aliases get resolved, and information gets lost.

After different approaches where taken, the most practical and reliable approach devised was to
provide a `visit` overload for non-resolved AST type `TypeIdentifier` and `TypeInstance`,
and compare the identifier to that of the template definition.
Fallback to post-semantic type when it isn't found.

Note that no attempt has been made whatsoever to handle the mess that would result from
expressions themselves being mangled. The reference doc for the ABI mentions that
"[...] this mangling is quite similar to the source token stream. (C++ Standard reference 14.5.5.1p5.)".
Original quote:
https://itanium-cxx-abi.github.io/cxx-abi/abi.html#expressions (5.1.6 Expressions)
2018-10-29 19:28:50 +09:00

11 lines
131 B
D

module cppmangle2;
extern(C++, Namespace18922)
{
struct Struct18922 { int i; }
}
extern(C++, std)
{
struct vector (T);
}