Skip to content

[libc++] Remove _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS #111964

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion libcxx/.clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ AttributeMacros: [
'_LIBCPP_HIDDEN',
'_LIBCPP_HIDE_FROM_ABI_AFTER_V1',
'_LIBCPP_HIDE_FROM_ABI',
'_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS',
'_LIBCPP_NO_SANITIZE',
'_LIBCPP_NO_UNIQUE_ADDRESS',
'_LIBCPP_NOALIAS',
Expand Down
29 changes: 0 additions & 29 deletions libcxx/docs/DesignDocs/VisibilityMacros.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,35 +105,6 @@ Visibility Macros
the extern template declaration) as exported on Windows, as discussed above.
On all other platforms, this macro has an empty definition.

**_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS**
Mark a symbol as hidden so it will not be exported from shared libraries. This
is intended specifically for method templates of either classes marked with
`_LIBCPP_TYPE_VIS` or classes with an extern template instantiation
declaration marked with `_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS`.

When building libc++ with hidden visibility, we want explicit template
instantiations to export members, which is consistent with existing Windows
behavior. We also want classes annotated with `_LIBCPP_TYPE_VIS` to export
their members, which is again consistent with existing Windows behavior.
Both these changes are necessary for clients to be able to link against a
libc++ DSO built with hidden visibility without encountering missing symbols.

An unfortunate side effect, however, is that method templates of classes
either marked `_LIBCPP_TYPE_VIS` or with extern template instantiation
declarations marked with `_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS` also get default
visibility when instantiated. These methods are often implicitly instantiated
inside other libraries which use the libc++ headers, and will therefore end up
being exported from those libraries, since those implicit instantiations will
receive default visibility. This is not acceptable for libraries that wish to
control their visibility, and led to PR30642.

Consequently, all such problematic method templates are explicitly marked
either hidden (via this macro) or inline, so that they don't leak into client
libraries. The problematic methods were found by running
`bad-visibility-finder <https://github.com/smeenai/bad-visibility-finder>`_
against the libc++ headers after making `_LIBCPP_TYPE_VIS` and
`_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS` expand to default visibility.

Links
=====

Expand Down
182 changes: 85 additions & 97 deletions libcxx/include/__condition_variable/condition_variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,60 +39,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_DECLARE_STRONG_ENUM(cv_status){no_timeout, timeout};
_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)

class _LIBCPP_EXPORTED_FROM_ABI condition_variable {
__libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;

public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;

# if _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
~condition_variable() = default;
# else
~condition_variable();
# endif

condition_variable(const condition_variable&) = delete;
condition_variable& operator=(const condition_variable&) = delete;

void notify_one() _NOEXCEPT;
void notify_all() _NOEXCEPT;

void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
template <class _Predicate>
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS void wait(unique_lock<mutex>& __lk, _Predicate __pred);

template <class _Clock, class _Duration>
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t);

template <class _Clock, class _Duration, class _Predicate>
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred);

template <class _Rep, class _Period>
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d);

template <class _Rep, class _Period, class _Predicate>
bool _LIBCPP_HIDE_FROM_ABI
wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);

typedef __libcpp_condvar_t* native_handle_type;
_LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; }

private:
void
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
# if _LIBCPP_HAS_COND_CLOCKWAIT
_LIBCPP_HIDE_FROM_ABI void
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
# endif
template <class _Clock>
_LIBCPP_HIDE_FROM_ABI void
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
};
#endif // _LIBCPP_HAS_THREADS

template <class _Rep, class _Period, __enable_if_t<is_floating_point<_Rep>::value, int> = 0>
inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {
using namespace chrono;
Expand Down Expand Up @@ -140,64 +86,106 @@ inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::
return nanoseconds(__result);
}

