[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