from all modes. Their symbols are still provided by the dynamic library for the benefit of
existing compiled code. All of these functions have always behaved as no-ops.
+- ``std::filesystem::path::iterator``, which (in our implementation) stashes
+ a ``path`` value inside itself similar to ``istream_iterator``, now sets its
+ ``reference`` type to ``path`` and its ``iterator_category`` to ``input_iterator_tag``,
+ so that it is a conforming input iterator in C++17 and a conforming
+ ``std::bidirectional_iterator`` in C++20. Before this release, it had set its
+ ``reference`` type to ``const path&`` and its ``iterator_category`` to
+ ``bidirectional_iterator_tag``, making it a non-conforming bidirectional iterator.
+ After this change, ``for`` loops of the form ``for (auto& c : path)`` must be rewritten
+ as either ``for (auto&& c : path)`` or ``for (const auto& c : path)``.
+ ``std::reverse_iterator<path::iterator>`` is no longer rejected.
+
+
ABI Changes
-----------
};
public:
- typedef bidirectional_iterator_tag iterator_category;
+ typedef input_iterator_tag iterator_category;
+ typedef bidirectional_iterator_tag iterator_concept;
typedef path value_type;
typedef ptrdiff_t difference_type;
typedef const path* pointer;
- typedef const path& reference;
-
- typedef void
- __stashing_iterator_tag; // See reverse_iterator and __is_stashing_iterator
+ typedef path reference;
public:
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Tp, class = void>
-struct __is_stashing_iterator : false_type {};
-
-template <class _Tp>
-struct __is_stashing_iterator<_Tp, typename __void_t<typename _Tp::__stashing_iterator_tag>::type>
- : true_type {};
-
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
template <class _Iter>
class _LIBCPP_TEMPLATE_VIS reverse_iterator
_Iter __t; // no longer used as of LWG #2360, not removed due to ABI break
#endif
- static_assert(!__is_stashing_iterator<_Iter>::value,
- "The specified iterator type cannot be used with reverse_iterator; "
- "Using stashing iterators with reverse_iterator causes undefined behavior");
-
protected:
_Iter current;
public:
+++ /dev/null
-//===----------------------------------------------------------------------===//
-//
-// 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
-
-// <filesystem>
-
-// class path
-
-#include "filesystem_include.h"
-#include <iterator>
-
-
-int main(int, char**) {
- using namespace fs;
- using RIt = std::reverse_iterator<path::iterator>;
-
- // expected-error-re@*:* {{static_assert failed{{.*}} "The specified iterator type cannot be used with reverse_iterator; Using stashing iterators with reverse_iterator causes undefined behavior"}}
- {
- RIt r;
- ((void)r);
- }
-
- return 0;
-}
#include "filesystem_include.h"
+#include <cassert>
#include <iterator>
#include <type_traits>
-#include <cassert>
#include "test_macros.h"
#include "filesystem_test_helper.h"
-
-
-template <class It>
-std::reverse_iterator<It> mkRev(It it) {
- return std::reverse_iterator<It>(it);
-}
-
void checkIteratorConcepts() {
using namespace fs;
using It = path::iterator;
using Traits = std::iterator_traits<It>;
- ASSERT_SAME_TYPE(Traits::iterator_category, std::bidirectional_iterator_tag);
+ ASSERT_SAME_TYPE(path::const_iterator, It);
+#if TEST_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
+ static_assert(std::bidirectional_iterator<It>);
+#endif
ASSERT_SAME_TYPE(Traits::value_type, path);
- ASSERT_SAME_TYPE(Traits::pointer, path const*);
- ASSERT_SAME_TYPE(Traits::reference, path const&);
+ LIBCPP_STATIC_ASSERT(std::is_same<Traits::iterator_category, std::input_iterator_tag>::value, "");
+ LIBCPP_STATIC_ASSERT(std::is_same<Traits::pointer, path const*>::value, "");
+ LIBCPP_STATIC_ASSERT(std::is_same<Traits::reference, path>::value, "");
{
It it;
ASSERT_SAME_TYPE(It&, decltype(++it));
#endif
assert(checkCollectionsEqual(p.begin(), p.end(), std::begin(expect), std::end(expect)));
assert(checkCollectionsEqualBackwards(p.begin(), p.end(), std::begin(expect), std::end(expect)));
-
}
{
path p("////foo/bar/baz///");
const path expect[] = {"/", "foo", "bar", "baz", ""};
assert(checkCollectionsEqual(p.begin(), p.end(), std::begin(expect), std::end(expect)));
assert(checkCollectionsEqualBackwards(p.begin(), p.end(), std::begin(expect), std::end(expect)));
-
}
-
}
int main(int, char**) {
static int count_path_elems(const fs::path& p) {
int count = 0;
- for (auto& elem : p) {
+ for (auto&& elem : p) {
if (elem != p.root_name() && elem != "/" && elem != "")
++count;
}