#if _LIBCPP_HAS_THREADS
template <class _Predicate>
void condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) {
while (!__pred())
wait(__lk);
}
class _LIBCPP_EXPORTED_FROM_ABI condition_variable {
__libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;

template <class _Clock, class _Duration>
cv_status condition_variable::wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t) {
using namespace chrono;
using __clock_tp_ns = time_point<_Clock, nanoseconds>;
public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;

typename _Clock::time_point __now = _Clock::now();
if (__t <= __now)
return cv_status::timeout;
# if _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
~condition_variable() = default;
# else
~condition_variable();
# endif

__clock_tp_ns __t_ns = __clock_tp_ns(std::__safe_nanosecond_cast(__t.time_since_epoch()));
condition_variable(const condition_variable&) = delete;
condition_variable& operator=(const condition_variable&) = delete;

__do_timed_wait(__lk, __t_ns);
return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
}
void notify_one() _NOEXCEPT;
void notify_all() _NOEXCEPT;

void wait(unique_lock<mutex>& __lk) _NOEXCEPT;

template <class _Clock, class _Duration, class _Predicate>
bool condition_variable::wait_until(
unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) {
while (!__pred()) {
if (wait_until(__lk, __t) == cv_status::timeout)
return __pred();
template <class _Predicate>
_LIBCPP_HIDE_FROM_ABI void wait(unique_lock<mutex>& __lk, _Predicate __pred) {
while (!__pred())
wait(__lk);
}
return true;
}

template <class _Rep, class _Period>
cv_status condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d) {
using namespace chrono;
if (__d <= __d.zero())
return cv_status::timeout;
using __ns_rep = nanoseconds::rep;
steady_clock::time_point __c_now = steady_clock::now();
template <class _Clock, class _Duration>
_LIBCPP_HIDE_FROM_ABI cv_status
wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t) {
using namespace chrono;
using __clock_tp_ns = time_point<_Clock, nanoseconds>;

typename _Clock::time_point __now = _Clock::now();
if (__t <= __now)
return cv_status::timeout;

__clock_tp_ns __t_ns = __clock_tp_ns(std::__safe_nanosecond_cast(__t.time_since_epoch()));

__do_timed_wait(__lk, __t_ns);
return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
}

template <class _Clock, class _Duration, class _Predicate>
_LIBCPP_HIDE_FROM_ABI bool
wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) {
while (!__pred()) {
if (wait_until(__lk, __t) == cv_status::timeout)
return __pred();
}
return true;
}

template <class _Rep, class _Period>
_LIBCPP_HIDE_FROM_ABI cv_status wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d) {
using namespace chrono;
if (__d <= __d.zero())
return cv_status::timeout;
using __ns_rep = nanoseconds::rep;
steady_clock::time_point __c_now = steady_clock::now();

# if _LIBCPP_HAS_COND_CLOCKWAIT
using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
__ns_rep __now_count_ns = std::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();
using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
__ns_rep __now_count_ns = std::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();
# else
using __clock_tp_ns = time_point<system_clock, nanoseconds>;
__ns_rep __now_count_ns = std::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
using __clock_tp_ns = time_point<system_clock, nanoseconds>;
__ns_rep __now_count_ns = std::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
# endif

__ns_rep __d_ns_count = std::__safe_nanosecond_cast(__d).count();
__ns_rep __d_ns_count = std::__safe_nanosecond_cast(__d).count();

if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
__do_timed_wait(__lk, __clock_tp_ns::max());
} else {
__do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
__do_timed_wait(__lk, __clock_tp_ns::max());
} else {
__do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
}

return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : cv_status::timeout;
}

return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : cv_status::timeout;
}
template <class _Rep, class _Period, class _Predicate>
bool _LIBCPP_HIDE_FROM_ABI
wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);

typedef __libcpp_condvar_t* native_handle_type;
_LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; }

private:
void
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
# if _LIBCPP_HAS_COND_CLOCKWAIT
_LIBCPP_HIDE_FROM_ABI void
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
# endif
template <class _Clock>
_LIBCPP_HIDE_FROM_ABI void
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
};
#endif // _LIBCPP_HAS_THREADS

