Given this code:
class Foo { public: public: Foo() = default; virtual ~Foo() = default; }; class Bar : public Foo { static Bar Shared; Bar() = default; public: static Bar *get() { return &Shared; } int X = 0; }; Bar Bar::Shared; int main(int argc, char **argv) { return Bar::get()->X; }
Compile and dump the dynamic initializer symbols with both clang-cl and cl. You get the following:
$ clang-cl /Z7 /EHsc /c foo.cpp && dumpbin /symbols foo.obj | grep __E 052 00000000 SECT1 notype () Static | ??__EShared@Bar@@0V1@A@YAXXZ (??__EShared@Bar@@0V1@A@YAXXZ) $ cl /Z7 /EHsc /c foo.cpp && dumpbin /symbols foo.obj | grep __E 03B 00000000 SECT11 notype () Static | ??__E?Shared@Bar@@0V1@A@@YAXXZ (void __cdecl `dynamic initializer for 'private: static class Bar Bar::Shared''(void))
As we can see, clang-cl produces a different mangling which cannot be demangled by undname. AFAICT, this was not done for compatibility with an old version, and is in fact just broken (I tested back to MSVC 2013).
It makes sense that they would put the ? there, because it's a disambiguator between static data member and global. Previously my demangling code was a little hacky right here because I thought there was no disambiguator.
After this patch, we can run the same clang-cl command again and undname can demangle our symbol name.
$ clang-cl /Z7 /EHsc /c foo.cpp && dumpbin /symbols foo.obj | grep __E 052 00000000 SECT1 notype () Static | ??__E?Shared@Bar@@0V1@A@@YAXXZ (void __cdecl `dynamic initializer for 'private: static class Bar Bar::Shared''(void))