llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.37k stars 12.14k forks source link

clang-cl does not work with `/MDd` (dynamic debug CRT) due to `std::locale` link errors #18630

Open b1622bb8-0285-400e-ba44-ba0e5027e546 opened 10 years ago

b1622bb8-0285-400e-ba44-ba0e5027e546 commented 10 years ago
Bugzilla Link 18256
Version trunk
OS Windows XP
Depends On llvm/llvm-project#11542
CC @DougGregor,@rnk

Extended Description

Atempting to link an executable while testing Boost libraries with clang-cl I am seeing this error in a number of situations:

clang-win.link ..\..\..\bin.v2\libs\vmd\test\test_begin_identifier.test\clang-vc11-win-3.4\debug\test_begin_identifier.exe
test_begin_identifier.obj : error LNK2019: unresolved external symbol "public: static class std::locale::id std::ctype<char>::id" (?id@?$ctype@D@std@@2V0locale@2@A) referenced in function "class std::ctype<char> const & __cdecl std::use_facet<class std::ctype<char> >(class std::locale const &)" (??$use_facet@V?$ctype@D@std@@@std@@YAABV?$ctype@D@0@ABVlocale@0@@Z)
test_begin_identifier.obj : error LNK2019: unresolved external symbol "public: static class std::locale::id std::ctype<wchar_t>::id" (?id@?$ctype@_W@std@@2V0locale@2@A) referenced in function "class std::ctype<wchar_t> const & __cdecl std::use_facet<class std::ctype<wchar_t> >(class std::locale const &)" (??$use_facet@V?$ctype@_W@std@@@std@@YAABV?$ctype@_W@0@ABVlocale@0@@Z)
test_begin_identifier.obj : error LNK2019: unresolved external symbol "private: static int std::locale::id::_Id_cnt" (?_Id_cnt@id@locale@std@@0HA) referenced in function "public: __thiscall std::locale::id::operator unsigned int(void)" (??Bid@locale@std@@QAEIXZ)
test_begin_identifier.obj : error LNK2019: unresolved external symbol "void __cdecl std::_DebugHeapDelete<void>(void *)" (??$_DebugHeapDelete@X@std@@YAXPAX@Z) referenced in function "private: void __thiscall std::numpunct<wchar_t>::_Tidy(void)" (?_Tidy@?$numpunct@_W@std@@AAEXXZ)

The command line for clang-cl has these options: -TP /Od /Ob0 /W3 /GR /MDd /Zc:forScope /Zc:wchar_t -fmsc-version=1700 /wd4675 /EHs /D_HAS_EXCEPTIONS=0 /GR- -c

rnk commented 10 years ago

I fixed the _DebugHeapDelete problem in r207771, but the others remain with /D_DEBUG /MDd. They are blocked on importing a full class definition, which is llvm/llvm-project#11542 .

rnk commented 10 years ago

I can reproduce the problem by streaming a number, which invokes the locale machinery:

$ cat t.cpp
#include <iostream>
int main() {
  int x = 123;
  std::cout << x << '\n';
}
$ cl -nologo -D_HAS_EXCEPTIONS=0 -GR- -MTd -D_DEBUG -c t.cpp && dumpbin /symbols t.obj | grep 'DebugHeapDelete<void>'
t.cpp
585 00000000 SECTAC notype ()    External     | ??$_DebugHeapDelete@X@std@@YAXPAX@Z (void __cdecl std::_DebugHeapDelete<void>(void *))

$ clang-cl -D_HAS_EXCEPTIONS=0 -GR- -MTd -D_DEBUG -c t.cpp && dumpbin /symbols t.obj | grep 'DebugHeapDelete<void>'
3F1 00000000 UNDEF  notype       External     | ??$_DebugHeapDelete@X@std@@YAXPAX@Z (void __cdecl std::_DebugHeapDelete<void>(void *))

MSVC provides a definition for std::_DebugHeapDelete<void>(void*), but Clang does not. Clang should emit an error if it fails template instantiation, so I'm not sure why this compiles successfully at all.

If I use /MTd to get the static CRT, a definition is provided. However if I use /MDd, I get link errors. I've been linking the CRT statically because clang doesn't support dllimport / export of full classes yet (#11170 ).

llvmbot commented 10 years ago

Sorry, left out that the same header also provides the following macro:

#define _DELETE_CRT_VEC(ptr)    _STD _DebugHeapDelete((void *)ptr)

So it's definitely intentional that _DebugHeapDelete<void> be called here.

llvmbot commented 10 years ago

In Visual Studio 2012, when building with _DEBUG, the xdebug header provides a template function:

template<class _Ty> void _DebugHeapDelete(_Ty *_Ptr)
{
 if (_Ptr != 0)
 {
  _Ptr->~_Ty();
  free(_Ptr);
 }
}

with no other overrides or overloads that I can see.

The clang-cl I'm using here just reports no matching function call, as the above template fails substitition [with _Ty = void], due to the call to (void*)->~void.

So it's probably not resolving when linking because it's supposed to be an instantiated template that MSVC's CL doesn't fail on, but clang-cl does.

This is using the LLVM-3.5.r198737-win32 snapshot with -cxx-abi itanium, I'm guessing one of the compiler switches in the original report is causing clang-cl to turn the "cannot instantiate template" into an implicit "extern template class". /Ob0 "Disable inlining" perhaps?

b1622bb8-0285-400e-ba44-ba0e5027e546 commented 10 years ago

The compiler command line shows that it is compiling the debug version. The linker line, which invokes the Microsoft linker is:

link /nologo /DEBUG /MACHINE:X86 /MANIFEST /subsystem:console /out:"..\..\..\bin.v2\libs\vmd\test\test_after_identifier.test\clang-vc11-win-3.4\debug\test_after_identifier.exe"   @"..\..\..\bin.v2\libs\vmd\test\test_after_identifier.test\clang-vc11-win-3.4\debug\test_after_identifier.exe.rsp"

where the response file is simply:

"..\..\..\bin.v2\libs\vmd\test\test_after_identifier.test\clang-vc11-win-3.4\debug\test_after_identifier.obj"

The compile succeeds but the link gives an error.

If you think the .obj file will help you discover what the problem is I can attach it if you like.

rnk commented 10 years ago

I don't understand the first error, but the last looks like there's some kind of debug/release mismatch (std::_DebugHeapDelete<void>):

test_begin_identifier.obj : error LNK2019: unresolved external symbol "void __cdecl std::_DebugHeapDelete<void>(void *)" (??$_DebugHeapDelete@X@std@@YAXPAX@Z) referenced in function "private: void __thiscall std::numpunct<wchar_t>::_Tidy(void)" (?_Tidy@?$numpunct@_W@std@@AAEXXZ)

This is probably a mangler bug, or we're failing to instantiate an inline function that VC++ normally instantiates.