[libcxx-commits] [libcxx] [libc++][strings] P2591R5: Concatenation of strings and string views (PR #88389)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Fri May 10 03:18:30 PDT 2024
================
@@ -0,0 +1,170 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <string>
+
+// [string.op.plus]
+//
+// template<class charT, class traits, class Allocator>
+// constexpr basic_string<charT, traits, Allocator>
+// operator+(const basic_string<charT, traits, Allocator>& lhs,
+// type_identity_t<basic_string_view<charT, traits>> rhs); // Since C++26
+// template<class charT, class traits, class Allocator>
+// constexpr basic_string<charT, traits, Allocator>
+// operator+(basic_string<charT, traits, Allocator>&& lhs,
+// type_identity_t<basic_string_view<charT, traits>> rhs); // Since C++26
+// template<class charT, class traits, class Allocator>
+// constexpr basic_string<charT, traits, Allocator>
+// operator+(type_identity_t<basic_string_view<charT, traits>> lhs,
+// const basic_string<charT, traits, Allocator>& rhs); // Since C++26
+// template<class charT, class traits, class Allocator>
+// constexpr basic_string<charT, traits, Allocator>
+// operator+(type_identity_t<basic_string_view<charT, traits>> lhs,
+// basic_string<charT, traits, Allocator>&& rhs); // Since C++26
+
+#include <cassert>
+#include <concepts>
+#include <string>
+#include <utility>
+
+#include "asan_testing.h"
+#include "constexpr_char_traits.h"
+#include "make_string.h"
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+#define CS(S) MAKE_CSTRING(CharT, S)
+#define ST(S, a) std::basic_string<CharT, TraitsT, AllocT>(MAKE_CSTRING(CharT, S), MKSTR_LEN(CharT, S), a)
+#define SV(S) std::basic_string_view<CharT, TraitsT>(MAKE_CSTRING(CharT, S), MKSTR_LEN(CharT, S))
+
+template <typename CharT, typename TraitsT, typename AllocT>
+constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
+ AllocT allocator;
+
+ // string& + string_view
+ {
+ std::basic_string<CharT, TraitsT, AllocT> st{x, allocator};
+ std::basic_string_view<CharT, TraitsT> sv{y};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = st + sv;
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(st + sv));
+ }
+ // const string& + string_view
+ {
+ const std::basic_string<CharT, TraitsT, AllocT> st{x, allocator};
+ std::basic_string_view<CharT, TraitsT> sv{y};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = st + sv;
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(st + sv));
+ }
+ // string&& + string_view
+ {
+ std::basic_string<CharT, TraitsT, AllocT> st{x, allocator};
+ std::basic_string_view<CharT, TraitsT> sv{y};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = std::move(st) + sv;
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(st + sv));
+ }
+ // string_view + string&
+ {
+ std::basic_string_view<CharT, TraitsT> sv{x};
+ std::basic_string<CharT, TraitsT, AllocT> st{y, allocator};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st;
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(sv + st));
+ }
+ // string_view + const string&
+ {
+ std::basic_string_view<CharT, TraitsT> sv{x};
+ const std::basic_string<CharT, TraitsT, AllocT> st{y, allocator};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st;
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(sv + st));
+ }
+ // string_view + string&&
+ {
+ std::basic_string<CharT, TraitsT, AllocT> st_{x, allocator};
+ std::basic_string_view<CharT, TraitsT> sv{st_};
+ std::basic_string<CharT, TraitsT, AllocT> st{y, allocator};
----------------
H-G-Hristov wrote:
This is a workaround. The following results in an error:
```suggestion
{
std::basic_string_view<CharT, TraitsT> sv{x};
std::basic_string<CharT, TraitsT, AllocT> st{y, allocator};
```
```
.---command stderr------------
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:154:17: error: static assertion expression is not an integral constant expression
# | 154 | static_assert(test<char>());
# | | ^~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/support/constexpr_char_traits.h:127:10: note: comparison of addresses of literals has unspecified value
# | 127 | if (s1 == s2)
# | | ^
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:2948:7: note: in call to 'move(&st.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:915:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0], &"short"[0], 5)'
# | 2948 | traits_type::move(__p + __pos, __s, __n);
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1525:12: note: in call to 'this->insert(0, &"short"[0], 5)'
# | 1525 | return insert(__pos1, __sv.data(), __sv.size());
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4118:3: note: in call to '__rhs.insert<std::basic_string_view<char, constexpr_char_traits<char>>, 0>(0, __lhs)'
# | 4118 | __rhs.insert(0, __lhs);
# | | ^~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:107:85: note: in call to 'operator+<char, constexpr_char_traits<char>, std::allocator<char>>({&"short"[0], 5}, st)'
# | 107 | std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + std::move(st);
# | | ^~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:123:3: note: in call to 'test<char, constexpr_char_traits<char>, std::allocator<char>>(&"short"[0], &""[0], &"short"[0])'
# | 123 | test<CharT, TraitsT, AllocT>(CS("short"), CS(""), CS("short"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:144:3: note: in call to 'test<char, constexpr_char_traits<char>, std::allocator<char>>()'
# | 144 | test<CharT, constexpr_char_traits<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:154:17: note: in call to 'test<char>()'
# | 154 | static_assert(test<char>());
# | | ^~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:157:17: error: static assertion expression is not an integral constant expression
# | 157 | static_assert(test<wchar_t>());
# | | ^~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/support/constexpr_char_traits.h:127:10: note: comparison of addresses of literals has unspecified value
# | 127 | if (s1 == s2)
# | | ^
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:2948:7: note: in call to 'move(&st.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:915:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0], &L"B"[0], 1)'
# | 2948 | traits_type::move(__p + __pos, __s, __n);
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1525:12: note: in call to 'this->insert(0, &L"B"[0], 1)'
# | 1525 | return insert(__pos1, __sv.data(), __sv.size());
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4118:3: note: in call to '__rhs.insert<std::basic_string_view<wchar_t, constexpr_char_traits<wchar_t>>, 0>(0, __lhs)'
# | 4118 | __rhs.insert(0, __lhs);
# | | ^~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:107:85: note: in call to 'operator+<wchar_t, constexpr_char_traits<wchar_t>, std::allocator<wchar_t>>({&L"B"[0], 1}, st)'
# | 107 | std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + std::move(st);
# | | ^~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:128:3: note: in call to 'test<wchar_t, constexpr_char_traits<wchar_t>, std::allocator<wchar_t>>(&L"B"[0], &L"D"[0], &L"BD"[0])'
# | 128 | test<CharT, TraitsT, AllocT>(CS("B"), CS("D"), CS("BD"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:144:3: note: in call to 'test<wchar_t, constexpr_char_traits<wchar_t>, std::allocator<wchar_t>>()'
# | 144 | test<CharT, constexpr_char_traits<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:157:17: note: in call to 'test<wchar_t>()'
# | 157 | static_assert(test<wchar_t>());
# | | ^~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:161:17: error: static assertion expression is not an integral constant expression
# | 161 | static_assert(test<char8_t>());
# | | ^~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/support/constexpr_char_traits.h:127:10: note: comparison of addresses of literals has unspecified value
# | 127 | if (s1 == s2)
# | | ^
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:2948:7: note: in call to 'move(&st.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:915:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0], &u8"short"[0], 5)'
# | 2948 | traits_type::move(__p + __pos, __s, __n);
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1525:12: note: in call to 'this->insert(0, &u8"short"[0], 5)'
# | 1525 | return insert(__pos1, __sv.data(), __sv.size());
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4118:3: note: in call to '__rhs.insert<std::basic_string_view<char8_t, constexpr_char_traits<char8_t>>, 0>(0, __lhs)'
# | 4118 | __rhs.insert(0, __lhs);
# | | ^~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:107:85: note: in call to 'operator+<char8_t, constexpr_char_traits<char8_t>, std::allocator<char8_t>>({&u8"short"[0], 5}, st)'
# | 107 | std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + std::move(st);
# | | ^~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:123:3: note: in call to 'test<char8_t, constexpr_char_traits<char8_t>, std::allocator<char8_t>>(&u8"short"[0], &u8""[0], &u8"short"[0])'
# | 123 | test<CharT, TraitsT, AllocT>(CS("short"), CS(""), CS("short"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:144:3: note: in call to 'test<char8_t, constexpr_char_traits<char8_t>, std::allocator<char8_t>>()'
# | 144 | test<CharT, constexpr_char_traits<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:161:17: note: in call to 'test<char8_t>()'
# | 161 | static_assert(test<char8_t>());
# | | ^~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:164:17: error: static assertion expression is not an integral constant expression
# | 164 | static_assert(test<char16_t>());
# | | ^~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/support/constexpr_char_traits.h:127:10: note: comparison of addresses of literals has unspecified value
# | 127 | if (s1 == s2)
# | | ^
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:2948:7: note: in call to 'move(&st.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:915:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0], &u"short"[0], 5)'
# | 2948 | traits_type::move(__p + __pos, __s, __n);
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1525:12: note: in call to 'this->insert(0, &u"short"[0], 5)'
# | 1525 | return insert(__pos1, __sv.data(), __sv.size());
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4118:3: note: in call to '__rhs.insert<std::basic_string_view<char16_t, constexpr_char_traits<char16_t>>, 0>(0, __lhs)'
# | 4118 | __rhs.insert(0, __lhs);
# | | ^~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:107:85: note: in call to 'operator+<char16_t, constexpr_char_traits<char16_t>, std::allocator<char16_t>>({&u"short"[0], 5}, st)'
# | 107 | std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + std::move(st);
# | | ^~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:123:3: note: in call to 'test<char16_t, constexpr_char_traits<char16_t>, std::allocator<char16_t>>(&u"short"[0], &u""[0], &u"short"[0])'
# | 123 | test<CharT, TraitsT, AllocT>(CS("short"), CS(""), CS("short"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:144:3: note: in call to 'test<char16_t, constexpr_char_traits<char16_t>, std::allocator<char16_t>>()'
# | 144 | test<CharT, constexpr_char_traits<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:164:17: note: in call to 'test<char16_t>()'
# | 164 | static_assert(test<char16_t>());
# | | ^~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:166:17: error: static assertion expression is not an integral constant expression
# | 166 | static_assert(test<char32_t>());
# | | ^~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/support/constexpr_char_traits.h:127:10: note: comparison of addresses of literals has unspecified value
# | 127 | if (s1 == s2)
# | | ^
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:2948:7: note: in call to 'move(&st.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:915:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0], &U"B"[0], 1)'
# | 2948 | traits_type::move(__p + __pos, __s, __n);
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1525:12: note: in call to 'this->insert(0, &U"B"[0], 1)'
# | 1525 | return insert(__pos1, __sv.data(), __sv.size());
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4118:3: note: in call to '__rhs.insert<std::basic_string_view<char32_t, constexpr_char_traits<char32_t>>, 0>(0, __lhs)'
# | 4118 | __rhs.insert(0, __lhs);
# | | ^~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:107:85: note: in call to 'operator+<char32_t, constexpr_char_traits<char32_t>, std::allocator<char32_t>>({&U"B"[0], 1}, st)'
# | 107 | std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + std::move(st);
# | | ^~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:128:3: note: in call to 'test<char32_t, constexpr_char_traits<char32_t>, std::allocator<char32_t>>(&U"B"[0], &U"D"[0], &U"BD"[0])'
# | 128 | test<CharT, TraitsT, AllocT>(CS("B"), CS("D"), CS("BD"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:144:3: note: in call to 'test<char32_t, constexpr_char_traits<char32_t>, std::allocator<char32_t>>()'
# | 144 | test<CharT, constexpr_char_traits<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:166:17: note: in call to 'test<char32_t>()'
# | 166 | static_assert(test<char32_t>());
# | | ^~~~~~~~~~~~~~~~
# | 5 errors generated.
```
https://github.com/llvm/llvm-project/pull/88389
More information about the libcxx-commits
mailing list