[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
Wed Jul 10 14:09:07 PDT 2024


https://github.com/Zingam updated https://github.com/llvm/llvm-project/pull/88389

>From 2d606f402e34d446322c44598ada051c14fa6057 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 11 Apr 2024 10:28:35 +0300
Subject: [PATCH 01/17] [libc++][strings] P2591R5: Concatenation of strings and
 string views

Implemented: https://wg21.link/P2591R5
---
 libcxx/docs/FeatureTestMacroTable.rst         |   2 +
 libcxx/docs/ReleaseNotes/19.rst               |   1 +
 libcxx/docs/Status/Cxx2cPapers.csv            |   2 +-
 libcxx/include/string                         | 104 ++++++++++++++----
 libcxx/include/version                        |   5 +-
 .../string.version.compile.pass.cpp           |   5 +-
 .../string_view.version.compile.pass.cpp      |   5 +-
 .../version.version.compile.pass.cpp          |   5 +-
 .../string_op+/string.string_view.pass.cpp    |  76 +++++++++++++
 .../generate_feature_test_macro_components.py |   2 +-
 10 files changed, 176 insertions(+), 31 deletions(-)
 create mode 100644 libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 3197d2cd1b271..0b8abe38e8bd7 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -456,6 +456,8 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_sstream_from_string_view``                     ``202306L``
     ---------------------------------------------------------- -----------------
+    ``__cpp_lib_string_view``                                  ``202403L``
+    ---------------------------------------------------------- -----------------
     ``__cpp_lib_submdspan``                                    *unimplemented*
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_text_encoding``                                *unimplemented*
diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index 81c05b9112bd2..6fbac70593cc0 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -45,6 +45,7 @@ Implemented Papers
 - P2867R2 - Remove Deprecated ``strstream``\s From C++26
 - P2872R3 - Remove ``wstring_convert`` From C++26
 - P3142R0 - Printing Blank Lines with ``println`` (as DR against C++23)
+- P2591R5 - Concatenation of strings and string views
 - P2302R4 - ``std::ranges::contains``
 - P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with``
 
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index fa11da62bc080..8793d9385b79a 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -55,7 +55,7 @@
 "`P2845R8 <https://wg21.link/P2845R8>`__","LWG","Formatting of ``std::filesystem::path``","Tokyo March 2024","","","|format|"
 "`P0493R5 <https://wg21.link/P0493R5>`__","LWG","Atomic minimum/maximum","Tokyo March 2024","","",""
 "`P2542R8 <https://wg21.link/P2542R8>`__","LWG","``views::concat``","Tokyo March 2024","","","|ranges|"
-"`P2591R5 <https://wg21.link/P2591R5>`__","LWG","Concatenation of strings and string views","Tokyo March 2024","","",""
+"`P2591R5 <https://wg21.link/P2591R5>`__","LWG","Concatenation of strings and string views","Tokyo March 2024","|Complete|","19.0",""
 "`P2248R8 <https://wg21.link/P2248R8>`__","LWG","Enabling list-initialization for algorithms","Tokyo March 2024","","",""
 "`P2810R4 <https://wg21.link/P2810R4>`__","LWG","``is_debugger_present`` ``is_replaceable``","Tokyo March 2024","","",""
 "`P1068R11 <https://wg21.link/P1068R11>`__","LWG","Vector API for random number generation","Tokyo March 2024","","",""
diff --git a/libcxx/include/string b/libcxx/include/string
index a456f8cb80ee3..7758a4ae42e04 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -407,6 +407,24 @@ template<class charT, class traits, class Allocator>
 basic_string<charT, traits, Allocator>
 operator+(const basic_string<charT, traits, Allocator>& lhs, charT rhs);                        // constexpr since C++20
 
+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
+
+
 template<class charT, class traits, class Allocator>
 bool operator==(const basic_string<charT, traits, Allocator>& lhs,
                 const basic_string<charT, traits, Allocator>& rhs) noexcept;                    // constexpr since C++20
@@ -1074,8 +1092,8 @@ public:
             __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value &&
                               !__is_same_uncvref<_Tp, basic_string>::value,
                           int> = 0>
-  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(
-      const _Tp& __t, const allocator_type& __a)
+  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const _Tp& __t, const allocator_type& __a)
       : __r_(__default_init_tag(), __a) {
     __self_view __sv = __t;
     __init(__sv.data(), __sv.size());
@@ -1307,8 +1325,8 @@ public:
                           int> = 0>
   _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20
 
-      basic_string&
-      append(const _Tp& __t, size_type __pos, size_type __n = npos);
+  basic_string&
+  append(const _Tp& __t, size_type __pos, size_type __n = npos);
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(const value_type* __s, size_type __n);
   _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(const value_type* __s);
@@ -1997,15 +2015,15 @@ private:
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20
 #if _LIBCPP_ABI_VERSION >= 2 //  We want to use the function in the dylib in ABIv1
-      _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_HIDE_FROM_ABI
 #endif
-          _LIBCPP_DEPRECATED_("use __grow_by_without_replace") void __grow_by(
-              size_type __old_cap,
-              size_type __delta_cap,
-              size_type __old_sz,
-              size_type __n_copy,
-              size_type __n_del,
-              size_type __n_add = 0);
+  _LIBCPP_DEPRECATED_("use __grow_by_without_replace") void __grow_by(
+      size_type __old_cap,
+      size_type __delta_cap,
+      size_type __old_sz,
+      size_type __n_copy,
+      size_type __n_del,
+      size_type __n_add = 0);
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __grow_by_without_replace(
       size_type __old_cap,
       size_type __delta_cap,
@@ -2171,8 +2189,8 @@ template <class _CharT,
           class _Traits,
           class _Allocator = allocator<_CharT>,
           class            = enable_if_t<__is_allocator<_Allocator>::value> >
-explicit basic_string(basic_string_view<_CharT, _Traits>, const _Allocator& = _Allocator())
-    -> basic_string<_CharT, _Traits, _Allocator>;
+explicit basic_string(basic_string_view<_CharT, _Traits>,
+                      const _Allocator& = _Allocator()) -> basic_string<_CharT, _Traits, _Allocator>;
 
 template <class _CharT,
           class _Traits,
@@ -2407,15 +2425,15 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
 template <class _CharT, class _Traits, class _Allocator>
 void _LIBCPP_CONSTEXPR_SINCE_CXX20
 #if _LIBCPP_ABI_VERSION >= 2 // We want to use the function in the dylib in ABIv1
-    _LIBCPP_HIDE_FROM_ABI
+_LIBCPP_HIDE_FROM_ABI
 #endif
-    _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Traits, _Allocator>::__grow_by(
-        size_type __old_cap,
-        size_type __delta_cap,
-        size_type __old_sz,
-        size_type __n_copy,
-        size_type __n_del,
-        size_type __n_add) {
+_LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Traits, _Allocator>::__grow_by(
+    size_type __old_cap,
+    size_type __delta_cap,
+    size_type __old_sz,
+    size_type __n_copy,
+    size_type __n_del,
+    size_type __n_add) {
   size_type __ms = max_size();
   if (__delta_cap > __ms - __old_cap)
     __throw_length_error();
@@ -4005,6 +4023,48 @@ operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs, _CharT __rhs) {
 
 #endif // _LIBCPP_CXX03_LANG
 
+#if _LIBCPP_STD_VER >= 26
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
+          type_identity_t<basic_string_view<_CharT, _Traits>> __rhs) {
+  using _String = basic_string<_CharT, _Traits, _Allocator>;
+
+  _String __r = __lhs;
+  __r.append(__rhs);
+  return __r;
+}
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs,
+          type_identity_t<basic_string_view<_CharT, _Traits>> __rhs) {
+  __lhs.append(__rhs);
+  return std::move(__lhs);
+}
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
+          const basic_string<_CharT, _Traits, _Allocator>& __rhs) {
+  using _String = basic_string<_CharT, _Traits, _Allocator>;
+
+  _String __r = __rhs;
+  __r.insert(0, __lhs);
+  return __r;
+}
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
+          basic_string<_CharT, _Traits, _Allocator>&& __rhs) {
+  __rhs.insert(0, __lhs);
+  return std::move(__rhs);
+}
+
+#endif // _LIBCPP_STD_VER >= 26
+
 // swap
 
 template <class _CharT, class _Traits, class _Allocator>
