From d1e50738d78a9c1493667526653bb0da55091c98 Mon Sep 17 00:00:00 2001 From: Arthur O'Dwyer Date: Thu, 26 Aug 2021 10:55:18 -0400 Subject: [PATCH] [libc++] Define insert_iterator::iter with ranges::iterator_t. The `insert_iterator::iter` member is defined as `Container::iterator` but the standard requires `iter` to be defined in terms of `ranges::iterator_t` as of C++20. So, if in C++20 or later, define the `iter` member as `ranges::iterator_t`. Original patch by Joe Loser! Differential Revision: https://reviews.llvm.org/D108575 --- libcxx/include/__iterator/insert_iterator.h | 15 ++++-- .../cxx20_iter_member.pass.cpp | 54 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 libcxx/test/std/iterators/predef.iterators/insert.iterators/insert.iterator/cxx20_iter_member.pass.cpp diff --git a/libcxx/include/__iterator/insert_iterator.h b/libcxx/include/__iterator/insert_iterator.h index 9e41319d4877..33117419881b 100644 --- a/libcxx/include/__iterator/insert_iterator.h +++ b/libcxx/include/__iterator/insert_iterator.h @@ -14,6 +14,7 @@ #include <__iterator/iterator.h> #include <__iterator/iterator_traits.h> #include <__memory/addressof.h> +#include <__ranges/access.h> #include <__utility/move.h> #include @@ -23,6 +24,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES) +template +using __insert_iterator_iter_t = ranges::iterator_t<_Container>; +#else +template +using __insert_iterator_iter_t = typename _Container::iterator; +#endif + _LIBCPP_SUPPRESS_DEPRECATED_PUSH template class _LIBCPP_TEMPLATE_VIS insert_iterator @@ -33,7 +42,7 @@ class _LIBCPP_TEMPLATE_VIS insert_iterator _LIBCPP_SUPPRESS_DEPRECATED_POP protected: _Container* container; - typename _Container::iterator iter; // FIXME: `ranges::iterator_t` in C++20 mode + __insert_iterator_iter_t<_Container> iter; public: typedef output_iterator_tag iterator_category; typedef void value_type; @@ -46,7 +55,7 @@ public: typedef void reference; typedef _Container container_type; - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 insert_iterator(_Container& __x, typename _Container::iterator __i) + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 insert_iterator(_Container& __x, __insert_iterator_iter_t<_Container> __i) : container(_VSTD::addressof(__x)), iter(__i) {} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 insert_iterator& operator=(const typename _Container::value_type& __value_) {iter = container->insert(iter, __value_); ++iter; return *this;} @@ -62,7 +71,7 @@ public: template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 insert_iterator<_Container> -inserter(_Container& __x, typename _Container::iterator __i) +inserter(_Container& __x, __insert_iterator_iter_t<_Container> __i) { return insert_iterator<_Container>(__x, __i); } diff --git a/libcxx/test/std/iterators/predef.iterators/insert.iterators/insert.iterator/cxx20_iter_member.pass.cpp b/libcxx/test/std/iterators/predef.iterators/insert.iterators/insert.iterator/cxx20_iter_member.pass.cpp new file mode 100644 index 000000000000..0327fd973af0 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/insert.iterators/insert.iterator/cxx20_iter_member.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// insert_iterator +// C++20 and above use ranges::iterator_t instead of Container::iterator. + +#include + +#include +#include + +#include "test_macros.h" + +struct NoIteratorAlias { + double data_[3] = {}; + using value_type = int; + double *begin(); + constexpr double *insert(double *pos, int value) { + *pos = value; + return pos; + } +}; + +static_assert(std::is_constructible_v, NoIteratorAlias&, double*>); +static_assert(!std::is_constructible_v, NoIteratorAlias&, int*>); + +constexpr bool test() { + NoIteratorAlias c; + double half = 0.5; + auto it = std::insert_iterator(c, c.data_); + ASSERT_SAME_TYPE(decltype(std::inserter(c, c.data_)), std::insert_iterator); + *it++ = 1 + half; // test that RHS is still implicitly converted to _Container::value_type + *it++ = 2 + half; + assert(c.data_[0] == 1.0); + assert(c.data_[1] == 2.0); + assert(c.data_[2] == 0.0); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}