diff --git a/libcxx/docs/Status/Cxx17Issues.csv b/libcxx/docs/Status/Cxx17Issues.csv --- a/libcxx/docs/Status/Cxx17Issues.csv +++ b/libcxx/docs/Status/Cxx17Issues.csv @@ -143,7 +143,7 @@ "`2441 `__","Exact-width atomic typedefs should be provided","Oulu","|Complete|","" "`2451 `__","[fund.ts.v2] optional should 'forward' T's implicit conversions","Oulu","|Nothing To Do|","" "`2509 `__","[fund.ts.v2] any_cast doesn't work with rvalue reference targets and cannot move with a value target","Oulu","|Complete|","" -"`2516 `__","[fund.ts.v2] Public ""exposition only"" members in observer_ptr","Oulu","","" +"`2516 `__","[fund.ts.v2] Public ""exposition only"" members in observer_ptr","Oulu","|Complete|","18.0" "`2542 `__","Missing const requirements for associative containers","Oulu","","" "`2549 `__","Tuple EXPLICIT constructor templates that take tuple parameters end up taking references to temporaries and will create dangling references","Oulu","|Complete|","" "`2550 `__","Wording of unordered container's clear() method complexity","Oulu","|Complete|","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -908,6 +908,7 @@ experimental/iterator experimental/list experimental/map + experimental/memory experimental/memory_resource experimental/propagate_const experimental/regex diff --git a/libcxx/include/__std_clang_module b/libcxx/include/__std_clang_module --- a/libcxx/include/__std_clang_module +++ b/libcxx/include/__std_clang_module @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) diff --git a/libcxx/include/experimental/memory b/libcxx/include/experimental/memory new file mode 100644 --- /dev/null +++ b/libcxx/include/experimental/memory @@ -0,0 +1,198 @@ +// -*- 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_EXPERIMENTAL_MEMORY +#define _LIBCPP_EXPERIMENTAL_MEMORY + +/* + experimental/memory synopsis + +namespace std::experimental::inline fundamentals_v2 { + +template class observer_ptr { +public: + using element_type = W; + using pointer = add_pointer_t; // exposition-only + using reference = add_lvalue_reference_t; // exposition-only + + // default ctor + constexpr observer_ptr() noexcept; + + // pointer-accepting ctors + constexpr observer_ptr(nullptr_t) noexcept; + constexpr explicit observer_ptr(pointer) noexcept; + + // copying ctors (in addition to compiler-generated copy ctor) + template constexpr observer_ptr(observer_ptr) noexcept; + + // observers + constexpr pointer get() const noexcept; + constexpr reference operator*() const; + constexpr pointer operator->() const noexcept; + constexpr explicit operator bool() const noexcept; + + // conversions + constexpr explicit operator pointer() const noexcept; + + // modifiers + constexpr pointer release() noexcept; + constexpr void reset(pointer = nullptr) noexcept; + constexpr void swap(observer_ptr&) noexcept; +}; + +} +*/ + +#include <__functional/hash.h> +#include <__functional/operations.h> +#include <__type_traits/add_lvalue_reference.h> +#include <__type_traits/add_pointer.h> +#include <__type_traits/common_type.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_convertible.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#ifdef _LIBCPP_ENABLE_EXPERIMENTAL + +_LIBCPP_BEGIN_NAMESPACE_LFTS_V2 + +#if _LIBCPP_STD_VER >= 17 + +template +class observer_ptr { + typedef add_pointer_t<_Wp> pointer; + typedef add_lvalue_reference_t<_Wp> reference; + + pointer __ptr_; + +public: + typedef _Wp element_type; + + // constructors + constexpr observer_ptr() noexcept : __ptr_(nullptr) {} + constexpr observer_ptr(nullptr_t) noexcept : __ptr_(nullptr) {} + constexpr explicit observer_ptr(pointer __p) noexcept : __ptr_(__p) {} + + template ::value>> + constexpr observer_ptr(observer_ptr<_W2> __other) noexcept : __ptr_(__other.get()) {} + + // observers + constexpr pointer get() const noexcept { return __ptr_; } + constexpr reference operator*() const { return *__ptr_; } + constexpr pointer operator->() const noexcept { return __ptr_; } + constexpr explicit operator bool() const noexcept { return __ptr_ != nullptr; } + + // conversions + constexpr operator pointer() const noexcept { return __ptr_; } + + // modifiers + constexpr void reset(pointer __p = nullptr) { __ptr_ = __p; } + constexpr void swap(observer_ptr& __other) noexcept { + observer_ptr __tmp = __other; + __other = *this; + *this = __tmp; + } + constexpr pointer release() noexcept { + observer_ptr __p; + __p.swap(*this); + return __p.get(); + } +}; + +// specializations + +template +void swap(observer_ptr<_Wp>& __a, observer_ptr<_Wp>& __b) noexcept { + __a.swap(__b); +} + +template +observer_ptr<_Wp> make_observer(_Wp* __ptr) noexcept { + return observer_ptr<_Wp>{__ptr}; +} + +template +bool operator==(observer_ptr<_W1> __a, observer_ptr<_W2> __b) { + return __a.get() == __b.get(); +} + +template +bool operator!=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) { + return !(__a == __b); +} + +template +bool operator==(observer_ptr<_Wp> __p, nullptr_t) { + return !__p; +} + +template +bool operator==(nullptr_t, observer_ptr<_Wp> __p) { + return !__p; +} + +template +bool operator!=(observer_ptr<_Wp> __p, nullptr_t) { + return (bool)__p; +} + +template +bool operator!=(nullptr_t, observer_ptr<_Wp> __p) { + return (bool)__p; +} + +template +bool operator<(observer_ptr<_W1> __a, observer_ptr<_W2> __b) { + return std::less::type>()(__a.get(), __b.get()); +} + +template +bool operator>(observer_ptr<_W1> __a, observer_ptr<_W2> __b) { + return __b < __a; +} + +template +bool operator<=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) { + return !(__a > __b); +} + +template +bool operator>=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) { + return !(__a < __b); +} + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_LFTS_V2 + +_LIBCPP_BEGIN_NAMESPACE_STD + +// hash + +#if _LIBCPP_STD_VER >= 17 +template +struct hash> { + typedef experimental::observer_ptr<_Tp> argument_type; + typedef size_t result_type; + + _LIBCPP_HIDE_FROM_ABI result_type operator()(const argument_type& __ptr) const noexcept { + return hash<_Tp*>()(__ptr.get()); + } +}; +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_ENABLE_EXPERIMENTAL + +#endif /* _LIBCPP_EXPERIMENTAL_MEMORY */ 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 @@ -540,6 +540,10 @@ header "experimental/map" export * } + module memory { + header "experimental/memory" + export * + } module memory_resource { header "experimental/memory_resource" export * diff --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/conv.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/conv.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/conv.pass.cpp @@ -0,0 +1,41 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// REQUIRES: c++experimental + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +template +void test_convertibility() { + typedef std::experimental::observer_ptr OP; + static_assert(std::is_convertible::value, ""); +} + +struct Foo; + +struct Bar {}; + +int main(int, char**) { + test_convertibility(); + test_convertibility(); + test_convertibility(); + test_convertibility(); + test_convertibility(); + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.pass.cpp @@ -0,0 +1,126 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// REQUIRES: c++experimental + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +template +void custom_delete(T* ptr) { + delete ptr; +} +void custom_delete(void* ptr) { delete (int*)ptr; } + +template +void assert_constructability() { + typedef std::experimental::observer_ptr OP; + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible>::value == + std::is_convertible::value, + ""); +} + +template +void construct_nullptr() { + { + std::experimental::observer_ptr ptr; + assert(ptr.get() == nullptr); + } + { + std::experimental::observer_ptr ptr(nullptr); + assert(ptr.get() == nullptr); + } +} + +template +void construct_ptr(T* raw_ptr) { + std::experimental::observer_ptr ptr(raw_ptr); + assert(ptr.get() == raw_ptr); + custom_delete(raw_ptr); +} + +template +void construct_other(U* raw_ptr) { + std::experimental::observer_ptr uptr(raw_ptr); + std::experimental::observer_ptr tptr(uptr); + assert(uptr.get() == raw_ptr); + assert(tptr.get() == raw_ptr); + custom_delete(raw_ptr); +} + +template +void test_copy_move(T* raw_ptr) { + std::experimental::observer_ptr ptr_a(raw_ptr); + std::experimental::observer_ptr ptr_b(ptr_a); + std::experimental::observer_ptr ptr_c(std::move(ptr_a)); + assert(ptr_b.get() == raw_ptr); + assert(ptr_c.get() == raw_ptr); + custom_delete(raw_ptr); +} + +struct Foo; +struct Bar { + Bar(int) {} +}; + +int main(int, char**) { + { + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + } + { + construct_nullptr(); + construct_nullptr(); + construct_nullptr(); + construct_nullptr(); + } + { + construct_ptr(new int); + construct_ptr(new Bar(42)); + construct_ptr((void*)new int); + } + { + construct_other(new int); + construct_other(new Bar(42)); + + // overload resolution + typedef std::experimental::observer_ptr OP1; + typedef std::experimental::observer_ptr OP2; + typedef std::experimental::observer_ptr OP3; + static_assert(!std::is_nothrow_constructible::value, ""); + static_assert(!std::is_nothrow_constructible::value, ""); + } + { + test_copy_move(new int); + test_copy_move((void*)new int); + test_copy_move(new Bar(42)); + } + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/hash.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/hash.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/hash.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03, c++11, c++14 +// REQUIRES: c++experimental + +// + +// observer_ptr + +#include +#include + +#include "poisoned_hash_helper.h" +#include "test_macros.h" + +struct A {}; + +int main(int, char**) { + { + int* ptr = new int; + std::experimental::observer_ptr p(ptr); + std::hash> f; + std::size_t h = f(p); + assert(h == std::hash()(ptr)); + } + { + test_hash_enabled_for_type>(); + test_hash_enabled_for_type>(); + } + + return 0; +} diff --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/mod/release.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/mod/release.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/mod/release.pass.cpp @@ -0,0 +1,46 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// REQUIRES: c++experimental + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +constexpr bool test_constexpr() { + int x = 42; + std::experimental::observer_ptr ptr(&x); + return ptr.release() == &x && ptr.get() == nullptr; +} + +int main(int, char**) { + { + std::experimental::observer_ptr ptr; + assert(ptr.release() == nullptr); + assert(ptr.get() == nullptr); + } + { + int* raw_ptr = new int; + std::experimental::observer_ptr ptr(raw_ptr); + assert(ptr.release() == raw_ptr); + assert(ptr.get() == nullptr); + delete raw_ptr; + } + + static_assert(test_constexpr()); + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/mod/reset.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/mod/reset.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/mod/reset.pass.cpp @@ -0,0 +1,53 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// REQUIRES: c++experimental + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +constexpr bool reset_constexpr() { + int a = 42; + int b = 101; + + std::experimental::observer_ptr ptr(&a); + ptr.reset(&b); + return ptr.get() == &b; +} + +int main(int, char**) { + int* raw_ptr1 = new int; + int* raw_ptr2 = new int; + + { + std::experimental::observer_ptr ptr; + ptr.reset(raw_ptr1); + assert(ptr.get() == raw_ptr1); + } + { + std::experimental::observer_ptr ptr(raw_ptr1); + ptr.reset(raw_ptr2); + assert(ptr.get() == raw_ptr2); + } + + delete raw_ptr1; + delete raw_ptr2; + + static_assert(reset_constexpr()); + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/mod/swap.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/mod/swap.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/mod/swap.pass.cpp @@ -0,0 +1,73 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// REQUIRES: c++experimental + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +constexpr bool constexpr_swap() { + int x = 42; + int y = 55; + + auto op1 = std::experimental::observer_ptr(&x); + auto op2 = std::experimental::observer_ptr(&y); + + op1.swap(op2); + return *op1 == 55 && *op2 == 42; +} + +int main(int, char**) { + int* raw_ptr1 = new int; + int* raw_ptr2 = new int; + + { + std::experimental::observer_ptr ptr1; + std::experimental::observer_ptr ptr2; + ptr1.swap(ptr2); + assert(ptr1.get() == nullptr); + assert(ptr2.get() == nullptr); + } + { + std::experimental::observer_ptr ptr1(raw_ptr1); + std::experimental::observer_ptr ptr2; + ptr1.swap(ptr2); + assert(ptr1.get() == nullptr); + assert(ptr2.get() == raw_ptr1); + } + { + std::experimental::observer_ptr ptr1; + std::experimental::observer_ptr ptr2(raw_ptr2); + ptr1.swap(ptr2); + assert(ptr1.get() == raw_ptr2); + assert(ptr2.get() == nullptr); + } + { + std::experimental::observer_ptr ptr1(raw_ptr1); + std::experimental::observer_ptr ptr2(raw_ptr2); + ptr1.swap(ptr2); + assert(ptr1.get() == raw_ptr2); + assert(ptr2.get() == raw_ptr1); + } + + delete raw_ptr1; + delete raw_ptr2; + + static_assert(constexpr_swap()); + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/obs.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/obs.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/obs.pass.cpp @@ -0,0 +1,53 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// REQUIRES: c++experimental + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +struct Foo { + const int x; + constexpr Foo(const int x) : x(x) {} +}; + +int main(int, char**) { + static constexpr int x = 42; + constexpr const int* raw_ptr = &x; + { + constexpr std::experimental::observer_ptr ptr(raw_ptr); + static_assert(ptr.get() == raw_ptr); + } + { + constexpr std::experimental::observer_ptr ptr1; + const bool check1 = ptr1; + static_assert(check1 == false); + + constexpr std::experimental::observer_ptr ptr2(raw_ptr); + const bool check2 = ptr2; + static_assert(check2 == true); + } + { + static constexpr Foo f = Foo(42); + constexpr const Foo* foo_ptr = &f; + constexpr std::experimental::observer_ptr ptr(foo_ptr); + static_assert(ptr->x == 42); + static_assert((*ptr).x == 42); + } + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/spec.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/spec.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/spec.pass.cpp @@ -0,0 +1,85 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// REQUIRES: c++experimental + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + { + std::experimental::observer_ptr ptr1(new int(42)); + std::experimental::observer_ptr ptr2(new int(101)); + std::experimental::swap(ptr1, ptr2); + + assert(*ptr1 == 101); + assert(*ptr2 == 42); + + delete ptr1.get(); + delete ptr2.get(); + } + { + int* raw = new int; + std::experimental::observer_ptr ptr = std::experimental::make_observer(raw); + assert(ptr.get() == raw); + delete raw; + } + + std::experimental::observer_ptr ptr1(new int); + std::experimental::observer_ptr ptr2(new int); + std::experimental::observer_ptr ptr3; + std::experimental::observer_ptr vptr((void*)new int); + { + assert(ptr1 == ptr1); + assert(!(ptr1 == ptr2)); + } + { assert(ptr1 != ptr2); } + { + assert(ptr3 == nullptr); + assert(nullptr == ptr3); + assert(!(ptr1 == nullptr)); + assert(!(nullptr == ptr1)); + } + { + assert(!(ptr3 != nullptr)); + assert(!(nullptr != ptr3)); + assert(ptr1 != nullptr); + assert(nullptr != ptr1); + } + { + assert((ptr1 < ptr1) == (ptr1.get() < ptr1.get())); + assert((ptr1 < vptr) == (ptr1.get() < vptr.get())); + } + { + assert((ptr1 > ptr1) == (ptr1.get() > ptr1.get())); + assert((ptr1 > vptr) == (ptr1.get() > vptr.get())); + } + { + assert((ptr1 <= ptr1) != (ptr1.get() > ptr1.get())); + assert((ptr1 <= vptr) != (ptr1.get() > vptr.get())); + } + { + assert((ptr1 >= ptr1) != (ptr1.get() < ptr1.get())); + assert((ptr1 >= vptr) != (ptr1.get() < vptr.get())); + } + + delete ptr1.get(); + delete ptr2.get(); + delete (int*)vptr.get(); + + return 0; +} \ No newline at end of file