#if _LIBCPP_HAS_THREADS

template <class _Rep, class _Period, class _Predicate>
inline bool
Expand Down
8 changes: 0 additions & 8 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,6 @@ typedef __char32_t char32_t;
# endif

# define _LIBCPP_HIDDEN
# define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
# define _LIBCPP_TEMPLATE_VIS
# define _LIBCPP_TEMPLATE_DATA_VIS
# define _LIBCPP_NAMESPACE_VISIBILITY
Expand All @@ -407,13 +406,6 @@ typedef __char32_t char32_t;
# define _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_VISIBILITY("default")
# endif

# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
// The inline should be removed once PR32114 is resolved
# define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS inline _LIBCPP_HIDDEN
# else
# define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
# endif

// This is kept to avoid a huge library-wide diff in the first step.
// TODO: Remove this in a follow-up patch
# define _LIBCPP_TEMPLATE_VIS
Expand Down
32 changes: 14 additions & 18 deletions libcxx/include/__locale
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD

class _LIBCPP_EXPORTED_FROM_ABI locale;

template <class _CharT>
class collate;

template <class _Facet>
_LIBCPP_HIDE_FROM_ABI bool has_facet(const locale&) _NOEXCEPT;

Expand Down Expand Up @@ -84,7 +87,12 @@ public:
const locale& operator=(const locale&) _NOEXCEPT;

template <class _Facet>
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS locale combine(const locale&) const;
_LIBCPP_HIDE_FROM_ABI locale combine(const locale& __other) const {
if (!std::has_facet<_Facet>(__other))
__throw_runtime_error("locale::combine: locale missing facet");

return locale(*this, std::addressof(const_cast<_Facet&>(std::use_facet<_Facet>(__other))));
}

// locale operations:
string name() const;
Expand All @@ -93,8 +101,11 @@ public:
_LIBCPP_HIDE_FROM_ABI bool operator!=(const locale& __y) const { return !(*this == __y); }
# endif
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
operator()(const basic_string<_CharT, _Traits, _Allocator>&, const basic_string<_CharT, _Traits, _Allocator>&) const;
_LIBCPP_HIDE_FROM_ABI bool operator()(const basic_string<_CharT, _Traits, _Allocator>& __x,
const basic_string<_CharT, _Traits, _Allocator>& __y) const {
return std::use_facet<std::collate<_CharT> >(*this).compare(
__x.data(), __x.data() + __x.size(), __y.data(), __y.data() + __y.size()) < 0;
}

// global locale objects:
static locale global(const locale&);
Expand Down Expand Up @@ -155,14 +166,6 @@ inline _LIBCPP_HIDE_FROM_ABI locale::locale(const locale& __other, _Facet* __f)
__install_ctor(__other, __f, __f ? __f->id.__get() : 0);
}

template <class _Facet>
locale locale::combine(const locale& __other) const {
if (!std::has_facet<_Facet>(__other))
std::__throw_runtime_error("locale::combine: locale missing facet");

return locale(*this, std::addressof(const_cast<_Facet&>(std::use_facet<_Facet>(__other))));
}

template <class _Facet>
inline _LIBCPP_HIDE_FROM_ABI bool has_facet(const locale& __l) _NOEXCEPT {
return __l.has_facet(_Facet::id);
Expand Down Expand Up @@ -289,13 +292,6 @@ protected:
};
# endif

template <class _CharT, class _Traits, class _Allocator>
bool locale::operator()(const basic_string<_CharT, _Traits, _Allocator>& __x,
const basic_string<_CharT, _Traits, _Allocator>& __y) const {
return std::use_facet<std::collate<_CharT> >(*this).compare(
__x.data(), __x.data() + __x.size(), __y.data(), __y.data() + __y.size()) < 0;
}

// template <class charT> class ctype

class _LIBCPP_EXPORTED_FROM_ABI ctype_base {
Expand Down
Loading
Loading