diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 53cfc3739d2be..b548322b1b2b8 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -346,7 +346,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_optional`` ``202110L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_out_ptr`` *unimplemented* + ``__cpp_lib_out_ptr`` ``202106L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_print`` ``202207L`` ---------------------------------------------------------- ----------------- @@ -450,7 +450,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_optional_range_support`` *unimplemented* ---------------------------------------------------------- ----------------- - ``__cpp_lib_out_ptr`` *unimplemented* + ``__cpp_lib_out_ptr`` ``202311L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_philox_engine`` *unimplemented* ---------------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst index 80f43256f1270..242b01417ef47 100644 --- a/libcxx/docs/ReleaseNotes/19.rst +++ b/libcxx/docs/ReleaseNotes/19.rst @@ -38,6 +38,7 @@ What's New in Libc++ 19.0.0? Implemented Papers ------------------ +- P1132R8 - ``out_ptr`` - a scalable output pointer abstraction - P2637R3 - Member ``visit`` - P2652R2 - Disallow User Specialization of ``allocator_traits`` - P2819R2 - Add ``tuple`` protocol to ``complex`` diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv index cc601b3cd3c96..547d38c25c1da 100644 --- 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|","19.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|","19.0","" "`3772 `__","``repeat_view``'s ``piecewise`` constructor is missing Postconditions","February 2023","|Complete|","17.0","|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 index 4f589cd938d7c..6dd6bdad07658 100644 --- 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|","19.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/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv index b5732ee981ffb..dec9af1c12656 100644 --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -24,7 +24,7 @@ "`3749 `__","``common_iterator`` should handle integer-class difference types","Kona November 2023","","","" "`3809 `__","Is ``std::subtract_with_carry_engine`` supposed to work","Kona November 2023","","","" "`3892 `__","Incorrect formatting of nested ranges and tuples","Kona November 2023","|Complete|","17.0","|format|" -"`3897 `__","``inout_ptr`` will not update raw pointer to 0","Kona November 2023","","","" +"`3897 `__","``inout_ptr`` will not update raw pointer to 0","Kona November 2023","|Complete|","19.0","" "`3946 `__","The definition of ``const_iterator_t`` should be reworked","Kona November 2023","","","" "`3947 `__","Unexpected constraints on ``adjacent_transform_view::base()``","Kona November 2023","","","|ranges|" "`3948 `__","``possibly-const-range and as-const-pointer`` should be ``noexcept``","Kona November 2023","","","|ranges|" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index cd64fe91449c2..08e4e51595825 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -533,6 +533,8 @@ set(files __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 index ac564f0e6fa0c..c5fcc89327b8f 100644 --- a/libcxx/include/__memory/allocator_traits.h +++ b/libcxx/include/__memory/allocator_traits.h @@ -41,7 +41,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD struct NAME<_Tp, __void_t > : true_type {} // __pointer -_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_pointer, pointer); template , diff --git a/libcxx/include/__memory/inout_ptr.h b/libcxx/include/__memory/inout_ptr.h new file mode 100644 index 0000000000000..72e1a21ad6867 --- /dev/null +++ b/libcxx/include/__memory/inout_ptr.h @@ -0,0 +1,109 @@ +// -*- 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 <__utility/forward.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_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 with std::inout_ptr."); + +public: + _LIBCPP_HIDE_FROM_ABI explicit inout_ptr_t(_Smart& __smart, _Args... __args) + : __s_(__smart), __a_(std::forward<_Args>(__args)...), __p_([&__smart] { + if constexpr (is_pointer_v<_Smart>) { + return __smart; + } else { + return __smart.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() { + // LWG-3897 inout_ptr will not update raw pointer to null + if constexpr (!is_pointer_v<_Smart>) { + 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 { + static_assert(is_constructible_v<_Smart, _SP, _Args...>, + "The smart pointer must be constructible from arguments of types _Smart, _Pointer, _Args..."); + std::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>, "The conversion to void** requires _Pointer to be a raw 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 + +_LIBCPP_POP_MACROS + +#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 index 0000000000000..95aa2029c9231 --- /dev/null +++ b/libcxx/include/__memory/out_ptr.h @@ -0,0 +1,101 @@ +// -*- 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 <__utility/forward.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_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> || sizeof...(_Args) > 0, + "Using std::shared_ptr<> without a deleter in std::out_ptr is not supported."); + +public: + _LIBCPP_HIDE_FROM_ABI explicit out_ptr_t(_Smart& __smart, _Args... __args) + : __s_(__smart), __a_(std::forward<_Args>(__args)...), __p_() { + using _Ptr = decltype(__smart); + 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>, + "The adapted pointer type must have a reset() member function or be default constructible."); + } + } + + _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 { + static_assert(is_constructible_v<_Smart, _SP, _Args...>, + "The smart pointer must be constructible from arguments of types _Smart, _Pointer, _Args..."); + std::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>, "The conversion to void** requires _Pointer to be a raw 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 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___OUT_PTR_H diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h index fcd2c3edd9f6a..0914aceb318b7 100644 --- a/libcxx/include/__memory/pointer_traits.h +++ b/libcxx/include/__memory/pointer_traits.h @@ -20,19 +20,28 @@ #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) # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _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 {}; @@ -240,6 +249,59 @@ to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) { } #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 +_LIBCPP_POP_MACROS + #endif // _LIBCPP___MEMORY_POINTER_TRAITS_H diff --git a/libcxx/include/memory b/libcxx/include/memory index d52ee7b4c8eee..e1b8462191f84 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -911,6 +911,22 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space); 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 */ @@ -924,6 +940,8 @@ template #include <__memory/allocator_arg_t.h> #include <__memory/allocator_traits.h> #include <__memory/auto_ptr.h> +#include <__memory/inout_ptr.h> +#include <__memory/out_ptr.h> #include <__memory/pointer_traits.h> #include <__memory/raw_storage_iterator.h> #include <__memory/shared_ptr.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 7608aef3f3a43..d2a82b68efad7 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1521,6 +1521,8 @@ module std_private_memory_concepts [system] { 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_fwd [system] { header "__fwd/memory.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 index 7d9fad1cb1eb2..68aa88a48fa8f 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -477,7 +477,7 @@ __cpp_lib_void_t 201411L // # 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_const 202207L # define __cpp_lib_ranges_as_rvalue 202207L @@ -536,7 +536,7 @@ __cpp_lib_void_t 201411L # define __cpp_lib_mdspan 202406L // # define __cpp_lib_optional_range_support 202406L # undef __cpp_lib_out_ptr -// # define __cpp_lib_out_ptr 202311L +# define __cpp_lib_out_ptr 202311L // # define __cpp_lib_philox_engine 202406L // # define __cpp_lib_ranges_concat 202403L # define __cpp_lib_ratio 202306L diff --git a/libcxx/modules/std/memory.inc b/libcxx/modules/std/memory.inc index 56c621c0cf17f..c15f37a21239c 100644 --- a/libcxx/modules/std/memory.inc +++ b/libcxx/modules/std/memory.inc @@ -177,17 +177,19 @@ export namespace std { // [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 index 45d9271faa578..aa1170658b103 100644 --- 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 @@ -485,17 +485,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 @@ -622,17 +616,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 != 202311L -# error "__cpp_lib_out_ptr should have the value 202311L 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 != 202311L +# error "__cpp_lib_out_ptr should have the value 202311L 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 index e1af3061725df..945de95df67e1 100644 --- 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 @@ -5542,17 +5542,11 @@ # error "__cpp_lib_optional_range_support should not be defined before c++26" # 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) @@ -7383,17 +7377,11 @@ # endif # 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 != 202311L -# error "__cpp_lib_out_ptr should have the value 202311L 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 != 202311L +# error "__cpp_lib_out_ptr should have the value 202311L in c++26" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr.general.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr.general.pass.cpp new file mode 100644 index 0000000000000..d55a0c2abd464 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr.general.pass.cpp @@ -0,0 +1,206 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include "../types.h" + +// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a non-void pointer type. +// The API returns a new valid object. +void test_replace_int_p() { + auto replace_int_p = [](int** pp) { + assert(**pp == 90); + + delete *pp; + *pp = new int{84}; + }; + + // raw pointer + { + auto rPtr = new int{90}; + + replace_int_p(std::inout_ptr(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + + // std::unique_ptr + { + auto uPtr = std::make_unique(90); + + replace_int_p(std::inout_ptr(uPtr)); + assert(*uPtr == 84); + } + + { + MoveOnlyDeleter del; + std::unique_ptr> uPtr{new int{90}}; + + replace_int_p(std::inout_ptr(uPtr, std::move(del))); + assert(*uPtr == 84); + assert(uPtr.get_deleter().wasMoveInitilized == true); + } + + // pointer-like ConstructiblePtr + { + ConstructiblePtr cPtr(new int{90}); + + replace_int_p(std::inout_ptr(cPtr)); + assert(cPtr == 84); + } + + // pointer-like ResettablePtr + { + ResettablePtr rPtr(new int{90}); + + replace_int_p(std::inout_ptr(rPtr)); + assert(rPtr == 84); + } + + // pointer-like NonConstructiblePtr + { + NonConstructiblePtr nPtr; + nPtr.reset(new int{90}); + + replace_int_p(std::inout_ptr(nPtr)); + assert(nPtr == 84); + } +} + +// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a non-void pointer type. +// The API returns `nullptr`. +void test_replace_int_p_with_nullptr() { + auto replace_int_p_with_nullptr = [](int** pp) -> void { + assert(**pp == 90); + + delete *pp; + *pp = nullptr; + }; + + // raw pointer + { + // LWG-3897 inout_ptr will not update raw pointer to null + auto rPtr = new int{90}; + + replace_int_p_with_nullptr(std::inout_ptr(rPtr)); + assert(rPtr == nullptr); + } + + // std::unique_ptr + { + auto uPtr = std::make_unique(90); + + replace_int_p_with_nullptr(std::inout_ptr(uPtr)); + assert(uPtr == nullptr); + } +} + +// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a void pointer type. +// The API returns a new valid object. +void test_replace_int_void_p() { + auto replace_int_void_p = [](void** pp) { + assert(*(static_cast(*pp)) == 90); + + delete static_cast(*pp); + *pp = new int{84}; + }; + + // raw pointer + { + auto rPtr = new int{90}; + + replace_int_void_p(std::inout_ptr(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + + // std::unique_ptr + { + auto uPtr = std::make_unique(90); + + replace_int_void_p(std::inout_ptr(uPtr)); + assert(*uPtr == 84); + } +} + +// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a non-void pointer type. +// The API returns `nullptr`. +void test_replace_int_void_p_with_nullptr() { + auto replace_int_void_p_with_nullptr = [](void** pp) { + assert(*(static_cast(*pp)) == 90); + + delete static_cast(*pp); + *pp = nullptr; + }; + + // raw pointer + { + auto rPtr = new int{90}; + + replace_int_void_p_with_nullptr(std::inout_ptr(rPtr)); + assert(rPtr == nullptr); + } + + // std::unique_ptr + { + auto uPtr = std::make_unique(90); + + replace_int_void_p_with_nullptr(std::inout_ptr(uPtr)); + assert(uPtr == nullptr); + } +} + +// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a void pointer type. +// The API returns a new valid object. +void test_replace_nullptr_with_int_p() { + auto replace_nullptr_with_int_p = [](int** pp) { + assert(*pp == nullptr); + + *pp = new int{84}; + }; + + // raw pointer + { + int* rPtr = nullptr; + + replace_nullptr_with_int_p(std::inout_ptr(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + + // std::unique_ptr + { + std::unique_ptr uPtr; + + replace_nullptr_with_int_p(std::inout_ptr(uPtr)); + assert(*uPtr == 84); + } +} + +int main(int, char**) { + test_replace_int_p(); + test_replace_int_p_with_nullptr(); + test_replace_int_void_p(); + test_replace_int_void_p_with_nullptr(); + test_replace_nullptr_with_int_p(); + + 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 index 0000000000000..d6d70782c5eb5 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr.verify.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 +#include + +#include "../types.h" + +int main(int, char**) { + // `std::inout_ptr<>` does not support `std::shared_ptr<>`. + { + std::shared_ptr sPtr; + + // expected-error-re@*:* {{static assertion failed due to requirement {{.*}}std::shared_ptr<> is not supported}} + std::ignore = std::inout_ptr(sPtr); + // expected-error@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr' to 'std::inout_ptr_t, _Ptr>' (aka 'inout_ptr_t, int *>'}} + std::ignore = std::inout_ptr(sPtr); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.convert.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.convert.pass.cpp new file mode 100644 index 0000000000000..230402af07cfe --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.convert.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// operator Pointer*() const noexcept; +// operator void**() const noexcept; + +#include +#include +#include + +int main(int, char**) { + // operator Pointer*() + { + std::unique_ptr uPtr = std::make_unique(84); + + const std::inout_ptr_t, int*> ioPtr{uPtr}; + + static_assert(noexcept(ioPtr.operator int**())); + std::same_as decltype(auto) pPtr = ioPtr.operator int**(); + + assert(**pPtr == 84); + } + + { + std::unique_ptr> uPtr = std::make_unique(84); + + const std::inout_ptr_t> ioPtr{uPtr, std::default_delete{}}; + + static_assert(noexcept(ioPtr.operator int**())); + std::same_as decltype(auto) pPtr = ioPtr.operator int**(); + + assert(**pPtr == 84); + } + + // operator void**() + { + std::unique_ptr uPtr = std::make_unique(84); + + const std::inout_ptr_t, void*> ioPtr{uPtr}; + + static_assert(noexcept(ioPtr.operator void**())); + std::same_as decltype(auto) pPtr = ioPtr.operator void**(); + + assert(**reinterpret_cast(pPtr) == 84); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.ctor.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.ctor.pass.cpp new file mode 100644 index 0000000000000..c7e173a76e728 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/inout_ptr/inout_ptr_t.ctor.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// explicit inout_ptr_t(Smart&, Args...); + +#include +#include + +#include "test_convertible.h" +#include "../types.h" + +int main(int, char**) { + { + std::unique_ptr uPtr; + + std::inout_ptr_t, int*>{uPtr}; + + static_assert( + !test_convertible, int*>>(), "This constructor must be explicit"); + + // Test the state of the pointer after construction. Complete tests are available in inout_ptr.general.pass.cpp. + assert(uPtr == nullptr); + } + + { + auto deleter = [](auto* p) { delete p; }; + std::unique_ptr uPtr; + + std::inout_ptr_t, int*>{uPtr}; + + static_assert(!test_convertible, int*>>(), + "This constructor must be explicit"); + + // Test the state of the pointer after construction. Complete tests are available in inout_ptr.general.pass.cpp. + assert(uPtr == nullptr); + } + + { + std::unique_ptr> uPtr; + + std::inout_ptr_t>{uPtr, MoveOnlyDeleter{}}; + + // Test the state of the pointer after construction. Complete tests are available in inout_ptr.general.pass.cpp. + assert(uPtr == nullptr); + } + + 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 index 0000000000000..2270c4c3fc785 --- /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 assertion failed due to requirement {{.*}}std::shared_ptr<> is not supported with std::inout_ptr.}} + std::inout_ptr_t, int*>{sPtr}; + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr.general.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr.general.pass.cpp new file mode 100644 index 0000000000000..a78e22f69abc0 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr.general.pass.cpp @@ -0,0 +1,230 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include "../types.h" + +// Test updating an `out_ptr_t`-managed pointer for an API with a non-void pointer type. +// The API returns a new valid object. +void test_get_int_p() { + auto get_int_p = [](int** pp) { *pp = new int{84}; }; + + // raw pointer + { + int* rPtr; + + get_int_p(std::out_ptr(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + + // std::unique_ptr + { + std::unique_ptr uPtr; + + get_int_p(std::out_ptr(uPtr)); + assert(*uPtr == 84); + } + + { + MoveOnlyDeleter del; + std::unique_ptr> uPtr; + + get_int_p(std::out_ptr(uPtr, std::move(del))); + assert(*uPtr == 84); + assert(uPtr.get_deleter().wasMoveInitilized == true); + } + + // std::shared_ptr + { + std::shared_ptr sPtr; + + get_int_p(std::out_ptr(sPtr, [](auto* p) { + assert(*p == 84); + + delete p; + })); + assert(*sPtr == 84); + } + + // pointer-like ConstructiblePtr + { + ConstructiblePtr cPtr; + + get_int_p(std::out_ptr(cPtr)); + assert(cPtr == 84); + } + + // pointer-like ResettablePtr + { + ResettablePtr rPtr{nullptr}; + + get_int_p(std::out_ptr(rPtr)); + assert(rPtr == 84); + } + + // NonConstructiblePtr + { + NonConstructiblePtr nPtr; + + get_int_p(std::out_ptr(nPtr)); + assert(nPtr == 84); + } +} + +// Test updating an `out_ptr_t`-managed pointer for an API with a non-void pointer type. +// The API returns `nullptr`. +void test_get_int_p_nullptr() { + auto get_int_p_nullptr = [](int** pp) { *pp = nullptr; }; + // raw pointer + { + int* rPtr; + + get_int_p_nullptr(std::out_ptr(rPtr)); + assert(rPtr == nullptr); + + delete rPtr; + } + + // std::unique_ptr + { + std::unique_ptr uPtr; + + get_int_p_nullptr(std::out_ptr(uPtr)); + assert(uPtr == nullptr); + } + + // std::shared_ptr + { + std::shared_ptr sPtr; + + get_int_p_nullptr(std::out_ptr(sPtr, [](auto* p) { + assert(p == nullptr); + + delete p; + })); + assert(sPtr == nullptr); + } +} + +// Test updating an `out_ptr_t`-managed pointer for an API with a void pointer type. +// The API returns a new valid object. +void test_get_int_void_p() { + auto get_int_void_p = [](void** pp) { *(reinterpret_cast(pp)) = new int{84}; }; + + // raw pointer + { + int* rPtr; + + get_int_void_p(std::out_ptr(rPtr)); + assert(*rPtr == 84); + + delete rPtr; + } + + // std::unique_ptr + { + std::unique_ptr uPtr; + + get_int_void_p(std::out_ptr(uPtr)); + assert(*uPtr == 84); + } + + // std::shared_ptr + { + std::shared_ptr sPtr; + + get_int_void_p(std::out_ptr(sPtr, [](auto* p) { + assert(*p == 84); + + delete p; + })); + assert(*sPtr == 84); + } + + // pointer-like ConstructiblePtr + { + ConstructiblePtr cPtr; + + get_int_void_p(std::out_ptr(cPtr)); + assert(cPtr == 84); + } + + // pointer-like ResettablePtr + { + ResettablePtr rPtr{nullptr}; + + get_int_void_p(std::out_ptr(rPtr)); + assert(rPtr == 84); + } + + // NonConstructiblePtr + { + NonConstructiblePtr nPtr; + + get_int_void_p(std::out_ptr(nPtr)); + assert(nPtr == 84); + } +} + +// Test updating an `out_ptr_t`-managed pointer for an API with a void pointer type. +// The API returns `nullptr`. +void test_get_int_void_p_nullptr() { + auto get_int_void_p_nullptr = [](void** pp) { *pp = nullptr; }; + + // raw pointer + { + int* rPtr; + + get_int_void_p_nullptr(std::out_ptr(rPtr)); + assert(rPtr == nullptr); + + delete rPtr; + } + + // std::unique_ptr + { + std::unique_ptr uPtr; + + get_int_void_p_nullptr(std::out_ptr(uPtr)); + assert(uPtr == nullptr); + } + + // std::shared_ptr + { + std::shared_ptr sPtr; + + get_int_void_p_nullptr(std::out_ptr(sPtr, [](auto* p) { + assert(p == nullptr); + + delete p; + })); + assert(sPtr == nullptr); + } +} + +int main(int, char**) { + test_get_int_p(); + test_get_int_p_nullptr(); + test_get_int_void_p(); + test_get_int_void_p_nullptr(); + + 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 index 0000000000000..1fe78ecb22789 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr.verify.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 +#include + +#include "../types.h" + +int main(int, char**) { + // `std::out_ptr<>` requires `std::shared_ptr<>` with a deleter. + { + std::shared_ptr sPtr; + + // expected-error-re@*:* {{static assertion failed due to requirement {{.*}}Using std::shared_ptr<> without a deleter in std::out_ptr is not supported.}} + std::ignore = std::out_ptr(sPtr); + // expected-error@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr' to 'std::out_ptr_t, _Ptr>' (aka 'out_ptr_t, int *>')}} + std::ignore = std::out_ptr(sPtr); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.convert.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.convert.pass.cpp new file mode 100644 index 0000000000000..828a5d0ba31ea --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.convert.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// operator Pointer*() const noexcept; +// operator void**() const noexcept; + +#include +#include +#include + +int main(int, char**) { + // operator Pointer*() + { + std::unique_ptr uPtr; + + const std::out_ptr_t, int*> oPtr{uPtr}; + + static_assert(noexcept(oPtr.operator int**())); + std::same_as decltype(auto) pPtr = oPtr.operator int**(); + + assert(*pPtr == nullptr); + } + + { + std::unique_ptr> uPtr; + + const std::out_ptr_t> oPtr{uPtr, std::default_delete{}}; + + static_assert(noexcept(oPtr.operator int**())); + std::same_as decltype(auto) pPtr = oPtr.operator int**(); + + assert(*pPtr == nullptr); + } + + // operator void**() + { + std::unique_ptr uPtr; + + const std::out_ptr_t, void*> oPtr{uPtr}; + + static_assert(noexcept(oPtr.operator void**())); + std::same_as decltype(auto) pPtr = oPtr.operator void**(); + + assert(*pPtr == nullptr); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.ctor.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.ctor.pass.cpp new file mode 100644 index 0000000000000..29e1258845bc9 --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/out_ptr/out_ptr_t.ctor.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// explicit out_ptr_t(Smart&, Args...); + +#include +#include + +#include "test_convertible.h" +#include "../types.h" + +int main(int, char**) { + { + std::unique_ptr uPtr; + + std::out_ptr_t, int*>{uPtr}; + + static_assert(!test_convertible, int*>>(), "This constructor must be explicit"); + + // Test the state of the pointer after construction. Complete tests are available in out_ptr.general.pass.cpp + assert(uPtr == nullptr); + } + + { + std::unique_ptr> uPtr; + + std::out_ptr_t>{uPtr, std::default_delete{}}; + + static_assert(!test_convertible>>(), + "This constructor must be explicit"); + + // Test the state of the pointer after construction. Complete tests are available in out_ptr.general.pass.cpp + assert(uPtr == nullptr); + } + + { + std::unique_ptr> uPtr; + + std::out_ptr_t>{uPtr, MoveOnlyDeleter{}}; + + // Test the state of the pointer after construction. Complete tests are available in out_ptr.general.pass.cpp + assert(uPtr == nullptr); + } + + 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 index 0000000000000..cbe96e752ac92 --- /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 assertion failed due to requirement {{.*}}Using std::shared_ptr<> without a deleter in std::out_ptr is not supported.}} + std::out_ptr_t, int*>{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 index 0000000000000..0da6007ba394f --- /dev/null +++ b/libcxx/test/std/utilities/smartptr/adapt/types.h @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "test_macros.h" + +// Custom deleters. + +template +struct MoveOnlyDeleter { + MoveOnlyDeleter() = default; + MoveOnlyDeleter(const MoveOnlyDeleter&) = delete; + MoveOnlyDeleter& operator=(const MoveOnlyDeleter&) = delete; + MoveOnlyDeleter(MoveOnlyDeleter&&) : wasMoveInitilized{true} {} + MoveOnlyDeleter& operator=(MoveOnlyDeleter&&) = default; + + void operator()(T* p) const { delete p; } + + bool wasMoveInitilized = false; +}; + +// Custom pointer types. + +template +struct ConstructiblePtr { + using pointer = T*; + std::unique_ptr ptr; + + ConstructiblePtr() = default; + explicit ConstructiblePtr(T* p) : ptr{p} {} + + auto operator==(T val) { return *ptr == val; } + + auto* get() const { return ptr.get(); } + + void release() { ptr.release(); } +}; + +LIBCPP_STATIC_ASSERT(std::is_same_v>, int* >); +static_assert(std::is_constructible_v< ConstructiblePtr, int* >); + +struct ResetArg {}; + +template +struct ResettablePtr { + using element_type = T; + std::unique_ptr ptr; + + explicit ResettablePtr(T* p) : ptr{p} {} + + auto operator*() const { return *ptr; } + + auto operator==(T val) { return *ptr == val; } + + void reset() { ptr.reset(); } + void reset(T* p, ResetArg) { ptr.reset(p); } + + auto* get() const { return ptr.get(); } + + void release() { ptr.release(); } +}; + +LIBCPP_STATIC_ASSERT(std::is_same_v>, int* >); +static_assert(std::is_constructible_v< ResettablePtr, int* >); + +template +struct NonConstructiblePtr : public ResettablePtr { + NonConstructiblePtr() : NonConstructiblePtr::ResettablePtr(nullptr) {}; + + void reset(T* p) { ResettablePtr::ptr.reset(p); } +}; + +LIBCPP_STATIC_ASSERT(std::is_same_v>, int* >); +static_assert(!std::is_constructible_v< NonConstructiblePtr, int* >); + +#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 index a267e5774e2ad..93e7db44a1116 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -949,7 +949,6 @@ def add_version_header(tc): "c++26": 202311, # P2833R2 Freestanding Library: inout expected span }, "headers": ["memory"], - "unimplemented": True, }, { "name": "__cpp_lib_parallel_algorithm",