This function was unimplemented, simply returning the native format string instead.
PR libstdc++/93245 * include/experimental/bits/fs_path.h (path::generic_string<C,T,A>()): * testsuite/experimental/filesystem/path/generic/generic_string.cc: Improve test coverage. Tested powerpc64le-linux and x86_64-w64-mingw32, committed to master. I think this could be safely backported too.
commit a577c0c26931090e7c25e56ef5ffc807627961ec Author: Jonathan Wakely <jwak...@redhat.com> Date: Sat Mar 21 22:11:44 2020 +0000 libstdc++: Fix experimental::path::generic_string (PR 93245) This function was unimplemented, simply returning the native format string instead. PR libstdc++/93245 * include/experimental/bits/fs_path.h (path::generic_string<C,T,A>()): * testsuite/experimental/filesystem/path/generic/generic_string.cc: Improve test coverage. diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h index 7b3d9926e60..d7234c08a00 100644 --- a/libstdc++-v3/include/experimental/bits/fs_path.h +++ b/libstdc++-v3/include/experimental/bits/fs_path.h @@ -1086,34 +1086,56 @@ namespace __detail inline std::u32string path::u32string() const { return string<char32_t>(); } -#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS template<typename _CharT, typename _Traits, typename _Allocator> inline std::basic_string<_CharT, _Traits, _Allocator> path::generic_string(const _Allocator& __a) const - { return string<_CharT, _Traits, _Allocator>(__a); } + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + const _CharT __slash = is_same<_CharT, wchar_t>::value + ? _CharT(L'/') + : _CharT('/'); // Assume value is correct for the encoding. +#else + const _CharT __slash = _CharT('/'); +#endif + basic_string<_CharT, _Traits, _Allocator> __str(__a); + __str.reserve(_M_pathname.size()); + bool __add_slash = false; + for (auto& __elem : *this) + { + if (__elem._M_type == _Type::_Root_dir) + { + __str += __slash; + continue; + } + if (__add_slash) + __str += __slash; + __str += __elem.string<_CharT, _Traits, _Allocator>(__a); + __add_slash = __elem._M_type == _Type::_Filename; + } + return __str; + } inline std::string - path::generic_string() const { return string(); } + path::generic_string() const { return generic_string<char>(); } #if _GLIBCXX_USE_WCHAR_T inline std::wstring - path::generic_wstring() const { return wstring(); } + path::generic_wstring() const { return generic_string<wchar_t>(); } #endif #ifdef _GLIBCXX_USE_CHAR8_T inline std::u8string - path::generic_u8string() const { return u8string(); } + path::generic_u8string() const { return generic_string<char8_t>(); } #else inline std::string - path::generic_u8string() const { return u8string(); } + path::generic_u8string() const { return generic_string<char>(); } #endif inline std::u16string - path::generic_u16string() const { return u16string(); } + path::generic_u16string() const { return generic_string<char16_t>(); } inline std::u32string - path::generic_u32string() const { return u32string(); } -#endif + path::generic_u32string() const { return generic_string<char32_t>(); } inline int path::compare(const string_type& __s) const { return compare(path(__s)); } diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/generic/generic_string.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/generic/generic_string.cc index 40b39d22023..aa977847436 100644 --- a/libstdc++-v3/testsuite/experimental/filesystem/path/generic/generic_string.cc +++ b/libstdc++-v3/testsuite/experimental/filesystem/path/generic/generic_string.cc @@ -23,27 +23,55 @@ #include <experimental/filesystem> #include <testsuite_fs.h> -#include <testsuite_hooks.h> +#include <testsuite_allocator.h> using std::experimental::filesystem::path; void test01() { - for (const path& p : __gnu_test::test_paths) + __gnu_test::compare_paths( path("///a//b///").generic_string(), "/a/b/." ); + __gnu_test::compare_paths( path("///a//b").generic_u16string(), "/a/b" ); + __gnu_test::compare_paths( path("//a//b").generic_u16string(), "//a/b" ); +} + +using __gnu_test::SimpleAllocator; + +void +test02() +{ + path p = "//foo//bar//."; + using C = char16_t; + auto g = p.generic_string<C, std::char_traits<C>, SimpleAllocator<C>>(); + VERIFY( g == u"//foo/bar/." ); +} + + +void +test03() +{ + for (path p : { "/a///b//c", "///a//b//c", "a:b//c", "a://b///c" }) { - path p2(p), p3; - p2.swap(p3); - VERIFY( p2 == path() ); - VERIFY( p3 == p ); - p2.swap(p3); - VERIFY( p2 == p ); - VERIFY( p3 == path() ); + // 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 ); } + + // Except when the original consists entirely of a root-directory with + // multiple slashes, because path("///").native() is "///" but the + // generic format string is "/". In the Filesystem TS path::compare just + // compares native strings, so path("///") != path("/"). + VERIFY( path("///").generic_string() == "/" ); } int main() { test01(); + test02(); + test03(); }