libstdc++/71005 fix post-increment for filesystem iterators
authorJonathan Wakely <jwakely@redhat.com>
Tue, 10 May 2016 11:25:06 +0000 (12:25 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 10 May 2016 11:25:06 +0000 (12:25 +0100)
PR libstdc++/71005
* include/experimental/bits/fs_dir.h (__directory_iterator_proxy):
New type.
(directory_iterator::operator++(int)): Return proxy.
(recursive_directory_iterator::operator++(int)): Likewise.
* testsuite/experimental/filesystem/iterators/directory_iterator.cc:
Test post-increment.
* testsuite/experimental/filesystem/iterators/
recursive_directory_iterator.cc: Likewise.

From-SVN: r236072

libstdc++-v3/ChangeLog
libstdc++-v3/include/experimental/bits/fs_dir.h
libstdc++-v3/testsuite/experimental/filesystem/iterators/directory_iterator.cc
libstdc++-v3/testsuite/experimental/filesystem/iterators/recursive_directory_iterator.cc

index 1cdb7f4e911816b9293030703276c57058cd7179..58f6646b8546ff60632d68fa9c6d90b19bc9bfff 100644 (file)
@@ -1,3 +1,15 @@
+2016-05-10  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/71005
+       * include/experimental/bits/fs_dir.h (__directory_iterator_proxy):
+       New type.
+       (directory_iterator::operator++(int)): Return proxy.
+       (recursive_directory_iterator::operator++(int)): Likewise.
+       * testsuite/experimental/filesystem/iterators/directory_iterator.cc:
+       Test post-increment.
+       * testsuite/experimental/filesystem/iterators/
+       recursive_directory_iterator.cc: Likewise.
+
 2016-05-09  Jonathan Wakely  <jwakely@redhat.com>
 
        PR libstdc++/71004
@@ -20,7 +32,7 @@
        * include/experimental/bits/fs_dir.h (recursive_directory_iterator):
        Initialize scalar member variables in default constructor.
        * testsuite/experimental/filesystem/iterators/
-       recursive_directory_iterator.cc: Teste default construction.
+       recursive_directory_iterator.cc: Test default construction.
 
 2016-05-05  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
index f128ccecf7acec6c76334210eb864320e8110eba..5fd41c2127fdaa2acdd353898d6ea7cd55a6ec98 100644 (file)
@@ -153,8 +153,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   };
 
   struct _Dir;
+  class directory_iterator;
   class recursive_directory_iterator;
 
+  struct __directory_iterator_proxy
+  {
+    const directory_entry& operator*() const noexcept { return _M_entry; }
+
+  private:
+    friend class directory_iterator;
+    friend class recursive_directory_iterator;
+
+    explicit
+    __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }
+
+    directory_entry _M_entry;
+  };
+
   class directory_iterator
   {
   public:
@@ -177,7 +192,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     : directory_iterator(__p, directory_options::none, __ec) { }
 
     directory_iterator(const path& __p,
-      directory_options __options, error_code& __ec) noexcept
+                      directory_options __options,
+                      error_code& __ec) noexcept
     : directory_iterator(__p, __options, &__ec) { }
 
     directory_iterator(const directory_iterator& __rhs) = default;
@@ -186,19 +202,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
     ~directory_iterator() = default;
 
-    directory_iterator& operator=(const directory_iterator& __rhs) = default;
-    directory_iterator& operator=(directory_iterator&& __rhs) noexcept = default;
+    directory_iterator&
+    operator=(const directory_iterator& __rhs) = default;
+
+    directory_iterator&
+    operator=(directory_iterator&& __rhs) noexcept = default;
 
     const directory_entry& operator*() const;
     const directory_entry* operator->() const { return &**this; }
     directory_iterator&    operator++();
     directory_iterator&    increment(error_code& __ec) noexcept;
 
-    directory_iterator operator++(int)
+    __directory_iterator_proxy operator++(int)
     {
-      auto __tmp = *this;
+      __directory_iterator_proxy __pr{**this};
       ++*this;
-      return __tmp;
+      return __pr;
     }
 
   private:
@@ -274,18 +293,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
     // modifiers
     recursive_directory_iterator&
-      operator=(const recursive_directory_iterator& __rhs) noexcept;
+    operator=(const recursive_directory_iterator& __rhs) noexcept;
     recursive_directory_iterator&
