[cfe-dev] Visibility in libc++

Nico Rieck nico.rieck at gmail.com
Thu Aug 1 05:07:01 PDT 2013


On 09.07.2013 16:41, Howard Hinnant wrote:
 > [... explanation for class template visibility ...]

So if I understand this correctly, the reason is that the Itanium ABI 
requires typeinfos to compare via their addresses, which breaks if a 
class template might be hidden in case libc++ headers get non-default 
visibility applied. And a user would have to explicitly specify the 
visibility for template instantiations (at least I think that this is 
possible).

> I don't know how Windows works, but others here do.  I don't thinkexceptions
> are working yet with clang on Windows, but I could be wrong.  It would be good
> to know how clang/exceptions are going to work on Windows before too much libc++
> design on Windows happens.  If we need some macro redesign work in libc++ in
> order to get libc++ working on Windows with clang, exceptions and visibility,
> I'm open to that.  Naturally we can't break other platforms in the process.
> Someone who can test on Windows will have to drive it, and that isn't me.

I don't think exceptions affect libc++ much in this regard. If the 
exception is in a shared library, and not header-only, it must be 
properly exported and imported. And due to how DLLs work, equal 
typeinfos can have different addresses and must use strcmp for comparison.

I currently have libc++ running as a DLL, and it passes all but 361 
tests. Most of these fail due to missing exception support or broken 
vtables, which are C++ ABI issues. For the rest I haven't implemented 
the necessary libc functions yet.

I encountered the following problems:

1. As said before, public templates have visibility applied which
    expands to import/export. Such templates must never be decorated
    with import/export because libc++ does obviously not export all
    instantiations (example: vector<T>).

2. A lot of internal globals, types, functions and specializations
    (internal as in those prefixed with "__") are undecorated, but
    must be imported/exported. And I think these must also have
    visibility applied (a few like class __thread_id already do).

    Examples:
    - extern __ph<1> _1;
    - __rs_default __rs_get()
    - template<> __codecvt_utf8<wchar_t>;

3. Extern template instantiations are undecorated but must be
    imported/exported.

    Examples:
    - extern template class __vector_base_common<true>;
    - extern template class class basic_istream<char>;

4. A few public types and functions are undecorated.

    I'm listing all I found to ensure it's ok to apply visibility
    to them. They are:

    exception:
    - exception_ptr current_exception()
    - void rethrow_exception(exception_ptr)
    future:
    - template<> class promise<void>
    memory:
    - void declare_reachable(void*)
    - void declare_no_pointers(char*, size_t)
    - void undeclare_no_pointers(char*, size_t)
    - pointer_safety get_pointer_safety() noexcept
    string:
    - void* align(size_t, size_t, void*&, size_t&)
    - narrow/wide versions of stoi, stol, stoul, stoll, stoull, stof,
      stod, stold
    - to_string, to_wstring
    system_error:
    - const error_category& generic_category() noexcept
    - const error_category& system_category() noexcept
    thread:
    - void sleep_for(const chrono::nanoseconds&)
    iostream.cpp:
    - cin, cout, cerr, clog and their wide counterparts (their
      declarations in <iostream> are decorated, but iostream.cpp
      does not include <iostream>, and thus the definitions are
      not imported/exported)

5. Exception classes/functions

    What exactly does _LIBCPP_EXCEPTION_ABI mean? At first I thought it
    applies to things defined in libc++abi, but it's also found
    on other types like regex_error, bad_weak_ptr, future_error etc.

    Also, the main exception classes like logic_error, runtime_error
    etc. are split between libc++ and libc++abi which requires importing
    one half and exporting the other half. This can be done by decorating
    the members explicitly.

    In any case there must be a distinction whether a header is used to
    compile libc++abi or if it's used to compile something using
    libc++abi.

Because a distinction between public and internal entities seems 
unnecessary, just one additional macro is needed that only ever expands 
to type visibility (case A):

A. Default type visibility (for templates)
B. Default type visibility + import/export (for public classes and
    public extern template instantiations)
C. Default visibility + import/export (for other public/internal
    entities)

I've named A. "_LIBCPP_TYPE_VIS_ONLY" so far, but am not exactly happy 
with that name.

Depending on how case 5 will be resolved, additional macros might be 
needed, but they don't affect cases A-C.

-Nico



More information about the cfe-dev mailing list