On recent trunk: > $ cat test.cc > struct Color {}; > template<typename> struct SharedPtr {}; > struct Canvas { > virtual ~Canvas() {} > virtual void getClip() = 0; > virtual SharedPtr<Color> createColor() = 0; > }; > struct BitmapCanvas: virtual Canvas {}; > struct ImplCanvas: virtual Canvas { > virtual ~ImplCanvas(); > void getClip() override; > SharedPtr<Color> createColor() override; > }; > struct ImplBitmapCanvas: virtual BitmapCanvas, virtual ImplCanvas { > virtual ~ImplBitmapCanvas(); > }; > ImplBitmapCanvas::~ImplBitmapCanvas() {} > ImplBitmapCanvas c; > $ clang-cl -c test.cc > $ llvm-nm test.obj | grep -F '?getClip@ImplCanvas@@$' > 00000000 T ?getClip@ImplCanvas@@$4PPPPPPPM@A@EAAXXZ > 00000000 T ?getClip@ImplCanvas@@$R4BA@M@PPPPPPPM@BA@EAAXXZ > $ llvm-nm test.obj | grep -F '?createColor@ImplCanvas@@$' > U ?createColor@ImplCanvas@@$4PPPPPPPM@A@EAA?AU?$SharedPtr@UColor@@@@XZ > U ?createColor@ImplCanvas@@$R4BA@M@PPPPPPPM@BA@EAA?AU?$SharedPtr@UColor@@@@XZ The vtordisp thunks for getClip are emitted, while those for createColor are erroneously missing. The reason is that CodeGenVTabels::maybeEmitThunkForVtable (lib/CodeGen/CGVtables.cpp) returns early if !isFuncTypeConvertible, which hits here as the ClassTemplateSpecializationDecl for SharedPtr<Color> is !isCompleteDefinition, as there's no code in Sema that happens to call Sema::RequireCompleteType -> Sema::InstantiateClassTemplateSpecialization on it.
Stephan, The vtordisp thunk should be emitted with whichever TU contains the definition of ImplCanvas::createColor. Your TU doesn't provide a definition of ImplCanvas::createColor and thus misses out on the thunk.
Ah, but MSVC will not provide the thunk if *they* provide the definition... This is indeed an ABI break on our side.
*** Bug 33417 has been marked as a duplicate of this bug. ***
*** Bug 36952 has been marked as a duplicate of this bug. ***
Should be fixed by r329009.