diff --git a/libcxx/include/version b/libcxx/include/version
index 0ed77345baa71..d7e98fdb47208 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -222,7 +222,8 @@ __cpp_lib_stdatomic_h                                   202011L <stdatomic.h>
 __cpp_lib_string_contains                               202011L <string> <string_view>
 __cpp_lib_string_resize_and_overwrite                   202110L <string>
 __cpp_lib_string_udls                                   201304L <string>
-__cpp_lib_string_view                                   201803L <string> <string_view>
+__cpp_lib_string_view                                   202403L <string> <string_view>
+                                                        201803L // C++20
                                                         201606L // C++17
 __cpp_lib_submdspan                                     202306L <mdspan>
 __cpp_lib_syncbuf                                       201803L <syncstream>
@@ -530,6 +531,8 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 # define __cpp_lib_span_at                              202311L
 # define __cpp_lib_span_initializer_list                202311L
 # define __cpp_lib_sstream_from_string_view             202306L
+# undef  __cpp_lib_string_view
+# define __cpp_lib_string_view                          202403L
 // # define __cpp_lib_submdspan                            202306L
 // # define __cpp_lib_text_encoding                        202306L
 # undef  __cpp_lib_to_chars
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
index 8d944a194faf4..4fb733716b99e 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
@@ -29,6 +29,7 @@
     __cpp_lib_string_udls                                   201304L [C++14]
     __cpp_lib_string_view                                   201606L [C++17]
                                                             201803L [C++20]
+                                                            202403L [C++26]
     __cpp_lib_to_string                                     202306L [C++23]
 */
 
@@ -492,8 +493,8 @@
 # ifndef __cpp_lib_string_view
 #   error "__cpp_lib_string_view should be defined in c++26"
 # endif
-# if __cpp_lib_string_view != 201803L
-#   error "__cpp_lib_string_view should have the value 201803L in c++26"
+# if __cpp_lib_string_view != 202403L
+#   error "__cpp_lib_string_view should have the value 202403L in c++26"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp
index a86ab2adff6a9..f3c70cf977973 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp
@@ -23,6 +23,7 @@
     __cpp_lib_string_contains             202011L [C++23]
     __cpp_lib_string_view                 201606L [C++17]
                                           201803L [C++20]
+                                          202403L [C++26]
 */
 
 #include <string_view>
@@ -252,8 +253,8 @@
 # ifndef __cpp_lib_string_view
 #   error "__cpp_lib_string_view should be defined in c++26"
 # endif
-# if __cpp_lib_string_view != 201803L
-#   error "__cpp_lib_string_view should have the value 201803L in c++26"
+# if __cpp_lib_string_view != 202403L
+#   error "__cpp_lib_string_view should have the value 202403L in c++26"
 # endif
 
 #endif // TEST_STD_VER > 23
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 3ec548f56cea1..35bbfd916ac80 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -206,6 +206,7 @@
     __cpp_lib_string_udls                                   201304L [C++14]
     __cpp_lib_string_view                                   201606L [C++17]
                                                             201803L [C++20]
+                                                            202403L [C++26]
     __cpp_lib_submdspan                                     202306L [C++26]
     __cpp_lib_syncbuf                                       201803L [C++20]
     __cpp_lib_text_encoding                                 202306L [C++26]
@@ -7686,8 +7687,8 @@
 # ifndef __cpp_lib_string_view
 #   error "__cpp_lib_string_view should be defined in c++26"
 # endif
-# if __cpp_lib_string_view != 201803L
-#   error "__cpp_lib_string_view should have the value 201803L in c++26"
+# if __cpp_lib_string_view != 202403L
+#   error "__cpp_lib_string_view should have the value 202403L in c++26"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
new file mode 100644
index 0000000000000..efa57442997e7
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <string>
+#include <utility>
+
+#include "asan_testing.h"
+#include "constexpr_char_traits.h"
+#include "make_string.h"
+#include "min_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() {
+  AllocT allocator;
+  std::basic_string<CharT, TraitsT, AllocT> st{ST("Hello", allocator)};
+  std::basic_string_view<CharT, TraitsT> sv{SV("World")};
+
+  assert(st + sv == ST("HelloWorld", allocator));
+  assert(st + sv != ST("Hello World", allocator));
+}
+
+constexpr bool test() {
+  test<char, std::char_traits<char>, min_allocator<char>>();
+  test<char, constexpr_char_traits<char>, min_allocator<char>>();
+  test<char, std::char_traits<char>, safe_allocator<char>>();
+  test<char, constexpr_char_traits<char>, safe_allocator<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t, std::char_traits<wchar_t>, min_allocator<wchar_t>>();
+  test<wchar_t, constexpr_char_traits<wchar_t>, min_allocator<wchar_t>>();
+  test<wchar_t, std::char_traits<wchar_t>, safe_allocator<wchar_t>>();
+  test<wchar_t, constexpr_char_traits<wchar_t>, safe_allocator<wchar_t>>();
+#endif
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index f2b8d55c0e11b..1afdb6475b187 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1202,7 +1202,7 @@ def add_version_header(tc):
             "values": {
                 "c++17": 201606,
                 "c++20": 201803,
-                # "c++26": 202403, # P2591R5: Concatenation of strings and string views
+                "c++26": 202403, # P2591R5: Concatenation of strings and string views
             },
             "headers": ["string", "string_view"],
         },

