From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2153) id 92D5839FE496; Thu, 17 Sep 2020 17:13:56 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 92D5839FE496 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1600362836; bh=dk0XM+BdB2aJbgMWqw3yUWTATJmNdKT/s+tsvuzKfuY=; h=From:To:Subject:Date:From; b=xNRCgFJglGjQaVmlt2moIlSkZNi+lm3QYzdFiB2Gw0ZG84/6qFg/jtvNn7UbWAqF3 qOj+WXHYrqq1TtbQLWuxQmX4YwOjXUXkbQc/SlvW6xh7AcXkCrtzUbtfdLqUhWLViK A5Vri6rz/9w44jqjZryeK3aiHh6WWhuVxZF2V6wg= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Jakub Jelinek To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc(refs/vendors/redhat/heads/gcc-8-branch)] libstdc++: Fix path::generic_string allocator handling (PR 94242) X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/vendors/redhat/heads/gcc-8-branch X-Git-Oldrev: a97ecd2487fc99f40e9e183c69e6f39009e80aca X-Git-Newrev: 1678d503a54ebf31a4bcb4ba2cdfeafd55270917 Message-Id: <20200917171356.92D5839FE496@sourceware.org> Date: Thu, 17 Sep 2020 17:13:56 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 17 Sep 2020 17:13:56 -0000 https://gcc.gnu.org/g:1678d503a54ebf31a4bcb4ba2cdfeafd55270917 commit 1678d503a54ebf31a4bcb4ba2cdfeafd55270917 Author: Jonathan Wakely Date: Sat Mar 21 21:51:07 2020 +0000 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. (cherry picked from commit 9fc985118d9f5014afc1caf32a411ee5803fba61) Diff: --- libstdc++-v3/include/bits/fs_path.h | 11 +++-- .../27_io/filesystem/path/generic/94242.cc | 53 ++++++++++++++++++++++ .../filesystem/path/generic/generic_string.cc | 35 ++++++++++++++ 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h index 7ae68f623d1..f121d82c032 100644 --- a/libstdc++-v3/include/bits/fs_path.h +++ b/libstdc++-v3/include/bits/fs_path.h @@ -477,7 +477,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 template static basic_string<_CharT, _Traits, _Allocator> - _S_str_convert(const string_type&, const _Allocator& __a); + _S_str_convert(basic_string_view, const _Allocator&); static bool _S_is_dir_sep(value_type __ch) { @@ -873,7 +873,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 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) { if (__str.size() == 0) return std::basic_string<_CharT, _Traits, _Allocator>(__a); @@ -971,7 +972,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #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); @@ -983,7 +986,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { 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..4bb32f83867 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generic/94242.cc @@ -0,0 +1,53 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// 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 16335443c76..c813987ca42 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 @@ -22,6 +22,7 @@ // C++17 30.10.7.4.7 path generic format observers [fs.path.generic.obs] #include +#include #include using std::filesystem::path; @@ -35,11 +36,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/" ); @@ -47,8 +52,38 @@ test01() VERIFY( path("/a//b//.").generic_string() == "/a/b/." ); } +void +test02() +{ + if constexpr (path::preferred_separator == L'\\') + { + // PR libstdc++/93244 + VERIFY( path("C:\\foo\\bar").generic_string() == "C:/foo/bar" ); + VERIFY( path("C://foo//bar").generic_string() == "C:/foo/bar" ); + } +} + +void +test03() +{ + for (path p : { "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. + // For GCC 8 this only works for some paths, because LWG 2936 is not + // implemented on the branch, so e.g. "/" and "//" compare not equal + 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(); }