Skip to content

Commit 61bd192

Browse files
committed
[libc++] Explicitly enumerate std::string external instantiations.
The external instantiation of std::string is a problem for libc++. Additions and removals of inline functions in string can cause ABI breakages, including introducing new symbols. This patch aims to: (1) Make clear which functions are explicitly instatiated. (2) Prevent new functions from being accidentally instantiated. (3) Allow a migration path for adding or removing functions from the explicit instantiation over time. Although this new formulation is uglier, it is preferable from a maintainability and readability standpoint because it explicitly enumerates the functions we've chosen to expose in our ABI. Changing this list is non-trivial and requires thought and planning. (3) is achieved by making it possible to control the extern template declaration separately from it's definition. Meaning we could add a new definition to the dylib, wait for it to roll out, then add the extern template declaration to the header. Similarly, we could remove existing extern template declarations while still keeping the definition to prevent ABI breakages.
1 parent fc3367d commit 61bd192

File tree

4 files changed

+62
-4
lines changed

4 files changed

+62
-4
lines changed

libcxx/include/__config

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,10 @@ typedef unsigned int char32_t;
897897
#define _LIBCPP_EXTERN_TEMPLATE2(...) extern template __VA_ARGS__;
898898
#endif
899899

900+
#ifndef _LIBCPP_EXTERN_TEMPLATE_DEFINE
901+
#define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template __VA_ARGS__;
902+
#endif
903+
900904
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_LIBCPP_MSVCRT_LIKE) || \
901905
defined(__sun__) || defined(__NetBSD__) || defined(__CloudABI__)
902906
#define _LIBCPP_LOCALE__L_EXTENSIONS 1

libcxx/include/__string

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,60 @@ _LIBCPP_PUSH_MACROS
7070

7171
_LIBCPP_BEGIN_NAMESPACE_STD
7272

73+
// The the extern template ABI lists are kept outside of <string> to improve the
74+
// readability of that header.
75+
76+
#define _LIBCPP_STRING_EXTERN_TEMPLATE_LIST(_Func, _CharType) \
77+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::replace(size_type, size_type, value_type const*, size_type)) \
78+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::rfind(value_type const*, size_type, size_type) const) \
79+
_Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__init(value_type const*, size_type, size_type)) \
80+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::basic_string(basic_string const&)) \
81+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::replace(size_type, size_type, value_type const*)) \
82+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::basic_string(basic_string const&, std::allocator<_CharType> const&)) \
83+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_last_not_of(value_type const*, size_type, size_type) const) \
84+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::~basic_string()) \
85+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_first_not_of(value_type const*, size_type, size_type) const) \
86+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::insert(size_type, size_type, value_type)) \
87+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::operator=(value_type)) \
88+
_Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__init(value_type const*, size_type)) \
89+
_Func(_LIBCPP_FUNC_VIS const _CharType& basic_string<_CharType>::at(size_type) const) \
90+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::insert(size_type, value_type const*, size_type)) \
91+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_first_of(value_type const*, size_type, size_type) const) \
92+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::replace(size_type, size_type, size_type, value_type)) \
93+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(value_type const*, size_type)) \
94+
_Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::reserve(size_type)) \
95+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::append(value_type const*, size_type)) \
96+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(basic_string const&, size_type, size_type)) \
97+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::copy(value_type*, size_type, size_type) const) \
98+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::basic_string(basic_string const&, size_type, size_type, std::allocator<_CharType> const&)) \
99+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find(value_type, size_type) const) \
100+
_Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__init(size_type, value_type)) \
101+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::insert(size_type, value_type const*)) \
102+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_last_of(value_type const*, size_type, size_type) const) \
103+
_Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__grow_by(size_type, size_type, size_type, size_type, size_type, size_type)) \
104+
_Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__grow_by_and_replace(size_type, size_type, size_type, size_type, size_type, size_type, value_type const*)) \
105+
_Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::push_back(value_type)) \
106+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::append(size_type, value_type)) \
107+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::rfind(value_type, size_type) const) \
108+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::npos) \
109+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(size_type, value_type)) \
110+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::erase(size_type, size_type)) \
111+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::append(basic_string const&, size_type, size_type)) \
112+
_Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(value_type const*) const) \
113+
_Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(size_type, size_type, value_type const*) const) \
114+
_Func(_LIBCPP_FUNC_VIS _CharType& basic_string<_CharType>::at(size_type)) \
115+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(value_type const*)) \
116+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find(value_type const*, size_type, size_type) const) \
117+
_Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(size_type, size_type, basic_string const&, size_type, size_type) const) \
118+
_Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(size_type, size_type, value_type const*, size_type) const) \
119+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::operator=(basic_string const&)) \
120+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::append(value_type const*)) \
121+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::replace(size_type, size_type, basic_string const&, size_type, size_type)) \
122+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::iterator basic_string<_CharType>::insert(basic_string::const_iterator, value_type)) \
123+
_Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::resize(size_type, value_type)) \
124+
_Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::insert(size_type, basic_string const&, size_type, size_type))
125+
126+
73127
// char_traits
74128

75129
template <class _CharT>

libcxx/include/string

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,6 +1676,8 @@ basic_string(basic_string_view<_CharT, _Traits>, _Sz, _Sz, const _Allocator& = _
16761676
-> basic_string<_CharT, _Traits, _Allocator>;
16771677
#endif
16781678

1679+
_LIBCPP_STRING_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE, char)
1680+
_LIBCPP_STRING_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE, wchar_t)
16791681

16801682
template <class _CharT, class _Traits, class _Allocator>
16811683
inline
@@ -4330,8 +4332,6 @@ basic_string<_CharT, _Traits, _Allocator>::__subscriptable(const const_iterator*
43304332

43314333
#endif // _LIBCPP_DEBUG_LEVEL >= 2
43324334

4333-
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_string<char>)
4334-
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_string<wchar_t>)
43354335

43364336
#if _LIBCPP_STD_VER > 11
43374337
// Literal suffixes for basic_string [basic.string.literals]

libcxx/src/string.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2020

2121
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
2222

23-
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
24-
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<wchar_t>;
23+
_LIBCPP_STRING_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
24+
_LIBCPP_STRING_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
2525

2626
template
2727
string

0 commit comments

Comments
 (0)