c++templatesname-manglingitanium-abi

In the Itanium C++ ABI, why does the mangled name for template functions not resolve dependent typedefs?


For example:

template <typename T>
struct foo
{
    using bar = int;
};

// _Z3bazi
void baz(foo<int>::bar quux) {
}

template <typename T>
void baz(typename foo<T>::bar quux) {
}

// _Z3bazIiEvN3fooIT_E3barE
template void baz<int>(foo<int>::bar quux);

Why does the mangled form of baz<int> mention foo at all? How come it's not _Z3bazIiEvi?

This is apparently the reason that the C++17 std::default_order<T> proposal is dead in the water.


Solution

  • The issue comes from the <unresolved-name> construct in the ABI. Why would we ever want to use an unresolved name? It's all about declaration matching and overloads. C++14 §14.5.6.1/3 notes,

    Two distinct function templates may have identical function return types and function parameter lists, even if overload resolution alone cannot distinguish them.

    You can have another function in a different file,

    template <typename T>
    void baz(int quux) { std::abort(); }
    

    Although this signature can't peacefully coexist in the same file — it cannot be named because of overload ambiguity — it can exist in a different file so it needs a distinct mangling.

    (Even this level of coexistence is not guaranteed by the standard for all templates. It's a matter of QOI that the compiler uses the exact form of a function template declaration to perform declaration matching, so that copy-pasting a declaration into a definition will tend to provide an exact match and not a surprising conflict with another function template that resolves to the same signature. See §14.5.6.1/5-6.)

    As for raining on default_order's parade, the problem is that template-ids implicitly pull default arguments from templates. So the user could unintentionally have a dependent typename in a signature just by mentioning std::set.