diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -336,7 +336,7 @@ ------------------------------------------------- ----------------- ``__cpp_lib_optional`` ``202110L`` ------------------------------------------------- ----------------- - ``__cpp_lib_out_ptr`` *unimplemented* + ``__cpp_lib_out_ptr`` ``202106L`` ------------------------------------------------- ----------------- ``__cpp_lib_ranges_as_rvalue`` ``202207L`` ------------------------------------------------- ----------------- diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -192,7 +192,7 @@ "`3515 `__","§[stacktrace.basic.nonmem]: ``operator<<`` should be less templatized", "November 2022","","","" "`3545 `__","``std::pointer_traits`` should be SFINAE-friendly", "November 2022","","","" "`3569 `__","``join_view`` fails to support ranges of ranges with non-default_initializable iterators", "November 2022","","","|ranges|" -"`3594 `__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","","","" +"`3594 `__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","|Complete|","17.0","" "`3597 `__","Unsigned integer types don't model advanceable", "November 2022","","","|ranges|" "`3600 `__","Making ``istream_iterator`` copy constructor trivial is an ABI break", "November 2022","","","" "`3629 `__","``make_error_code`` and ``make_error_condition`` are customization points","November 2022","|Complete|","16.0","" @@ -282,7 +282,7 @@ "`3645 `__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","February 2023","|Complete|","14.0","" "`3655 `__","The ``INVOKE`` operation and union types","February 2023","","","" "`3723 `__","``priority_queue::push_range`` needs to ``append_range``","February 2023","","","|ranges|" -"`3734 `__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","","","" +"`3734 `__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","|Complete|","17.0","" "`3772 `__","``repeat_view``'s ``piecewise`` constructor is missing Postconditions","February 2023","","","|ranges|" "`3786 `__","Flat maps' deduction guide needs to default ``Allocator`` to be useful","February 2023","","","" "`3803 `__","``flat_foo`` constructors taking ``KeyContainer`` lack ``KeyCompare`` parameter","February 2023","","","" diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -13,7 +13,7 @@ "","","","","","","" "`P0401R6 `__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0" "`P0448R4 `__","LWG","A strstream replacement using span as buffer","June 2021","","" -"`P1132R8 `__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","","" +"`P1132R8 `__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","|Complete|","17.0" "`P1328R1 `__","LWG","Making std::type_info::operator== constexpr","June 2021","|Complete|","17.0" "`P1425R4 `__","LWG","Iterators pair constructors for stack and queue","June 2021","|Complete|","14.0","|ranges|" "`P1518R2 `__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -476,6 +476,8 @@ __memory/concepts.h __memory/construct_at.h __memory/destruct_n.h + __memory/inout_ptr.h + __memory/out_ptr.h __memory/pointer_traits.h __memory/ranges_construct_at.h __memory/ranges_uninitialized_algorithms.h diff --git a/libcxx/include/__memory/inout_ptr.h b/libcxx/include/__memory/inout_ptr.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__memory/inout_ptr.h @@ -0,0 +1,97 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___INOUT_PTR_H +#define _LIBCPP___INOUT_PTR_H + +#include <__config> +#include <__memory/addressof.h> +#include <__memory/pointer_traits.h> +#include <__memory/shared_ptr.h> +#include <__memory/unique_ptr.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_specialization.h> +#include <__type_traits/is_void.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +class _LIBCPP_TEMPLATE_VIS inout_ptr_t { + static_assert(!__is_specialization_v<_Smart, shared_ptr>, "std::shared_ptr<> is not supported"); + +public: + _LIBCPP_HIDE_FROM_ABI explicit inout_ptr_t(_Smart& __s, _Args... __args) + : s{__s}, a{std::forward<_Args>(__args)...}, p{[&__s] { + if constexpr (requires { __s.get(); }) { + return __s.get(); + } else { + return __s; + } + }()} { + if constexpr (requires { __s.release(); }) { + __s.release(); + } else { + __s = _Smart(); + } + } + + _LIBCPP_HIDE_FROM_ABI inout_ptr_t(const inout_ptr_t&) = delete; + + _LIBCPP_HIDE_FROM_ABI ~inout_ptr_t() { + if (!p) { + return; + } + + using _SP = __pointer_of_or_t<_Smart, _Pointer>; + if constexpr (is_pointer_v<_Smart>) { + apply([&](auto&&... args) { s = _Smart{static_cast<_SP>(p), std::forward<_Args>(args)...}; }, std::move(a)); + } else if constexpr (__resettable_pointer<_Smart, _Pointer, _Args...>) { + apply([&](auto&&... args) { s.reset(static_cast<_SP>(p), std::forward<_Args>(args)...); }, std::move(a)); + } else if constexpr (is_constructible_v<_Smart, _SP, _Args...>) { + apply([&](auto&&... args) { s = _Smart{static_cast<_SP>(p), std::forward<_Args>(args)...}; }, std::move(a)); + } + } + + _LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return addressof(const_cast<_Pointer&>(p)); } + + _LIBCPP_HIDE_FROM_ABI operator void**() const noexcept + requires(!is_same_v<_Pointer, void*>) + { + static_assert(is_pointer_v<_Pointer>); + + return reinterpret_cast(static_cast<_Pointer*>(*this)); + } + +private: + _Smart& s; + tuple<_Args...> a; + _Pointer p; +}; + +template +_LIBCPP_HIDE_FROM_ABI auto inout_ptr(_Smart& s, _Args&&... __args) { + if constexpr (!is_void_v<_Pointer>) { + return std::inout_ptr_t<_Smart, _Pointer, _Args&&...>{s, std::forward<_Args>(__args)...}; + } else { + return std::inout_ptr_t<_Smart, std::__pointer_of_t<_Smart>, _Args&&...>{s, std::forward<_Args>(__args)...}; + } +} + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___INOUT_PTR_H diff --git a/libcxx/include/__memory/out_ptr.h b/libcxx/include/__memory/out_ptr.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__memory/out_ptr.h @@ -0,0 +1,90 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___OUT_PTR_H +#define _LIBCPP___OUT_PTR_H + +#include <__config> +#include <__memory/addressof.h> +#include <__memory/pointer_traits.h> +#include <__memory/shared_ptr.h> +#include <__memory/unique_ptr.h> +#include <__type_traits/is_specialization.h> +#include <__type_traits/is_void.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +class _LIBCPP_TEMPLATE_VIS out_ptr_t { + static_assert(!__is_specialization_v<_Smart, shared_ptr> || + (__is_specialization_v<_Smart, shared_ptr> && sizeof...(_Args) > 0), + "Specialization of std::shared_ptr<> requires a deleter."); + +public: + _LIBCPP_HIDE_FROM_ABI explicit out_ptr_t(_Smart& __s, _Args... __args) : s{__s}, a{std::forward<_Args>(__args)...} { + if constexpr (requires { __s.reset(); }) { + s.reset(); + } else { + static_assert(is_constructible_v<_Smart>); + s = _Smart{}; + } + } + + _LIBCPP_HIDE_FROM_ABI out_ptr_t(const out_ptr_t&) = delete; + + _LIBCPP_HIDE_FROM_ABI ~out_ptr_t() { + if (!p) { + return; + } + + using _SP = __pointer_of_or_t<_Smart, _Pointer>; + if constexpr (__resettable_pointer<_Smart, _Pointer, _Args...>) { + apply([&](auto&&... args) { s.reset(static_cast<_SP>(p), std::forward<_Args>(args)...); }, std::move(a)); + } else if constexpr (is_constructible_v<_Smart, _SP, _Args...>) { + apply([&](auto&&... args) { s = _Smart{static_cast<_SP>(p), std::forward<_Args>(args)...}; }, std::move(a)); + }; + } + + _LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(p)); } + + _LIBCPP_HIDE_FROM_ABI operator void**() const noexcept + requires(!is_same_v<_Pointer, void*>) + { + static_assert(is_pointer_v<_Pointer>); + + return reinterpret_cast(static_cast<_Pointer*>(*this)); + } + +private: + _Smart& s; + tuple<_Args...> a; + _Pointer p; +}; + +template +_LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) { + if constexpr (!is_void_v<_Pointer>) { + return std::out_ptr_t<_Smart, _Pointer, _Args&&...>(__s, std::forward<_Args>(__args)...); + } else { + return std::out_ptr_t<_Smart, std::__pointer_of_t<_Smart>, _Args&&...>(__s, std::forward<_Args>(__args)...); + } +} + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___OUT_PTR_H diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h --- a/libcxx/include/__memory/pointer_traits.h +++ b/libcxx/include/__memory/pointer_traits.h @@ -20,6 +20,7 @@ #include <__type_traits/is_void.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> +#include <__utility/forward.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -237,6 +238,39 @@ } #endif +#if _LIBCPP_STD_VER >= 23 + +template +struct __pointer_of_or {}; + +template + requires requires { typename __pointer_traits_element_type<_Tp>::element_type; } +struct __pointer_of_or<_Tp, _Up> { + using type _LIBCPP_NODEBUG = _Tp; +}; + +template + requires(!requires { typename __pointer_traits_element_type<_Tp>::element_type; }) +struct __pointer_of_or<_Tp, _Up> { + using type _LIBCPP_NODEBUG = _Up; +}; + +template +using __pointer_of_or_t = typename __pointer_of_or<_Tp, _Up>::type; + +template +using __pointer_of = __pointer_of_or<_Tp, typename std::pointer_traits<_Tp>::element_type*>; + +template +using __pointer_of_t = typename __pointer_of<_Tp>::type; + +template +concept __resettable_pointer = requires(_Smart __s, _Pointer __p, _Args... __args) { + __s.reset(static_cast<__pointer_of_or_t<_Smart, _Pointer>>(__p), std::forward<_Args>(__args)...); +}; + +#endif + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___MEMORY_POINTER_TRAITS_H diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -873,6 +873,22 @@ template [[nodiscard]] constexpr T* assume_aligned(T* ptr); // since C++20 +// [out.ptr.t], class template out_ptr_t +template + class out_ptr_t; // since c++23 + +// [out.ptr], function template out_ptr +template + auto out_ptr(Smart& s, Args&&... args); // since c++23 + +// [inout.ptr.t], class template inout_ptr_t +template + class inout_ptr_t; // since c++23 + +// [inout.ptr], function template inout_ptr +template + auto inout_ptr(Smart& s, Args&&... args); // since c++23 + } // std */ @@ -891,6 +907,8 @@ #include <__memory/compressed_pair.h> #include <__memory/concepts.h> #include <__memory/construct_at.h> +#include <__memory/inout_ptr.h> +#include <__memory/out_ptr.h> #include <__memory/pointer_traits.h> #include <__memory/ranges_construct_at.h> #include <__memory/ranges_uninitialized_algorithms.h> diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1181,6 +1181,8 @@ } module construct_at { private header "__memory/construct_at.h" } module destruct_n { private header "__memory/destruct_n.h" } + module inout_ptr { private header "__memory/inout_ptr.h" } + module out_ptr { private header "__memory/out_ptr.h" } module pointer_traits { private header "__memory/pointer_traits.h" } module ranges_construct_at { private header "__memory/ranges_construct_at.h" } module ranges_uninitialized_algorithms { diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -411,7 +411,7 @@ // # define __cpp_lib_move_only_function 202110L # undef __cpp_lib_optional # define __cpp_lib_optional 202110L -// # define __cpp_lib_out_ptr 202106L +# define __cpp_lib_out_ptr 202106L # define __cpp_lib_ranges_as_rvalue 202207L // # define __cpp_lib_ranges_chunk 202202L // # define __cpp_lib_ranges_chunk_by 202202L diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -508,6 +508,8 @@ #include <__memory/concepts.h> // expected-error@*:* {{use of private header from outside its module: '__memory/concepts.h'}} #include <__memory/construct_at.h> // expected-error@*:* {{use of private header from outside its module: '__memory/construct_at.h'}} #include <__memory/destruct_n.h> // expected-error@*:* {{use of private header from outside its module: '__memory/destruct_n.h'}} +#include <__memory/inout_ptr.h> // expected-error@*:* {{use of private header from outside its module: '__memory/inout_ptr.h'}} +#include <__memory/out_ptr.h> // expected-error@*:* {{use of private header from outside its module: '__memory/out_ptr.h'}} #include <__memory/pointer_traits.h> // expected-error@*:* {{use of private header from outside its module: '__memory/pointer_traits.h'}} #include <__memory/ranges_construct_at.h> // expected-error@*:* {{use of private header from outside its module: '__memory/ranges_construct_at.h'}} #include <__memory/ranges_uninitialized_algorithms.h> // expected-error@*:* {{use of private header from outside its module: '__memory/ranges_uninitialized_algorithms.h'}} diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp @@ -467,17 +467,11 @@ # error "__cpp_lib_make_unique should have the value 201304L in c++2b" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should be defined in c++2b" -# endif -# if __cpp_lib_out_ptr != 202106L -# error "__cpp_lib_out_ptr should have the value 202106L in c++2b" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_out_ptr +# error "__cpp_lib_out_ptr should be defined in c++2b" +# endif +# if __cpp_lib_out_ptr != 202106L +# error "__cpp_lib_out_ptr should have the value 202106L in c++2b" # endif # ifndef __cpp_lib_ranges 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 --- 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 @@ -4550,17 +4550,11 @@ # error "__cpp_lib_optional should have the value 202110L in c++2b" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should be defined in c++2b" -# endif -# if __cpp_lib_out_ptr != 202106L -# error "__cpp_lib_out_ptr should have the value 202106L in c++2b" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_out_ptr +# error "__cpp_lib_out_ptr should be defined in c++2b" +# endif +# if __cpp_lib_out_ptr != 202106L +# error "__cpp_lib_out_ptr should have the value 202106L in c++2b" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.fail.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.fail.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [inout.ptr], function template inout_ptr +// template +// auto inout_ptr(Smart& s, Args&&... args); // since c++23 + +#include + +int main(int, char**) { + // `std::inout_ptr<>` does not support `std::shared_ptr<>`. + { + std::shared_ptr sPtr; + + auto inoutUPtr1 = std::inout_ptr(sPtr); + auto inoutUPtr2 = std::inout_ptr(sPtr); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [inout.ptr], function template inout_ptr +// template +// auto inout_ptr(Smart& s, Args&&... args); // since c++23 + +#include + +int main(int, char**) { + { + std::unique_ptr uPtr; + + auto inoutUPtr1 = std::inout_ptr(uPtr); + auto inoutUPtr2 = std::inout_ptr(uPtr); + } + { + std::unique_ptr uPtr; + + auto inoutUPtr1 = std::inout_ptr(uPtr, [](auto* p) { delete p; }); + auto inoutUPtr2 = std::inout_ptr(uPtr, [](auto* p) { delete p; }); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp @@ -0,0 +1,145 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [inout.ptr.t], class template inout_ptr_t +// template +// class inout_ptr_t; // since c++23 + +// [inout.ptr], function template inout_ptr +// template +// auto inout_ptr(Smart& s, Args&&... args); // since c++23 + +#include +#include + +#include "../types.h" + +// Test helpers. + +void replace_int_p(int** pp) { + assert(**pp == 5); + *pp = new int{10}; +} + +void replace_int_p_nullptr(int** pp) { + assert(**pp == 5); + *pp = nullptr; +} + +void replace_int_void_p(void** pp) { + assert(*(static_cast(*pp)) == 5); + *pp = new int{20}; +} + +void replace_int_void_p_nullptr(void** pp) { + assert(*(static_cast(*pp)) == 5); + *pp = nullptr; +} + +void replace_SomeInt_p(SomeInt** pp) { + auto si = **pp; + *pp = new SomeInt{si.value * 2}; +} + +void replace_SomeInt_void_p(void** pp) { + auto si = *reinterpret_cast(*pp); + *pp = reinterpret_cast(new SomeInt{si.value * 2}); +} + +// Test `std::inout_ptr()` function. + +bool test_raw_ptr() { + { + auto n{5}; + auto rPtr = &n; + + replace_int_p(std::inout_ptr(rPtr)); + assert(*rPtr == 10); + delete rPtr; + } + { + auto n{5}; + auto rPtr = &n; + + replace_int_p_nullptr(std::inout_ptr(rPtr)); + assert(rPtr == nullptr); + } + { + auto n{5}; + auto rPtr = &n; + + replace_int_void_p(std::inout_ptr(rPtr)); + assert(*rPtr == 20); + delete rPtr; + } + { + auto n{5}; + auto rPtr = &n; + + replace_int_void_p_nullptr(std::inout_ptr(rPtr)); + assert(rPtr == nullptr); + } + { + SomeInt si{5}; + auto* rPtr = &si; + + replace_SomeInt_p(std::inout_ptr(rPtr)); + assert(rPtr->value == 10); + delete rPtr; + } + { + SomeInt si{5}; + auto* rPtr = &si; + + replace_SomeInt_void_p(std::inout_ptr(rPtr)); + assert(rPtr->value == 10); + delete rPtr; + } + + return true; +} + +bool test_unique_ptr() { + { + auto uPtr = std::make_unique(5); + + replace_int_p(std::inout_ptr(uPtr)); + assert(*uPtr == 10); + } + { + auto uPtr = std::make_unique(5); + + replace_int_void_p(std::inout_ptr(uPtr)); + assert(*uPtr == 20); + } + { + auto uPtr = std::make_unique(5); + + replace_SomeInt_p(std::inout_ptr(uPtr)); + assert(uPtr->value == 10); + } + { + auto uPtr = std::make_unique(5); + + replace_SomeInt_void_p(std::inout_ptr(uPtr)); + assert(uPtr->value == 10); + } + + return true; +} + +int main(int, char**) { + assert(test_raw_ptr()); + assert(test_unique_ptr()); + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.fail.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.fail.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [inout.ptr.t], class template inout_ptr_t +// template +// class inout_ptr_t; // since c++23 + +#include + +int main(int, char**) { + // `std::inout_ptr<>` does not support `std::shared_ptr<>`. + { + std::shared_ptr sPtr; + + std::inout_ptr_t, int*>{sPtr}; + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [inout.ptr.t], class template inout_ptr_t +// template +// class inout_ptr_t; // since c++23 + +#include + +int main(int, char**) { + { + std::unique_ptr uPtr; + + std::inout_ptr_t, int*>{uPtr}; + } + { + std::unique_ptr uPtr; + + std::inout_ptr_t, int*>{uPtr}; + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.fail.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.fail.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [out.ptr], function template out_ptr +// template +// auto out_ptr(Smart& s, Args&&... args); // since c++23 + +#include + +int main(int, char**) { + // `std::out_ptr<>` requires `std::shared_ptr<>` with a deleter. + { + std::shared_ptr sPtr; + + auto outSPtr1 = std::out_ptr(sPtr); + auto outSPtr2 = std::out_ptr(sPtr); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [out.ptr], function template out_ptr +// template +// auto out_ptr(Smart& s, Args&&... args); // since c++23 + +#include + +int main(int, char**) { + { + std::unique_ptr uPtr; + + auto outUPtr1 = std::out_ptr(uPtr); + auto outUPtr2 = std::out_ptr(uPtr); + } + { + std::shared_ptr sPtr; + + auto outSPtr1 = std::out_ptr(sPtr, [](auto* p) { delete p; }); + auto outSPtr2 = std::out_ptr(sPtr, [](auto* p) { delete p; }); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp @@ -0,0 +1,139 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [out.ptr.t], class template out_ptr_t +// template +// class out_ptr_t; // since c++23 + +// [out.ptr], function template out_ptr +// template +// auto out_ptr(Smart& s, Args&&... args); // since c++23 + +#include +#include + +#include "../types.h" + +// Test helpers. + +void get_int_p(int** pp) { *pp = new int{10}; } + +void get_int_p_nullptr(int** pp) { *pp = nullptr; } + +void get_int_void_p(void** pp) { *(reinterpret_cast(pp)) = new int{20}; } + +void get_int_void_p_nullptr(void** pp) { *pp = nullptr; } + +void get_SomeInt_p(SomeInt** pp) { *pp = new SomeInt{10}; } + +void get_SomeInt_void_p(void** pp) { *pp = reinterpret_cast(new SomeInt{10}); } + +// Test `std::out_ptr()` function. + +bool test_raw_ptr() { + { + auto n{5}; + auto rPtr = &n; + + get_int_p(std::inout_ptr(rPtr)); + assert(*rPtr == 10); + delete rPtr; + + get_int_p_nullptr(std::out_ptr(rPtr)); + assert(rPtr == nullptr); + + get_int_void_p(std::inout_ptr(rPtr)); + assert(*rPtr == 20); + delete rPtr; + + get_int_void_p_nullptr(std::out_ptr(rPtr)); + assert(rPtr == nullptr); + } + { + SomeInt si{5}; + auto* rPtr = &si; + + get_SomeInt_p(std::out_ptr(rPtr)); + assert(rPtr->value == 10); + delete rPtr; + } + { + SomeInt si{5}; + auto* rPtr = &si; + + get_SomeInt_void_p(std::out_ptr(rPtr)); + assert(rPtr->value == 10); + delete rPtr; + } + + return true; +} + +bool test_shared_ptr() { + { + auto sPtr = std::make_shared(5); + + get_int_p(std::out_ptr(sPtr, [](auto* p) { delete p; })); + assert(*sPtr == 10); + + get_int_void_p(std::out_ptr(sPtr, [](auto* p) { delete p; })); + assert(*sPtr == 20); + } + { + auto sPtr = std::make_shared(5); + + get_SomeInt_p(std::out_ptr(sPtr, [](auto* p) { delete p; })); + assert(sPtr->value == 10); + } + { + auto sPtr = std::make_shared(5); + + get_SomeInt_void_p(std::out_ptr(sPtr, [](auto* p) { delete p; })); + assert(sPtr->value == 10); + } + + return true; +} + +bool test_unique_ptr() { + { + auto uPtr = std::make_unique(5); + + get_int_p(std::out_ptr(uPtr)); + assert(*uPtr == 10); + + get_int_void_p(std::out_ptr(uPtr)); + assert(*uPtr == 20); + } + { + auto uPtr = std::make_unique(5); + + get_SomeInt_p(std::out_ptr(uPtr)); + assert(uPtr->value == 10); + } + { + auto uPtr = std::make_unique(5); + + get_SomeInt_void_p(std::out_ptr(uPtr)); + assert(uPtr->value == 10); + } + + return true; +} + +int main(int, char**) { + assert(test_raw_ptr()); + assert(test_shared_ptr()); + assert(test_unique_ptr()); + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.fail.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.fail.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [out.ptr.t], class template out_ptr_t +// template +// class out_ptr_t; // since c++23 + +#include + +int main(int, char**) { + // `std::out_ptr_t<>` requires `std::shared_ptr<>` with a deleter. + { + std::shared_ptr sPtr; + std::out_ptr_t, int*>{sPtr}; + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// [out.ptr.t], class template out_ptr_t +// template +// class out_ptr_t; // since c++23 + +#include + +int main(int, char**) { + { + std::unique_ptr uPtr; + + std::out_ptr_t, int*>{uPtr}; + } + { + std::unique_ptr> uPtr; + + std::out_ptr_t>{uPtr, std::default_delete{}}; + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/types.h b/libcxx/test/std/utilities/smartptr/adapt/types.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/types.h @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H +#define TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H + +// Custom pointer types. + +class ConstructablePtr {}; + +class ResettablePtr {}; + +// Custom types. + +struct SomeInt { + int value; + + explicit SomeInt(int value) : value{value} {} +}; + +#endif // TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -531,7 +531,6 @@ "name": "__cpp_lib_out_ptr", "values": { "c++2b": 202106 }, "headers": ["memory"], - "unimplemented": True, }, { "name": "__cpp_lib_parallel_algorithm", "values": { "c++17": 201603 }, diff --git a/llvm/utils/gn/secondary/libcxx/include/BUILD.gn b/llvm/utils/gn/secondary/libcxx/include/BUILD.gn --- a/llvm/utils/gn/secondary/libcxx/include/BUILD.gn +++ b/llvm/utils/gn/secondary/libcxx/include/BUILD.gn @@ -550,6 +550,8 @@ "__memory/concepts.h", "__memory/construct_at.h", "__memory/destruct_n.h", + "__memory/inout_ptr.h", + "__memory/out_ptr.h", "__memory/pointer_traits.h", "__memory/ranges_construct_at.h", "__memory/ranges_uninitialized_algorithms.h",