From 706e2c7374ac18fdb0e2d65a85f352651ac24a71 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Thu, 13 Apr 2017 02:54:13 +0000 Subject: [PATCH] Diagnose when reverse_iterator is used on path::iterator. path::iterator isn't a strictly conforming iterator. Specifically it stashes the current element inside the iterator. This leads to UB when used with reverse_iterator since it requires the element to outlive the lifetime of the iterator. This patch adds a static_assert inside reverse_iterator to disallow "stashing iterator types", and it tags path::iterator as such a type. Additionally this patch removes all uses of reverse_iterator within the tests. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@300164 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/experimental/filesystem | 12 ++----- include/iterator | 13 ++++++++ ...erse_iterator_produces_diagnostic.fail.cpp | 31 +++++++++++++++++++ .../path.decompose/path.decompose.pass.cpp | 12 +++---- 4 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 test/libcxx/experimental/filesystem/class.path/path.itr/reverse_iterator_produces_diagnostic.fail.cpp diff --git a/include/experimental/filesystem b/include/experimental/filesystem index 04180d179..42157ba30 100644 --- a/include/experimental/filesystem +++ b/include/experimental/filesystem @@ -1092,20 +1092,12 @@ class _LIBCPP_TYPE_VIS path::iterator public: typedef bidirectional_iterator_tag iterator_category; - // FIXME: As of 3/April/2017 Clang warns on `value_type` shadowing the - // definition in path. Clang should be fixed and this should be removed. -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wshadow" -#endif typedef path value_type; -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - typedef std::ptrdiff_t difference_type; typedef const path* pointer; typedef const path& reference; + + typedef void __stashing_iterator_tag; // See reverse_iterator and __is_stashing_iterator public: _LIBCPP_INLINE_VISIBILITY iterator() : __stashed_elem_(), __path_ptr_(nullptr), diff --git a/include/iterator b/include/iterator index b8f657085..66d1a310d 100644 --- a/include/iterator +++ b/include/iterator @@ -615,6 +615,14 @@ prev(_BidiretionalIter __x, return __x; } + +template +struct __is_stashing_iterator : false_type {}; + +template +struct __is_stashing_iterator<_Tp, typename __void_t::type> + : true_type {}; + template class _LIBCPP_TEMPLATE_VIS reverse_iterator : public iterator::iterator_category, @@ -625,6 +633,11 @@ class _LIBCPP_TEMPLATE_VIS reverse_iterator { private: /*mutable*/ _Iter __t; // no longer used as of LWG #2360, not removed due to ABI break + + 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: diff --git a/test/libcxx/experimental/filesystem/class.path/path.itr/reverse_iterator_produces_diagnostic.fail.cpp b/test/libcxx/experimental/filesystem/class.path/path.itr/reverse_iterator_produces_diagnostic.fail.cpp new file mode 100644 index 000000000..6f839befb --- /dev/null +++ b/test/libcxx/experimental/filesystem/class.path/path.itr/reverse_iterator_produces_diagnostic.fail.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +#include +#include + + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + using RIt = std::reverse_iterator; + + // expected-error@iterator:* {{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); + } +} diff --git a/test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp b/test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp index 4c83481aa..078e00666 100644 --- a/test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp +++ b/test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp @@ -54,12 +54,6 @@ #include "count_new.hpp" #include "filesystem_test_helper.hpp" -template -std::reverse_iterator mkRev(It it) { - return std::reverse_iterator(it); -} - - namespace fs = std::experimental::filesystem; struct PathDecomposeTestcase { @@ -147,7 +141,11 @@ void decompPathTest() assert(checkCollectionsEqual(p.begin(), p.end(), TC.elements.begin(), TC.elements.end())); // check backwards - assert(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()), + + std::vector Parts; + for (auto it = p.end(); it != p.begin(); ) + Parts.push_back(*--it); + assert(checkCollectionsEqual(Parts.begin(), Parts.end(), TC.elements.rbegin(), TC.elements.rend())); } }