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 @@ -190,7 +190,7 @@ "`3118 `__","``fpos`` equality comparison unspecified", "November 2022","","","" "`3177 `__","Limit permission to specialize variable templates to program-defined types", "November 2022","|Nothing to do|","","" "`3515 `__","§[stacktrace.basic.nonmem]: ``operator<<`` should be less templatized", "November 2022","","","" -"`3545 `__","``std::pointer_traits`` should be SFINAE-friendly", "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","","","" "`3597 `__","Unsigned integer types don't model advanceable", "November 2022","","","|ranges|" 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 @@ -35,7 +35,7 @@ struct __has_element_type<_Tp, __void_t > : true_type {}; template ::value> -struct __pointer_traits_element_type; +struct __pointer_traits_element_type {}; template struct __pointer_traits_element_type<_Ptr, true> @@ -111,12 +111,14 @@ typedef _Sp<_Up, _Args...> type; }; +template +struct __pointer_traits_impl {}; + template -struct _LIBCPP_TEMPLATE_VIS pointer_traits -{ - typedef _Ptr pointer; - typedef typename __pointer_traits_element_type::type element_type; - typedef typename __pointer_traits_difference_type::type difference_type; +struct __pointer_traits_impl<_Ptr, __void_t::type>> { + typedef _Ptr pointer; + typedef typename __pointer_traits_element_type::type element_type; + typedef typename __pointer_traits_difference_type::type difference_type; #ifndef _LIBCPP_CXX03_LANG template using rebind = typename __pointer_traits_rebind::type; @@ -133,6 +135,9 @@ {return pointer::pointer_to(__r);} }; +template +struct _LIBCPP_TEMPLATE_VIS pointer_traits : __pointer_traits_impl<_Ptr> {}; + template struct _LIBCPP_TEMPLATE_VIS pointer_traits<_Tp*> { diff --git a/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.verify.cpp b/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.verify.cpp deleted file mode 100644 --- a/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.verify.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 - -// This test checks that std::contiguous_iterator uses std::to_address, which is not SFINAE-friendly -// when the type is missing the `T::element_type` typedef. - -#include - -#include -#include - -struct no_element_type { - typedef std::contiguous_iterator_tag iterator_category; - typedef int value_type; - typedef std::ptrdiff_t difference_type; - typedef int* pointer; - typedef int& reference; - typedef no_element_type self; - - no_element_type(); - - reference operator*() const; - pointer operator->() const; - auto operator<=>(const self&) const = default; - - self& operator++(); - self operator++(int); - - self& operator--(); - self operator--(int); - - self& operator+=(difference_type n); - self operator+(difference_type n) const; - friend self operator+(difference_type n, self x); - - self& operator-=(difference_type n); - self operator-(difference_type n) const; - difference_type operator-(const self& n) const; - - reference operator[](difference_type n) const; -}; - -void test() { - (void) std::contiguous_iterator; - // expected-error@*:* {{implicit instantiation of undefined template}} - // expected-note@*:* {{to_address}} -} diff --git a/libcxx/test/std/utilities/memory/pointer.conversion/to_address.verify.cpp b/libcxx/test/std/utilities/memory/pointer.conversion/to_address.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/pointer.conversion/to_address.verify.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template constexpr auto to_address(const Ptr& p) noexcept; +// Mandates: one of pointer_traits::to_address() or Ptr::operator->() +// is present. + +#include + +struct NotPtr {}; + +void test() { + (void)std::to_address(NotPtr()); // expected-error@*:* {{no matching function for call to 'to_address'}} +} diff --git a/libcxx/test/std/utilities/memory/pointer.conversion/to_address_without_pointer_traits.pass.cpp b/libcxx/test/std/utilities/memory/pointer.conversion/to_address_without_pointer_traits.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/pointer.conversion/to_address_without_pointer_traits.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template constexpr auto to_address(const Ptr& p) noexcept; +// Should not require a specialization of pointer_traits for Ptr. + +#include + +struct IntPtr { + constexpr int* operator->() const { return ptr; } + + int* ptr; +}; + +template +struct TemplatedPtr { + constexpr T* operator->() const { return ptr; } + + T* ptr; +}; + +constexpr bool test() { + int i = 0; + + static_assert(std::to_address(IntPtr(nullptr)) == nullptr); + static_assert(std::to_address(IntPtr(&i)) == &i); + + bool b = false; + + static_assert(std::to_address(TemplatedPtr(nullptr)) == nullptr); + static_assert(std::to_address(TemplatedPtr(&b)) == &b); + + return true; +} + +int main(int, char**) { + static_assert(test()); + return 0; +}