>From af56ab902866a6971fad6034b483ad55e02ccdef Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 11 Apr 2024 21:01:34 +0300
Subject: [PATCH 02/17] Implemented tests

---
 libcxx/include/string                         |  11 +-
 .../string_op+/string.string_view.pass.cpp    | 107 ++++++++++++++++--
 .../generate_feature_test_macro_components.py |   2 +-
 3 files changed, 107 insertions(+), 13 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index 7758a4ae42e04..eb5f2b78af082 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -4050,8 +4050,8 @@ operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
           const basic_string<_CharT, _Traits, _Allocator>& __rhs) {
   using _String = basic_string<_CharT, _Traits, _Allocator>;
 
-  _String __r = __rhs;
-  __r.insert(0, __lhs);
+  _String __r{__lhs};
+  __r.append(__rhs);
   return __r;
 }
 
@@ -4059,8 +4059,11 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
           basic_string<_CharT, _Traits, _Allocator>&& __rhs) {
-  __rhs.insert(0, __lhs);
-  return std::move(__rhs);
+  using _String = basic_string<_CharT, _Traits, _Allocator>;
+
+  _String __r{__lhs};
+  __r.append(std::move(__rhs));
+  return __r;
 }
 
 #endif // _LIBCPP_STD_VER >= 26
diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index efa57442997e7..21936d76d0632 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -30,6 +30,7 @@
 //               basic_string<charT, traits, Allocator>&& rhs);                                    // Since C++26
 
 #include <cassert>
+#include <concepts>
 #include <string>
 #include <utility>
 
@@ -37,6 +38,7 @@
 #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)
@@ -44,25 +46,114 @@
 #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() {
+constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
   AllocT allocator;
-  std::basic_string<CharT, TraitsT, AllocT> st{ST("Hello", allocator)};
-  std::basic_string_view<CharT, TraitsT> sv{SV("World")};
 
