diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -338,7 +338,7 @@ --------------------------------------------------- ----------------- ``__cpp_lib_optional`` ``202110L`` --------------------------------------------------- ----------------- - ``__cpp_lib_out_ptr`` *unimplemented* + ``__cpp_lib_out_ptr`` ``202106L`` --------------------------------------------------- ----------------- ``__cpp_lib_print`` *unimplemented* --------------------------------------------------- ----------------- diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv --- a/libcxx/docs/Status/Cxx23Issues.csv +++ b/libcxx/docs/Status/Cxx23Issues.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","|Complete|","18.0","" "`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","|Complete|","18.0","" "`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/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.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 @@ -525,6 +525,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/allocator_traits.h b/libcxx/include/__memory/allocator_traits.h --- a/libcxx/include/__memory/allocator_traits.h +++ b/libcxx/include/__memory/allocator_traits.h @@ -38,7 +38,6 @@ template struct NAME<_Tp, __void_t > : true_type { } // __pointer -_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_pointer, pointer); template , bool = __has_pointer<_RawAlloc>::value> 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,100 @@ +// -*- 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 (is_pointer_v<_Smart>) { + return __s; + } else { + return __s.get(); + } + }()) { + 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>) { + std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::move(__a_)); + } else if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) { + std::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...>) { + std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::move(__a_)); + } else { + static_assert(is_pointer_v<_Smart> || __resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...> || + is_constructible_v<_Smart, _SP, _Args...>); + } + } + + _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 inout_ptr(_Smart& __s, _Args&&... __args) { + using _Ptr = conditional_t, __pointer_of_t<_Smart>, _Pointer>; + return std::inout_ptr_t<_Smart, _Ptr, _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,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___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 +concept __resettable_adapted_ptr = requires(_Tp __ptr) { __ptr().reset(); }; + +template +class _LIBCPP_TEMPLATE_VIS out_ptr_t { + static_assert(!__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)...), __p_() { + using _Ptr = decltype(__s); + if constexpr (__resettable_smart_pointer<_Ptr>) { + __s_.reset(); + } else if constexpr (is_constructible_v<_Smart>) { + __s_ = _Smart(); + } else { + static_assert(__resettable_smart_pointer<_Ptr> || is_constructible_v<_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_smart_pointer_with_args<_Smart, _Pointer, _Args...>) { + std::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...>) { + std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::move(__a_)); + } else { + static_assert(__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...> || + is_constructible_v<_Smart, _SP, _Args...>); + } + } + + _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_ = _Pointer(); +}; + +template +_LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) { + using _Ptr = conditional_t, __pointer_of_t<_Smart>, _Pointer>; + return std::out_ptr_t<_Smart, _Ptr, _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 @@ -15,11 +15,14 @@ #include <__type_traits/conditional.h> #include <__type_traits/conjunction.h> #include <__type_traits/decay.h> +#include <__type_traits/enable_if.h> #include <__type_traits/is_class.h> #include <__type_traits/is_function.h> #include <__type_traits/is_void.h> +#include <__type_traits/negation.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> +#include <__utility/forward.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -28,11 +31,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template -struct __has_element_type : false_type {}; +// clang-format off +#define _LIBCPP_CLASS_TRAITS_HAS_XXX(NAME, PROPERTY) \ + template \ + struct NAME : false_type {}; \ + template \ + struct NAME<_Tp, __void_t > : true_type {} +// clang-format on -template -struct __has_element_type<_Tp, __void_t > : true_type {}; +_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer, pointer); +_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type, element_type); template ::value> struct __pointer_traits_element_type {}; @@ -242,6 +250,57 @@ } #endif +#if _LIBCPP_STD_VER >= 23 + +template +struct __pointer_of {}; + +template + requires(__has_pointer<_Tp>::value) +struct __pointer_of<_Tp> { + using type = typename _Tp::pointer; +}; + +template + requires(!__has_pointer<_Tp>::value && __has_element_type<_Tp>::value) +struct __pointer_of<_Tp> { + using type = typename _Tp::element_type*; +}; + +template + requires(!__has_pointer<_Tp>::value && !__has_element_type<_Tp>::value && + __has_element_type>::value) +struct __pointer_of<_Tp> { + using type = typename pointer_traits<_Tp>::element_type*; +}; + +template +using __pointer_of_t = typename __pointer_of<_Tp>::type; + +template +struct __pointer_of_or { + using type _LIBCPP_NODEBUG = _Up; +}; + +template + requires requires { typename __pointer_of_t<_Tp>; } +struct __pointer_of_or<_Tp, _Up> { + using type _LIBCPP_NODEBUG = __pointer_of_t<_Tp>; +}; + +template +using __pointer_of_or_t = typename __pointer_of_or<_Tp, _Up>::type; + +template +concept __resettable_smart_pointer = requires(_Smart __s) { __s.reset(); }; + +template +concept __resettable_smart_pointer_with_args = 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 @@ -910,6 +910,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 */ @@ -928,6 +944,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 @@ -1535,6 +1535,8 @@ } module std_private_memory_construct_at [system] { header "__memory/construct_at.h" } module std_private_memory_destruct_n [system] { header "__memory/destruct_n.h" } +module std_private_memory_inout_ptr [system] { header "__memory/inout_ptr.h" } +module std_private_memory_out_ptr [system] { header "__memory/out_ptr.h" } module std_private_memory_pointer_traits [system] { header "__memory/pointer_traits.h" } module std_private_memory_ranges_construct_at [system] { header "__memory/ranges_construct_at.h" } module std_private_memory_ranges_uninitialized_algorithms [system] { diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -431,7 +431,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_print 202207L # define __cpp_lib_ranges_as_rvalue 202207L // # define __cpp_lib_ranges_chunk 202202L diff --git a/libcxx/modules/std/memory.inc b/libcxx/modules/std/memory.inc --- a/libcxx/modules/std/memory.inc +++ b/libcxx/modules/std/memory.inc @@ -177,17 +177,19 @@ // [util.smartptr.atomic], atomic smart pointers // using std::atomic; +#if _LIBCPP_STD_VER >= 23 // [out.ptr.t], class template out_ptr_t - // using std::out_ptr_t; + using std::out_ptr_t; // [out.ptr], function template out_ptr - // using std::out_ptr; + using std::out_ptr; // [inout.ptr.t], class template inout_ptr_t - // using std::inout_ptr_t; + using std::inout_ptr_t; // [inout.ptr], function template inout_ptr - // using std::inout_ptr; + using std::inout_ptr; +#endif // _LIBCPP_STD_VER >= 23 #ifndef _LIBCPP_HAS_NO_THREADS // [depr.util.smartptr.shared.atomic] 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 @@ -484,17 +484,11 @@ # error "__cpp_lib_make_unique should have the value 201304L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should be defined in c++23" -# endif -# if __cpp_lib_out_ptr != 202106L -# error "__cpp_lib_out_ptr should have the value 202106L in c++23" -# 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++23" +# endif +# if __cpp_lib_out_ptr != 202106L +# error "__cpp_lib_out_ptr should have the value 202106L in c++23" # endif # ifndef __cpp_lib_ranges @@ -621,17 +615,11 @@ # error "__cpp_lib_make_unique should have the value 201304L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should be defined in c++26" -# endif -# if __cpp_lib_out_ptr != 202106L -# error "__cpp_lib_out_ptr should have the value 202106L in c++26" -# 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++26" +# endif +# if __cpp_lib_out_ptr != 202106L +# error "__cpp_lib_out_ptr should have the value 202106L in c++26" # 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 @@ -4885,17 +4885,11 @@ # error "__cpp_lib_optional should have the value 202110L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should be defined in c++23" -# endif -# if __cpp_lib_out_ptr != 202106L -# error "__cpp_lib_out_ptr should have the value 202106L in c++23" -# 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++23" +# endif +# if __cpp_lib_out_ptr != 202106L +# error "__cpp_lib_out_ptr should have the value 202106L in c++23" # endif # if !defined(_LIBCPP_VERSION) @@ -6426,17 +6420,11 @@ # error "__cpp_lib_optional should have the value 202110L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_out_ptr -# error "__cpp_lib_out_ptr should be defined in c++26" -# endif -# if __cpp_lib_out_ptr != 202106L -# error "__cpp_lib_out_ptr should have the value 202106L in c++26" -# 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++26" +# endif +# if __cpp_lib_out_ptr != 202106L +# error "__cpp_lib_out_ptr should have the value 202106L in c++26" # endif # if !defined(_LIBCPP_VERSION) 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,35 @@ +//===----------------------------------------------------------------------===// +// +// 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); + } + { + auto deleter = [](auto* p) { delete p; }; + std::unique_ptr uPtr; + + auto inoutUPtr1 = std::inout_ptr(uPtr, deleter); + auto inoutUPtr2 = std::inout_ptr(uPtr, deleter); + } + + 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,205 @@ +//===----------------------------------------------------------------------===// +// +// 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 == 90); + delete *pp; + *pp = new int{84}; +} + +void replace_int_p_with_nullptr(int** pp) { + assert(**pp == 90); + delete *pp; + *pp = nullptr; +} + +void replace_nullptr_with_int_p(int** pp) { + assert(*pp == nullptr); + *pp = new int{84}; +} + +void replace_int_void_p(void** pp) { + assert(*(static_cast(*pp)) == 90); + delete static_cast(*pp); + *pp = new int{84}; +} + +void replace_int_void_p_with_nullptr(void** pp) { + assert(*(static_cast(*pp)) == 90); + delete static_cast(*pp); + *pp = nullptr; +} + +void replace_nullptr_with_int_void_p(void** pp) { + assert(*pp == nullptr); + *pp = new int{84}; +} + +void replace_SomeInt_p(SomeInt** pp) { + auto si = **pp; + assert(si.value == 90); + delete static_cast(*pp); + *pp = new SomeInt{9084}; +} + +void replace_SomeInt_void_p(void** pp) { + assert(reinterpret_cast(*pp)->value == 90); + delete static_cast(*pp); + *pp = reinterpret_cast(new SomeInt{9084}); +} + +// Test `std::inout_ptr()` function. + +void test_raw_ptr() { + { + auto rPtr = new int{90}; + + replace_int_p(std::inout_ptr(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + { + auto rPtr = new int{90}; + + replace_int_p_with_nullptr(std::inout_ptr(rPtr)); + assert(rPtr == nullptr); + } + { + int* rPtr = nullptr; + + replace_nullptr_with_int_p(std::inout_ptr(rPtr)); + assert(*rPtr == 84); + delete rPtr; + } + { + auto rPtr = new int{90}; + + replace_int_void_p(std::inout_ptr(rPtr)); + assert(*rPtr == 84); + delete rPtr; + } + { + auto rPtr = new int{90}; + + replace_int_void_p_with_nullptr(std::inout_ptr(rPtr)); + assert(rPtr == nullptr); + } + { + int* rPtr = nullptr; + + replace_nullptr_with_int_void_p(std::inout_ptr(rPtr)); + assert(*rPtr == 84); + delete rPtr; + } + { + auto* rPtr = new SomeInt{90}; + + replace_SomeInt_p(std::inout_ptr(rPtr)); + assert(rPtr->value == 9084); + delete rPtr; + } + { + auto* rPtr = new SomeInt{90}; + + replace_SomeInt_void_p(std::inout_ptr(rPtr)); + assert(rPtr->value == 9084); + delete rPtr; + } +} + +void test_unique_ptr() { + { + auto uPtr = std::make_unique(90); + + replace_int_p(std::inout_ptr(uPtr)); + assert(*uPtr == 84); + } + { + std::unique_ptr uPtr; + + replace_nullptr_with_int_p(std::inout_ptr(uPtr)); + assert(*uPtr == 84); + } + { + auto uPtr = std::make_unique(90); + + replace_int_void_p(std::inout_ptr(uPtr)); + assert(*uPtr == 84); + } + { + std::unique_ptr uPtr; + + replace_nullptr_with_int_void_p(std::inout_ptr(uPtr)); + assert(*uPtr == 84); + } + { + auto uPtr = std::make_unique(90); + + replace_SomeInt_p(std::inout_ptr(uPtr)); + assert(uPtr->value == 9084); + } + { + auto uPtr = std::make_unique(90); + + replace_SomeInt_void_p(std::inout_ptr(uPtr)); + assert(uPtr->value == 9084); + } +} + +void test_custom_ptr() { + // ConstructiblePtr + { + ConstructiblePtr cPtr(new int{90}); + + replace_int_p(std::inout_ptr(cPtr)); + assert(cPtr == 84); + } + // ResettablePtr + { + ResettablePtr rPtr(new int{90}); + + replace_int_p(std::inout_ptr(rPtr)); + assert(rPtr == 84); + } + // NonConstructiblePtr + { + NonConstructiblePtr nPtr; + nPtr.reset(new int{90}); + + replace_int_p(std::inout_ptr(nPtr)); + assert(nPtr == 84); + } +} + +int main(int, char**) { + test_raw_ptr(); + test_unique_ptr(); + test_custom_ptr(); + + 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/inout.ptr/inout.ptr.t.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.verify.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.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; + + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement '!__is_specialization_v, std::shared_ptr>'{{.*}}std::shared_ptr<> is not supported}} + std::inout_ptr_t, int*>{sPtr}; + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// 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; + + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement '!__is_specialization_v, std::shared_ptr>'{{.*}}std::shared_ptr<> is not supported}} + auto inoutUPtr1 = std::inout_ptr(sPtr); + auto inoutUPtr2 = std::inout_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,163 @@ +//===----------------------------------------------------------------------===// +// +// 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{84}; } + +void get_int_p_nullptr(int** pp) { *pp = nullptr; } + +void get_int_void_p(void** pp) { *(reinterpret_cast(pp)) = new int{84}; } + +void get_int_void_p_nullptr(void** pp) { *pp = nullptr; } + +void get_SomeInt_p(SomeInt** pp) { *pp = new SomeInt{84}; } + +void get_SomeInt_void_p(void** pp) { *pp = reinterpret_cast(new int{84}); } + +// Test `std::out_ptr()` function. + +void test_raw_ptr() { + { + auto n{90}; + auto rPtr = &n; + + get_int_p(std::inout_ptr(rPtr)); + assert(*rPtr == 84); + delete rPtr; + + get_int_p_nullptr(std::out_ptr(rPtr)); + assert(rPtr == nullptr); + + get_int_void_p(std::inout_ptr(rPtr)); + assert(*rPtr == 84); + delete rPtr; + + get_int_void_p_nullptr(std::out_ptr(rPtr)); + assert(rPtr == nullptr); + } + { + SomeInt si{90}; + auto* rPtr = &si; + + get_SomeInt_p(std::out_ptr(rPtr)); + assert(rPtr->value == 84); + delete rPtr; + } + { + SomeInt si{90}; + auto* rPtr = &si; + + get_SomeInt_void_p(std::out_ptr(rPtr)); + assert(rPtr->value == 84); + delete rPtr; + } +} + +void test_shared_ptr() { + { + auto sPtr = std::make_shared(90); + + get_int_p(std::out_ptr(sPtr, [](auto* p) { delete p; })); + assert(*sPtr == 84); + + sPtr.reset(new int(90)); + + get_int_void_p(std::out_ptr(sPtr, [](auto* p) { delete p; })); + assert(*sPtr == 84); + } + { + auto sPtr = std::make_shared(90); + + get_SomeInt_p(std::out_ptr(sPtr, [](auto* p) { delete p; })); + assert(sPtr->value == 84); + } + { + auto sPtr = std::make_shared(90); + + get_SomeInt_void_p(std::out_ptr(sPtr, [](auto* p) { delete p; })); + assert(sPtr->value == 84); + } +} + +void test_unique_ptr() { + { + auto uPtr = std::make_unique(90); + + get_int_p(std::out_ptr(uPtr)); + assert(*uPtr == 84); + + uPtr.reset(new int{90}); + + get_int_void_p(std::out_ptr(uPtr)); + assert(*uPtr == 84); + } + { + auto uPtr = std::make_unique(90); + + get_SomeInt_p(std::out_ptr(uPtr)); + assert(uPtr->value == 84); + } + { + auto uPtr = std::make_unique(90); + + get_SomeInt_void_p(std::out_ptr(uPtr)); + assert(uPtr->value == 84); + } +} + +void test_custom_ptr() { + // ConstructiblePtr + { + ConstructiblePtr cPtr(new int{90}); + + get_int_p(std::out_ptr(cPtr)); + assert(cPtr == 84); + } + // ResettablePtr + { + ResettablePtr rPtr(new int{90}); + + get_int_p(std::out_ptr(rPtr)); + assert(rPtr == 84); + } + // NonConstructiblePtr + { + NonConstructiblePtr nPtr; + nPtr.reset(new int{90}); + + get_int_p(std::out_ptr(nPtr)); + assert(nPtr == 84); + } +} + +int main(int, char**) { + test_raw_ptr(); + test_shared_ptr(); + test_unique_ptr(); + test_custom_ptr(); + + 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/out.ptr/out.ptr.t.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.verify.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.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; + + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement '!__is_specialization_v, std::shared_ptr> || sizeof...(_Args) > 0'{{.*}}Specialization of std::shared_ptr<> requires a deleter.}} + std::out_ptr_t, int*>{sPtr}; + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// 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; + + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement '!__is_specialization_v, std::shared_ptr> || sizeof...(_Args) > 0'{{.*}}Specialization of std::shared_ptr<> requires a deleter.}} + auto outSPtr1 = std::out_ptr(sPtr); + auto outSPtr2 = std::out_ptr(sPtr); + } + + 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,77 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include +#include + +struct ResetArg {}; + +// Custom pointer types. + +template +struct ConstructiblePtr { + using pointer = _Tp*; + std::unique_ptr<_Tp> ptr; + + ConstructiblePtr() = default; + explicit ConstructiblePtr(_Tp* p) : ptr{p} {} + + auto operator==(_Tp val) { return *ptr == val; } + + auto* get() const { return ptr.get(); } + + void release() { ptr.release(); } +}; + +static_assert(std::is_same_v>, int* >); +static_assert(std::is_constructible_v< ConstructiblePtr, int* >); + +template +struct ResettablePtr { + using element_type = _Tp; + std::unique_ptr<_Tp> ptr; + + explicit ResettablePtr(_Tp* p) : ptr{p} {} + + auto operator*() const { return *ptr; } + + auto operator==(_Tp val) { return *ptr == val; } + + void reset() { ptr.reset(); } + void reset(_Tp* p, ResetArg) { ptr.reset(p); } + + auto* get() const { return ptr.get(); } + + void release() { ptr.release(); } +}; + +static_assert(std::is_same_v>, int* >); +static_assert(std::is_constructible_v< ResettablePtr, int* >); + +template +struct NonConstructiblePtr : public ResettablePtr<_Tp> { + NonConstructiblePtr() : NonConstructiblePtr::ResettablePtr(nullptr){}; + + void reset(_Tp* p) { ResettablePtr<_Tp>::ptr.reset(p); } +}; + +static_assert(std::is_same_v>, int* >); +static_assert(!std::is_constructible_v< NonConstructiblePtr, int* >); + +// Custom types. + +struct SomeInt { + int value; + + constexpr explicit SomeInt(int val = 0) : value{val} {} +}; + +#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 @@ -754,7 +754,6 @@ "name": "__cpp_lib_out_ptr", "values": {"c++23": 202106}, "headers": ["memory"], - "unimplemented": True, }, { "name": "__cpp_lib_parallel_algorithm",