libc++ internals visibility rational


I’m wondering about libc++ visibility for the internals of the library. For example why do we define:

    void __construct_at_end(size_type __n, const_reference __x);
with inline/hidden visibility, but not this one:

template <class _ForwardIterator>
typename enable_if <__is_forward_iterator<_ForwardIterator>::value, void>::type
__construct_at_end(_ForwardIterator __first, _ForwardIterator __last, size_type __n);


Similarly with the public free template functions:

template <class _L0, class _L1>
lock(_L0& __l0, _L1& __l1)


template <class _L0, class _L1, class _L2, class ..._L3>
lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& …__l3)

Honestly I’ve been wondering about the same things.

Libc++ needs to re-evaluate it’s entire approach to symbol visibility especially w.r.t ABI management.
I think a lot of the existing behavior is purely historical, and newer parts of the library just try to mimic that
regardless of QoI. In particular I’m sceptical that libc++'s use of always_inline helps prevent “ABI problems”.

I would love to start a discussion on this, especially if it leads to concrete example
that can be turned into test cases


The context is that I’m working on the plan here:

Trying to remove “all" of the “always_inline”, making the public APIs hidden, and the internal APIs “internal_linkage”.

The kind of discrepancy I mentioned below puzzles me though.

I think this instance is just a bug.

As it was explained to me, libc++ attempts to make it possible to statically link together two libraries that use different versions of libc++ headers. These two libraries may reference inline template functions from libc++ with different definitions, but as long as all of the out-of-line symbols remain the same and implement the same functionality and use the same struct layouts, things are supposed to “work”.

With that in mind, any inline function in libc++ that isn’t always_inline or internal_linkage is probably a bug.

We should be able to have “ABI stable” function as well right?

The way I see it (with some help from Duncan) right now is that we have 5 conceptual categories for symbols. So instead of having macros like “INLINE_VISIBILITY” etc. I rather have macros that represent more accurately the category a function belongs to:

  1. Symbols present and exported in the dylib, these are ABI stable. Should be marked with _LIBCPP_DLL_VIS right now.
  2. Symbols that are public APIs (not starting with __), and ABI stable. These don’t have to be hidden or always_inline. I’d add a macro that would reflect this, like _LIBCPP_PUBLIC_ABISTABLE
  3. Symbols that are public APIs, and not ABI stable (do these exist?). These may need to stay hidden and always_inline, or possible made internal instead? The annotation could be _LIBCPP_PUBLIC_UNSTABLE
  4. Symbols that are private APIs, but ABI stable (likely rare?). We could mark them _LIBCPP_PRIVATE_ABISTABLE
  5. Symbols that are private APIs, and not ABI stable. Currently always_inline/hidden, but we’d like to change these to “internal_linkage”. We could mark them _LIBCPP_PRIVATE_UNSTABLE

This way we can expect every function to be decorated, and it should be fairly easy to spot a missing annotation.

And that’s just for the symbols, there is also the consideration about the type infos, vtables, etc. that I’m not totally sure about.