-  assert(st + sv == ST("HelloWorld", allocator));
-  assert(st + sv != ST("Hello World", 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_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 + std::move(st);
+    assert(result == expected);
+    assert(result.get_allocator() == allocator);
+    LIBCPP_ASSERT(is_string_asan_correct(sv + st));
+  }
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>, typename AllocT = std::allocator<CharT>>
+constexpr void test() {
+  // Concatinate with an empty string
+  test<CharT, TraitsT, AllocT>(CS(""), CS(""), CS(""));
+  test<CharT, TraitsT, AllocT>(CS(""), CS("short"), CS("short"));
+  test<CharT, TraitsT, AllocT>(CS(""), CS("not so short"), CS("not so short"));
+  test<CharT, TraitsT, AllocT>(CS(""), CS("this is a much longer string"), CS("this is a much longer string"));
+
+  test<CharT, TraitsT, AllocT>(CS(""), CS(""), CS(""));
+  test<CharT, TraitsT, AllocT>(CS("short"), CS(""), CS("short"));
+  test<CharT, TraitsT, AllocT>(CS("not so short"), CS(""), CS("not so short"));
+  test<CharT, TraitsT, AllocT>(CS("this is a much longer string"), CS(""), CS("this is a much longer string"));
+
+  // Non empty
+  test<CharT, TraitsT, AllocT>(CS("B"), CS("D"), CS("BD"));
+  test<CharT, TraitsT, AllocT>(CS("zmt94"), CS("+hkt82"), CS("zmt94+hkt82"));
+  test<CharT, TraitsT, AllocT>(CS("not so short"), CS("+is not bad"), CS("not so short+is not bad"));
+  test<CharT, TraitsT, AllocT>(
+      CS("this is a much longer string"),
+      CS("+which is so much better"),
+      CS("this is a much longer string+which is so much better"));
 }
 
 constexpr bool test() {
+  test<char, std::char_traits<char>>();
   test<char, std::char_traits<char>, min_allocator<char>>();
-  test<char, constexpr_char_traits<char>, min_allocator<char>>();
   test<char, std::char_traits<char>, safe_allocator<char>>();
+  // test<char, std::char_traits<char>, test_allocator<char>>();
+
+  test<char, constexpr_char_traits<char>>();
+  test<char, constexpr_char_traits<char>, min_allocator<char>>();
   test<char, constexpr_char_traits<char>, safe_allocator<char>>();
+  // test<char, constexpr_char_traits<char>, test_allocator<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test<wchar_t, std::char_traits<wchar_t>, min_allocator<wchar_t>>();
-  test<wchar_t, constexpr_char_traits<wchar_t>, min_allocator<wchar_t>>();
+  test<wchar_t, std::char_traits<wchar_t>>();
+  // test<wchar_t, std::char_traits<wchar_t>, min_allocator<wchar_t>>();
   test<wchar_t, std::char_traits<wchar_t>, safe_allocator<wchar_t>>();
+  // test<wchar_t, std::char_traits<wchar_t>, test_allocator<wchar_t>>();
+
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+  // test<wchar_t, constexpr_char_traits<wchar_t>, min_allocator<wchar_t>>();
   test<wchar_t, constexpr_char_traits<wchar_t>, safe_allocator<wchar_t>>();
+  // test<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>();
 #endif
 
   return true;
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 1afdb6475b187..1b938fa30c59d 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1202,7 +1202,7 @@ def add_version_header(tc):
             "values": {
                 "c++17": 201606,
                 "c++20": 201803,
-                "c++26": 202403, # P2591R5: Concatenation of strings and string views
+                "c++26": 202403,  # P2591R5: Concatenation of strings and string views
             },
             "headers": ["string", "string_view"],
         },

>From 474d5b9d8a15921369614cf82df46502fad13f7f Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 11 Apr 2024 21:03:43 +0300
Subject: [PATCH 03/17] Cleanup

---
 .../string_op+/string.string_view.pass.cpp               | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index 21936d76d0632..f2fb1dbe7195d 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -38,7 +38,6 @@
 #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)
@@ -113,7 +112,7 @@ constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>, typename AllocT = std::allocator<CharT>>
 constexpr void test() {
-  // Concatinate with an empty string
+  // Concatinate with an empty `string`/`string_view`
   test<CharT, TraitsT, AllocT>(CS(""), CS(""), CS(""));
   test<CharT, TraitsT, AllocT>(CS(""), CS("short"), CS("short"));
   test<CharT, TraitsT, AllocT>(CS(""), CS("not so short"), CS("not so short"));
@@ -138,22 +137,16 @@ constexpr bool test() {
   test<char, std::char_traits<char>>();
   test<char, std::char_traits<char>, min_allocator<char>>();
   test<char, std::char_traits<char>, safe_allocator<char>>();
-  // test<char, std::char_traits<char>, test_allocator<char>>();
 
   test<char, constexpr_char_traits<char>>();
   test<char, constexpr_char_traits<char>, min_allocator<char>>();
   test<char, constexpr_char_traits<char>, safe_allocator<char>>();
-  // test<char, constexpr_char_traits<char>, test_allocator<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t, std::char_traits<wchar_t>>();
-  // test<wchar_t, std::char_traits<wchar_t>, min_allocator<wchar_t>>();
   test<wchar_t, std::char_traits<wchar_t>, safe_allocator<wchar_t>>();
-  // test<wchar_t, std::char_traits<wchar_t>, test_allocator<wchar_t>>();
 
   test<wchar_t, constexpr_char_traits<wchar_t>>();
-  // test<wchar_t, constexpr_char_traits<wchar_t>, min_allocator<wchar_t>>();
   test<wchar_t, constexpr_char_traits<wchar_t>, safe_allocator<wchar_t>>();
-  // test<wchar_t, constexpr_char_traits<wchar_t>, test_allocator<wchar_t>>();
 #endif
 
   return true;

>From 38f6e853deb3dbc6b9020de509f30cfeb981b12f Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 11 Apr 2024 21:06:16 +0300
Subject: [PATCH 04/17] Restored formatting

---
 libcxx/include/string | 44 +++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index eb5f2b78af082..5af81486fa30d 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -1092,8 +1092,8 @@ public:
             __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value &&
                               !__is_same_uncvref<_Tp, basic_string>::value,
                           int> = 0>
-  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const _Tp& __t, const allocator_type& __a)
+  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(
+      const _Tp& __t, const allocator_type& __a)
       : __r_(__default_init_tag(), __a) {
     __self_view __sv = __t;
     __init(__sv.data(), __sv.size());
@@ -1325,8 +1325,8 @@ public:
                           int> = 0>
   _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20
 
-  basic_string&
-  append(const _Tp& __t, size_type __pos, size_type __n = npos);
+      basic_string&
+      append(const _Tp& __t, size_type __pos, size_type __n = npos);
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(const value_type* __s, size_type __n);
   _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(const value_type* __s);
@@ -2015,15 +2015,15 @@ private:
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20
 #if _LIBCPP_ABI_VERSION >= 2 //  We want to use the function in the dylib in ABIv1
-  _LIBCPP_HIDE_FROM_ABI
+      _LIBCPP_HIDE_FROM_ABI
 #endif
-  _LIBCPP_DEPRECATED_("use __grow_by_without_replace") void __grow_by(
-      size_type __old_cap,
-      size_type __delta_cap,
-      size_type __old_sz,
-      size_type __n_copy,
-      size_type __n_del,
-      size_type __n_add = 0);
+          _LIBCPP_DEPRECATED_("use __grow_by_without_replace") void __grow_by(
+              size_type __old_cap,
+              size_type __delta_cap,
+              size_type __old_sz,
+              size_type __n_copy,
+              size_type __n_del,
+              size_type __n_add = 0);
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __grow_by_without_replace(
       size_type __old_cap,
       size_type __delta_cap,
@@ -2189,8 +2189,8 @@ template <class _CharT,
           class _Traits,
           class _Allocator = allocator<_CharT>,
           class            = enable_if_t<__is_allocator<_Allocator>::value> >
-explicit basic_string(basic_string_view<_CharT, _Traits>,
-                      const _Allocator& = _Allocator()) -> basic_string<_CharT, _Traits, _Allocator>;
+explicit basic_string(basic_string_view<_CharT, _Traits>, const _Allocator& = _Allocator())
+    -> basic_string<_CharT, _Traits, _Allocator>;
 
 template <class _CharT,
           class _Traits,
@@ -2425,15 +2425,15 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
 template <class _CharT, class _Traits, class _Allocator>
 void _LIBCPP_CONSTEXPR_SINCE_CXX20
 #if _LIBCPP_ABI_VERSION >= 2 // We want to use the function in the dylib in ABIv1
-_LIBCPP_HIDE_FROM_ABI
+    _LIBCPP_HIDE_FROM_ABI
 #endif
-_LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Traits, _Allocator>::__grow_by(
-    size_type __old_cap,
-    size_type __delta_cap,
-    size_type __old_sz,
-    size_type __n_copy,
-    size_type __n_del,
-    size_type __n_add) {
+    _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Traits, _Allocator>::__grow_by(
+        size_type __old_cap,
+        size_type __delta_cap,
+        size_type __old_sz,
+        size_type __n_copy,
+        size_type __n_del,
+        size_type __n_add) {
   size_type __ms = max_size();
   if (__delta_cap > __ms - __old_cap)
     __throw_length_error();

>From ea270b6f3aff22da6cf8513fe2867453740b491c Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 13 Apr 2024 07:12:20 +0300
Subject: [PATCH 05/17] Addressed review comments

---
 libcxx/include/string                           | 17 +++++------------
 .../string_op+/string.string_view.pass.cpp      |  2 ++
 2 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index 5af81486fa30d..bd648a33b5cdd 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -4029,9 +4029,7 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
           type_identity_t<basic_string_view<_CharT, _Traits>> __rhs) {
-  using _String = basic_string<_CharT, _Traits, _Allocator>;
-
-  _String __r = __lhs;
+  basic_string<_CharT, _Traits, _Allocator> __r = __lhs;
   __r.append(__rhs);
   return __r;
 }
@@ -4048,10 +4046,8 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
           const basic_string<_CharT, _Traits, _Allocator>& __rhs) {
-  using _String = basic_string<_CharT, _Traits, _Allocator>;
-
-  _String __r{__lhs};
-  __r.append(__rhs);
+  basic_string<_CharT, _Traits, _Allocator> __r = __rhs;
+  __r.insert(0, __lhs);
   return __r;
 }
 
@@ -4059,11 +4055,8 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
           basic_string<_CharT, _Traits, _Allocator>&& __rhs) {
-  using _String = basic_string<_CharT, _Traits, _Allocator>;
-
-  _String __r{__lhs};
-  __r.append(std::move(__rhs));
-  return __r;
+  __rhs.insert(0, __lhs);
+  return std::move(__rhs);
 }
 
 #endif // _LIBCPP_STD_VER >= 26
diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index f2fb1dbe7195d..2d0981ed450be 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -143,9 +143,11 @@ constexpr bool test() {
   test<char, constexpr_char_traits<char>, safe_allocator<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t, std::char_traits<wchar_t>>();
+  test<wchar_t, std::char_traits<wchar_t>, min_allocator<wchar_t>>();
   test<wchar_t, std::char_traits<wchar_t>, safe_allocator<wchar_t>>();
 
   test<wchar_t, constexpr_char_traits<wchar_t>>();
+  test<wchar_t, constexpr_char_traits<wchar_t>, min_allocator<wchar_t>>();
   test<wchar_t, constexpr_char_traits<wchar_t>, safe_allocator<wchar_t>>();
 #endif
 

>From 292cd8f7a485d8ccdf9635c50bba1c4a88fc7532 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 13 Apr 2024 07:13:20 +0300
Subject: [PATCH 06/17] Removed `constexpr_char_traits` tests

---
 .../string_op+/string.string_view.pass.cpp                 | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index 2d0981ed450be..7f08d460a6fb1 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -138,17 +138,10 @@ constexpr bool test() {
   test<char, std::char_traits<char>, min_allocator<char>>();
   test<char, std::char_traits<char>, safe_allocator<char>>();
 
-  test<char, constexpr_char_traits<char>>();
-  test<char, constexpr_char_traits<char>, min_allocator<char>>();
-  test<char, constexpr_char_traits<char>, safe_allocator<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t, std::char_traits<wchar_t>>();
   test<wchar_t, std::char_traits<wchar_t>, min_allocator<wchar_t>>();
   test<wchar_t, std::char_traits<wchar_t>, safe_allocator<wchar_t>>();
-
-  test<wchar_t, constexpr_char_traits<wchar_t>>();
-  test<wchar_t, constexpr_char_traits<wchar_t>, min_allocator<wchar_t>>();
-  test<wchar_t, constexpr_char_traits<wchar_t>, safe_allocator<wchar_t>>();
 #endif
 
   return true;

>From 9a86ea1a9c1c0eefca8bec6223b14bec108ee445 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 15 Apr 2024 12:23:24 +0300
Subject: [PATCH 07/17] Use Will Hawkins implementation

---
 libcxx/include/string                         | 88 +++++++++++++++++--
 .../string_op+/string.string_view.pass.cpp    | 52 ++++++++---
 2 files changed, 121 insertions(+), 19 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index bd648a33b5cdd..2a8cbb0b49072 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -725,6 +725,26 @@ struct __can_be_converted_to_string_view
 struct __uninitialized_size_tag {};
 struct __init_with_sentinel_tag {};
 
+#if _LIBCPP_STD_VER >= 26
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
+          type_identity_t<basic_string_view<_CharT, _Traits>> __rhs);
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs, type_identity_t<basic_string_view<_CharT, _Traits>> __rhs);
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
+          const basic_string<_CharT, _Traits, _Allocator>& __rhs);
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs, basic_string<_CharT, _Traits, _Allocator>&& __rhs);
+#endif
+
 template <class _CharT, class _Traits, class _Allocator>
 class basic_string {
 private:
@@ -2158,6 +2178,30 @@ private:
   friend _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator+ <>(value_type, const basic_string&);
   friend _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator+ <>(const basic_string&, const value_type*);
   friend _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator+ <>(const basic_string&, value_type);
+#if _LIBCPP_STD_VER >= 26
+  // friend constexpr basic_string operator+ <>(const basic_string&, const __self_view&);
+
+  // friend constexpr basic_string operator+ <>(const __self_view&, const basic_string&);
+
+  // friend constexpr operator+ <>(type_identity_t<__self_view> __lhs,
+  //                               const basic_string& __rhs);
+
+  // friend constexpr basic_string operator+
+  //     <>(type_identity_t<basic_string_view<_CharT2, _Traits2>> __lhs,
+  //        const basic_string<_CharT2, _Traits2, _Allocator2>& __rhs);
+
+  // template <class _CharT2, class _Traits2, class _Allocator2>
+  // friend constexpr basic_string<_CharT2, _Traits2, _Allocator2>
+  // operator+(type_identity_t<basic_string_view<_CharT2, _Traits2>>, const basic_string<_CharT2, _Traits2, _Allocator2>&);
+
+
+  // friend constexpr basic_string operator+ <>(type_identity_t<basic_string_view>, const basic_string&);
+
+  friend constexpr basic_string operator+ <>(const basic_string&, type_identity_t<__self_view>);
+  friend constexpr basic_string operator+ <>(basic_string&&, type_identity_t<__self_view>);
+  friend constexpr basic_string operator+ <>(type_identity_t<__self_view>, const basic_string&);
+  friend constexpr basic_string operator+ <>(type_identity_t<__self_view>, basic_string&&);
+#endif
 };
 
 // These declarations must appear before any functions are implicitly used
@@ -4029,9 +4073,17 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
           type_identity_t<basic_string_view<_CharT, _Traits>> __rhs) {
-  basic_string<_CharT, _Traits, _Allocator> __r = __lhs;
-  __r.append(__rhs);
-  return __r;
+    using _String = basic_string<_CharT, _Traits, _Allocator>;
+    typename _String::size_type __lhs_sz = __lhs.size();
+    typename _String::size_type __rhs_sz = __rhs.size();
+    _String __r(__uninitialized_size_tag(),
+                __lhs_sz + __rhs_sz,
+                _String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator()));
+    auto __ptr = std::__to_address(__r.__get_pointer());
+    _Traits::copy(__ptr, __lhs.data(), __lhs_sz);
+    _Traits::copy(__ptr + __lhs_sz, __rhs.data(), __rhs_sz);
+    _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT());
+    return __r;
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -4046,8 +4098,19 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
           const basic_string<_CharT, _Traits, _Allocator>& __rhs) {
-  basic_string<_CharT, _Traits, _Allocator> __r = __rhs;
-  __r.insert(0, __lhs);
+  // basic_string<_CharT, _Traits, _Allocator> __r = __rhs;
+  // __r.insert(0, __lhs);
+  // return __r;
+  using _String                        = basic_string<_CharT, _Traits, _Allocator>;
+  typename _String::size_type __lhs_sz = __lhs.size();
+  typename _String::size_type __rhs_sz = __rhs.size();
+  _String __r(__uninitialized_size_tag(),
+              __lhs_sz + __rhs_sz,
+              _String::__alloc_traits::select_on_container_copy_construction(__rhs.get_allocator()));
+  auto __ptr = std::__to_address(__r.__get_pointer());
+  _Traits::copy(__ptr, __lhs.data(), __lhs_sz);
+  _Traits::copy(__ptr + __lhs_sz, __rhs.data(), __rhs_sz);
+  _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT());
   return __r;
 }
 
