diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h index ae6fbb6b59bcf..d12750d1f81ac 100644 --- a/libcxx/include/__iterator/bounded_iter.h +++ b/libcxx/include/__iterator/bounded_iter.h @@ -16,9 +16,13 @@ #include <__config> #include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/disjunction.h> #include <__type_traits/enable_if.h> #include <__type_traits/integral_constant.h> #include <__type_traits/is_convertible.h> +#include <__type_traits/is_same.h> +#include <__type_traits/make_const_lvalue_ref.h> #include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -70,7 +74,12 @@ struct __bounded_iter { _LIBCPP_HIDE_FROM_ABI __bounded_iter(__bounded_iter const&) = default; _LIBCPP_HIDE_FROM_ABI __bounded_iter(__bounded_iter&&) = default; - template ::value, int> = 0> + template < class _OtherIterator, + __enable_if_t< + _And< is_convertible, + _Or >, + is_same > > > >::value, + int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __bounded_iter(__bounded_iter<_OtherIterator> const& __other) _NOEXCEPT : __current_(__other.__current_), __begin_(__other.__begin_), diff --git a/libcxx/include/__iterator/static_bounded_iter.h b/libcxx/include/__iterator/static_bounded_iter.h index 9794c220384f5..8f4fbdf6dff96 100644 --- a/libcxx/include/__iterator/static_bounded_iter.h +++ b/libcxx/include/__iterator/static_bounded_iter.h @@ -17,9 +17,13 @@ #include <__cstddef/size_t.h> #include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/disjunction.h> #include <__type_traits/enable_if.h> #include <__type_traits/integral_constant.h> #include <__type_traits/is_convertible.h> +#include <__type_traits/is_same.h> +#include <__type_traits/make_const_lvalue_ref.h> #include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -93,7 +97,12 @@ struct __static_bounded_iter { _LIBCPP_HIDE_FROM_ABI __static_bounded_iter(__static_bounded_iter const&) = default; _LIBCPP_HIDE_FROM_ABI __static_bounded_iter(__static_bounded_iter&&) = default; - template ::value, int> = 0> + template , + _Or >, + is_same > > > >::value, + int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __static_bounded_iter(__static_bounded_iter<_OtherIterator, _Size> const& __other) _NOEXCEPT : __storage_(__other.__storage_.__current(), __other.__storage_.__begin()) {} @@ -264,7 +273,7 @@ struct __static_bounded_iter { private: template friend struct pointer_traits; - template + template friend struct __static_bounded_iter; __static_bounded_iter_storage<_Iterator, _Size> __storage_; diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index 2856833e60079..966c4675b7049 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -17,9 +17,13 @@ #include <__iterator/iterator_traits.h> #include <__memory/addressof.h> #include <__memory/pointer_traits.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/disjunction.h> #include <__type_traits/enable_if.h> #include <__type_traits/integral_constant.h> #include <__type_traits/is_convertible.h> +#include <__type_traits/is_same.h> +#include <__type_traits/make_const_lvalue_ref.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -45,9 +49,14 @@ class __wrap_iter { public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter() _NOEXCEPT : __i_() {} - template ::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter(const __wrap_iter<_Up>& __u) _NOEXCEPT - : __i_(__u.base()) {} + template < + class _OtherIter, + __enable_if_t< _And< is_convertible, + _Or >, + is_same > > > >::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter(const __wrap_iter<_OtherIter>& __u) _NOEXCEPT + : __i_(__u.__i_) {} _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT { return *__i_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pointer operator->() const _NOEXCEPT { return std::__to_address(__i_); diff --git a/libcxx/test/libcxx/iterators/contiguous_iterators.conv.compile.pass.cpp b/libcxx/test/libcxx/iterators/contiguous_iterators.conv.compile.pass.cpp new file mode 100644 index 0000000000000..372559594143e --- /dev/null +++ b/libcxx/test/libcxx/iterators/contiguous_iterators.conv.compile.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// + +// + +// __bounded_iter<_Iter> +// __static_bounded_iter<_Iter> +// __wrap_iter<_Iter> + +// Verify that libc++-wrapped iterators do not permit slicing conversion or construction. + +#include +#include +#include +#include + +#include "test_macros.h" + +struct Base {}; +struct Derived : Base {}; + +template ::iterator>::value> +struct test_array_helper : std::true_type { + typedef typename std::array::iterator BaseIter; + typedef typename std::array::iterator DerivedIter; + typedef typename std::array::const_iterator BaseConstIter; + typedef typename std::array::const_iterator DerivedConstIter; + + static_assert(!std::is_convertible::value, ""); + static_assert(!std::is_convertible::value, ""); + static_assert(!std::is_convertible::value, ""); + static_assert(!std::is_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); +}; + +template +struct test_array_helper : std::true_type {}; + +static_assert(test_array_helper::value, ""); + +static_assert(!std::is_convertible::iterator, std::vector::iterator>::value, ""); +static_assert(!std::is_convertible::iterator, std::vector::const_iterator>::value, ""); +static_assert(!std::is_convertible::const_iterator, std::vector::const_iterator>::value, ""); +static_assert(!std::is_constructible::iterator, std::vector::iterator>::value, ""); +static_assert(!std::is_constructible::const_iterator, std::vector::iterator>::value, ""); +static_assert(!std::is_constructible::const_iterator, std::vector::const_iterator>::value, + ""); + +#if TEST_STD_VER >= 20 +static_assert(!std::is_convertible_v::iterator, std::span::iterator>); +static_assert(!std::is_convertible_v::iterator, std::span::iterator>); +static_assert(!std::is_convertible_v::iterator, std::span::iterator>); +static_assert(!std::is_constructible_v::iterator, std::span::iterator>); +static_assert(!std::is_constructible_v::iterator, std::span::iterator>); +static_assert(!std::is_constructible_v::iterator, std::span::iterator>); +#endif