diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -757,6 +757,20 @@ // Just so we can migrate to the new macros gradually. #define _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI +// Selectively hide functions from ABI for either STABLE or UNSTABLE ABI. +// These macros allow ABI breakage for UNSTABLE while preserving STABLE ABI. +#ifdef _LIBCPP_ABI_UNSTABLE +#define _LIBCPP_HIDE_FROM_ABI_IN_STABLE +#define _LIBCPP_INLINE_IN_STABLE +#define _LIBCPP_HIDE_FROM_ABI_IN_UNSTABLE _LIBCPP_HIDE_FROM_ABI +#define _LIBCPP_INLINE_IN_UNSTABLE inline +#else +#define _LIBCPP_HIDE_FROM_ABI_IN_STABLE _LIBCPP_HIDE_FROM_ABI +#define _LIBCPP_INLINE_IN_STABLE inline +#define _LIBCPP_HIDE_FROM_ABI_IN_UNSTABLE +#define _LIBCPP_INLINE_IN_UNSTABLE +#endif + // Inline namespaces are available in Clang/GCC/MSVC regardless of C++ dialect. #define _LIBCPP_BEGIN_NAMESPACE_STD namespace std { inline namespace _LIBCPP_ABI_NAMESPACE { #define _LIBCPP_END_NAMESPACE_STD } } diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -2167,6 +2167,9 @@ }; #endif +// Tag used to default initialize one or both of the pair's elements. +struct __default_value_tag {}; + template ::value && !__libcpp_is_final<_Tp>::value> @@ -2177,6 +2180,7 @@ #ifndef _LIBCPP_CXX03_LANG _LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() : __value_() {} + _LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem(__default_value_tag) {} template ::type>::value diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -796,7 +796,9 @@ _NOEXCEPT; #endif - basic_string(const basic_string& __str); + _LIBCPP_HIDE_FROM_ABI_IN_UNSTABLE + basic_string(const basic_UNstring& __str); + _LIBCPP_HIDE_FROM_ABI_IN_UNSTABLE basic_string(const basic_string& __str, const allocator_type& __a); #ifndef _LIBCPP_CXX03_LANG @@ -1543,6 +1545,9 @@ inline void __init(size_type __n, value_type __c); + _LIBCPP_HIDE_FROM_ABI_IN_STABLE + void __init_long(const basic_string& __str); + template inline typename enable_if @@ -1793,6 +1798,21 @@ traits_type::assign(__p[__sz], value_type()); } +template +_LIBCPP_INLINE_IN_STABLE +void basic_string<_CharT, _Traits, _Allocator>::__init_long( + const basic_string& __str) { + const value_type* __s = _VSTD::__to_raw_pointer(__str.__get_long_pointer()); + size_type __sz = __str.__get_long_size(); + size_type __cap = __recommend(__sz); + pointer __p = __alloc_traits::allocate(__alloc(), __cap + 1); + __set_long_pointer(__p); + __set_long_cap(__cap + 1); + __set_long_size(__sz); + traits_type::copy(_VSTD::__to_raw_pointer(__p), __s, __sz); + traits_type::assign(__p[__sz], value_type()); +} + template template basic_string<_CharT, _Traits, _Allocator>::basic_string(const _CharT* __s, const _Allocator& __a) @@ -1829,27 +1849,29 @@ } template +_LIBCPP_INLINE_IN_UNSTABLE basic_string<_CharT, _Traits, _Allocator>::basic_string(const basic_string& __str) - : __r_(__second_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc())) + : __r_(__default_value_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc())) { if (!__str.__is_long()) __r_.first().__r = __str.__r_.first().__r; else - __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size()); + __init_long(__str); #if _LIBCPP_DEBUG_LEVEL >= 2 __get_db()->__insert_c(this); #endif } template +_LIBCPP_INLINE_IN_UNSTABLE basic_string<_CharT, _Traits, _Allocator>::basic_string( const basic_string& __str, const allocator_type& __a) - : __r_(__second_tag(), __a) + : __r_(__default_value_tag(), __a) { if (!__str.__is_long()) __r_.first().__r = __str.__r_.first().__r; else - __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size()); + __init_long(__str); #if _LIBCPP_DEBUG_LEVEL >= 2 __get_db()->__insert_c(this); #endif