@@ -4055,8 +4118,19 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
           basic_string<_CharT, _Traits, _Allocator>&& __rhs) {
-  __rhs.insert(0, __lhs);
-  return std::move(__rhs);
+  // __rhs.insert(0, __lhs);
+  // return std::move(__rhs);
+  using _String                        = basic_string<_CharT, _Traits, _Allocator>;
+  typename _String::size_type __lhs_sz = __lhs.size();
+  typename _String::size_type __rhs_sz = __rhs.size();
+  _String __r(__uninitialized_size_tag(),
+              __lhs_sz + __rhs_sz,
+              _String::__alloc_traits::select_on_container_copy_construction(__rhs.get_allocator()));
+  auto __ptr = std::__to_address(__r.__get_pointer());
+  _Traits::copy(__ptr, __lhs.data(), __lhs_sz);
+  _Traits::copy(__ptr + __lhs_sz, __rhs.data(), __rhs_sz);
+  _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT());
+  return __r;
 }
 
 #endif // _LIBCPP_STD_VER >= 26
diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index 7f08d460a6fb1..28a14950eef0a 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -110,9 +110,9 @@ constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
   }
 }
 
-template <typename CharT, typename TraitsT = std::char_traits<CharT>, typename AllocT = std::allocator<CharT>>
+template <typename CharT, typename TraitsT, typename AllocT = std::allocator<CharT>>
 constexpr void test() {
-  // Concatinate with an empty `string`/`string_view`
+  // Concatenate with an empty `string`/`string_view`
   test<CharT, TraitsT, AllocT>(CS(""), CS(""), CS(""));
   test<CharT, TraitsT, AllocT>(CS(""), CS("short"), CS("short"));
   test<CharT, TraitsT, AllocT>(CS(""), CS("not so short"), CS("not so short"));
@@ -133,23 +133,51 @@ constexpr void test() {
       CS("this is a much longer string+which is so much better"));
 }
 
