1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 10 11 // <string> 12 13 // constexpr basic_string(basic_string&& str, size_type pos, const Allocator& a = Allocator()); 14 // constexpr basic_string(basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); 15 16 #include <cassert> 17 #include <stdexcept> 18 #include <string> 19 20 #include "constexpr_char_traits.h" 21 #include "count_new.h" 22 #include "make_string.h" 23 #include "min_allocator.h" 24 #include "test_allocator.h" 25 #include "test_macros.h" 26 #include "asan_testing.h" 27 #include "operator_hijacker.h" 28 29 #define STR(string) MAKE_CSTRING(typename S::value_type, string) 30 31 constexpr struct should_throw_exception_t { 32 } should_throw_exception; 33 34 template <class S> 35 constexpr void test_string_pos(S orig, typename S::size_type pos, S expected) { 36 #ifdef _LIBCPP_VERSION 37 ConstexprDisableAllocationGuard g; 38 #endif 39 S substr(std::move(orig), pos); 40 LIBCPP_ASSERT(orig.__invariants()); 41 LIBCPP_ASSERT(orig.empty()); 42 LIBCPP_ASSERT(substr.__invariants()); 43 assert(substr == expected); 44 LIBCPP_ASSERT(is_string_asan_correct(orig)); 45 LIBCPP_ASSERT(is_string_asan_correct(substr)); 46 } 47 48 template <class S> 49 constexpr void test_string_pos(S orig, typename S::size_type pos, should_throw_exception_t) { 50 #ifndef TEST_HAS_NO_EXCEPTIONS 51 if (!std::is_constant_evaluated()) { 52 try { 53 [[maybe_unused]] S substr = S(std::move(orig), pos); 54 assert(false); 55 } catch (const std::out_of_range&) { 56 } 57 } 58 #else 59 (void)orig; 60 (void)pos; 61 #endif 62 } 63 64 template <class S> 65 constexpr void 66 test_string_pos_alloc(S orig, typename S::size_type pos, const typename S::allocator_type& alloc, S expected) { 67 S substr(std::move(orig), pos, alloc); 68 LIBCPP_ASSERT(orig.__invariants()); 69 LIBCPP_ASSERT(substr.__invariants()); 70 assert(substr == expected); 71 assert(substr.get_allocator() == alloc); 72 LIBCPP_ASSERT(is_string_asan_correct(orig)); 73 LIBCPP_ASSERT(is_string_asan_correct(substr)); 74 } 75 76 template <class S> 77 constexpr void test_string_pos_alloc( 78 S orig, typename S::size_type pos, const typename S::allocator_type& alloc, should_throw_exception_t) { 79 #ifndef TEST_HAS_NO_EXCEPTIONS 80 if (!std::is_constant_evaluated()) { 81 try { 82 [[maybe_unused]] S substr = S(std::move(orig), pos, alloc); 83 assert(false); 84 } catch (const std::out_of_range&) { 85 } 86 } 87 #else 88 (void)orig; 89 (void)pos; 90 (void)alloc; 91 #endif 92 } 93 94 template <class S> 95 constexpr void test_string_pos_n(S orig, typename S::size_type pos, typename S::size_type n, S expected) { 96 #ifdef _LIBCPP_VERSION 97 ConstexprDisableAllocationGuard g; 98 #endif 99 S substr(std::move(orig), pos, n); 100 LIBCPP_ASSERT(orig.__invariants()); 101 LIBCPP_ASSERT(orig.empty()); 102 LIBCPP_ASSERT(substr.__invariants()); 103 assert(substr == expected); 104 LIBCPP_ASSERT(is_string_asan_correct(orig)); 105 LIBCPP_ASSERT(is_string_asan_correct(substr)); 106 } 107 108 template <class S> 109 constexpr void test_string_pos_n(S orig, typename S::size_type pos, typename S::size_type n, should_throw_exception_t) { 110 #ifndef TEST_HAS_NO_EXCEPTIONS 111 if (!std::is_constant_evaluated()) { 112 try { 113 [[maybe_unused]] S substr = S(std::move(orig), pos, n); 114 assert(false); 115 } catch (const std::out_of_range&) { 116 } 117 } 118 #else 119 (void)orig; 120 (void)pos; 121 (void)n; 122 #endif 123 } 124 125 template <class S> 126 constexpr void test_string_pos_n_alloc( 127 S orig, typename S::size_type pos, typename S::size_type n, const typename S::allocator_type& alloc, S expected) { 128 S substr(std::move(orig), pos, n, alloc); 129 LIBCPP_ASSERT(orig.__invariants()); 130 LIBCPP_ASSERT(substr.__invariants()); 131 assert(substr == expected); 132 assert(substr.get_allocator() == alloc); 133 LIBCPP_ASSERT(is_string_asan_correct(orig)); 134 LIBCPP_ASSERT(is_string_asan_correct(substr)); 135 } 136 137 template <class S> 138 constexpr void test_string_pos_n_alloc( 139 S orig, 140 typename S::size_type pos, 141 typename S::size_type n, 142 const typename S::allocator_type& alloc, 143 should_throw_exception_t) { 144 #ifndef TEST_HAS_NO_EXCEPTIONS 145 if (!std::is_constant_evaluated()) { 146 try { 147 [[maybe_unused]] S substr = S(std::move(orig), pos, n, alloc); 148 assert(false); 149 } catch (const std::out_of_range&) { 150 } 151 } 152 #else 153 (void)orig; 154 (void)pos; 155 (void)n; 156 (void)alloc; 157 #endif 158 } 159 160 template <class S> 161 constexpr void test_string(const typename S::allocator_type& alloc) { 162 test_string_pos<S>(STR(""), 0, STR("")); 163 test_string_pos<S>(STR(""), 1, should_throw_exception); 164 test_string_pos<S>(STR("Banane"), 1, STR("anane")); 165 test_string_pos<S>(STR("Banane"), 6, STR("")); 166 test_string_pos<S>(STR("Banane"), 7, should_throw_exception); 167 test_string_pos<S>(STR("long long string so no SSO"), 0, STR("long long string so no SSO")); 168 test_string_pos<S>(STR("long long string so no SSO"), 10, STR("string so no SSO")); 169 test_string_pos<S>(STR("long long string so no SSO"), 26, STR("")); 170 test_string_pos<S>(STR("long long string so no SSO"), 27, should_throw_exception); 171 172 test_string_pos_alloc<S>(STR(""), 0, alloc, STR("")); 173 test_string_pos_alloc<S>(STR(""), 1, alloc, should_throw_exception); 174 test_string_pos_alloc<S>(STR("Banane"), 1, alloc, STR("anane")); 175 test_string_pos_alloc<S>(STR("Banane"), 6, alloc, STR("")); 176 test_string_pos_alloc<S>(STR("Banane"), 7, alloc, should_throw_exception); 177 test_string_pos_alloc<S>(STR("long long string so no SSO"), 0, alloc, STR("long long string so no SSO")); 178 test_string_pos_alloc<S>(STR("long long string so no SSO"), 10, alloc, STR("string so no SSO")); 179 test_string_pos_alloc<S>(STR("long long string so no SSO"), 26, alloc, STR("")); 180 test_string_pos_alloc<S>(STR("long long string so no SSO"), 27, alloc, should_throw_exception); 181 182 test_string_pos_n<S>(STR(""), 0, 0, STR("")); 183 test_string_pos_n<S>(STR(""), 0, 1, STR("")); 184 test_string_pos_n<S>(STR(""), 1, 0, should_throw_exception); 185 test_string_pos_n<S>(STR(""), 1, 1, should_throw_exception); 186 test_string_pos_n<S>(STR("Banane"), 1, 10, STR("anane")); 187 test_string_pos_n<S>(STR("Banane"), 6, 0, STR("")); 188 test_string_pos_n<S>(STR("Banane"), 6, 5, STR("")); 189 test_string_pos_n<S>(STR("Banane"), 7, 10, should_throw_exception); 190 test_string_pos_n<S>(STR("long long string so no SSO"), 0, 10, STR("long long ")); 191 test_string_pos_n<S>(STR("long long string so no SSO"), 10, 8, STR("string s")); 192 test_string_pos_n<S>(STR("long long string so no SSO"), 20, 10, STR("no SSO")); 193 test_string_pos_n<S>(STR("long long string so no SSO"), 26, 10, STR("")); 194 test_string_pos_n<S>(STR("long long string so no SSO"), 27, 10, should_throw_exception); 195 196 test_string_pos_n_alloc<S>(STR(""), 0, 0, alloc, STR("")); 197 test_string_pos_n_alloc<S>(STR(""), 0, 1, alloc, STR("")); 198 test_string_pos_n_alloc<S>(STR(""), 1, 0, alloc, should_throw_exception); 199 test_string_pos_n_alloc<S>(STR(""), 1, 1, alloc, should_throw_exception); 200 test_string_pos_n_alloc<S>(STR("Banane"), 1, 10, alloc, STR("anane")); 201 test_string_pos_n_alloc<S>(STR("Banane"), 6, 0, alloc, STR("")); 202 test_string_pos_n_alloc<S>(STR("Banane"), 6, 5, alloc, STR("")); 203 test_string_pos_n_alloc<S>(STR("Banane"), 7, 10, alloc, should_throw_exception); 204 test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 0, 10, alloc, STR("long long ")); 205 test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 10, 8, alloc, STR("string s")); 206 test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 20, 10, alloc, STR("no SSO")); 207 test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 26, 10, alloc, STR("")); 208 test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 27, 10, alloc, should_throw_exception); 209 } 210 211 template <class CharT, class CharTraits> 212 constexpr void test_allocators() { 213 test_string<std::basic_string<CharT, CharTraits, std::allocator<CharT>>>(std::allocator<CharT>{}); 214 test_string<std::basic_string<CharT, CharTraits, min_allocator<CharT>>>(min_allocator<CharT>{}); 215 test_string<std::basic_string<CharT, CharTraits, test_allocator<CharT>>>(test_allocator<CharT>{42}); 216 test_string<std::basic_string<CharT, CharTraits, operator_hijacker_allocator<CharT>>>( 217 operator_hijacker_allocator<CharT>{}); 218 } 219 220 template <class CharT> 221 constexpr bool test_char_traits() { 222 test_allocators<CharT, std::char_traits<CharT>>(); 223 test_allocators<CharT, constexpr_char_traits<CharT>>(); 224 225 return true; 226 } 227 228 int main(int, char**) { 229 // TODO: put these into a single function when we increase the constexpr step limit 230 test_char_traits<char>(); 231 static_assert(test_char_traits<char>()); 232 test_char_traits<char16_t>(); 233 static_assert(test_char_traits<char16_t>()); 234 test_char_traits<char32_t>(); 235 static_assert(test_char_traits<char32_t>()); 236 #ifndef TEST_HAS_NO_WIDE_CHARACTERS 237 test_char_traits<wchar_t>(); 238 static_assert(test_char_traits<wchar_t>()); 239 #endif 240 #ifndef TEST_HAS_NO_CHAR8_T 241 test_char_traits<char8_t>(); 242 static_assert(test_char_traits<char8_t>()); 243 #endif 244 245 return 0; 246 } 247