On Sat, Jun 13, 2026 at 8:13 PM Jonathan Wakely <[email protected]> wrote:

> On Mon, 8 Jun 2026 at 16:27, Tomasz Kamiński <[email protected]> wrote:
> >
> > 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.
> >         * 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]>
> > ---
> > This was just apporved by LWG in Brno.
> > Since RFC added FTM with the value corresponding to Brno.
> >
> > Tested on x86_64-linux. OK for trunk and 16 when approved
> > in plenary.
>
> OK for trunk and gcc-16, thanks.
>
This was merged for GCC-16 after Patrick's backport of r17-117-gc6

>
> >
> >  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 +-
> >  .../20_util/constant_wrapper/generic.cc       | 72 ++++++-------------
> >  .../constant_wrapper/other_wrappers.cc        | 14 ----
> >  .../constant_wrapper/type_param_neg.cc        |  9 +++
> >  8 files changed, 55 insertions(+), 122 deletions(-)
> >  create mode 100644
> libstdc++-v3/testsuite/20_util/constant_wrapper/type_param_neg.cc
> >
> > diff --git a/libstdc++-v3/include/bits/funcref_impl.h
> b/libstdc++-v3/include/bits/funcref_impl.h
> > index db85f173aab..8a00fde1b8e 100644
> > --- a/libstdc++-v3/include/bits/funcref_impl.h
> > +++ b/libstdc++-v3/include/bits/funcref_impl.h
> > @@ -132,12 +132,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 {
> > @@ -153,14 +152,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);
> >
> > @@ -176,12 +174,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 07163f3a5a3..670efa63b4a 100644
> > --- a/libstdc++-v3/include/bits/funcwrap.h
> > +++ b/libstdc++-v3/include/bits/funcwrap.h
> > @@ -592,16 +592,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>>;
> >
> >    /// @cond undocumented
> > diff --git a/libstdc++-v3/include/bits/utility.h
> b/libstdc++-v3/include/bits/utility.h
> > index dac02e4a479..320dd507b43 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 5dddf4cf345..40baefab4e4 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 787315033bb..de1d71fa935 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/testsuite/20_util/constant_wrapper/generic.cc
> b/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc
> > index bd41fc4ca3a..eb0a86d9095 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 fe45c5a8516..a5e2189ef80 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 00000000000..1548e0789e1
> > --- /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" }
> > --
> > 2.54.0
> >
>
>

Reply via email to