+template <typename CharT>
 constexpr bool test() {
-  test<char, std::char_traits<char>>();
-  test<char, std::char_traits<char>, min_allocator<char>>();
-  test<char, std::char_traits<char>, safe_allocator<char>>();
+  test<CharT, std::char_traits<CharT>>();
+  test<CharT, std::char_traits<CharT>, min_allocator<CharT>>();
+  test<CharT, std::char_traits<CharT>, safe_allocator<CharT>>();
 
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test<wchar_t, std::char_traits<wchar_t>>();
-  test<wchar_t, std::char_traits<wchar_t>, min_allocator<wchar_t>>();
-  test<wchar_t, std::char_traits<wchar_t>, safe_allocator<wchar_t>>();
-#endif
+  test<CharT, constexpr_char_traits<CharT>>();
+  test<CharT, constexpr_char_traits<CharT>, min_allocator<CharT>>();
+  test<CharT, constexpr_char_traits<CharT>, safe_allocator<CharT>>();
 
   return true;
 }
 
+// constexpr bool test() {
+//   test<char>();
+// #ifndef TEST_HAS_NO_WIDE_CHARACTERS
+//   test<wchar_t>();
+// #endif
+// #ifndef TEST_HAS_NO_CHAR8_T
+//   test<char8_t>();
+// #endif
+//   test<char16_t>();
+//   test<char32_t>();
+
+//   return true;
+// }
+
 int main(int, char**) {
-  test();
-  static_assert(test());
+  // test();
+  // static_assert(test());
+
+  test<char>();
+  static_assert(test<char>());
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  static_assert(test<wchar_t>());
+#endif
+#ifndef TEST_HAS_NO_CHAR8_T
+  test<char8_t>();
+  static_assert(test<char8_t>());
+#endif
+  test<char16_t>();
+  static_assert(test<char16_t>());
+  test<char32_t>();
+  static_assert(test<char32_t>());
 
   return 0;
 }

>From 695b4b61acaf072c75d573aeef3545276b04b99d Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 15 Apr 2024 12:28:33 +0300
Subject: [PATCH 08/17] Cleanup

---
 libcxx/include/string                         | 28 -------------------
 .../string_op+/string.string_view.pass.cpp    | 20 ++-----------
 2 files changed, 3 insertions(+), 45 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index 2a8cbb0b49072..a2606b73d5e57 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -731,10 +731,6 @@ _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
           type_identity_t<basic_string_view<_CharT, _Traits>> __rhs);
 
-template <class _CharT, class _Traits, class _Allocator>
-_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
-operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs, type_identity_t<basic_string_view<_CharT, _Traits>> __rhs);
-
 template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
@@ -2179,26 +2175,7 @@ private:
   friend _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator+ <>(const basic_string&, const value_type*);
   friend _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator+ <>(const basic_string&, value_type);
 #if _LIBCPP_STD_VER >= 26
-  // friend constexpr basic_string operator+ <>(const basic_string&, const __self_view&);
-
-  // friend constexpr basic_string operator+ <>(const __self_view&, const basic_string&);
-
-  // friend constexpr operator+ <>(type_identity_t<__self_view> __lhs,
-  //                               const basic_string& __rhs);
-
-  // friend constexpr basic_string operator+
-  //     <>(type_identity_t<basic_string_view<_CharT2, _Traits2>> __lhs,
-  //        const basic_string<_CharT2, _Traits2, _Allocator2>& __rhs);
-
-  // template <class _CharT2, class _Traits2, class _Allocator2>
-  // friend constexpr basic_string<_CharT2, _Traits2, _Allocator2>
-  // operator+(type_identity_t<basic_string_view<_CharT2, _Traits2>>, const basic_string<_CharT2, _Traits2, _Allocator2>&);
-
-
-  // friend constexpr basic_string operator+ <>(type_identity_t<basic_string_view>, const basic_string&);
-
   friend constexpr basic_string operator+ <>(const basic_string&, type_identity_t<__self_view>);
