Make filesystem::path safe for self assignment

The standard says "If *this and p are the same object, has no effect."
Previously we ended up clearing the path.

	* include/bits/fs_path.h (path::operator=(path&&)): Check for self
	assignment.
	* src/c++17/fs_path.cc (path::operator=(const path&)): Likewise.
	* testsuite/27_io/filesystem/path/assign/copy.cc: Test self
	assignment.

From-SVN: r270171
This commit is contained in:
Jonathan Wakely 2019-04-05 17:56:14 +01:00 committed by Jonathan Wakely
parent 10f26de915
commit d96f11a272
4 changed files with 30 additions and 0 deletions

View File

@ -1,5 +1,11 @@
2019-04-05 Jonathan Wakely <jwakely@redhat.com>
* include/bits/fs_path.h (path::operator=(path&&)): Check for self
assignment.
* src/c++17/fs_path.cc (path::operator=(const path&)): Likewise.
* testsuite/27_io/filesystem/path/assign/copy.cc: Test self
assignment.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.

View File

@ -877,6 +877,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
inline path&
path::operator=(path&& __p) noexcept
{
if (&__p == this) [[__unlikely__]]
return *this;
_M_pathname = std::move(__p._M_pathname);
_M_cmpts = std::move(__p._M_cmpts);
__p.clear();

View File

@ -444,6 +444,9 @@ path::_List::reserve(int newcap, bool exact = false)
path&
path::operator=(const path& p)
{
if (&p == this) [[__unlikely__]]
return *this;
_M_pathname.reserve(p._M_pathname.length());
_M_cmpts = p._M_cmpts; // might throw
_M_pathname = p._M_pathname; // won't throw because we reserved enough space

View File

@ -20,6 +20,7 @@
#include <filesystem>
#include <testsuite_fs.h>
#include <testsuite_hooks.h>
using std::filesystem::path;
using __gnu_test::compare_paths;
@ -47,9 +48,26 @@ test02()
}
}
void
test03()
{
// self assignment should have no effect
const path orig = "foo/bar/baz";
path p = orig;
const auto ptr1 = p.c_str();
const auto ptr2 = p.begin()->c_str();
p = std::move(p);
__gnu_test::compare_paths(p, orig);
p = p;
__gnu_test::compare_paths(p, orig);
VERIFY( ptr1 == p.c_str() );
VERIFY( ptr2 == p.begin()->c_str() );
}
int
main()
{
test01();
test02();
test03();
}