[libcxx-commits] [libcxx] 288a143 - [libc++] Explicitly enumerate std::string external instantiations - Attempt 2
Eric Fiselier via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jan 15 14:15:42 PST 2020
Author: Eric Fiselier
Date: 2020-01-15T17:12:49-05:00
New Revision: 288a1436392f1fbee2e647cb057086fe700f9c7e
URL: https://github.com/llvm/llvm-project/commit/288a1436392f1fbee2e647cb057086fe700f9c7e
DIFF: https://github.com/llvm/llvm-project/commit/288a1436392f1fbee2e647cb057086fe700f9c7e.diff
LOG: [libc++] Explicitly enumerate std::string external instantiations - Attempt 2
The GCC build failures have been addressed, and the LLDB failures were
fixed by LLDB.
I have also verified that the apple-clang 9.0 segfault no longer
occurs.
Original Message:
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.
Added:
Modified:
libcxx/include/__config
libcxx/include/__string
libcxx/include/string
libcxx/src/string.cpp
Removed:
################################################################################
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 032f39fb6638..d9132d138a5f 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -897,6 +897,10 @@ typedef unsigned int char32_t;
#define _LIBCPP_EXTERN_TEMPLATE2(...) extern template __VA_ARGS__;
#endif
+#ifndef _LIBCPP_EXTERN_TEMPLATE_DEFINE
+#define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template __VA_ARGS__;
+#endif
+
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_LIBCPP_MSVCRT_LIKE) || \
defined(__sun__) || defined(__NetBSD__) || defined(__CloudABI__)
#define _LIBCPP_LOCALE__L_EXTENSIONS 1
diff --git a/libcxx/include/__string b/libcxx/include/__string
index 056b9b80ea50..04ebfc550d32 100644
--- a/libcxx/include/__string
+++ b/libcxx/include/__string
@@ -70,6 +70,59 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
+// The the extern template ABI lists are kept outside of <string> to improve the
+// readability of that header.
+#define _LIBCPP_STRING_EXTERN_TEMPLATE_LIST(_Func, _CharType) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::replace(size_type, size_type, value_type const*, size_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::rfind(value_type const*, size_type, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__init(value_type const*, size_type, size_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::basic_string(basic_string const&)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::replace(size_type, size_type, value_type const*)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::basic_string(basic_string const&, std::allocator<_CharType> const&)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_last_not_of(value_type const*, size_type, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::~basic_string()) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_first_not_of(value_type const*, size_type, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::insert(size_type, size_type, value_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::operator=(value_type)) \
+ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__init(value_type const*, size_type)) \
+ _Func(_LIBCPP_FUNC_VIS const _CharType& basic_string<_CharType>::at(size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::insert(size_type, value_type const*, size_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_first_of(value_type const*, size_type, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::replace(size_type, size_type, size_type, value_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(value_type const*, size_type)) \
+ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::reserve(size_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::append(value_type const*, size_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(basic_string const&, size_type, size_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::copy(value_type*, size_type, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::basic_string(basic_string const&, size_type, size_type, std::allocator<_CharType> const&)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find(value_type, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__init(size_type, value_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::insert(size_type, value_type const*)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_last_of(value_type const*, size_type, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__grow_by(size_type, size_type, size_type, size_type, size_type, size_type)) \
+ _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*)) \
+ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::push_back(value_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::append(size_type, value_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::rfind(value_type, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS const basic_string<_CharType>::size_type basic_string<_CharType>::npos) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(size_type, value_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::erase(size_type, size_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::append(basic_string const&, size_type, size_type)) \
+ _Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(value_type const*) const) \
+ _Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(size_type, size_type, value_type const*) const) \
+ _Func(_LIBCPP_FUNC_VIS _CharType& basic_string<_CharType>::at(size_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(value_type const*)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find(value_type const*, size_type, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(size_type, size_type, basic_string const&, size_type, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(size_type, size_type, value_type const*, size_type) const) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::operator=(basic_string const&)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::append(value_type const*)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::replace(size_type, size_type, basic_string const&, size_type, size_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::iterator basic_string<_CharType>::insert(basic_string::const_iterator, value_type)) \
+ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::resize(size_type, value_type)) \
+ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::insert(size_type, basic_string const&, size_type, size_type))
+
+
// char_traits
template <class _CharT>
diff --git a/libcxx/include/string b/libcxx/include/string
index 0f84d87735b9..6a636bcb7560 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -4333,8 +4333,8 @@ basic_string<_CharT, _Traits, _Allocator>::__subscriptable(const const_iterator*
#endif // _LIBCPP_DEBUG_LEVEL >= 2
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_string<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_string<wchar_t>)
+_LIBCPP_STRING_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE, char)
+_LIBCPP_STRING_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE, wchar_t)
#if _LIBCPP_STD_VER > 11
// Literal suffixes for basic_string [basic.string.literals]
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index 4802d63c811b..1e98c686cbcf 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -20,8 +20,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
-template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
-template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<wchar_t>;
+_LIBCPP_STRING_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
+_LIBCPP_STRING_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
template
string
More information about the libcxx-commits
mailing list