From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id C3E4C3858C83 for ; Mon, 25 Apr 2022 16:58:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C3E4C3858C83 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-360-oiWArnF9OKauetYnf-uypA-1; Mon, 25 Apr 2022 12:58:38 -0400 X-MC-Unique: oiWArnF9OKauetYnf-uypA-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E76A33C025B7; Mon, 25 Apr 2022 16:58:37 +0000 (UTC) Received: from localhost (unknown [10.33.36.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5C3182024CBC; Mon, 25 Apr 2022 16:58:37 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Implement constexpr std::unique_ptr for C++23 (P2273R3) Date: Mon, 25 Apr 2022 17:58:36 +0100 Message-Id: <20220425165836.1961647-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-13.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 25 Apr 2022 16:58:43 -0000 Tested powerpc64le-linux, pushed to trunk. -- >8 -- libstdc++-v3/ChangeLog: * include/bits/ptr_traits.h (__cpp_lib_constexpr_memory): Define conditionally. * include/bits/unique_ptr.h (__cpp_lib_constexpr_memory): Define for C++23. (default_delete, default_delete, __uniq_ptr_impl) (unique_ptr, unique_ptr): Add constexpr to all member functions. * include/std/version (__cpp_lib_constexpr_memory): Define new value for C++23. * testsuite/20_util/unique_ptr/assign/constexpr.cc: New test. * testsuite/20_util/unique_ptr/comparison/constexpr.cc: New test. * testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc: New test. * testsuite/20_util/unique_ptr/creation/constexpr.cc: New test. * testsuite/20_util/unique_ptr/modifiers/constexpr.cc: New test. * testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc: New test. --- libstdc++-v3/include/bits/ptr_traits.h | 5 +- libstdc++-v3/include/bits/unique_ptr.h | 124 +++++++++++++++--- libstdc++-v3/include/std/version | 4 + .../20_util/unique_ptr/assign/constexpr.cc | 48 +++++++ .../unique_ptr/comparison/constexpr.cc | 73 +++++++++++ .../unique_ptr/cons/constexpr_c++20.cc | 85 ++++++++++++ .../20_util/unique_ptr/creation/constexpr.cc | 34 +++++ .../20_util/unique_ptr/modifiers/constexpr.cc | 68 ++++++++++ .../specialized_algorithms/constexpr.cc | 46 +++++++ 9 files changed, 466 insertions(+), 21 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/assign/constexpr.cc create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/comparison/constexpr.cc create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/creation/constexpr.cc create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/constexpr.cc create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h index c85e6d44ded..047efa5cf28 100644 --- a/libstdc++-v3/include/bits/ptr_traits.h +++ b/libstdc++-v3/include/bits/ptr_traits.h @@ -36,7 +36,10 @@ #if __cplusplus > 201703L #include -#define __cpp_lib_constexpr_memory 201811L +# ifndef __cpp_lib_constexpr_memory +// Defined to a newer value in bits/unique_ptr.h for C++23 +# define __cpp_lib_constexpr_memory 201811L +# endif namespace __gnu_debug { struct _Safe_iterator_base; } #endif diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index 8f4430f61f5..ad60fada59b 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -41,6 +41,14 @@ # include #endif +#if __cplusplus > 202002L && __cpp_constexpr_dynamic_alloc +# if __cpp_lib_constexpr_memory < 202202L +// Defined with older value in bits/ptr_traits.h for C++20 +# undef __cpp_lib_constexpr_memory +# define __cpp_lib_constexpr_memory 202202L +# endif +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -72,9 +80,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template>> + _GLIBCXX23_CONSTEXPR default_delete(const default_delete<_Up>&) noexcept { } /// Calls `delete __ptr` + _GLIBCXX23_CONSTEXPR void operator()(_Tp* __ptr) const { @@ -108,10 +118,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template>> + _GLIBCXX23_CONSTEXPR default_delete(const default_delete<_Up[]>&) noexcept { } /// Calls `delete[] __ptr` template + _GLIBCXX23_CONSTEXPR typename enable_if::value>::type operator()(_Up* __ptr) const { @@ -152,16 +164,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION " or an lvalue reference type" ); __uniq_ptr_impl() = default; + _GLIBCXX23_CONSTEXPR __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; } template - __uniq_ptr_impl(pointer __p, _Del&& __d) + _GLIBCXX23_CONSTEXPR + __uniq_ptr_impl(pointer __p, _Del&& __d) : _M_t(__p, std::forward<_Del>(__d)) { } + _GLIBCXX23_CONSTEXPR __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept : _M_t(std::move(__u._M_t)) { __u._M_ptr() = nullptr; } + _GLIBCXX23_CONSTEXPR __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept { reset(__u.release()); @@ -169,11 +185,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } + _GLIBCXX23_CONSTEXPR pointer& _M_ptr() noexcept { return std::get<0>(_M_t); } + _GLIBCXX23_CONSTEXPR pointer _M_ptr() const noexcept { return std::get<0>(_M_t); } + _GLIBCXX23_CONSTEXPR _Dp& _M_deleter() noexcept { return std::get<1>(_M_t); } + _GLIBCXX23_CONSTEXPR const _Dp& _M_deleter() const noexcept { return std::get<1>(_M_t); } + _GLIBCXX23_CONSTEXPR void reset(pointer __p) noexcept { const pointer __old_p = _M_ptr(); @@ -182,6 +203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_deleter()(__old_p); } + _GLIBCXX23_CONSTEXPR pointer release() noexcept { pointer __p = _M_ptr(); @@ -189,6 +211,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __p; } + _GLIBCXX23_CONSTEXPR void swap(__uniq_ptr_impl& __rhs) noexcept { @@ -281,6 +304,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * The deleter will be value-initialized. */ template> + _GLIBCXX23_CONSTEXPR explicit unique_ptr(pointer __p) noexcept : _M_t(__p) @@ -295,6 +319,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template>> + _GLIBCXX23_CONSTEXPR unique_ptr(pointer __p, const deleter_type& __d) noexcept : _M_t(__p, __d) { } @@ -307,6 +332,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template>> + _GLIBCXX23_CONSTEXPR unique_ptr(pointer __p, __enable_if_t::value, _Del&&> __d) noexcept @@ -315,6 +341,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template::type> + _GLIBCXX23_CONSTEXPR unique_ptr(pointer, __enable_if_t::value, _DelUnref&&>) = delete; @@ -341,6 +368,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __conditional_t::value, is_same<_Ep, _Dp>, is_convertible<_Ep, _Dp>>>> + _GLIBCXX23_CONSTEXPR unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) { } @@ -356,6 +384,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif /// Destructor, invokes the deleter if the stored pointer is not null. +#if __cplusplus > 202002L && __cpp_constexpr_dynamic_alloc + constexpr +#endif ~unique_ptr() noexcept { static_assert(__is_invocable::value, @@ -382,6 +413,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * Invokes the deleter if this object owns a pointer. */ template + _GLIBCXX23_CONSTEXPR typename enable_if< __and_< __safe_conversion_up<_Up, _Ep>, is_assignable @@ -395,6 +427,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// Reset the %unique_ptr to empty, invoking the deleter if necessary. + _GLIBCXX23_CONSTEXPR unique_ptr& operator=(nullptr_t) noexcept { @@ -405,6 +438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Observers. /// Dereference the stored pointer. + _GLIBCXX23_CONSTEXPR typename add_lvalue_reference::type operator*() const noexcept(noexcept(*std::declval())) { @@ -413,6 +447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// Return the stored pointer. + _GLIBCXX23_CONSTEXPR pointer operator->() const noexcept { @@ -421,27 +456,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// Return the stored pointer. + _GLIBCXX23_CONSTEXPR pointer get() const noexcept { return _M_t._M_ptr(); } /// Return a reference to the stored deleter. + _GLIBCXX23_CONSTEXPR deleter_type& get_deleter() noexcept { return _M_t._M_deleter(); } /// Return a reference to the stored deleter. + _GLIBCXX23_CONSTEXPR const deleter_type& get_deleter() const noexcept { return _M_t._M_deleter(); } /// Return @c true if the stored pointer is not null. + _GLIBCXX23_CONSTEXPR explicit operator bool() const noexcept { return get() == pointer() ? false : true; } // Modifiers. /// Release ownership of any stored pointer. + _GLIBCXX23_CONSTEXPR pointer release() noexcept { return _M_t.release(); } @@ -452,6 +492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * The deleter will be invoked if a pointer is already owned. */ + _GLIBCXX23_CONSTEXPR void reset(pointer __p = pointer()) noexcept { @@ -461,6 +502,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// Exchange the pointer and deleter with another object. + _GLIBCXX23_CONSTEXPR void swap(unique_ptr& __u) noexcept { @@ -551,6 +593,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename = _DeleterConstraint<_Vp>, typename = typename enable_if< __safe_conversion_raw<_Up>::value, bool>::type> + _GLIBCXX23_CONSTEXPR explicit unique_ptr(_Up __p) noexcept : _M_t(__p) @@ -567,8 +610,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template, is_copy_constructible<_Del>>> - unique_ptr(_Up __p, const deleter_type& __d) noexcept - : _M_t(__p, __d) { } + _GLIBCXX23_CONSTEXPR + unique_ptr(_Up __p, const deleter_type& __d) noexcept + : _M_t(__p, __d) { } /** Takes ownership of a pointer. * @@ -581,6 +625,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template, is_move_constructible<_Del>>> + _GLIBCXX23_CONSTEXPR unique_ptr(_Up __p, __enable_if_t::value, _Del&&> __d) noexcept @@ -608,11 +653,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __conditional_t::value, is_same<_Ep, _Dp>, is_convertible<_Ep, _Dp>>>> + _GLIBCXX23_CONSTEXPR unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) { } /// Destructor, invokes the deleter if the stored pointer is not null. +#if __cplusplus > 202002L && __cpp_constexpr_dynamic_alloc + constexpr +#endif ~unique_ptr() { auto& __ptr = _M_t._M_ptr(); @@ -638,6 +687,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * Invokes the deleter if this object owns a pointer. */ template + _GLIBCXX23_CONSTEXPR typename enable_if<__and_<__safe_conversion_up<_Up, _Ep>, is_assignable @@ -651,6 +701,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// Reset the %unique_ptr to empty, invoking the deleter if necessary. + _GLIBCXX23_CONSTEXPR unique_ptr& operator=(nullptr_t) noexcept { @@ -661,6 +712,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Observers. /// Access an element of owned array. + _GLIBCXX23_CONSTEXPR typename std::add_lvalue_reference::type operator[](size_t __i) const { @@ -669,27 +721,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// Return the stored pointer. + _GLIBCXX23_CONSTEXPR pointer get() const noexcept { return _M_t._M_ptr(); } /// Return a reference to the stored deleter. + _GLIBCXX23_CONSTEXPR deleter_type& get_deleter() noexcept { return _M_t._M_deleter(); } /// Return a reference to the stored deleter. + _GLIBCXX23_CONSTEXPR const deleter_type& get_deleter() const noexcept { return _M_t._M_deleter(); } /// Return @c true if the stored pointer is not null. + _GLIBCXX23_CONSTEXPR explicit operator bool() const noexcept { return get() == pointer() ? false : true; } // Modifiers. /// Release ownership of any stored pointer. + _GLIBCXX23_CONSTEXPR pointer release() noexcept { return _M_t.release(); } @@ -712,14 +769,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > >> + _GLIBCXX23_CONSTEXPR void reset(_Up __p) noexcept { _M_t.reset(std::move(__p)); } + _GLIBCXX23_CONSTEXPR void reset(nullptr_t = nullptr) noexcept { reset(pointer()); } /// Exchange the pointer and deleter with another object. + _GLIBCXX23_CONSTEXPR void swap(unique_ptr& __u) noexcept { @@ -740,6 +800,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 // Constrained free swap overload, see p0185r1 + _GLIBCXX23_CONSTEXPR typename enable_if<__is_swappable<_Dp>::value>::type #else void @@ -758,41 +819,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Equality operator for unique_ptr objects, compares the owned pointers template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator==(const unique_ptr<_Tp, _Dp>& __x, const unique_ptr<_Up, _Ep>& __y) { return __x.get() == __y.get(); } /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept { return !__x; } #ifndef __cpp_lib_three_way_comparison /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD + inline bool operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept { return !__x; } /// Inequality operator for unique_ptr objects, compares the owned pointers template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD + inline bool operator!=(const unique_ptr<_Tp, _Dp>& __x, const unique_ptr<_Up, _Ep>& __y) { return __x.get() != __y.get(); } /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD + inline bool operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept { return (bool)__x; } /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD + inline bool operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept { return (bool)__x; } #endif // three way comparison @@ -800,7 +867,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Relational operator for unique_ptr objects, compares the owned pointers template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator<(const unique_ptr<_Tp, _Dp>& __x, const unique_ptr<_Up, _Ep>& __y) { @@ -812,7 +880,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) { return std::less::pointer>()(__x.get(), @@ -821,7 +890,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) { return std::less::pointer>()(nullptr, @@ -831,34 +901,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Relational operator for unique_ptr objects, compares the owned pointers template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator<=(const unique_ptr<_Tp, _Dp>& __x, const unique_ptr<_Up, _Ep>& __y) { return !(__y < __x); } /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) { return !(nullptr < __x); } /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) { return !(__x < nullptr); } /// Relational operator for unique_ptr objects, compares the owned pointers template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator>(const unique_ptr<_Tp, _Dp>& __x, const unique_ptr<_Up, _Ep>& __y) { return (__y < __x); } /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) { return std::less::pointer>()(nullptr, @@ -867,7 +942,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) { return std::less::pointer>()(__x.get(), @@ -877,14 +953,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Relational operator for unique_ptr objects, compares the owned pointers template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator>=(const unique_ptr<_Tp, _Dp>& __x, const unique_ptr<_Up, _Ep>& __y) { return !(__x < __y); } /// unique_ptr comparison with nullptr template - _GLIBCXX_NODISCARD inline bool + _GLIBCXX_NODISCARD _GLIBCXX23_CONSTEXPR + inline bool operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) { return !(__x < nullptr); } @@ -898,6 +976,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template requires three_way_comparable_with::pointer, typename unique_ptr<_Up, _Ep>::pointer> + _GLIBCXX23_CONSTEXPR inline compare_three_way_result_t::pointer, typename unique_ptr<_Up, _Ep>::pointer> @@ -907,6 +986,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template requires three_way_comparable::pointer> + _GLIBCXX23_CONSTEXPR inline compare_three_way_result_t::pointer> operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) @@ -979,6 +1059,7 @@ namespace __detail * @relates unique_ptr */ template + _GLIBCXX23_CONSTEXPR inline __detail::__unique_ptr_t<_Tp> make_unique(_Args&&... __args) { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); } @@ -993,6 +1074,7 @@ namespace __detail * The array elements are value-initialized. */ template + _GLIBCXX23_CONSTEXPR inline __detail::__unique_ptr_array_t<_Tp> make_unique(size_t __num) { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); } @@ -1014,6 +1096,7 @@ namespace __detail * @relates unique_ptr */ template + _GLIBCXX23_CONSTEXPR inline __detail::__unique_ptr_t<_Tp> make_unique_for_overwrite() { return unique_ptr<_Tp>(new _Tp); } @@ -1026,6 +1109,7 @@ namespace __detail * @relates unique_ptr */ template + _GLIBCXX23_CONSTEXPR inline __detail::__unique_ptr_array_t<_Tp> make_unique_for_overwrite(size_t __num) { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]); } diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index d8ec658484f..22280e1a349 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -307,6 +307,10 @@ #if _GLIBCXX_HOSTED #define __cpp_lib_adaptor_iterator_pair_constructor 202106L +#if __cpp_constexpr_dynamic_alloc +# undef __cpp_lib_constexpr_memory +# define __cpp_lib_constexpr_memory 202202L +#endif #if __cpp_concepts >= 202002L # define __cpp_lib_expected 202202L #endif diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/constexpr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/constexpr.cc new file mode 100644 index 00000000000..fb4acbda2d5 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/constexpr.cc @@ -0,0 +1,48 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } + +#include +#include + +constexpr bool +test_move() +{ + std::unique_ptr p1(new int(2)); + std::unique_ptr p2; + p2 = std::move(p1); + VERIFY( *p2 == 2 ); + std::unique_ptr a1(new int[]{0, 1, 2}); + std::unique_ptr a2; + a2 = std::move(a1); + VERIFY( a2[2] == 2 ); + + return true; +} +static_assert( test_move() ); + +constexpr bool +test_convert() +{ + std::unique_ptr p1(new int(2)); + std::unique_ptr p2; + p2 = std::move(p1); + VERIFY( *p2 == 2 ); + std::unique_ptr a1(new int[]{0, 1, 2}); + std::unique_ptr a2; + a2 = std::move(a1); + VERIFY( a2[2] == 2 ); + + return true; +} +static_assert( test_convert() ); + +constexpr bool +test_null() +{ + std::unique_ptr p(new int(2)); + p = nullptr; + VERIFY( !p ); + p = nullptr; + return true; +} +static_assert( test_null() ); diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/constexpr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/constexpr.cc new file mode 100644 index 00000000000..83e4f0826a8 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/comparison/constexpr.cc @@ -0,0 +1,73 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } + +#include +#include + +constexpr bool +test_eq() +{ + std::unique_ptr p1, p2; + VERIFY( p1 == p2 ); + p1.reset(new int(1)); + VERIFY( p1 == p1 ); + VERIFY( p1 != p2 ); + struct null_deleter { constexpr void operator()(const void*) const { } }; + std::unique_ptr p3(p1.get()); + VERIFY( p3 == p3 ); + VERIFY( p1 == p3 ); + VERIFY( p3 != p2 ); + + return true; +} +static_assert( test_eq() ); + +constexpr bool +test_rel() +{ + std::unique_ptr p1, p2; + VERIFY( !(p1 < p2) ); + VERIFY( !(p1 > p2) ); + VERIFY( p1 <= p2 ); + VERIFY( p1 >= p2 ); + p1.reset(new int(1)); + VERIFY( p1 <= p1 ); + VERIFY( p1 >= p1 ); + VERIFY( p1 > p2 ); + VERIFY( p2 < p1 ); + VERIFY( p2 <= p1 ); + VERIFY( p1 >= p2 ); + struct null_deleter { constexpr void operator()(const void*) const { } }; + std::unique_ptr p3(p1.get()); + VERIFY( p3 <= p3 ); + VERIFY( p3 >= p3 ); + VERIFY( p1 <= p3 ); + VERIFY( p3 > p2 ); + VERIFY( p3 >= p2 ); + VERIFY( p2 < p3 ); + VERIFY( p2 <= p3 ); + + return true; +} +static_assert( test_rel() ); + +constexpr bool +test_3way() +{ + std::unique_ptr p1, p2; + VERIFY( (p1 <=> p1) == 0 ); + VERIFY( (p1 <=> p2) == 0 ); + p1.reset(new int(1)); + VERIFY( (p1 <=> p1) == 0 ); + VERIFY( (p1 <=> p2) > 0 ); + VERIFY( (p2 <=> p1) < 0 ); + struct null_deleter { constexpr void operator()(const void*) const { } }; + std::unique_ptr p3(p1.get()); + VERIFY( (p3 <=> p3) == 0 ); + VERIFY( (p1 <=> p3) == 0 ); + VERIFY( (p3 <=> p2) > 0 ); + VERIFY( (p2 <=> p3) < 0 ); + + return true; +} +static_assert( test_3way() ); diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc new file mode 100644 index 00000000000..243d80aaba5 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/constexpr_c++20.cc @@ -0,0 +1,85 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } + +#include + +#ifndef __cpp_lib_constexpr_memory +# error "Feature test macro for constexpr unique_ptr is missing in " +#elif __cpp_lib_constexpr_memory < 202202L +# error "Feature test macro for constexpr unique_ptr has wrong value in " +#endif + +#include + +constexpr bool +test_default() +{ + std::unique_ptr p; + std::unique_ptr np(nullptr); + VERIFY( p == np ); + + std::unique_ptr a; + std::unique_ptr na(nullptr); + VERIFY( a == na ); + + return true; +} +static_assert( test_default() ); + +constexpr bool +test_ptr() +{ + std::unique_ptr p(new int(2)); + VERIFY( *p == 2 ); + std::unique_ptr a(new int[]{0, 1, 2}); + VERIFY( a[2] == 2 ); + + return true; +} +static_assert( test_ptr() ); + +constexpr bool +test_del() +{ + const std::default_delete pd; + std::unique_ptr p1(new int(1), pd); + VERIFY( *p1 == 1 ); + std::unique_ptr p2(new int(2), std::default_delete{}); + VERIFY( *p2 == 2 ); + const std::default_delete ad; + std::unique_ptr a1(new int[]{3, 4}, ad); + VERIFY( a1[0] == 3 ); + std::unique_ptr a2(new int[]{5, 6}, std::default_delete{}); + VERIFY( a2[1] == 6 ); + + return true; +} +static_assert( test_del() ); + +constexpr bool +test_move() +{ + std::unique_ptr p1(new int(2)); + std::unique_ptr p2 = std::move(p1); + VERIFY( *p2 == 2 ); + std::unique_ptr a1(new int[]{0, 1, 2}); + std::unique_ptr a2 = std::move(a1); + VERIFY( a2[2] == 2 ); + + return true; +} +static_assert( test_move() ); + +constexpr bool +test_convert() +{ + std::unique_ptr p1(new int(2)); + std::unique_ptr p2 = std::move(p1); + VERIFY( *p2 == 2 ); + std::unique_ptr a1(new int[]{0, 1, 2}); + std::unique_ptr a2 = std::move(a1); + VERIFY( a2[2] == 2 ); + + return true; +} +static_assert( test_convert() ); diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/creation/constexpr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/creation/constexpr.cc new file mode 100644 index 00000000000..90d11198578 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/creation/constexpr.cc @@ -0,0 +1,34 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } + +#include +#include + +constexpr bool +test_creation_single() +{ + std::unique_ptr p = std::make_unique(1); + VERIFY( *p == 1 ); + p = std::make_unique_for_overwrite(); + *p = 2; + VERIFY( *p == 2 ); + + return true; +} +static_assert( test_creation_single() ); + +constexpr bool +test_creation_array() +{ + std::unique_ptr a = std::make_unique(2); + VERIFY( a[0] == 0 ); + VERIFY( a[1] == 0 ); + a = std::make_unique_for_overwrite(2); + a[0] = 1; + a[1] = 2; + VERIFY( a[0] == 1 ); + VERIFY( a[1] == 2 ); + + return true; +} +static_assert( test_creation_array() ); diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/constexpr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/constexpr.cc new file mode 100644 index 00000000000..81908fdc081 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/constexpr.cc @@ -0,0 +1,68 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } + +#include +#include + +constexpr bool +test_release() +{ + std::unique_ptr p1; + int* r = p1.release(); + VERIFY( !r ); + VERIFY( !p1 ); + + std::unique_ptr p2(new int(2)); + r = p2.release(); + VERIFY( r ); + VERIFY( !p2 ); + delete r; + + std::unique_ptr a1; + r = a1.release(); + VERIFY( !r ); + VERIFY( !a1 ); + + std::unique_ptr a2(new int[2]{}); + r = a2.release(); + VERIFY( r ); + VERIFY( !a2 ); + delete[] r; + + return true; +} +static_assert( test_release() ); + +constexpr bool +test_reset() +{ + std::unique_ptr p1; + p1.reset(); + VERIFY( !p1 ); + p1.reset(nullptr); + VERIFY( !p1 ); + p1.reset(new int(2)); + VERIFY( *p1 == 2 ); + p1.reset(new int(3)); + VERIFY( *p1 == 3 ); + p1.reset(nullptr); + VERIFY( !p1 ); + + std::unique_ptr a1; + a1.reset(); + VERIFY( !a1 ); + a1.reset(nullptr); + VERIFY( !a1 ); + a1.reset(new int[]{2,3}); + VERIFY( a1[0] == 2 ); + a1.reset(new int[]{4,5,6}); + VERIFY( a1[1] == 5 ); + a1.reset(nullptr); + VERIFY( !a1 ); + + std::unique_ptr a2; + a2.reset(new int[2]{}); + + return true; +} +static_assert( test_reset() ); diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc new file mode 100644 index 00000000000..91a0165d212 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/specialized_algorithms/constexpr.cc @@ -0,0 +1,46 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } + +#include +#include + +constexpr bool +test_swap_single() +{ + std::unique_ptr p1; + swap(p1, p1); + VERIFY( !p1 ); + std::unique_ptr p2; + swap(p1, p2); + VERIFY( !p1 && !p2 ); + std::unique_ptr p3(new int(3)); + swap(p3, p3); + VERIFY( *p3 == 3 ); + swap(p1, p3); + VERIFY( *p1 == 3 ); + std::unique_ptr p4(new int(4)); + swap(p4, p1); + VERIFY( *p4 == 3 ); + VERIFY( *p1 == 4 ); + + return true; +} +static_assert( test_swap_single() ); + +constexpr bool +test_swap_array() +{ + std::unique_ptr a1; + std::unique_ptr a2; + swap(a1, a2); + VERIFY( !a1 && !a2 ); + std::unique_ptr a3(new int[]{3}); + swap(a1, a3); + VERIFY( a1[0] == 3 ); + std::unique_ptr a4(new int[]{4, 5}); + swap(a1, a4); + VERIFY( a1[1] == 5 ); + + return true; +} +static_assert( test_swap_array() ); -- 2.34.1