-      operator=(recursive_directory_iterator&& __rhs) noexcept;
+    operator=(recursive_directory_iterator&& __rhs) noexcept;
 
     recursive_directory_iterator& operator++();
     recursive_directory_iterator& increment(error_code& __ec) noexcept;
 
-    recursive_directory_iterator operator++(int)
+    __directory_iterator_proxy operator++(int)
     {
-      auto __tmp = *this;
+      __directory_iterator_proxy __pr{**this};
       ++*this;
-      return __tmp;
+      return __pr;
     }
 
     void pop();
index 28b948f2b1284c923805f001c09249d1a74aa6d4..ce9f437b0df06080e40859779d9fc094e045a49e 100644 (file)
@@ -70,8 +70,53 @@ test01()
   remove_all(p, ec);
 }
 
+void
+test02()
+{
+  bool test __attribute__((unused)) = false;
+
+  std::error_code ec;
+  const auto p = __gnu_test::nonexistent_path();
+  create_directory(p, fs::current_path(), ec);
+  create_directory_symlink(p, p / "l", ec);
+  VERIFY( !ec );
+
+  // Test post-increment (libstdc++/71005)
+  auto iter = fs::directory_iterator(p, ec);
+  VERIFY( !ec );
+  VERIFY( iter != fs::directory_iterator() );
+  const auto entry1 = *iter;
+  const auto entry2 = *iter++;
+  VERIFY( entry1 == entry2 );
+  VERIFY( entry1.path() == p/"l" );
+  VERIFY( iter == fs::directory_iterator() );
+
+  remove_all(p, ec);
+}
+
+void
+test03()
+{
+  bool test __attribute__((unused)) = false;
+
+  std::error_code ec;
+  const auto p = __gnu_test::nonexistent_path();
+  create_directories(p / "longer_than_small_string_buffer", ec);
+  VERIFY( !ec );
+
+  // Test for no reallocation on each dereference (this is a GNU extension)
+  auto iter = fs::directory_iterator(p, ec);
+  const auto* s1 = iter->path().c_str();
+  const auto* s2 = iter->path().c_str();
+  VERIFY( s1 == s2 );
+
+  remove_all(p, ec);
+}
+
 int
 main()
 {
   test01();
+  test02();
+  test03();
 }
index b5f71be653dbce535c34556a03164cd363e87968..fb4c31ec9add7e33dba9898e1716dcc97f6706d9 100644 (file)
@@ -102,7 +102,53 @@ test02()
 {
   bool test __attribute__((unused)) = false;
 
-  // libstdc++71004
+  std::error_code ec;
+  const auto p = __gnu_test::nonexistent_path();
+  create_directories(p / "d1/d2", ec);
+  VERIFY( !ec );
+
+  // Test post-increment (libstdc++/71005)
+  auto iter = fs::recursive_directory_iterator(p, ec);
+  VERIFY( !ec );
+  VERIFY( iter != fs::recursive_directory_iterator() );
+  const auto entry1 = *iter;
+  const auto entry2 = *iter++;
+  VERIFY( entry1 == entry2 );
+  VERIFY( entry1.path() == p/"d1" );
+  const auto entry3 = *iter;
+  const auto entry4 = *iter++;
+  VERIFY( entry3 == entry4 );
+  VERIFY( entry3.path() == p/"d1/d2" );
+  VERIFY( iter == fs::recursive_directory_iterator() );
+
+  remove_all(p, ec);
+}
+
+void
+test03()
+{
+  bool test __attribute__((unused)) = false;
+
+  std::error_code ec;
+  const auto p = __gnu_test::nonexistent_path();
+  create_directories(p / "longer_than_small_string_buffer", ec);
+  VERIFY( !ec );
+
+  // Test for no reallocation on each dereference (this is a GNU extension)
+  auto iter = fs::recursive_directory_iterator(p, ec);
+  const auto* s1 = iter->path().c_str();
+  const auto* s2 = iter->path().c_str();
+  VERIFY( s1 == s2 );
+
+  remove_all(p, ec);
+}
+
+void
+test04()
+{
+  bool test __attribute__((unused)) = false;
+
+  // libstdc++/71004
   const fs::recursive_directory_iterator it;
   VERIFY( it == fs::recursive_directory_iterator() );
 }
@@ -112,4 +158,6 @@ main()
 {
   test01();
   test02();
+  test03();
+  test04();
 }