https://gcc.gnu.org/g:b7e3a1b99909091e83aab66622015bbe87c57264
commit r16-9153-gb7e3a1b99909091e83aab66622015bbe87c57264 Author: Tomasz Kamiński <[email protected]> Date: Thu Apr 30 20:07:14 2026 +0200 libstdc++: Implement P4206R0: Revert string support in std::constant_wrapper. We need to apply remove_cvref_t on decltype(_Xv) for default template argument due PR115314. The constant_wrapper::value is declared as decltype((__Xv)) due PR125188. libstdc++-v3/ChangeLog: * include/bits/version.def (constant_wrapper): Bump to 202606L. * include/bits/version.h: Regenerate. * include/bits/funcref_impl.h (function_ref::function_ref): Rename template parameter from __cwfn to __fn and use it direclty. * include/bits/funcwrap.h (function_ref): Rename template parameter to __fn. (std::constant_wrapper): Use auto as non-type template parameter, and refeference it as value. * include/bits/utility.h (__CwFixedValue): Remove. * include/std/mdspan (__mdspan::__is_constant_wrapper): Use auto as non-type template parameter. * testsuite/20_util/constant_wrapper/generic.cc: Remove arrays and string literal tests. Add test for address of value. * testsuite/20_util/constant_wrapper/other_wrappers.cc: Remove test_array. Reviewed-by: Patrick Palka <[email protected]> Reviewed-by: Jonathan Wakely <[email protected]> Signed-off-by: Tomasz Kamiński <[email protected]> (cherry picked from commit 4e3139439f9cda78f9ce9c079895d8d0f2dc2a0a) Diff: --- libstdc++-v3/include/bits/funcref_impl.h | 15 ++--- libstdc++-v3/include/bits/funcwrap.h | 8 +-- libstdc++-v3/include/bits/utility.h | 50 +++------------ libstdc++-v3/include/bits/version.def | 5 +- libstdc++-v3/include/bits/version.h | 4 +- libstdc++-v3/include/std/mdspan | 2 +- .../testsuite/20_util/constant_wrapper/generic.cc | 72 +++++++--------------- .../20_util/constant_wrapper/other_wrappers.cc | 14 ----- .../20_util/constant_wrapper/type_param_neg.cc | 9 +++ 9 files changed, 56 insertions(+), 123 deletions(-) diff --git a/libstdc++-v3/include/bits/funcref_impl.h b/libstdc++-v3/include/bits/funcref_impl.h index 9fcab570803f..af4313b07197 100644 --- a/libstdc++-v3/include/bits/funcref_impl.h +++ b/libstdc++-v3/include/bits/funcref_impl.h @@ -129,12 +129,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4256. Incorrect constrains for function_ref constructors from nontype /// Target object is __fn. There is no bound object. - template<auto __cwfn, typename _Fn> + template<auto __fn, typename _Fn> requires __is_invocable_using<const _Fn&> constexpr - function_ref(constant_wrapper<__cwfn, _Fn>) noexcept + function_ref(constant_wrapper<__fn, _Fn>) noexcept { - constexpr const _Fn& __fn = constant_wrapper<__cwfn, _Fn>::value; if constexpr (sizeof...(_ArgTypes) > 0) if constexpr ((... && _ConstExprParam<remove_cvref_t<_ArgTypes>>)) static_assert(!requires { @@ -151,14 +150,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Target object is equivalent to std::bind_front<_fn>(std::ref(__ref)). /// Bound object is object referenced by second parameter. - template<auto __cwfn, typename _Fn, typename _Up, + template<auto __fn, typename _Fn, typename _Up, typename _Td = remove_reference_t<_Up>> requires (!is_rvalue_reference_v<_Up&&>) && __is_invocable_using<const _Fn&, _Td _GLIBCXX_MOF_CV&> constexpr - function_ref(constant_wrapper<__cwfn, _Fn>, _Up&& __ref) noexcept + function_ref(constant_wrapper<__fn, _Fn>, _Up&& __ref) noexcept { - constexpr const _Fn& __fn = constant_wrapper<__cwfn, _Fn>::value; if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>) static_assert(__fn != nullptr); @@ -174,12 +172,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Target object is equivalent to std::bind_front<_fn>(__ptr). /// Bound object is object pointed by second parameter (if any). - template< auto __cwfn, typename _Fn, typename _Td> + template<auto __fn, typename _Fn, typename _Td> requires __is_invocable_using<const _Fn&, _Td _GLIBCXX_MOF_CV*> constexpr - function_ref(constant_wrapper<__cwfn, _Fn>, _Td _GLIBCXX_MOF_CV* __ptr) noexcept + function_ref(constant_wrapper<__fn, _Fn>, _Td _GLIBCXX_MOF_CV* __ptr) noexcept { - constexpr const _Fn& __fn = constant_wrapper<__cwfn, _Fn>::value; if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>) static_assert(__fn != nullptr); if constexpr (is_member_pointer_v<_Fn>) diff --git a/libstdc++-v3/include/bits/funcwrap.h b/libstdc++-v3/include/bits/funcwrap.h index b835e075295b..a7f274f98bdd 100644 --- a/libstdc++-v3/include/bits/funcwrap.h +++ b/libstdc++-v3/include/bits/funcwrap.h @@ -573,16 +573,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION requires is_function_v<_Fn> function_ref(_Fn*) -> function_ref<_Fn>; - template<auto __cwfn, typename _Fn> + template<auto __fn, typename _Fn> requires is_function_v<remove_pointer_t<_Fn>> - function_ref(constant_wrapper<__cwfn, _Fn>) + function_ref(constant_wrapper<__fn, _Fn>) -> function_ref<remove_pointer_t<_Fn>>; - template<auto __cwfn, typename _Fn, typename _Tp, + template<auto __fn, typename _Fn, typename _Tp, typename _SignaturePtr = decltype(__polyfunc::__deduce_funcref<_Fn, _Tp&>())> requires (!is_void_v<_SignaturePtr>) - function_ref(constant_wrapper<__cwfn, _Fn>, _Tp&&) + function_ref(constant_wrapper<__fn, _Fn>, _Tp&&) -> function_ref<remove_pointer_t<_SignaturePtr>>; #endif // __glibcxx_function_ref diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h index dac02e4a479d..320dd507b43d 100644 --- a/libstdc++-v3/include/bits/utility.h +++ b/libstdc++-v3/include/bits/utility.h @@ -141,42 +141,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif #ifdef __glibcxx_constant_wrapper // C++ >= 26 - template<typename _Tp> - struct _CwFixedValue - { - using __type = _Tp; - - constexpr - _CwFixedValue(__type __v) noexcept - : _M_data(__v) { } - - __type _M_data; - }; - - template<typename _Tp, size_t _Extent> - struct _CwFixedValue<_Tp[_Extent]> - { - using __type = _Tp[_Extent]; - - constexpr - _CwFixedValue(_Tp (&__arr)[_Extent]) noexcept - : _CwFixedValue(__arr, typename _Build_index_tuple<_Extent>::__type()) - { } - - template<size_t... _Indices> - constexpr - _CwFixedValue(_Tp (&__arr)[_Extent], _Index_tuple<_Indices...>) noexcept - : _M_data{__arr[_Indices]...} - { } - - _Tp _M_data[_Extent]; - }; - - template<typename _Tp, size_t _Extent> - _CwFixedValue(_Tp (&)[_Extent]) -> _CwFixedValue<_Tp[_Extent]>; - - template<_CwFixedValue _Xv, - typename = typename decltype(_CwFixedValue(_Xv))::__type> + // remove_cvref_t needed due PR115314 + template<auto _Xv, typename _Vt = remove_cvref_t<decltype(_Xv)>> struct constant_wrapper; template<typename _Tp> @@ -430,12 +396,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return {}; } }; - template<_CwFixedValue _Xv, typename> + template<auto _Xv, typename _Vt> struct constant_wrapper : _CwOperators { - static constexpr const auto& value = _Xv._M_data; + // Use decltype((_Xv)) instead of decltype(auto) due PR125188 + static constexpr decltype((_Xv)) value = (_Xv); using type = constant_wrapper; - using value_type = typename decltype(_Xv)::__type; + using value_type = decltype(_Xv); + static_assert(is_same_v<value_type, _Vt>); template<_ConstExprParam _Right> constexpr auto @@ -490,8 +458,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<auto __cw, typename _Fn> constexpr bool __is_constant_wrapper_v<constant_wrapper<__cw, _Fn>> = true; - template<_CwFixedValue _Tp> - constexpr auto cw = constant_wrapper<_Tp>{}; + template<auto _Xv> + constexpr auto cw = constant_wrapper<_Xv>{}; #endif #ifdef __glibcxx_integer_sequence // C++ >= 14 diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 276bd3b9057a..44099eccd036 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -410,9 +410,10 @@ ftms = { name = constant_wrapper; // 202506 P2781R9 std::constexpr_wrapper // 202603 P3978R3 constant_wrapper should unwrap on call and subscript + // 202606 P4206R0 Revert string support in std::constant_wrapper values = { - v = 202603; - cxxmin = 26; + v = 202606; + cxxmin = 26; // P4206R0 accepted as DR for C++26 }; }; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 5337ab79b38d..68f9a5d0b570 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -447,9 +447,9 @@ #if !defined(__cpp_lib_constant_wrapper) # if (__cplusplus > 202302L) -# define __glibcxx_constant_wrapper 202603L +# define __glibcxx_constant_wrapper 202606L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_constant_wrapper) -# define __cpp_lib_constant_wrapper 202603L +# define __cpp_lib_constant_wrapper 202606L # endif # endif #endif /* !defined(__cpp_lib_constant_wrapper) */ diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 5310fbbb956d..7ee0c351ad96 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -907,7 +907,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> constexpr bool __is_constant_wrapper = false; - template<_CwFixedValue _Xv, typename _Tp> + template<auto _Xv, typename _Tp> constexpr bool __is_constant_wrapper<constant_wrapper<_Xv, _Tp>> = true; diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc index bd41fc4ca3a1..eb0a86d9095d 100644 --- a/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc @@ -12,54 +12,6 @@ check_same(auto actual, auto expected) static_assert(std::same_as<decltype(actual), decltype(expected)>); }; - -constexpr void -test_c_arrays() -{ - constexpr double x[] = {1.1, 2.2, 3.3}; - auto cx = std::cw<x>; - auto access = [](auto x, size_t i) - { return x[i]; }; - - check_same(std::cw<x>[0], x[0]); - check_same(std::cw<x>[1], x[1]); - check_same(std::cw<x>[2], x[2]); - - check_same(cx[std::cw<0>], std::cw<x[0]>); - check_same(cx[std::cw<1>], std::cw<x[1]>); - check_same(cx[std::cw<2>], std::cw<x[2]>); -} - -constexpr size_t -deduce_cstr_size(auto str) -{ - size_t sz = 0; - while(str[sz++] != '\0') { } - return sz; -} - -constexpr void -test_string_literals() -{ - auto foo = std::cw<"foo">; - constexpr const typename decltype(foo)::value_type & cstr = foo; - constexpr size_t N = std::size(cstr); - constexpr auto foo_view = std::string_view(cstr, N-1); - - constexpr const char (&cstr1)[deduce_cstr_size(foo)] = foo; - constexpr size_t N1 = std::size(cstr); - - static_assert(static_cast<char const*>(cstr) == - static_cast<char const*>(cstr1)); - static_assert(N1 == N); - - static_assert(foo[0] == 'f'); - static_assert(foo[1] == 'o'); - static_assert(foo[2] == 'o'); - static_assert(foo[3] == '\0'); - static_assert(static_cast<char const *>(foo) == foo_view); -} - constexpr bool convert_constexpr(auto c) { @@ -93,6 +45,27 @@ test_ints() VERIFY(two + 3 == std::cw<5>); } +constexpr void +test_objects() +{ + if consteval { + return; + } + + auto check = []<auto V> + { + VERIFY(&V == &std::constant_wrapper<V>::value); + std::constant_wrapper<V> cw; + VERIFY(&V == &cw.value); + }; + + struct Obj + { int x; }; + + check.operator()<Obj{10}>(); + check.operator()<Obj{20}>(); +} + constexpr int add(int i, int j) { return i + j; } @@ -586,12 +559,11 @@ test_assignment() std::cw<ConstAssignable{2}>); } - constexpr bool test_all() { - test_c_arrays(); test_ints(); + test_objects(); test_function_object(); test_function_pointer(); test_indexable1(); diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc index fe45c5a85162..a5e2189ef80a 100644 --- a/libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc @@ -30,19 +30,6 @@ test_mix_integer_constant() check_same(w2 + c3, std::cw<5>); } -constexpr void -test_array() -{ - constexpr double x[] = {1.1, 2.2, 3.3}; - auto cx = std::cw<x>; - auto i2 = std::integral_constant<int, 2>{}; - auto w2 = ConstWrapper<int, 2>{}; - - check_same(x[i2], x[2]); - check_same(cx[i2], std::cw<x[2]>); - check_same(cx[w2], std::cw<x[2]>); -} - constexpr void test_function_object() { @@ -61,7 +48,6 @@ constexpr bool test_all() { test_mix_integer_constant(); - test_array(); test_function_object(); return true; } diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/type_param_neg.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/type_param_neg.cc new file mode 100644 index 000000000000..1548e0789e11 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/type_param_neg.cc @@ -0,0 +1,9 @@ +// { dg-do compile { target c++26 } } +#include <utility> + +std::constant_wrapper<1, float> c1; // { dg-error "from here" } +std::constant_wrapper<1.0, int> c2; // { dg-error "from here" } +std::constant_wrapper<1, int const> c3; // { dg-error "from here" } +std::constant_wrapper<1, int const&> c4; // { dg-error "from here" } + +// { dg-prune-output "static assertion failed" }
