Open
Description
https://godbolt.org/z/TK7Yr8b6c shows a difference in C++ mangling, or what symbol reference gets generated, between GCC and and Clang.
#include <type_traits>
namespace rocket {
template<typename charT>
class basic_tinyfmt;
using tinyfmt = basic_tinyfmt<char>;
using ::std::enable_if;
using ::std::is_arithmetic;
using ::std::is_same;
template<typename charT, typename valueT,
typename enable_if<is_arithmetic<valueT>::value
&& !is_same<valueT, charT>::value
>::type* = nullptr>
inline
basic_tinyfmt<charT>&
operator<<(basic_tinyfmt<charT>& fmt, valueT value); //...
extern template tinyfmt& operator<<(tinyfmt&, signed char);
extern template tinyfmt& operator<<(tinyfmt&, signed short);
extern template tinyfmt& operator<<(tinyfmt&, signed int);
extern template tinyfmt& operator<<(tinyfmt&, signed long);
extern template tinyfmt& operator<<(tinyfmt&, signed long long);
} // namespace rocket
void
do_format(::rocket::tinyfmt& fmt, int value)
{
fmt << value;
}
$ g++ -S -o - cxx-mismatch.cpp -O2
[...]
_Z9do_formatRN6rocket13basic_tinyfmtIcEEi:
jmp _ZN6rocketlsIciLPv0EEERNS_13basic_tinyfmtIT_EES5_T0_@PLT
$ clang++ -S -o - cxx-mismatch.cpp -O2
_Z9do_formatRN6rocket13basic_tinyfmtIcEEi:
jmp _ZN6rocketlsIciTnPNSt9enable_ifIXaasr13is_arithmeticIT0_EE5valuentsr7is_sameIS2_T_EE5valueEvE4typeELPv0EEERNS_13basic_tinyfmtIS3_EESA_S2_@PLT
The generated function name is the same in both cases, _Z9do_formatRN6rocket13basic_tinyfmtIcEEi
, but GCC references a function named _ZN6rocketlsIciLPv0EEERNS_13basic_tinyfmtIT_EES5_T0_
while Clang references a function named _ZN6rocketlsIciTnPNSt9enable_ifIXaasr13is_arithmeticIT0_EE5valuentsr7is_sameIS2_T_EE5valueEvE4typeELPv0EEERNS_13basic_tinyfmtIS3_EESA_S2_
; this can end up causing undefined references. Both symbols demangle into the same, rocket::basic_tinyfmt<char>& rocket::operator<<<char, int, (void*)0>(rocket::basic_tinyfmt<char>&, int)
.
Issue originally encountered by @lhmouse.