Open
Description
Consider:
C:\src\llvm-project>cat \src\temp\a.cc
template <typename>
struct Fruit {
__attribute((exclude_from_explicit_instantiation)) Fruit() {}
virtual void __attribute((exclude_from_explicit_instantiation)) draw() {}
};
extern template struct Fruit<int>;
int main() {
Fruit<int> f;
return 0;
}
C:\src\llvm-project>build\bin\clang-cl \src\temp\a.cc -fuse-ld=lld
lld-link: error: undefined symbol: public: virtual void __cdecl Fruit<int>::draw(void)
>>> referenced by c:\src\temp\a-6ec007.obj:(const Fruit<int>::`vftable')
clang-cl: error: linker command failed with exit code 1 (use -v to see invocation)
It seems that despite the exclude_from_explicit_instantiation
attribute on Fruit<>::draw
, the explicit instantiation decl prevents the definition from being emitted when referenced by the vtable. Instead the definition of Fruit<>::draw
will only get emitted once there's an explicit instantiation definition.
However, after 84216d1 that stopped working across DLL boundaries, since the method will no longer be dllimport/export.
It seems the exclusion from explicit instantiation is not working completely.
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
llvmbot commentedon Sep 20, 2023
@llvm/issue-subscribers-clang-codegen
It seems that despite the
exclude_from_explicit_instantiation
attribute onFruit<>::draw
, the explicit instantiation decl prevents the definition from being emitted when referenced by the vtable. Instead the definition ofFruit<>::draw
will only get emitted once there's an explicit instantiation definition.However, after 84216d1 that stopped working across DLL boundaries, since the method will no longer be dllimport/export.
It seems the exclusion from explicit instantiation is not working completely.
Revert "[clang] Don't inherit dllimport/dllexport to exclude_from_exp…
zmodem commentedon Sep 21, 2023
I think the crux of the problem is in
Sema::DefineUsedVTables()
(which in our case gets called afterInstantiateFunctionDefinition
ofFruit<int>::Fruit
):That does not hold in our case: because the
Fruit
constructor is markedexclude_from_explicit_instantiation
we will emit that constructor, and it will try to emit the vtable.But because
Sema::DefineUsedVTables()
decided not to emit the vtable, it has not markedFruit<int>::draw()
as referenced as it normally would (MarkVirtualMembersReferenced
), and so the vtable ends up referencing an undefined function.