llvm / llvm-project

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

clang fails to make visible explicit template instantiation. #38072

Open llvmbot opened 6 years ago

llvmbot commented 6 years ago
Bugzilla Link 38724
Version 6.0
OS Linux
Attachments Preprocessed source to reproduce the issue.
Reporter LLVM Bugzilla Contributor
CC @Lastique,@apolukhin,@DougGregor,@zygoloid,@rnk

Extended Description

We have a problem in Boost.Regex where compiling with clang++ -fvisibility=hidden results in certain explicit template instantiations not being visible from the final shared library - while the same code with g++ is just fine. Further more the template instances are marked "W" in the object file, yet somehow still end up being hidden in the final .so regardless of whether g++ or clang++ is used as the linker.

I've tried pretty hard to boil this down to a simple test case - but miserably failed as all the simple cases work as expected. So the attached test case is our code pre-processed with g++, and can then be compiled with either g++ or clang.

To reproduce, build with:

clang++ -fvisibility=hidden -DBOOST_REGEX_DYN_LINK -shared -I../../.. -fPIC  -o t.so instances-gcc-pp.cpp

Or

g++ -fvisibility=hidden -DBOOST_REGEX_DYN_LINK -shared -I../../.. -fPIC  -o t.so instances-gcc-pp.cpp

Then:

nm -D t.so

And search for "maybe_assign" - the g++ compiled .so will have two such records, while clang++ has none.

rnk commented 6 years ago

As a workaround, can you add __attribute__((visibility("default"))) to the explicit instantiation? That's what one would do for DLLs on Windows to fix the same issue.

While I acknowledge that this is an ABI incompatbility, clang's behavior seems reasonable to me. As a user, I would be somewhat annoyed if I added explicit instantiations of unannotated, DSO-internal class and suddenly they ended up in .dynsym.

apolukhin commented 6 years ago

We've been hit by this issue again in Boost.Filesystem.

GCC has extern template codecvt https://github.com/gcc-mirror/gcc/blob/9768d7eb98d3b5462e4423f806e241434a90648d/libstdc%2B%2B-v3/include/bits/codecvt.h#L480-L502

Attempt to use libstdc++ with -fvisibility=hidden on Calng++ gives sanitizer errors: https://travis-ci.org/vinniefalco/beast/jobs/429373840#L1289

libs/filesystem/src/path_traits.cpp:76:14: runtime error:member call on address 0x60300001d740 which does not point to an object of type 'std::__codecvt_abstract_base<wchar_t, char, __mbstate_t>'
0x60300001d740: note:object is of type 'std::codecvt<wchar_t, char, __mbstate_t>'
 02 00 80 1b  18 3e 73 1b 56 7f 00 00  01 00 00 00 be be be be  40 d2 00 00 30 61 00 00  00 00 00 00
              ^~~~~~~~~~~~~~~~~~~~~~~
              vptr for 'std::codecvt<wchar_t, char, __mbstate_t>'