aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2018-05-23 17:11:06 +0100
committerJonathan Wakely <redi@gcc.gnu.org>2018-05-23 17:11:06 +0100
commitcf290ea3255625513b6ad5a5c4e189c833a67a92 (patch)
treeef3d41a212735827f10935b6954e5389c86704c2
parent7aa132501308fcb42ee2b189b9971df5a04ea0e7 (diff)
downloadgcc-cf290ea3255625513b6ad5a5c4e189c833a67a92.zip
gcc-cf290ea3255625513b6ad5a5c4e189c833a67a92.tar.gz
gcc-cf290ea3255625513b6ad5a5c4e189c833a67a92.tar.bz2
Fix handling of an empty filename at end of a path
The C++17 std::filesystem::path grammar allows an empty filename as the last component (to signify a trailing slash). The existing code does not handle this consistently, sometimes an empty filename has type _Multi and sometimes it has type _Filename. This can result in a non-empty iterator range for an empty filename component. This change ensures that empty paths always have type _Filename and will yield an empty iterator range. * include/bits/fs_path.h (path::_M_type): Change default member initializer to _Filename. (path::begin): Create past-the-end iterator for empty path. * src/filesystem/std-path.cc (path::remove_filename()): Remove debugging check. (path::has_relative_path()): Return false for empty filenames. (path::_M_split_cmpts): Set _M_type to _Filename for empty paths. Fix offset of empty final component. * testsuite/27_io/filesystem/path/itr/components.cc: New. * testsuite/27_io/filesystem/path/itr/traversal.cc: Add new inputs. From-SVN: r260616
-rw-r--r--libstdc++-v3/ChangeLog13
-rw-r--r--libstdc++-v3/include/bits/fs_path.h4
-rw-r--r--libstdc++-v3/src/filesystem/std-path.cc17
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/itr/components.cc51
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc2
5 files changed, 75 insertions, 12 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 9ca6ec6..f5d6b10 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,16 @@
+2018-05-23 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/bits/fs_path.h (path::_M_type): Change default member
+ initializer to _Filename.
+ (path::begin): Create past-the-end iterator for empty path.
+ * src/filesystem/std-path.cc (path::remove_filename()): Remove
+ debugging check.
+ (path::has_relative_path()): Return false for empty filenames.
+ (path::_M_split_cmpts): Set _M_type to _Filename for empty paths.
+ Fix offset of empty final component.
+ * testsuite/27_io/filesystem/path/itr/components.cc: New.
+ * testsuite/27_io/filesystem/path/itr/traversal.cc: Add new inputs.
+
2018-05-21 Jonathan Wakely <jwakely@redhat.com>
Add support for opening file streams from wide character strings.
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index 51af289..79a3418 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -497,7 +497,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
struct _Cmpt;
using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
_List _M_cmpts; // empty unless _M_type == _Type::_Multi
- _Type _M_type = _Type::_Multi;
+ _Type _M_type = _Type::_Filename;
};
template<>
@@ -1076,7 +1076,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{
if (_M_type == _Type::_Multi)
return iterator(this, _M_cmpts.begin());
- return iterator(this, false);
+ return iterator(this, empty());
}
inline path::iterator
diff --git a/libstdc++-v3/src/filesystem/std-path.cc b/libstdc++-v3/src/filesystem/std-path.cc
index 6f594ce..755cb7c 100644
--- a/libstdc++-v3/src/filesystem/std-path.cc
+++ b/libstdc++-v3/src/filesystem/std-path.cc
@@ -63,8 +63,6 @@ path::remove_filename()
}
else if (_M_type == _Type::_Filename)
clear();
- if (!empty() && _M_pathname.back() != '/')
- throw 1;
return *this;
}
@@ -292,7 +290,7 @@ path::has_root_path() const
bool
path::has_relative_path() const
{
- if (_M_type == _Type::_Filename)
+ if (_M_type == _Type::_Filename && !_M_pathname.empty())
return true;
if (!_M_cmpts.empty())
{
@@ -301,7 +299,7 @@ path::has_relative_path() const
++__it;
if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
++__it;
- if (__it != _M_cmpts.end())
+ if (__it != _M_cmpts.end() && !__it->_M_pathname.empty())
return true;
}
return false;
@@ -514,11 +512,13 @@ path::_M_find_extension() const
void
path::_M_split_cmpts()
{
- _M_type = _Type::_Multi;
_M_cmpts.clear();
-
if (_M_pathname.empty())
- return;
+ {
+ _M_type = _Type::_Filename;
+ return;
+ }
+ _M_type = _Type::_Multi;
size_t pos = 0;
const size_t len = _M_pathname.size();
@@ -593,8 +593,7 @@ path::_M_split_cmpts()
// An empty element, if trailing non-root directory-separator present.
if (_M_cmpts.back()._M_type == _Type::_Filename)
{
- const auto& last = _M_cmpts.back();
- pos = last._M_pos + last._M_pathname.size();
+ pos = _M_pathname.size();
_M_cmpts.emplace_back(string_type(), _Type::_Filename, pos);
}
}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/itr/components.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/components.cc
new file mode 100644
index 0000000..15736b2
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/components.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <iterator>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+void
+test01()
+{
+ for (std::filesystem::path p : __gnu_test::test_paths)
+ {
+ if (p.empty())
+ VERIFY(std::distance(p.begin(), p.end()) == 0);
+ else
+ VERIFY(std::distance(p.begin(), p.end()) != 0);
+
+ for (const std::filesystem::path& cmpt : p)
+ {
+ if (cmpt.empty())
+ VERIFY(std::distance(cmpt.begin(), cmpt.end()) == 0);
+ else
+ VERIFY(std::distance(cmpt.begin(), cmpt.end()) == 1);
+ }
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc
index 3fc60d4..c23cb14 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc
@@ -104,7 +104,7 @@ test02()
void
test03()
{
- path paths[] = { "single", "multiple/elements" };
+ path paths[] = { "single", "multiple/elements", "trailing/slash/", "/." };
for (const path& p : paths)
for (auto iter = p.begin(); iter != p.end(); ++iter)
{