Reputation: 1490
I was playing around with GCC (4.9.2) abi::__cxa_demangle and I got to a case where it couldn't demangle a specific symbol name.
That symbol is:
_ZNK12DebugWrapperIR5TestClsE5getIdIIEEEDTcldtcl7declvalIS1_EEL_ZNKS0_5getIdEvEspfp_EEDpOT_
I'm surprise to see "declval" in there.
That specific function is defined using this macro:
template <typename WrappedType>
class DebugWrapper
{
private:
WrappedType VALUE;
std::string NAME;
mutable std::string CALLER;
public:
...
#define WRAP_CONST_FUNCTION(name, enterLogging, exitLogging) \
template <typename ...Args> \
auto name(Args&&... args) const -> decltype(std::declval<WrappedType>().name(args...)) \
{ \
\
struct dummy \
{ \
const char* const FUNCTION = nullptr; \
const std::string& CALLER; \
const WrappedType& VALUE; \
\
dummy( const char* const input, \
const std::string& caller, \
const WrappedType& value): \
FUNCTION(input), CALLER(caller), VALUE(value) \
{ \
enterLogging; \
} \
\
~dummy() \
{ \
exitLogging; \
} \
}dummy(#name, CALLER, VALUE); \
\
return VALUE.name(args...); \
}
WRAP_CONST_FUNCTION(getId, <whatever>, <whatever>)
...
};
I also did a quick seach through the itanium c++ abi spec for declval but no result.
Why is it there ? and why can't abi::__cxa_demangle demangle it?
Upvotes: 3
Views: 156
Reputation:
Template functions need to have their return type appear in the mangled name because template functions can be overloaded on return type alone. A simpler example is
template <typename T> void f() { }
template <typename T> auto g() -> decltype(f<T>()) { }
inline void h() { }
int main() { g<int>(); h(); }
Compiling this and inspecting the output, I see:
$ g++ -c h.cc -std=c++11 && nm h.o | c++filt 0000000000000000 T main 0000000000000000 W decltype ((f)()) g() 0000000000000000 W h()
You can see the return type there for g
, but not for h
. The fact that h
is not a template function already means there cannot be another function h
in the same namespace with the same parameters.
This is also why getId
appears twice in your mangled name. One of those is the name itself, the other is coming from its appearance in the return type.
declval
is not special here, which is why it's not called out in the C++ ABI. Any function, library or user, gets treated the same way.
As for why it won't demangle, it's hard to tell. A real code example that generates the mangled name in your question would help here, but the 5TestCls
looks wrong, as the number that precedes a name indicates the length, and I do get the impression that TestCls
was supposed to be the full name. If that was indeed the name, then the demangling fails because the mangled name is invalid.
Based on the complete example, the one that you posted in the comments, I can come up with a reduced program, and it seems like it's the member access operator that's not handled properly by the demangler:
extern struct A { void f(); static void g(); } a;
template <typename...T> auto f(T...t) -> decltype(a.f(t...));
template <typename...T> auto g(T...t) -> decltype(A::g(t...));
int main() { f(); g(); }
$ g++ -std=c++11 -pedantic -c h.cc && nm h.o && nm -C h.o 0000000000000000 T main U _Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_ U _Z1gIJEEDTclL_ZN1A1gEvEspfp_EEDpT_ 0000000000000000 T main U _Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_ U decltype (A::g({parm#1}...)) g<>()
The difference between _Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_
and _Z1gIJEEDTclL_ZN1A1gEvEspfp_EEDpT_
is more apparent with some extra spacing:
_Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_ _Z1gIJEEDTcl L_ZN1A1gEvEspfp_EEDpT_
The only differences are f
vs. g
, and dtL_Z1aE
.
The Itanium C++ ABI specifies that x.y
is mangled as dt <expression> <unresolved-name>
. Here, <expression>
is L_Z1aE
. That part looks right. That indicates the "mangled" (not really) name of the a
global variable. But <unresolved-name>
is _ZN1A1fEvE
. That's wrong. That's right for the decltype(A::g(t...))
version, where the left-most operand of the function call operator can be represented as a mangled name through the <expr-primary> ::= L <mangled-name> E
production, but not for the decltype(a.f(t...))
version. It would mean something like A::f()
, but <unresolved-name>
is not supposed to have namespace qualifiers unless they actually appear in the source code, and even then, only with a special prefix (sr
). It also isn't supposed to have parameter info. The <unresolved-name>
should just be 1f
.
If the corrected name is used, then the demangler can handle it:
$ c++filt <<< _Z1fIJEEDTcldtL_Z1aE1fspfp_EEDpT_ decltype ((a.f)({parm#1}...)) f<>()
clang does generate the correct name, as can be seen on Coliru simply by changing g++
to clang++
in your command invocation. You may want to report this as a bug to the GCC developers.
Upvotes: 2