diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -770,7 +770,20 @@ static_assert(sizeof(__short) == (sizeof(value_type) * (__min_cap + 1)), "__short has an unexpected size."); +#ifdef _LIBCPP_CXX03_LANG union __ulx{__long __lx; __short __lxx;}; +#else + // Since C++03, unions can contain members with non-trivial special member functions (C++03 doesn't allow unions to + // contain members with non-trivial special member functions). In this case, the corresponding special member + // function in the union will be deleted and therefore must be explicitly defined. Therefore, to support fancy + // pointers with non-trivial constructors in __long, we must explicitly define a constructor in __ulx. + union __ulx { + _LIBCPP_CONSTEXPR_SINCE_CXX20 __ulx() _NOEXCEPT : __lx{} {} + + __long __lx; + __short __lxx; + }; +#endif // _LIBCPP_CXX03_LANG enum {__n_words = sizeof(__ulx) / sizeof(size_type)}; @@ -779,6 +792,7 @@ size_type __words[__n_words]; }; +#ifdef _LIBCPP_CXX03_LANG struct __rep { union @@ -788,6 +802,60 @@ __raw __r; }; }; +#else + // Since C++03, unions can contain members with non-trivial special member functions (C++03 doesn't allow unions to + // contain members with non-trivial special member functions). In this case, the corresponding special member + // function in the union will be deleted and therefore must be explicitly defined. Therefore, to support fancy + // pointers with non-trivial special member functions in __long, we must explicitly define a constructor, copy + // constructor and copy assignment operator in __rep. + struct __rep { + _LIBCPP_CONSTEXPR_SINCE_CXX20 __rep() _NOEXCEPT : __l{} {} + _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__rep() _NOEXCEPT {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_rep_long(const __rep& __str_rep) const _NOEXCEPT { + if (__libcpp_is_constant_evaluated()) + return true; + return __str_rep.__l.__is_long_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 __rep(const __rep& __other) _NOEXCEPT : __l{} { + // For certain fancy pointers such as offset pointers, the value of __l.__data_ will be different for 2 pointers + // pointing to the same object (because the offset is calculated with respect to the pointer itself). Therefore, + // the copy assignment operator of the underlying pointer needs to be explicitly called. For a short string, the + // memory should be directly copied. + if (__is_rep_long(__other)) { + __l.__is_long_ = __other.__l.__is_long_; + __l.__cap_ = __other.__l.__cap_; + __l.__size_ = __other.__l.__size_; + __l.__data_ = __other.__l.__data_; + } else { + for (unsigned __i = 0; __i < __n_words; ++__i) + __r.__words[__i] = __other.__r.__words[__i]; + } + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 __rep& operator=(const __rep& __other) _NOEXCEPT { + if (this != &__other) { + if (__is_rep_long(__other)) { + __l.__is_long_ = __other.__l.__is_long_; + __l.__cap_ = __other.__l.__cap_; + __l.__size_ = __other.__l.__size_; + __l.__data_ = __other.__l.__data_; + } else { + for (unsigned __i = 0; __i < __n_words; ++__i) + __r.__words[__i] = __other.__r.__words[__i]; + } + } + return *this; + } + + union { + __long __l; + __short __s; + __raw __r; + }; + }; +#endif // _LIBCPP_CXX03_LANG __compressed_pair<__rep, allocator_type> __r_;