[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