[libcxx-commits] [libcxx] 4a19be5 - [libc++][strings] P2591R5: Concatenation of strings and string views (#88389)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 18 03:26:40 PDT 2024


Author: Hristo Hristov
Date: 2024-07-18T13:26:37+03:00
New Revision: 4a19be5d45e4b1e02c2512023151be5d56ef5744

URL: https://github.com/llvm/llvm-project/commit/4a19be5d45e4b1e02c2512023151be5d56ef5744
DIFF: https://github.com/llvm/llvm-project/commit/4a19be5d45e4b1e02c2512023151be5d56ef5744.diff

LOG: [libc++][strings] P2591R5: Concatenation of strings and string views (#88389)

Implemented: https://wg21.link/P2591R5
- https://eel.is/c++draft/string.syn
- https://eel.is/c++draft/string.op.plus

---------

Co-authored-by: Hristo Hristov <zingam at outlook.com>

Added: 
    libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/ReleaseNotes/19.rst
    libcxx/docs/Status/Cxx2cPapers.csv
    libcxx/include/string
    libcxx/include/version
    libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 1e347d043ef69..53cfc3739d2be 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -474,6 +474,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 80b9e18cec901..80f43256f1270 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -46,6 +46,7 @@ Implemented Papers
 - P2872R3 - Remove ``wstring_convert`` From C++26
 - P3142R0 - Printing Blank Lines with ``println`` (as DR against C++23)
 - P2944R3 - Comparisons for ``reference_wrapper`` (comparison operators for ``reference_wrapper`` only)
+- P2591R5 - Concatenation of strings and string views
 - P2968R2 - Make ``std::ignore`` a first-class object
 - 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 2c498f336b125..968d82a973a79 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 9a52ab6aef41e..90394e9edbe83 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
@@ -687,6 +705,28 @@ 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+(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&);
 
@@ -2150,6 +2190,10 @@ 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&, type_identity_t<__self_view>);
+  friend constexpr basic_string operator+ <>(type_identity_t<__self_view>, const basic_string&);
+#endif
 };
 
 // These declarations must appear before any functions are implicitly used
@@ -4007,6 +4051,60 @@ 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>;
+  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>
+_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>;
+  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;
+}
+
+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 c971336bcb85c..7d9fad1cb1eb2 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -231,7 +231,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>
@@ -547,6 +548,8 @@ __cpp_lib_void_t                                        201411L <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 af6386a40a458..69a938edd1cb9 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++26]
 */
 
