From 9fc985118d9f5014afc1caf32a411ee5803fba61 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Sat, 21 Mar 2020 21:51:07 +0000 Subject: [PATCH] libstdc++: Fix path::generic_string allocator handling (PR 94242) It's not possible to construct a path::string_type from an allocator of a different type. Create the correct specialization of basic_string, and adjust path::_S_str_convert to use a basic_string_view so that it is independent of the allocator type. PR libstdc++/94242 * include/bits/fs_path.h (path::_S_str_convert): Replace first parameter with basic_string_view so that strings with different allocators can be accepted. (path::generic_string()): Use basic_string object that uses the right allocator type. * testsuite/27_io/filesystem/path/generic/94242.cc: New test. * testsuite/27_io/filesystem/path/generic/generic_string.cc: Improve test coverage. --- libstdc++-v3/ChangeLog | 12 +++++ libstdc++-v3/include/bits/fs_path.h | 11 ++-- .../27_io/filesystem/path/generic/94242.cc | 52 +++++++++++++++++++ .../filesystem/path/generic/generic_string.cc | 32 ++++++++++++ 4 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 libstdc++-v3/testsuite/27_io/filesystem/path/generic/94242.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index e58aef733ae..52944dd475c 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,15 @@ +2020-03-21 Jonathan Wakely + + PR libstdc++/94242 + * include/bits/fs_path.h (path::_S_str_convert): Replace first + parameter with basic_string_view so that strings with different + allocators can be accepted. + (path::generic_string()): Use basic_string object that uses the + right allocator type. + * testsuite/27_io/filesystem/path/generic/94242.cc: New test. + * testsuite/27_io/filesystem/path/generic/generic_string.cc: Improve + test coverage. + 2020-03-18 Jonathan Wakely PR libstdc++/94033 diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h index bf1f09929c3..fb6e8a5247f 100644 --- a/libstdc++-v3/include/bits/fs_path.h +++ b/libstdc++-v3/include/bits/fs_path.h @@ -579,7 +579,7 @@ namespace __detail template static basic_string<_CharT, _Traits, _Allocator> - _S_str_convert(const string_type&, const _Allocator& __a); + _S_str_convert(basic_string_view, const _Allocator&); void _M_split_cmpts(); @@ -1015,7 +1015,8 @@ namespace __detail /// @cond undocumented template std::basic_string<_CharT, _Traits, _Allocator> - path::_S_str_convert(const string_type& __str, const _Allocator& __a) + path::_S_str_convert(basic_string_view __str, + const _Allocator& __a) { static_assert(!is_same_v<_CharT, value_type>); @@ -1126,7 +1127,9 @@ namespace __detail #else const value_type __slash = '/'; #endif - string_type __str(__a); + using _Alloc2 = typename allocator_traits<_Allocator>::template + rebind_alloc; + basic_string, _Alloc2> __str(__a); if (_M_type() == _Type::_Root_dir) __str.assign(1, __slash); @@ -1145,7 +1148,7 @@ namespace __detail #endif if (__add_slash) __str += __slash; - __str += __elem._M_pathname; + __str += basic_string_view(__elem._M_pathname); __add_slash = __elem._M_type() == _Type::_Filename; } } diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generic/94242.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generic/94242.cc new file mode 100644 index 00000000000..c917daed94e --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generic/94242.cc @@ -0,0 +1,52 @@ +// { dg-options "-std=gnu++17" } +// { dg-do run { target c++17 } } + +// Copyright (C) 2020 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 +// . + +// C++17 30.10.7.4.7 path generic format observers [fs.path.generic.obs] + +#include +#include + +using std::filesystem::path; +using __gnu_test::SimpleAllocator; + +void +test01() +{ + path p = "//foo//bar//."; + using C = path::value_type; + auto g = p.generic_string, SimpleAllocator>(); + VERIFY( g == path("/foo/bar/.").c_str() ); +} + +void +test02() +{ + path p = "//foo//bar//."; + using C = char16_t; + auto g = p.generic_string, SimpleAllocator>(); + VERIFY( g == u"/foo/bar/." ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc index 5caf079ed9b..8554e9f8f63 100644 --- a/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc @@ -21,6 +21,7 @@ // C++17 30.10.7.4.7 path generic format observers [fs.path.generic.obs] #include +#include #include using std::filesystem::path; @@ -34,11 +35,15 @@ test01() #ifdef __CYGWIN__ VERIFY( path("//a").generic_string() == "//a" ); VERIFY( path("//a/").generic_string() == "//a/" ); + VERIFY( path("//a//").generic_string() == "//a/" ); VERIFY( path("//a/b").generic_string() == "//a/b" ); + VERIFY( path("//a//b").generic_string() == "//a/b" ); #else VERIFY( path("//a").generic_string() == "/a" ); VERIFY( path("//a/").generic_string() == "/a/" ); + VERIFY( path("//a//").generic_string() == "/a/" ); VERIFY( path("//a/b").generic_string() == "/a/b" ); + VERIFY( path("//a//b").generic_string() == "/a/b" ); #endif VERIFY( path("/a//b").generic_string() == "/a/b" ); VERIFY( path("/a//b/").generic_string() == "/a/b/" ); @@ -57,9 +62,36 @@ test02() } } +void +test03() +{ + for (path p : __gnu_test::test_paths) + { + // A path constructed from the generic format string should compare equal + // to the original, because they represent the same path. + VERIFY( path(p.generic_string()) == p ); + VERIFY( path(p.generic_wstring()) == p ); + VERIFY( path(p.generic_u8string()) == p ); + VERIFY( path(p.generic_u16string()) == p ); + VERIFY( path(p.generic_u32string()) == p ); + } + + for (path p : { "a///b//c", "///a//b//c", "a:b//c", "a://b///c" }) + { + // A path constructed from the generic format string should compare equal + // to the original, because they represent the same path. + VERIFY( path(p.generic_string()) == p ); + VERIFY( path(p.generic_wstring()) == p ); + VERIFY( path(p.generic_u8string()) == p ); + VERIFY( path(p.generic_u16string()) == p ); + VERIFY( path(p.generic_u32string()) == p ); + } +} + int main() { test01(); test02(); + test03(); } -- 2.30.2