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 @@ -164,11 +164,12 @@ // to_address -template struct __to_address_helper; - -template <> struct __to_address_helper { +template +struct __to_address_helper { template - using __return_type = decltype(pointer_traits<_Pointer>::to_address(_VSTD::declval())); + using __return_type = typename decay< + decltype(pointer_traits<_Pointer>::to_address(declval())) + >::type; template _LIBCPP_CONSTEXPR @@ -198,7 +199,9 @@ template <> struct __to_address_helper { template - using __return_type = typename pointer_traits<_Pointer>::element_type*; + using __return_type = typename decay< + decltype(_VSTD::__to_address(declval().operator->())) + >::type; template _LIBCPP_CONSTEXPR @@ -206,7 +209,6 @@ __do_it(const _Pointer &__p) _NOEXCEPT { return _VSTD::__to_address(__p.operator->()); } }; - #if _LIBCPP_STD_VER > 17 template inline _LIBCPP_INLINE_VISIBILITY constexpr diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -1352,7 +1352,7 @@ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), "Attempted to dereference a non-dereferenceable iterator"); #endif - return (pointer)_VSTD::addressof(*__i); + return _VSTD::__to_address(__i); } _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator++() _NOEXCEPT { diff --git a/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address.pass.cpp b/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// template constexpr T* __to_address(T* p) noexcept; +// template constexpr auto __to_address(const Ptr& p) noexcept; + +#include +#include +#include "test_macros.h" + +struct Irrelevant {}; + +struct P1 { + using element_type = Irrelevant; + TEST_CONSTEXPR explicit P1(int *p) : p_(p) { } + TEST_CONSTEXPR int *operator->() const { return p_; } + int *p_; +}; + +struct P2 { + using element_type = Irrelevant; + TEST_CONSTEXPR explicit P2(int *p) : p_(p) { } + TEST_CONSTEXPR P1 operator->() const { return p_; } + P1 p_; +}; + +struct P3 { + TEST_CONSTEXPR explicit P3(int *p) : p_(p) { } + int *p_; +}; + +template<> +struct std::pointer_traits { + static TEST_CONSTEXPR int *to_address(const P3& p) { return p.p_; } +}; + +struct P4 { + TEST_CONSTEXPR explicit P4(int *p) : p_(p) { } + int *operator->() const; // should never be called + int *p_; +}; + +template<> +struct std::pointer_traits { + static TEST_CONSTEXPR int *to_address(const P4& p) { return p.p_; } +}; + +struct P5 { + using element_type = Irrelevant; + int const* const& operator->() const; +}; + +struct P6 {}; + +template<> +struct std::pointer_traits { + static int const* const& to_address(const P6&); +}; + +TEST_CONSTEXPR_CXX14 bool test() { + int i = 0; + ASSERT_NOEXCEPT(std::__to_address(&i)); + assert(std::__to_address(&i) == &i); + P1 p1(&i); + ASSERT_NOEXCEPT(std::__to_address(p1)); + assert(std::__to_address(p1) == &i); + P2 p2(&i); + ASSERT_NOEXCEPT(std::__to_address(p2)); + assert(std::__to_address(p2) == &i); + P3 p3(&i); + ASSERT_NOEXCEPT(std::__to_address(p3)); + assert(std::__to_address(p3) == &i); + P4 p4(&i); + ASSERT_NOEXCEPT(std::__to_address(p4)); + assert(std::__to_address(p4) == &i); + + ASSERT_SAME_TYPE(decltype(std::__to_address(std::declval())), int const*); + ASSERT_SAME_TYPE(decltype(std::__to_address(std::declval())), int const*); + ASSERT_SAME_TYPE(decltype(std::__to_address(std::declval())), int const*); + + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 14 + static_assert(test(), ""); +#endif + return 0; +} diff --git a/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address_std_iterators.pass.cpp b/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address_std_iterators.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address_std_iterators.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// template constexpr T* __to_address(T* p) noexcept; +// template constexpr auto __to_address(const Ptr& p) noexcept; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include "test_macros.h" + +template +void test_container_iterators(C c) +{ + const C& cc = c; + assert(std::__to_address(c.begin()) == c.data()); + assert(std::__to_address(c.end()) == c.data() + c.size()); + assert(std::__to_address(cc.begin()) == cc.data()); + assert(std::__to_address(cc.end()) == cc.data() + cc.size()); +} + +void test_valarray_iterators() +{ + std::valarray v(100); + int *p = std::__to_address(std::begin(v)); + int *q = std::__to_address(std::end(v)); + assert(q - p == 100); +} + +int main(int, char**) { + test_container_iterators(std::array()); + test_container_iterators(std::vector(3)); + test_container_iterators(std::string("abc")); +#if TEST_STD_VER >= 17 + test_container_iterators(std::string_view("abc")); +#endif +#if TEST_STD_VER >= 20 + test_container_iterators(std::span("abc")); +#endif + test_valarray_iterators(); + + return 0; +} diff --git a/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp b/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp --- a/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp +++ b/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp @@ -17,110 +17,81 @@ #include #include "test_macros.h" -class P1 -{ -public: - using element_type = int; +struct Irrelevant {}; - constexpr explicit P1(int* p) - : p_(p) { } - - constexpr int* operator->() const noexcept - { return p_; } - -private: - int* p_; +struct P1 { + using element_type = Irrelevant; + constexpr explicit P1(int *p) : p_(p) { } + constexpr int *operator->() const { return p_; } + int *p_; }; -class P2 -{ -public: - using element_type = int; - - constexpr explicit P2(int* p) - : p_(p) { } - - constexpr P1 operator->() const noexcept - { return p_; } - -private: +struct P2 { + using element_type = Irrelevant; + constexpr explicit P2(int *p) : p_(p) { } + constexpr P1 operator->() const { return p_; } P1 p_; }; -class P3 -{ -public: - constexpr explicit P3(int* p) - : p_(p) { } - - constexpr int* get() const noexcept - { return p_; } - -private: - int* p_; +struct P3 { + constexpr explicit P3(int *p) : p_(p) { } + int *p_; }; -namespace std -{ template<> -struct pointer_traits<::P3> -{ - static constexpr int* to_address(const ::P3& p) noexcept - { return p.get(); } +struct std::pointer_traits { + static constexpr int *to_address(const P3& p) { return p.p_; } }; -} -class P4 -{ -public: - constexpr explicit P4(int* p) - : p_(p) { } - - constexpr int* operator->() const noexcept - { return nullptr; } +struct P4 { + constexpr explicit P4(int *p) : p_(p) { } + int *operator->() const; // should never be called + int *p_; +}; - constexpr int* get() const noexcept - { return p_; } +template<> +struct std::pointer_traits { + static constexpr int *to_address(const P4& p) { return p.p_; } +}; -private: - int* p_; +struct P5 { + using element_type = Irrelevant; + int const* const& operator->() const; }; -namespace std -{ +struct P6 {}; + template<> -struct pointer_traits<::P4> -{ - constexpr static int* to_address(const ::P4& p) noexcept - { return p.get(); } +struct std::pointer_traits { + static int const* const& to_address(const P6&); }; -} - -int n = 0; -static_assert(std::to_address(&n) == &n); constexpr bool test() { - int i = 0; - ASSERT_NOEXCEPT(std::to_address(&i)); - assert(std::to_address(&i) == &i); - P1 p1(&i); - ASSERT_NOEXCEPT(std::to_address(p1)); - assert(std::to_address(p1) == &i); - P2 p2(&i); - ASSERT_NOEXCEPT(std::to_address(p2)); - assert(std::to_address(p2) == &i); - P3 p3(&i); - ASSERT_NOEXCEPT(std::to_address(p3)); - assert(std::to_address(p3) == &i); - P4 p4(&i); - ASSERT_NOEXCEPT(std::to_address(p4)); - assert(std::to_address(p4) == &i); - - return true; + int i = 0; + ASSERT_NOEXCEPT(std::to_address(&i)); + assert(std::to_address(&i) == &i); + P1 p1(&i); + ASSERT_NOEXCEPT(std::to_address(p1)); + assert(std::to_address(p1) == &i); + P2 p2(&i); + ASSERT_NOEXCEPT(std::to_address(p2)); + assert(std::to_address(p2) == &i); + P3 p3(&i); + ASSERT_NOEXCEPT(std::to_address(p3)); + assert(std::to_address(p3) == &i); + P4 p4(&i); + ASSERT_NOEXCEPT(std::to_address(p4)); + assert(std::to_address(p4) == &i); + + ASSERT_SAME_TYPE(decltype(std::to_address(std::declval())), int const*); + ASSERT_SAME_TYPE(decltype(std::to_address(std::declval())), int const*); + ASSERT_SAME_TYPE(decltype(std::to_address(std::declval())), int const*); + + return true; } int main(int, char**) { - test(); - static_assert(test()); - return 0; + test(); + static_assert(test()); + return 0; } diff --git a/libcxx/test/std/utilities/memory/pointer.conversion/to_address_std_iterators.pass.cpp b/libcxx/test/std/utilities/memory/pointer.conversion/to_address_std_iterators.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/pointer.conversion/to_address_std_iterators.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// TODO: We should enable this test in Debug mode once we fix __wrap_iter +// to be a proper contiguous_iterator. +// UNSUPPORTED: LIBCXX-DEBUG-FIXME + +// template constexpr T* to_address(T* p) noexcept; +// template constexpr auto to_address(const Ptr& p) noexcept; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include "test_macros.h" + +template +void test_container_iterators(C c) +{ + const C& cc = c; + assert(std::to_address(c.begin()) == c.data()); + assert(std::to_address(c.end()) == c.data() + c.size()); + assert(std::to_address(cc.begin()) == cc.data()); + assert(std::to_address(cc.end()) == cc.data() + cc.size()); +} + +void test_valarray_iterators() +{ + std::valarray v(100); + int *p = std::to_address(std::begin(v)); + int *q = std::to_address(std::end(v)); + assert(q - p == 100); +} + +int main(int, char**) { + test_container_iterators(std::array()); + test_container_iterators(std::vector(3)); + test_container_iterators(std::string("abc")); + test_container_iterators(std::string_view("abc")); + test_container_iterators(std::span("abc")); + test_valarray_iterators(); + + return 0; +}