[libcxx-commits] [libcxx] [libc++] Implement P4206R0 Revert string support in std::constant_wrapper (PR #203338)

Yihan Wang via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jun 11 20:46:26 PDT 2026


https://github.com/yronglin updated https://github.com/llvm/llvm-project/pull/203338

>From d227c3bfe25b5f3019398fac379b2ff97f1c9db7 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Fri, 12 Jun 2026 01:05:39 +0800
Subject: [PATCH 1/2] [libc++] Implement P4206R0 Revert string support in
 std::constant_wrapper

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/docs/FeatureTestMacroTable.rst         |  2 +-
 libcxx/docs/Status/Cxx2cPapers.csv            |  1 +
 libcxx/include/__utility/constant_wrapper.h   | 52 ++++-------
 libcxx/include/utility                        |  7 +-
 libcxx/include/version                        |  4 +-
 .../utility.version.compile.pass.cpp          |  4 +-
 .../version.version.compile.pass.cpp          |  4 +-
 .../const.wrap.class/convert.pass.cpp         | 18 +---
 .../const.wrap.class/ctad.compile.pass.cpp    | 32 -------
 .../utilities/const.wrap.class/cw.pass.cpp    | 16 +---
 .../cw_fixed.array.ctor.pass.cpp              | 86 -------------------
 .../const.wrap.class/cw_fixed.ctor.pass.cpp   | 70 ---------------
 .../const.wrap.class/subscript.pass.cpp       |  6 --
 .../const.wrap.class/template.verify.cpp      | 23 +++++
 .../const.wrap.class/types.compile.pass.cpp   | 23 +++--
 .../generate_feature_test_macro_components.py |  2 +-
 16 files changed, 73 insertions(+), 277 deletions(-)
 delete mode 100644 libcxx/test/std/utilities/const.wrap.class/ctad.compile.pass.cpp
 delete mode 100644 libcxx/test/std/utilities/const.wrap.class/cw_fixed.array.ctor.pass.cpp
 delete mode 100644 libcxx/test/std/utilities/const.wrap.class/cw_fixed.ctor.pass.cpp
 create mode 100644 libcxx/test/std/utilities/const.wrap.class/template.verify.cpp

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 1b748e37293df..405414b270759 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -432,7 +432,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_bitset``                                       ``202306L``
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_constant_wrapper``                             ``202603L``
+    ``__cpp_lib_constant_wrapper``                             ``202606L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_constexpr_algorithms``                         ``202306L``
     ---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 2132e80251657..6099725f566df 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -216,3 +216,4 @@
 "`P4159R0 <https://wg21.link/P4159R0>`__","Make ``sender_in`` and ``receiver_of`` exposition-only","2026-03 (Croydon)","","","`#189632 <https://github.com/llvm/llvm-project/issues/189632>`__",""
 "`P4154R0 <https://wg21.link/P4154R0>`__","Renaming various execution things","2026-03 (Croydon)","","","`#189633 <https://github.com/llvm/llvm-project/issues/189633>`__",""
 "","","","","","",""
+"`P3726R2 <https://wg21.link/4206R0>`__","Revert string support in ``std::constant_wrapper``","2026-06 (Brno)","|Complete|","23","`#203336 <https://github.com/llvm/llvm-project/issues/203336>`__",""
diff --git a/libcxx/include/__utility/constant_wrapper.h b/libcxx/include/__utility/constant_wrapper.h
index 6bae95fc1878a..68a8096bc91ad 100644
--- a/libcxx/include/__utility/constant_wrapper.h
+++ b/libcxx/include/__utility/constant_wrapper.h
@@ -14,6 +14,7 @@
 #include <__functional/invoke.h>
 #include <__type_traits/invoke.h>
 #include <__type_traits/is_constructible.h>
+#include <__type_traits/is_same.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/declval.h>
 #include <__utility/forward.h>
@@ -27,36 +28,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 26
 
-template <class _Tp>
-struct __cw_fixed_value {
-  using __type _LIBCPP_NODEBUG = _Tp;
-  _LIBCPP_HIDE_FROM_ABI constexpr __cw_fixed_value(__type __v) noexcept : __data(__v) {}
-  _Tp __data;
-};
-
-template <class _Tp, size_t _Extent>
-struct __cw_fixed_value<_Tp[_Extent]> {
-  using __type _LIBCPP_NODEBUG = _Tp[_Extent];
-  _Tp __data[_Extent];
-
-  _LIBCPP_HIDE_FROM_ABI constexpr __cw_fixed_value(_Tp (&__arr)[_Extent]) noexcept
-      : __cw_fixed_value(__arr, make_index_sequence<_Extent>{}) {}
-
-private:
-  template <size_t... _Idxs>
-  _LIBCPP_HIDE_FROM_ABI constexpr __cw_fixed_value(_Tp (&__arr)[_Extent], index_sequence<_Idxs...>) noexcept
-      : __data{__arr[_Idxs]...} {}
-};
-
-template <class _Tp, size_t _Extent>
-__cw_fixed_value(_Tp (&)[_Extent]) -> __cw_fixed_value<_Tp[_Extent]>;
-
-template <__cw_fixed_value _Xp,
+template <auto _Xp,
 #  ifdef _LIBCPP_COMPILER_GCC
-          // gcc bug:  https://gcc.gnu.org/PR117392
-          class = typename decltype(__cw_fixed_value(_Xp))::__type
+          // gcc bug: https://gcc.gnu.org/PR117392
+          class = remove_cvref_t<decltype(_Xp)>
 #  else
-          class = typename decltype(_Xp)::__type
+          class = decltype(_Xp)
 #  endif
           >
 struct constant_wrapper;
@@ -64,7 +41,7 @@ struct constant_wrapper;
 template <class _Tp>
 concept __constexpr_param = requires { typename constant_wrapper<_Tp::value>; };
 
-template <__cw_fixed_value _Xp>
+template <auto _Xp>
 constexpr auto cw = constant_wrapper<_Xp>{};
 
 struct __cw_operators {
@@ -288,11 +265,20 @@ concept __constexpr_indexable = (__constexpr_param<remove_cvref_t<_Args>> && ...
   typename constant_wrapper<_Obj[remove_cvref_t<_Args>::value...]>;
 };
 
-template <__cw_fixed_value _Xp, class>
+template <auto _Xp, class _Tp>
 struct constant_wrapper : __cw_operators {
-  static constexpr const auto& value = _Xp.__data;
-  using type                         = constant_wrapper;
-  using value_type                   = decltype(_Xp)::__type;
+#  ifdef _LIB_CPP_COMPILER_GCC
+  // gcc bug: https://gcc.gnu.org/PR125188
+  static constexpr decltype((_Xp)) value = (_Xp);
+#  else
+  static constexpr decltype(auto) value = (_Xp);
+#  endif
+
+  using type       = constant_wrapper;
+  using value_type = decltype(_Xp);
+
+  static_assert(is_same_v<_Tp, value_type>,
+                "the second template parameter of std::constant_wrapper must be its value_type");
 
   template <__constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator=(_Rp) const noexcept
diff --git a/libcxx/include/utility b/libcxx/include/utility
index e0c97efc6424d..940dc4f354984 100644
--- a/libcxx/include/utility
+++ b/libcxx/include/utility
@@ -196,10 +196,7 @@ template<class T1, class T2>
     constexpr const T1&& get(const pair<T2, T1>&&) noexcept; // C++14
 
 // [const.wrap.class], class template constant_wrapper
-template<class T>
-  struct cw-fixed-value;                                    // exposition only, since C++26
-
-template<cw-fixed-value X, class = typename decltype(X)::type>
+template<auto X, class = decltype(X)>
   struct constant_wrapper;                                  // since C++26
 
 template<class T>
@@ -208,7 +205,7 @@ template<class T>
 
 struct cw-operators;                                        // exposition only, since C++26
 
-template<cw-fixed-value X>
+template<auto X>
   constexpr auto cw = constant_wrapper<X>{};                // since C++26
 
 // C++14
diff --git a/libcxx/include/version b/libcxx/include/version
index d4d29b4d31a72..ae12300308eb6 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -64,7 +64,7 @@ __cpp_lib_common_reference                              202302L <type_traits>
 __cpp_lib_common_reference_wrapper                      202302L <functional>
 __cpp_lib_complex_udls                                  201309L <complex>
 __cpp_lib_concepts                                      202207L <concepts>
-__cpp_lib_constant_wrapper                              202603L <utility>
+__cpp_lib_constant_wrapper                              202606L <utility>
 __cpp_lib_constexpr_algorithms                          202306L <algorithm> <utility>
                                                         201806L // C++20
 __cpp_lib_constexpr_bitset                              202207L <bitset>
@@ -562,7 +562,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # undef  __cpp_lib_bind_front
 # define __cpp_lib_bind_front                           202306L
 # define __cpp_lib_bitset                               202306L
-# define __cpp_lib_constant_wrapper                     202603L
+# define __cpp_lib_constant_wrapper                     202606L
 # undef  __cpp_lib_constexpr_algorithms
 # define __cpp_lib_constexpr_algorithms                 202306L
 # define __cpp_lib_constexpr_flat_map                   202502L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp
index 8cbd16d242f74..bff6e905e4dee 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp
@@ -404,8 +404,8 @@
 #  ifndef __cpp_lib_constant_wrapper
 #    error "__cpp_lib_constant_wrapper should be defined in c++26"
 #  endif
-#  if __cpp_lib_constant_wrapper != 202603L
-#    error "__cpp_lib_constant_wrapper should have the value 202603L in c++26"
+#  if __cpp_lib_constant_wrapper != 202606L
+#    error "__cpp_lib_constant_wrapper should have the value 202606L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_constexpr_algorithms
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 20c16700ef76a..c1aa2f41f7c2e 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
@@ -6609,8 +6609,8 @@
 #  ifndef __cpp_lib_constant_wrapper
 #    error "__cpp_lib_constant_wrapper should be defined in c++26"
 #  endif
-#  if __cpp_lib_constant_wrapper != 202603L
-#    error "__cpp_lib_constant_wrapper should have the value 202603L in c++26"
+#  if __cpp_lib_constant_wrapper != 202606L
+#    error "__cpp_lib_constant_wrapper should have the value 202606L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_constexpr_algorithms
diff --git a/libcxx/test/std/utilities/const.wrap.class/convert.pass.cpp b/libcxx/test/std/utilities/const.wrap.class/convert.pass.cpp
index a9567cb08b009..f7c59401dcd2a 100644
--- a/libcxx/test/std/utilities/const.wrap.class/convert.pass.cpp
+++ b/libcxx/test/std/utilities/const.wrap.class/convert.pass.cpp
@@ -27,11 +27,10 @@ constexpr bool test() {
   {
     // int conversion
     std::constant_wrapper<6> cw6;
-    const int& result = cw6;
+    int result = cw6;
     assert(result == 6);
-    assert(&result == &cw6.value);
 
-    static_assert(noexcept(static_cast<const int&>(cw6)));
+    static_assert(noexcept(static_cast<int>(cw6)));
   }
 
   {
@@ -45,19 +44,6 @@ constexpr bool test() {
     static_assert(noexcept(static_cast<const S&>(cws)));
   }
 
-  {
-    // array conversion
-    constexpr int arr[] = {1, 2, 3};
-    std::constant_wrapper<arr> cwArr;
-    const int (&result)[3] = cwArr;
-    assert(result[0] == 1);
-    assert(result[1] == 2);
-    assert(result[2] == 3);
-    assert(&result == &cwArr.value);
-
-    static_assert(noexcept(static_cast<const int (&)[3]>(cwArr)));
-  }
-
   {
     // function pointer conversion
     constexpr int (*fptr)(int) = [](int x) constexpr { return x * 2; };
diff --git a/libcxx/test/std/utilities/const.wrap.class/ctad.compile.pass.cpp b/libcxx/test/std/utilities/const.wrap.class/ctad.compile.pass.cpp
deleted file mode 100644
index 7210d7e2152d5..0000000000000
--- a/libcxx/test/std/utilities/const.wrap.class/ctad.compile.pass.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// REQUIRES: std-at-least-c++26
-
-// constant_wrapper
-
-// template<class T, size_t Extent>
-//   cw-fixed-value(T (&)[Extent]) -> cw-fixed-value<T[Extent]>;                   // exposition only
-
-#include <type_traits>
-#include <utility>
-
-constexpr int arr[] = {1, 2, 3};
-using T1            = std::constant_wrapper<arr>;
-static_assert(std::is_same_v<T1::value_type, const int[3]>);
-
-using T2 = std::constant_wrapper<"hello world">;
-static_assert(std::is_same_v<T2::value_type, const char[12]>);
-
-struct S {
-  int value;
-};
-
-constexpr S s[] = {{1}, {2}, {3}};
-using T3        = std::constant_wrapper<s>;
-static_assert(std::is_same_v<T3::value_type, const S[3]>);
diff --git a/libcxx/test/std/utilities/const.wrap.class/cw.pass.cpp b/libcxx/test/std/utilities/const.wrap.class/cw.pass.cpp
index 4f660ee378239..8d8371a0a68a1 100644
--- a/libcxx/test/std/utilities/const.wrap.class/cw.pass.cpp
+++ b/libcxx/test/std/utilities/const.wrap.class/cw.pass.cpp
@@ -10,12 +10,13 @@
 
 // constant_wrapper
 
-//   template<cw-fixed-value X>
+//   template<auto X>
 //    constexpr auto cw = constant_wrapper<X>{};
 
 #include <cassert>
 #include <concepts>
 #include <utility>
+#include <cstddef>
 
 struct S {
   int value;
@@ -41,7 +42,7 @@ constexpr bool test() {
 
   {
     // array constant
-    constexpr int arr[] = {1, 2, 3};
+    constexpr static int arr[] = {1, 2, 3};
     // gcc complains that cw_val is unused
     [[maybe_unused]] std::same_as<const std::constant_wrapper<arr>> decltype(auto) cw_val = std::cw<arr>;
     static_assert(cw_val[0] == 1);
@@ -49,17 +50,6 @@ constexpr bool test() {
     static_assert(cw_val[2] == 3);
   }
 
-  {
-    // string literals
-    [[maybe_unused]] std::same_as<const std::constant_wrapper<"hello">> decltype(auto) cw_val = std::cw<"hello">;
-    static_assert(cw_val[0] == 'h');
-    static_assert(cw_val[1] == 'e');
-    static_assert(cw_val[2] == 'l');
-    static_assert(cw_val[3] == 'l');
-    static_assert(cw_val[4] == 'o');
-    static_assert(cw_val[5] == '\0');
-  }
-
   return true;
 }
 
diff --git a/libcxx/test/std/utilities/const.wrap.class/cw_fixed.array.ctor.pass.cpp b/libcxx/test/std/utilities/const.wrap.class/cw_fixed.array.ctor.pass.cpp
deleted file mode 100644
index 8bccfcfaaaa43..0000000000000
--- a/libcxx/test/std/utilities/const.wrap.class/cw_fixed.array.ctor.pass.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// REQUIRES: std-at-least-c++26
-
-// constant_wrapper
-
-// constexpr cw-fixed-value(T (&arr)[Extent]) noexcept;
-
-#include <cassert>
-#include <utility>
-
-template <auto v>
-auto helper(std::constant_wrapper<v>) -> decltype(v);
-
-template <class T>
-using cw_fixed_value = decltype(helper(std::constant_wrapper<T{}>{}));
-
-struct S {
-  int value;
-
-  constexpr S(int v = 0) : value(v) {}
-
-  constexpr bool operator==(const S& other) const { return value == other.value; }
-};
-
-constexpr bool test() {
-  {
-    // int array construction
-    // the conversion from int array to cw-fixed-value<int array> uses the constructor
-    constexpr int arr[] = {1, 2, 3};
-    std::constant_wrapper<arr> cw{};
-    assert(cw.value[0] == 1);
-    assert(cw.value[1] == 2);
-    assert(cw.value[2] == 3);
-  }
-
-  {
-    // struct array construction
-    constexpr S s[] = {{1}, {2}, {3}};
-    std::constant_wrapper<s> cw{};
-    assert(cw.value[0] == S{1});
-    assert(cw.value[1] == S{2});
-    assert(cw.value[2] == S{3});
-  }
-
-  {
-    // calling the constructor
-    constexpr int arr[] = {1, 2, 3, 4, 5};
-    constexpr cw_fixed_value<const int[5]> ci(arr);
-    std::constant_wrapper<ci> cw;
-    assert(cw.value[0] == 1);
-    assert(cw.value[1] == 2);
-    assert(cw.value[2] == 3);
-    assert(cw.value[3] == 4);
-    assert(cw.value[4] == 5);
-
-    static_assert(noexcept(cw_fixed_value<const int[5]>{arr}));
-  }
-
-  {
-    // the constructor is implicit
-    constexpr int arr[]                       = {1, 2, 3, 4, 5};
-    constexpr cw_fixed_value<const int[5]> ci = arr;
-    std::constant_wrapper<ci> cw;
-    assert(cw.value[0] == 1);
-    assert(cw.value[1] == 2);
-    assert(cw.value[2] == 3);
-    assert(cw.value[3] == 4);
-    assert(cw.value[4] == 5);
-  }
-
-  return true;
-}
-
-int main(int, char**) {
-  test();
-  static_assert(test());
-
-  return 0;
-}
diff --git a/libcxx/test/std/utilities/const.wrap.class/cw_fixed.ctor.pass.cpp b/libcxx/test/std/utilities/const.wrap.class/cw_fixed.ctor.pass.cpp
deleted file mode 100644
index 30c2952f57d4c..0000000000000
--- a/libcxx/test/std/utilities/const.wrap.class/cw_fixed.ctor.pass.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// REQUIRES: std-at-least-c++26
-
-// constant_wrapper
-
-// constexpr cw-fixed-value(type v) noexcept : data(v) {}
-
-#include <cassert>
-#include <utility>
-
-template <auto v>
-auto helper(std::constant_wrapper<v>) -> decltype(v);
-
-template <class T>
-using cw_fixed_value = decltype(helper(std::constant_wrapper<T{}>{}));
-
-struct S {
-  int value;
-
-  constexpr S(int v = 0) : value(v) {}
-
-  constexpr bool operator==(const S& other) const { return value == other.value; }
-};
-
-constexpr bool test() {
-  {
-    // int construction
-    // the conversion from int to cw-fixed-value<int> uses the constructor
-    std::constant_wrapper<42> cw{};
-    assert(cw.value == 42);
-  }
-
-  {
-    // struct construction
-    std::constant_wrapper<S{13}> cw{};
-    assert(cw.value == S{13});
-  }
-
-  {
-    // calling the constructor
-    constexpr cw_fixed_value<int> ci{42};
-    std::constant_wrapper<ci> cw;
-    assert(cw == 42);
-
-    static_assert(noexcept(cw_fixed_value<int>{42}));
-  }
-
-  {
-    // the constructor is implicit
-    constexpr cw_fixed_value<int> ci = 42;
-    std::constant_wrapper<ci> cw;
-    assert(cw == 42);
-  }
-
-  return true;
-}
-
-int main(int, char**) {
-  test();
-  static_assert(test());
-
-  return 0;
-}
diff --git a/libcxx/test/std/utilities/const.wrap.class/subscript.pass.cpp b/libcxx/test/std/utilities/const.wrap.class/subscript.pass.cpp
index 7efefa85fed95..bfa77a4662afc 100644
--- a/libcxx/test/std/utilities/const.wrap.class/subscript.pass.cpp
+++ b/libcxx/test/std/utilities/const.wrap.class/subscript.pass.cpp
@@ -171,12 +171,6 @@ constexpr bool test() {
     assert(result == 42);
   }
 
-  {
-    // just use the index operator
-    assert(std::cw<"abcd">[2] == 'c');
-    assert(std::cw<"abcd">[std::cw<3>] == 'd');
-  }
-
   {
     // integral_constant
     using T                                                      = std::constant_wrapper<arr>;
diff --git a/libcxx/test/std/utilities/const.wrap.class/template.verify.cpp b/libcxx/test/std/utilities/const.wrap.class/template.verify.cpp
new file mode 100644
index 0000000000000..f8902212299ec
--- /dev/null
+++ b/libcxx/test/std/utilities/const.wrap.class/template.verify.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+#include <utility>
+
+// expected-error at +1 {{pointer to subobject of string literal is not allowed in a template argument}}
+std::constant_wrapper<"hello"> string_literal;
+
+// expected-error-re@*:* {{static assertion failed{{.*}}the second template parameter of std::constant_wrapper must be its value_type}}
+std::constant_wrapper<1, float> wrong_type1; // expected-note {{in instantiation of template class}}
+// expected-error-re@*:* {{static assertion failed{{.*}}the second template parameter of std::constant_wrapper must be its value_type}}
+std::constant_wrapper<1.0, int> wrong_type2; // expected-note {{in instantiation of template class}}
+// expected-error-re@*:* {{static assertion failed{{.*}}the second template parameter of std::constant_wrapper must be its value_type}}
+std::constant_wrapper<1, const int> wrong_type3; // expected-note {{in instantiation of template class}}
+// expected-error-re@*:* {{static assertion failed{{.*}}the second template parameter of std::constant_wrapper must be its value_type}}
+std::constant_wrapper<1, const int&> wrong_type4; // expected-note {{in instantiation of template class}}
diff --git a/libcxx/test/std/utilities/const.wrap.class/types.compile.pass.cpp b/libcxx/test/std/utilities/const.wrap.class/types.compile.pass.cpp
index 96dce9e055209..a85a44efd5cfd 100644
--- a/libcxx/test/std/utilities/const.wrap.class/types.compile.pass.cpp
+++ b/libcxx/test/std/utilities/const.wrap.class/types.compile.pass.cpp
@@ -10,16 +10,15 @@
 
 // constant_wrapper
 
-// static constexpr const auto & value = X.data;
+// static constexpr decltype(auto) value = (X);
 // using type = constant_wrapper;
-// using value_type = decltype(X)::type;
+// using value_type = decltype(X);
 
-#include <algorithm>
 #include <concepts>
 #include <utility>
 
 static_assert(std::constant_wrapper<42>::value == 42);
-static_assert(std::same_as<decltype(std::constant_wrapper<42>::value), const int&>);
+static_assert(std::same_as<decltype(std::constant_wrapper<42>::value), const int>);
 static_assert(std::same_as<std::constant_wrapper<42>::type, std::constant_wrapper<42>>);
 static_assert(std::same_as<std::constant_wrapper<42>::value_type, int>);
 
@@ -32,7 +31,15 @@ static_assert(std::same_as<decltype(std::constant_wrapper<S{5}>::value), const S
 static_assert(std::same_as<std::constant_wrapper<S{5}>::type, std::constant_wrapper<S{5}>>);
 static_assert(std::same_as<std::constant_wrapper<S{5}>::value_type, S>);
 
-static_assert(std::ranges::equal(std::constant_wrapper<"abcd">::value, "abcd"));
-static_assert(std::same_as<decltype(std::constant_wrapper<"abcd">::value), const char (&)[5]>);
-static_assert(std::same_as<std::constant_wrapper<"abcd">::type, std::constant_wrapper<"abcd">>);
-static_assert(std::same_as<std::constant_wrapper<"abcd">::value_type, const char[5]>);
+template <auto V>
+consteval bool value_ref_to_template_parameter_object() {
+  return &V == &std::constant_wrapper<V>::value;
+}
+
+static_assert(value_ref_to_template_parameter_object<S{5}>());
+
+constexpr int arr[] = {1, 2, 3, 4, 5};
+
+static_assert(std::constant_wrapper<arr>::value == arr);
+static_assert(std::same_as<std::constant_wrapper<arr>::type, std::constant_wrapper<arr>>);
+static_assert(std::same_as<std::constant_wrapper<arr>::value_type, const int*>);
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index d8fb575b97b2f..64e1f1cb7f9a7 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -337,7 +337,7 @@ def add_version_header(tc):
         {
             "name": "__cpp_lib_constant_wrapper",
             "values": {
-                "c++26": 202603,
+                "c++26": 202606,
             },
             "headers": ["utility"],
         },

>From 05a15b4ed00f0f953b7480d0610d909a550d8088 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Fri, 12 Jun 2026 11:46:01 +0800
Subject: [PATCH 2/2] [libc++] Workaround GCC bugs and clang 22

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/include/__utility/constant_wrapper.h | 86 ++++++++++-----------
 1 file changed, 43 insertions(+), 43 deletions(-)

diff --git a/libcxx/include/__utility/constant_wrapper.h b/libcxx/include/__utility/constant_wrapper.h
index 68a8096bc91ad..c76c282adfb11 100644
--- a/libcxx/include/__utility/constant_wrapper.h
+++ b/libcxx/include/__utility/constant_wrapper.h
@@ -47,130 +47,130 @@ constexpr auto cw = constant_wrapper<_Xp>{};
 struct __cw_operators {
   // unary operators
   template <__constexpr_param _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator+(_Tp) noexcept -> constant_wrapper<(+_Tp::value)> {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator+(_Tp) noexcept -> constant_wrapper<auto(+_Tp::value)> {
     return {};
   }
   template <__constexpr_param _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator-(_Tp) noexcept -> constant_wrapper<(-_Tp::value)> {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator-(_Tp) noexcept -> constant_wrapper<auto(-_Tp::value)> {
     return {};
   }
   template <__constexpr_param _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator~(_Tp) noexcept -> constant_wrapper<(~_Tp::value)> {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator~(_Tp) noexcept -> constant_wrapper<auto(~_Tp::value)> {
     return {};
   }
   template <__constexpr_param _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator!(_Tp) noexcept -> constant_wrapper<(!_Tp::value)> {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator!(_Tp) noexcept -> constant_wrapper<auto(!_Tp::value)> {
     return {};
   }
   template <__constexpr_param _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator&(_Tp) noexcept -> constant_wrapper<(&_Tp::value)> {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator&(_Tp) noexcept -> constant_wrapper<auto(&_Tp::value)> {
     return {};
   }
   template <__constexpr_param _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator*(_Tp) noexcept -> constant_wrapper<(*_Tp::value)> {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator*(_Tp) noexcept -> constant_wrapper<auto(*_Tp::value)> {
     return {};
   }
 
   // binary operators
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator+(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value + _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value + _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator-(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value - _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value - _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator*(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value * _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value * _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator/(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value / _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value / _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator%(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value % _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value % _Rp::value)> {
     return {};
   }
 
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<<(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value << _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value << _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator>>(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value >> _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value >> _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator&(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value & _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value & _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator|(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value | _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value | _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator^(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value ^ _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value ^ _Rp::value)> {
     return {};
   }
 
   template <__constexpr_param _Lp, __constexpr_param _Rp>
     requires(!is_constructible_v<bool, decltype(_Lp::value)> || !is_constructible_v<bool, decltype(_Rp::value)>)
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator&&(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value && _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value && _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
     requires(!is_constructible_v<bool, decltype(_Lp::value)> || !is_constructible_v<bool, decltype(_Rp::value)>)
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator||(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value || _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value || _Rp::value)> {
     return {};
   }
 
   // comparisons
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value <=> _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value <=> _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value < _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value < _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value <= _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value <= _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator==(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value == _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value == _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator!=(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value != _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value != _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator>(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value > _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value > _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator>=(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value >= _Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value >= _Rp::value)> {
     return {};
   }
 
@@ -179,78 +179,78 @@ struct __cw_operators {
 
   template <__constexpr_param _Lp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator->*(_Lp, _Rp) noexcept
-      -> constant_wrapper<(_Lp::value->*_Rp::value)> {
+      -> constant_wrapper<auto(_Lp::value->*_Rp::value)> {
     return {};
   }
 
   // pseudo-mutators
   template <__constexpr_param _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator++(this _Tp) noexcept -> constant_wrapper<(++_Tp::value)> {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator++(this _Tp) noexcept -> constant_wrapper<auto(++_Tp::value)> {
     return {};
   }
   template <__constexpr_param _Tp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator++(this _Tp, int) noexcept
-      -> constant_wrapper<(_Tp::value++)> {
+      -> constant_wrapper<auto(_Tp::value++)> {
     return {};
   }
   template <__constexpr_param _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator--(this _Tp) noexcept -> constant_wrapper<(--_Tp::value)> {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator--(this _Tp) noexcept -> constant_wrapper<auto(--_Tp::value)> {
     return {};
   }
   template <__constexpr_param _Tp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator--(this _Tp, int) noexcept
-      -> constant_wrapper<(_Tp::value--)> {
+      -> constant_wrapper<auto(_Tp::value--)> {
     return {};
   }
 
   template <__constexpr_param _Tp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator+=(this _Tp, _Rp) noexcept
-      -> constant_wrapper<(_Tp::value += _Rp::value)> {
+      -> constant_wrapper<auto(_Tp::value += _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Tp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator-=(this _Tp, _Rp) noexcept
-      -> constant_wrapper<(_Tp::value -= _Rp::value)> {
+      -> constant_wrapper<auto(_Tp::value -= _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Tp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator*=(this _Tp, _Rp) noexcept
-      -> constant_wrapper<(_Tp::value *= _Rp::value)> {
+      -> constant_wrapper<auto(_Tp::value *= _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Tp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator/=(this _Tp, _Rp) noexcept
-      -> constant_wrapper<(_Tp::value /= _Rp::value)> {
+      -> constant_wrapper<auto(_Tp::value /= _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Tp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator%=(this _Tp, _Rp) noexcept
-      -> constant_wrapper<(_Tp::value %= _Rp::value)> {
+      -> constant_wrapper<auto(_Tp::value %= _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Tp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator&=(this _Tp, _Rp) noexcept
-      -> constant_wrapper<(_Tp::value &= _Rp::value)> {
+      -> constant_wrapper<auto(_Tp::value &= _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Tp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator|=(this _Tp, _Rp) noexcept
-      -> constant_wrapper<(_Tp::value |= _Rp::value)> {
+      -> constant_wrapper<auto(_Tp::value |= _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Tp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator^=(this _Tp, _Rp) noexcept
-      -> constant_wrapper<(_Tp::value ^= _Rp::value)> {
+      -> constant_wrapper<auto(_Tp::value ^= _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Tp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator<<=(this _Tp, _Rp) noexcept
-      -> constant_wrapper<(_Tp::value <<= _Rp::value)> {
+      -> constant_wrapper<auto(_Tp::value <<= _Rp::value)> {
     return {};
   }
   template <__constexpr_param _Tp, __constexpr_param _Rp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator>>=(this _Tp, _Rp) noexcept
-      -> constant_wrapper<(_Tp::value >>= _Rp::value)> {
+      -> constant_wrapper<auto(_Tp::value >>= _Rp::value)> {
     return {};
   }
 };
@@ -262,12 +262,12 @@ concept __constexpr_callable = (__constexpr_param<remove_cvref_t<_Args>> && ...)
 
 template <const auto& _Obj, class... _Args>
 concept __constexpr_indexable = (__constexpr_param<remove_cvref_t<_Args>> && ...) && requires {
-  typename constant_wrapper<_Obj[remove_cvref_t<_Args>::value...]>;
+  typename constant_wrapper<auto(_Obj[remove_cvref_t<_Args>::value...])>;
 };
 
 template <auto _Xp, class _Tp>
 struct constant_wrapper : __cw_operators {
-#  ifdef _LIB_CPP_COMPILER_GCC
+#  ifdef _LIBCPP_COMPILER_GCC
   // gcc bug: https://gcc.gnu.org/PR125188
   static constexpr decltype((_Xp)) value = (_Xp);
 #  else
@@ -306,7 +306,7 @@ struct constant_wrapper : __cw_operators {
   template <class... _Args>
     requires __constexpr_indexable<value, _Args...>
   [[nodiscard]]
-  _LIBCPP_HIDE_FROM_ABI static constexpr constant_wrapper<value[remove_cvref_t<_Args>::value...]>
+  _LIBCPP_HIDE_FROM_ABI static constexpr constant_wrapper<auto(value[remove_cvref_t<_Args>::value...])>
   operator[](_Args&&...) noexcept {
     return {};
   }



More information about the libcxx-commits mailing list