Open
Description
a.cc:
template <class>
concept True = true;
namespace test2 {
template<typename T> struct A {
template<typename U>
friend void h(...) requires True<U> {}
template<typename S>
friend void g(...) requires True<S>;
};
template<typename S>
void g(...) requires True<S> {}
void call() {
A<int> ai;
h<void>(ai);
g<void>(ai);
}
}
In the above snippet:
- the call
h<void>(ai)
is mangled as_ZN5test21hIvEEvzQ4TrueITL0__E
. Note that the constrained parameterU
is mangled asTL0_
(4TrueITL0__E
), i.e., a second-level template parameter (presumably the next level after the template parameters of the enclosing classA
). Note that the enclosing class template specializationA<int>
is not part of the mangling. - the call
g<void>(ai)
is mangled as_ZN5test21gIvEEvzQ4TrueIT_E
. Note that the constrained parameterU
is mangled asT_
(4TrueIT_E
), i.e., a first-level template parameter. - the difference between
h
andg
is that the definition of friend template functionh
is inside ofstruct A
, and the definition ofg
is outside. Otherwise, their signatures are identical.
The mangling of h<void>(ai)
makes it impossible to implement demangling of template parameter substitutions, since the substitution TL0_
cannot be demangled.
Options:
- Include the enclosing class template specialization
A<int>
into the mangling ofh<void>(ai)
, i.e., in cases when the friend function definition is part of the enclosing class. - Mangle the constraint
True<U>
in the definition ofh
asTrueIT_E
, i.e., as a first-level template parameter (ignoring the enclosing class), since as per https://eel.is/c++draft/temp.friend#9 and mangling for constrained templates itanium-cxx-abi/cxx-abi#24 (comment),h
is not a member-like constrained friend.
The latter option seems to fit better into the proposal in itanium-cxx-abi/cxx-abi#24 (comment).