-  friend constexpr basic_string operator+ <>(basic_string&&, type_identity_t<__self_view>);
   friend constexpr basic_string operator+ <>(type_identity_t<__self_view>, const basic_string&);
   friend constexpr basic_string operator+ <>(type_identity_t<__self_view>, basic_string&&);
 #endif
@@ -4098,9 +4075,6 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
           const basic_string<_CharT, _Traits, _Allocator>& __rhs) {
-  // basic_string<_CharT, _Traits, _Allocator> __r = __rhs;
-  // __r.insert(0, __lhs);
-  // return __r;
   using _String                        = basic_string<_CharT, _Traits, _Allocator>;
   typename _String::size_type __lhs_sz = __lhs.size();
   typename _String::size_type __rhs_sz = __rhs.size();
@@ -4118,8 +4092,6 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
           basic_string<_CharT, _Traits, _Allocator>&& __rhs) {
-  // __rhs.insert(0, __lhs);
-  // return std::move(__rhs);
   using _String                        = basic_string<_CharT, _Traits, _Allocator>;
   typename _String::size_type __lhs_sz = __lhs.size();
   typename _String::size_type __rhs_sz = __rhs.size();
diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index 28a14950eef0a..7efaa1125efb0 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -38,6 +38,7 @@
 #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)
@@ -138,32 +139,17 @@ constexpr bool test() {
   test<CharT, std::char_traits<CharT>>();
   test<CharT, std::char_traits<CharT>, min_allocator<CharT>>();
   test<CharT, std::char_traits<CharT>, safe_allocator<CharT>>();
+  test<CharT, std::char_traits<CharT>, test_allocator<CharT>>();
 
   test<CharT, constexpr_char_traits<CharT>>();
   test<CharT, constexpr_char_traits<CharT>, min_allocator<CharT>>();
   test<CharT, constexpr_char_traits<CharT>, safe_allocator<CharT>>();
+  test<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>();
 
   return true;
 }
 
-// constexpr bool test() {
-//   test<char>();
-// #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-//   test<wchar_t>();
-// #endif
-// #ifndef TEST_HAS_NO_CHAR8_T
-//   test<char8_t>();
-// #endif
-//   test<char16_t>();
-//   test<char32_t>();
-
-//   return true;
-// }
-
 int main(int, char**) {
-  // test();
-  // static_assert(test());
-
   test<char>();
   static_assert(test<char>());
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS

>From 6b77e5a8428bffcd124f5dffb157ca9732c809b9 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 16 Apr 2024 09:41:32 +0300
Subject: [PATCH 09/17] Reordered forward declared functions

---
 libcxx/include/string | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index fd6d894d0f63e..65968d78163a2 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -706,6 +706,24 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>
 operator+(const basic_string<_CharT, _Traits, _Allocator>& __x, _CharT __y);
 
+#if _LIBCPP_STD_VER >= 26
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
+          type_identity_t<basic_string_view<_CharT, _Traits>> __rhs);
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
+          const basic_string<_CharT, _Traits, _Allocator>& __rhs);
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs, basic_string<_CharT, _Traits, _Allocator>&& __rhs);
+
+#endif
+
 extern template _LIBCPP_EXPORTED_FROM_ABI string operator+
     <char, char_traits<char>, allocator<char> >(char const*, string const&);
 
@@ -726,22 +744,6 @@ struct __can_be_converted_to_string_view
 struct __uninitialized_size_tag {};
 struct __init_with_sentinel_tag {};
 
-#if _LIBCPP_STD_VER >= 26
-template <class _CharT, class _Traits, class _Allocator>
-_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
-operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
-          type_identity_t<basic_string_view<_CharT, _Traits>> __rhs);
-
-template <class _CharT, class _Traits, class _Allocator>
-_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
-operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
-          const basic_string<_CharT, _Traits, _Allocator>& __rhs);
-
-template <class _CharT, class _Traits, class _Allocator>
-_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
-operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs, basic_string<_CharT, _Traits, _Allocator>&& __rhs);
-#endif
-
 template <class _CharT, class _Traits, class _Allocator>
 class basic_string {
 private:

>From 694e6fdbd767d53c8634a6aa9e3861b686e1a242 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 9 May 2024 20:01:17 +0300
Subject: [PATCH 10/17] Fixed rvalue argument overload

---
 libcxx/include/string | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index 072e039b4bd6d..5d2f3aff35195 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -4120,17 +4120,8 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
           basic_string<_CharT, _Traits, _Allocator>&& __rhs) {
-  using _String                        = basic_string<_CharT, _Traits, _Allocator>;
-  typename _String::size_type __lhs_sz = __lhs.size();
-  typename _String::size_type __rhs_sz = __rhs.size();
-  _String __r(__uninitialized_size_tag(),
-              __lhs_sz + __rhs_sz,
-              _String::__alloc_traits::select_on_container_copy_construction(__rhs.get_allocator()));
-  auto __ptr = std::__to_address(__r.__get_pointer());
-  _Traits::copy(__ptr, __lhs.data(), __lhs_sz);
-  _Traits::copy(__ptr + __lhs_sz, __rhs.data(), __rhs_sz);
-  _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT());
-  return __r;
+  __rhs.insert(0, __lhs);
+  return std::move(__rhs);
 }
 
 #endif // _LIBCPP_STD_VER >= 26

>From be56164074ad254a3db80a7eeee9a33a616c1230 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 10 May 2024 08:44:25 +0300
Subject: [PATCH 11/17] Workaround for `constexpr_char_traits` not compatible
 with  literals

---
 .../string_op+/string.string_view.pass.cpp    | 22 ++++++++++---------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index 7efaa1125efb0..f0ee9e58a59d2 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -91,7 +91,8 @@ constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
   }
   // string_view + const string&
   {
-    std::basic_string_view<CharT, TraitsT> sv{x};
+    std::basic_string<CharT, TraitsT, AllocT> st_{x, allocator};
+    std::basic_string_view<CharT, TraitsT> sv{st_};
     const std::basic_string<CharT, TraitsT, AllocT> st{y, allocator};
 
     std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st;
@@ -101,7 +102,8 @@ constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
   }
   // string_view + string&&
   {
-    std::basic_string_view<CharT, TraitsT> sv{x};
+    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};
 
     std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + std::move(st);