@@ -483,8 +484,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 a01ee702a5172..e1af3061725df 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
@@ -216,6 +216,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]
@@ -7894,8 +7895,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..3d981e8b3a3cd
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
@@ -0,0 +1,216 @@
+//===----------------------------------------------------------------------===//
+//
+// 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"
+
+template <typename CharT, class TraitsT = std::char_traits<CharT>>
+class ConvertibleToStringView {
+public:
+  constexpr explicit ConvertibleToStringView(const CharT* cs) : cs_{cs} {}
+
+  constexpr operator std::basic_string_view<CharT, TraitsT>() { return std::basic_string_view<CharT, TraitsT>(cs_); }
+  constexpr operator std::basic_string_view<CharT, TraitsT>() const {
+    return std::basic_string_view<CharT, TraitsT>(cs_);
+  }
+
+private:
+  const CharT* cs_;
+};
+
+static_assert(std::constructible_from<std::basic_string_view<char>, const ConvertibleToStringView<char>>);
+static_assert(std::convertible_to<const ConvertibleToStringView<char>, std::basic_string_view<char>>);
+
+static_assert(std::constructible_from<std::basic_string_view<char>, ConvertibleToStringView<char>>);
+static_assert(std::convertible_to<ConvertibleToStringView<char>, std::basic_string_view<char>>);
+
+#define CS(S) MAKE_CSTRING(CharT, S)
+
+template <template <typename, typename> typename StringViewT, 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};
+    StringViewT<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};
+    StringViewT<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};
+    StringViewT<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(std::move(st) + sv));
+  }
+  // string_view + string&
+  {
+    StringViewT<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&
+  {
+    StringViewT<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&&
+  {
+    // TODO: Remove workaround once https://github.com/llvm/llvm-project/issues/92382 is fixed.
+    // 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.
+    if constexpr (std::same_as<StringViewT<CharT, TraitsT>, std::basic_string_view<CharT, TraitsT>>) {
+      std::basic_string<CharT, TraitsT, AllocT> st_{x, allocator};
+      StringViewT<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);
+      assert(result == expected);
+      assert(result.get_allocator() == allocator);
+      LIBCPP_ASSERT(is_string_asan_correct(sv + std::move(st)));
+    }
+  }
+}
+
+template <template <typename, typename> typename StringViewT,
+          typename CharT,
+          typename TraitsT,
+          typename AllocT = std::allocator<CharT>>
+constexpr void test() {
+  // Concatenate with an empty `string`/`string_view`
+  test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS(""), CS(""));
+  test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS("short"), CS("short"));
+  test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS("not so short"), CS("not so short"));
+  test<StringViewT, CharT, TraitsT, AllocT>(
+      CS(""), CS("this is a much longer string"), CS("this is a much longer string"));
+
+  test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS(""), CS(""));
+  test<StringViewT, CharT, TraitsT, AllocT>(CS("short"), CS(""), CS("short"));
+  test<StringViewT, CharT, TraitsT, AllocT>(CS("not so short"), CS(""), CS("not so short"));
+  test<StringViewT, CharT, TraitsT, AllocT>(
+      CS("this is a much longer string"), CS(""), CS("this is a much longer string"));
+
+  // Non empty
+  test<StringViewT, CharT, TraitsT, AllocT>(CS("B"), CS("D"), CS("BD"));
+  test<StringViewT, CharT, TraitsT, AllocT>(CS("zmt94"), CS("+hkt82"), CS("zmt94+hkt82"));
+  test<StringViewT, CharT, TraitsT, AllocT>(CS("not so short"), CS("+is not bad"), CS("not so short+is not bad"));
+  test<StringViewT, 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"));
+}
+
+template <template <typename, typename> typename StringViewT, typename CharT>
+constexpr bool test() {
+  test<StringViewT, CharT, std::char_traits<CharT>>();
+  test<StringViewT, CharT, std::char_traits<CharT>, min_allocator<CharT>>();
+  test<StringViewT, CharT, std::char_traits<CharT>, safe_allocator<CharT>>();
+  test<StringViewT, CharT, std::char_traits<CharT>, test_allocator<CharT>>();
+
+  test<StringViewT, CharT, constexpr_char_traits<CharT>>();
+  test<StringViewT, CharT, constexpr_char_traits<CharT>, min_allocator<CharT>>();
+  test<StringViewT, CharT, constexpr_char_traits<CharT>, safe_allocator<CharT>>();
+  test<StringViewT, CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>();
+
+  return true;
+}
+
+int main(int, char**) {
+  // std::basic_string_view
+  test<std::basic_string_view, char>();
+  static_assert(test<std::basic_string_view, char>());
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<std::basic_string_view, wchar_t>();
+  static_assert(test<std::basic_string_view, wchar_t>());
+#endif
+#ifndef TEST_HAS_NO_CHAR8_T
+  test<std::basic_string_view, char8_t>();
+  static_assert(test<std::basic_string_view, char8_t>());
+#endif
+  test<std::basic_string_view, char16_t>();
+  static_assert(test<std::basic_string_view, char16_t>());
+  test<std::basic_string_view, char32_t>();
+  static_assert(test<std::basic_string_view, char32_t>());
+
+  // ConvertibleToStringView
+  test<ConvertibleToStringView, char>();
+  static_assert(test<ConvertibleToStringView, char>());
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<ConvertibleToStringView, wchar_t>();
+  static_assert(test<ConvertibleToStringView, wchar_t>());
+#endif
+#ifndef TEST_HAS_NO_CHAR8_T
+  test<ConvertibleToStringView, char8_t>();
+  static_assert(test<ConvertibleToStringView, char8_t>());
+#endif
+  test<ConvertibleToStringView, char16_t>();
+  static_assert(test<ConvertibleToStringView, char16_t>());
+  test<ConvertibleToStringView, char32_t>();
+  static_assert(test<ConvertibleToStringView, char32_t>());
+
+  return 0;
+}

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 773b1523cde4e..a267e5774e2ad 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1267,7 +1267,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"],
         },


        


More information about the libcxx-commits mailing list