This is an archive of the discontinued LLVM Phabricator instance.

[libc++] Add _LIBCPP_EXTERN_TEMPLATE_INLINE_VISIBILITY to support GCC ABI compatibility
ClosedPublic

Authored by EricWF on Sep 14 2016, 9:39 PM.

Details

Summary

GCC and Clang handle visibility attributes on the out-of-line definition of externally instantiated templates differently. For example in the reproducer below Clang will emit both 'foo' and 'bar' with default visibility while GCC only emits a non-hidden 'foo'.

// RUN: g++ -std=c++11 -shared -O3 test.cpp && sym_extract.py a.out
// RUN: clang++ -std=c++11 -shared -O3 test.cpp && sym_extract.py a.out
#define INLINE_VISIBILITY __attribute__((visibility("hidden"), always_inline))

template <class T>
struct Foo {
  void foo();
  void bar();
};

template <class T>
void Foo<T>::foo() {}

template <class T>
inline INLINE_VISIBILITY
void Foo<T>::bar() {}

template struct Foo<int>;

This difference creates ABI incompatibilities between Clang and GCC built dylibs. Specifically GCC built dylibs lack definitions for various member functions of basic_string, basic_istream, basic_ostream, basic_iostream, and basic_streambuf (All of these types are externally instantiated).

Surprisingly these missing symbols don't cause many problems because the functions are marked always_inline therefore the dylib definition is rarely needed. However when an out-of-line definition is required then GCC built dylibs will fail to link. For example GCC built dylibs cannot build Clang.

This patch works around this issue by adding _LIBCPP_EXTERN_TEMPLATE_INLINE_VISIBILITY which is used to mark externally instantiated member functions as always inline. When building the library _LIBCPP_EXTERN_TEMPLATE_INLINE_VISIBILITY sets the symbol's visibility to "default" instead of "hidden", otherwise it acts exactly the same as _LIBCPP_INLINE_VISIBILITY.

After applying this patch GCC dylibs now contain:

  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE7sungetcEv
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE5gbumpEi
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE7sungetcEv
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE9sputbackcEc
  • _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE3getERNS_15basic_streambufIwS2_EE
  • _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEElsEPFRNS_9basic_iosIwS2_EES6_E
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE4setpEPcS4_
  • _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEEC1EPNS_15basic_streambufIwS2_EE
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE6snextcEv
  • _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEE4swapERS3_
  • _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE4swapERS3_
  • _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcm
  • _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEErsEPFRNS_8ios_baseES5_E
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE9pubsetbufEPcl
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE10pubseekoffExNS_8ios_base7seekdirEj
  • _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEErsEPFRNS_9basic_iosIwS2_EES6_E
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE5pbumpEi
  • _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE5seekpENS_4fposI11__mbstate_tEE
  • _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEE7getlineEPcl
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5sgetcEv
  • _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEE3getERNS_15basic_streambufIcS2_EE
  • _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEPFRNS_8ios_baseES5_E
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE8in_availEv
  • _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEErsEPFRNS_8ios_baseES5_E
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE6sbumpcEv
  • _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEPFRNS_9basic_iosIcS2_EES6_E
  • _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEE3getERc
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE6snextcEv
  • _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6__initEmw
  • _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE7getlineEPwl
  • _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE5tellpEv
  • _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE3getERw
  • _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEmc
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE7pubsyncEv
  • _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEE3getEPcl
  • _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEEC2EPNS_15basic_streambufIcS2_EE
  • _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEErsEPFRNS_9basic_iosIcS2_EES6_E
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE7pubsyncEv
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5sputcEc
  • _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEE5seekpExNS_8ios_base7seekdirE
  • _ZNKSt3__115basic_streambufIcNS_11char_traitsIcEEE6getlocEv
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5gbumpEi
  • _ZNSt3__114basic_iostreamIcNS_11char_traitsIcEEE4swapERS3_
  • _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEE5seekpENS_4fposI11__mbstate_tEE
  • _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEE5tellpEv
  • _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEElsEPFRS3_S4_E
  • _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE3getEPwl
  • _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEEC2EPNS_15basic_streambufIwS2_EE
  • _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEPFRS3_S4_E
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE4setgEPcS4_S4_
  • _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6__initEPKwmm
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE4setgEPwS4_S4_
  • _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEEC1EPNS_15basic_streambufIwS2_EE
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE8pubimbueERKNS_6localeE
  • _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE4swapERS3_
  • _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEEC2EPNS_15basic_streambufIwS2_EE
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE10pubseekposENS_4fposI11__mbstate_tEEj
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5pbumpEi
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE5sgetcEv
  • _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEE4swapERS3_
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE10pubseekposENS_4fposI11__mbstate_tEEj
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5sputnEPKcl
  • _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE5seekpExNS_8ios_base7seekdirE
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE5sgetnEPwl
  • _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEElsEPFRNS_8ios_baseES5_E
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE4setpEPwS4_
  • _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5sgetnEPcl
  • _ZNKSt3__115basic_streambufIwNS_11char_traitsIwEEE6getlocEv
  • _ZNSt3__114basic_iostreamIcNS_11char_traitsIcEEEC2EPNS_15basic_streambufIcS2_EE
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE8pubimbueERKNS_6localeE
  • _ZNSt3__114basic_iostreamIcNS_11char_traitsIcEEEC1EPNS_15basic_streambufIcS2_EE
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE8in_availEv
  • _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEEC1EPNS_15basic_streambufIcS2_EE
  • _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcmm
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE6sbumpcEv
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE10pubseekoffExNS_8ios_base7seekdirEj
  • _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEEC2EPNS_15basic_streambufIcS2_EE
  • _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEErsEPFRS3_S4_E
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE9sputbackcEw
  • _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6__initEPKwm
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE5sputnEPKwl
  • _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEErsEPFRS3_S4_E
  • _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEEC1EPNS_15basic_streambufIcS2_EE
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE9pubsetbufEPwl
  • _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE5sputcEw

This patch has no effect on Clang based builds.

Diff Detail

Event Timeline

EricWF updated this revision to Diff 71474.Sep 14 2016, 9:39 PM
EricWF retitled this revision from to [libc++] Add _LIBCPP_EXTERN_TEMPLATE_INLINE_VISIBILITY to support GCC ABI compatibility.
EricWF updated this object.
EricWF added a subscriber: cfe-commits.

I should mention that before this patch a GCC compiled dylib had 62 additional symbols and was missing 105 symbols. Now there are only 20 missing symbols and 62 additional.

EricWF updated this revision to Diff 71574.Sep 15 2016, 5:06 PM
  • Update the patch based on r281673.
  • Add doc for _LIBCPP_EXTERN_TEMPLATE_INLINE_VISIBILITY
  • Move all uses of _LIBCPP_EXTERN_TEMPLATE_INLINE_VISIBILITY to the first declaration in order to support __attribute__((internal_linkage)). I took the liberty of moving many of the definitions in-line to reduce duplication.
EricWF accepted this revision.Sep 15 2016, 5:08 PM
EricWF added a reviewer: EricWF.

Accepting to commit. Post commit review is very welcome (but nobody likes looking at visibility patches).

This revision is now accepted and ready to land.Sep 15 2016, 5:08 PM
EricWF closed this revision.Sep 15 2016, 5:09 PM