@@ -152,18 +154,18 @@ constexpr bool test() {
 int main(int, char**) {
   test<char>();
   static_assert(test<char>());
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
-  static_assert(test<wchar_t>());
-#endif
-#ifndef TEST_HAS_NO_CHAR8_T
+    static_assert(test<wchar_t>());
+  #endif
+  #ifndef TEST_HAS_NO_CHAR8_T
   test<char8_t>();
-  static_assert(test<char8_t>());
-#endif
+    static_assert(test<char8_t>());
+  #endif
   test<char16_t>();
-  static_assert(test<char16_t>());
+    static_assert(test<char16_t>());
   test<char32_t>();
-  static_assert(test<char32_t>());
+    static_assert(test<char32_t>());
 
   return 0;
 }

>From 20b9120dcb071cb2b46c191052965b379ca4b6f0 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 10 May 2024 08:45:50 +0300
Subject: [PATCH 12/17] Minor cleanup

---
 .../string.nonmembers/string_op+/string.string_view.pass.cpp   | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index f0ee9e58a59d2..3c146484ed5b5 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -91,8 +91,7 @@ constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
   }
   // string_view + const string&
   {
-    std::basic_string<CharT, TraitsT, AllocT> st_{x, allocator};
-    std::basic_string_view<CharT, TraitsT> sv{st_};
+    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;

>From a8c28fbfc83af1bc7cb6cd4ceeb1e6b4906e1a05 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 10 May 2024 08:48:30 +0300
Subject: [PATCH 13/17] Fixed formatting

---
 .../string_op+/string.string_view.pass.cpp       | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index 3c146484ed5b5..e5624e265042a 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -153,18 +153,18 @@ constexpr bool test() {
 int main(int, char**) {
   test<char>();
   static_assert(test<char>());
-  #ifndef TEST_HAS_NO_WIDE_CHARACTERS
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
-    static_assert(test<wchar_t>());
-  #endif
-  #ifndef TEST_HAS_NO_CHAR8_T
+  static_assert(test<wchar_t>());
+#endif
+#ifndef TEST_HAS_NO_CHAR8_T
   test<char8_t>();
-    static_assert(test<char8_t>());
-  #endif
+  static_assert(test<char8_t>());
+#endif
   test<char16_t>();
-    static_assert(test<char16_t>());
+  static_assert(test<char16_t>());
   test<char32_t>();
-    static_assert(test<char32_t>());
+  static_assert(test<char32_t>());
 
   return 0;
 }

>From bdbaf38a56b9958238ab292362f5f8c2cc17d274 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 10 May 2024 09:39:42 +0300
Subject: [PATCH 14/17] Cleanup

---
 libcxx/include/string | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index 5d2f3aff35195..1eddb9f9a507f 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -717,10 +717,6 @@ _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
           const basic_string<_CharT, _Traits, _Allocator>& __rhs);
 
-template <class _CharT, class _Traits, class _Allocator>
-_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
-operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs, basic_string<_CharT, _Traits, _Allocator>&& __rhs);
-
 #endif
 
 extern template _LIBCPP_EXPORTED_FROM_ABI string operator+
@@ -2205,7 +2201,6 @@ private:
 #if _LIBCPP_STD_VER >= 26
   friend constexpr basic_string operator+ <>(const basic_string&, type_identity_t<__self_view>);
   friend constexpr basic_string operator+ <>(type_identity_t<__self_view>, const basic_string&);
-  friend constexpr basic_string operator+ <>(type_identity_t<__self_view>, basic_string&&);
 #endif
 };
 

>From 9f27ece1a6cf29b469db0b55b2975680f7c5f589 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 10 May 2024 15:26:46 +0300
Subject: [PATCH 15/17] Try to fix ASAN tests

---
 .../string.nonmembers/string_op+/string.string_view.pass.cpp  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index e5624e265042a..c1a3b34e2557f 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -77,7 +77,7 @@ constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
     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));
+    LIBCPP_ASSERT(is_string_asan_correct(std::move(st) + sv));
   }
   // string_view + string&
   {
@@ -108,7 +108,7 @@ constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
     std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + std::move(st);
     assert(result == expected);
     assert(result.get_allocator() == allocator);
-    LIBCPP_ASSERT(is_string_asan_correct(sv + st));
+    LIBCPP_ASSERT(is_string_asan_correct(sv + std::move(st)));
   }
 }
 

>From d56da5f1ef690bf9b117ca1a3d808df5a896c9b0 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 16 May 2024 21:19:58 +0300
Subject: [PATCH 16/17] Add a workaround note

---
 .../string.nonmembers/string_op+/string.string_view.pass.cpp   | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
index c1a3b34e2557f..58c3b0bf7f163 100644
--- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -101,6 +101,9 @@ constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
   }
   // string_view + string&&
   {
+    // Create a `basic_string` to workaround clang bug:
+    // https://github.com/llvm/llvm-project/issues/92382
+    // Comparison between pointers to a string literal and some other object results in constant evaluation failure.
     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};

>From da99993e40ee4672f2b6bd7f3c1ee03693262742 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 10 Jul 2024 22:53:52 +0300
Subject: [PATCH 17/17] Fixed formatting

---
 libcxx/include/string | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index 6f56d381759da..2cc3cccc11c98 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -4049,17 +4049,17 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
 operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
           type_identity_t<basic_string_view<_CharT, _Traits>> __rhs) {
-    using _String = basic_string<_CharT, _Traits, _Allocator>;
-    typename _String::size_type __lhs_sz = __lhs.size();
-    typename _String::size_type __rhs_sz = __rhs.size();
-    _String __r(__uninitialized_size_tag(),
-                __lhs_sz + __rhs_sz,
-                _String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator()));
-    auto __ptr = std::__to_address(__r.__get_pointer());
-    _Traits::copy(__ptr, __lhs.data(), __lhs_sz);
-    _Traits::copy(__ptr + __lhs_sz, __rhs.data(), __rhs_sz);
-    _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT());
-    return __r;
+  using _String                        = basic_string<_CharT, _Traits, _Allocator>;
+  typename _String::size_type __lhs_sz = __lhs.size();
+  typename _String::size_type __rhs_sz = __rhs.size();
+  _String __r(__uninitialized_size_tag(),
+              __lhs_sz + __rhs_sz,
+              _String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator()));
+  auto __ptr = std::__to_address(__r.__get_pointer());
+  _Traits::copy(__ptr, __lhs.data(), __lhs_sz);
+  _Traits::copy(__ptr + __lhs_sz, __rhs.data(), __rhs_sz);
+  _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT());
+  return __r;
 }
 
 template <class _CharT, class _Traits, class _Allocator>



More information about the libcxx-commits mailing list