diff --git a/.travis.yml b/.travis.yml index 51e5a0a..41d04e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,7 @@ matrix: - os: osx env: MATRIX_EVAL="CC=clang && CXX=clang++ && GENERATOR=Xcode" osx_image: xcode10.2 - + install: - eval "${MATRIX_EVAL}" - | diff --git a/CMakeLists.txt b/CMakeLists.txt index 39e3d85..d538b50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9) +cmake_minimum_required(VERSION 3.7.2) project(ghcfilesystem) if(NOT DEFINED CMAKE_CXX_STANDARD) @@ -32,3 +32,19 @@ if(NOT hasParent) add_subdirectory(test) add_subdirectory(examples) endif() + +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) + +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) +set(PACKAGECONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + +configure_package_config_file(cmake/config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION ${PACKAGECONFIG_INSTALL_DIR} + PATH_VARS INCLUDE_INSTALL_DIR) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + DESTINATION ${PACKAGECONFIG_INSTALL_DIR}) diff --git a/README.md b/README.md index abade4d..0a8208b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![Supported Platforms](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-blue.svg) [![Build Status](https://travis-ci.org/gulrak/filesystem.svg?branch=master)](https://travis-ci.org/gulrak/filesystem) [![Build status](https://ci.appveyor.com/api/projects/status/t07wp3k2cddo0hpo/branch/master?svg=true)](https://ci.appveyor.com/project/gulrak/filesystem) -![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg) +[![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.1.4) # Filesystem @@ -97,6 +97,11 @@ in the standard, and there might be issues in these implementations too. ## Usage +### Downloads + +The latest release version is [v1.1.4](https://github.com/gulrak/filesystem/tree/v1.1.4) and +source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.1.4). + ### Using it as Single-File-Header As `ghc::filesystem` is at first a header-only library, it should be enough to copy the header @@ -291,18 +296,20 @@ between this and the standard C++17 API. ### LWG Defects This implementation has switchable behavior for the LWG defects +[#2682](https://wg21.cmeerw.net/lwg/issue2682), [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935) and [#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937). The currently selected behavior is following +[#2682](https://wg21.cmeerw.net/lwg/issue2682), [#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937) but not following [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935), as I feel it is a bug to report no error on a `create_directory()` or `create_directories()` where a regular file of the same name prohibits the creation of a directory and forces the user of those functions to double-check via `fs::is_directory` if it really worked. - -Update: The more intuitive approach to directory creation of treating a file with that name as an +The more intuitive approach to directory creation of treating a file with that name as an error is also advocated by the newer paper -[WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf) +[WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf), the revison +P1161R1 was agreed upon on Kona 2019 meeting [see merge](https://github.com/cplusplus/draft/issues/2703) and GCC by now switched to following its proposal ([GCC #86910](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86910)). @@ -438,6 +445,35 @@ to the expected behavior. ## Release Notes +### [v1.1.4](https://github.com/gulrak/filesystem/releases/tag/v1.1.4) + +* Additional Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)), + error in old unified `readdir/readdir_r` code of `fs::directory_iterator`; + as `readdir_r` is now depricated, I decided to drop it and the resulting + code is much easier, shorter and due to more refactoring faster +* Fix for crashing unit tests against MSVC C++17 std::filesystem +* Travis-CI now additionally test with Xcode 10.2 on macOS +* Some minor refactorings + +### [v1.1.2](https://github.com/gulrak/filesystem/releases/tag/v1.1.2) + +* Bugfix for ([#11](https://github.com/gulrak/filesystem/issues/11)), + `fs::path::lexically_normal()` had some issues with `".."`-sequences. +* Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)), + `fs::recursive_directory_iterator` could run into endless loops, + the methods depth() and pop() had issues and the copy behaviour and + `input_iterator_tag` conformance was broken, added tests +* Restructured some CMake code into a macro to ease the support for + C++17 std::filesystem builds of tests and examples for interoperability + checks. +* Some fixes on Windows tests to ease interoperability test runs. +* Reduced noise on `fs::weakly_canonical()` tests against `std::fs` +* Added simple `du` example showing the `recursive_directory_iterator` + used to add the sizes of files in a directory tree. +* Added error checking in `fs::file_time_type` test helpers +* `fs::copy()` now conforms LWG #2682, disallowing the use of + `copy_option::create_symlinks' to be used on directories + ### [v1.1.0](https://github.com/gulrak/filesystem/releases/tag/v1.1.0) * Restructuring of the project directory. The header files are now using diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in new file mode 100644 index 0000000..3d25f9f --- /dev/null +++ b/cmake/config.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +set_and_check(ghcfilesystem_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@") + +check_required_components(ghcfilesystem) diff --git a/examples/du.cpp b/examples/du.cpp index c10381f..95b9580 100644 --- a/examples/du.cpp +++ b/examples/du.cpp @@ -29,11 +29,22 @@ int main(int argc, char* argv[]) } uint64_t totalSize = 0; + int totalDirs = 0; + int totalFiles = 0; + int maxDepth = 0; try { - for(auto de : fs::recursive_directory_iterator(dir)) { + auto rdi = fs::recursive_directory_iterator(dir); + for(auto de : rdi) { + if(rdi.depth() > maxDepth) { + maxDepth = rdi.depth(); + } if(de.is_regular_file()) { totalSize += de.file_size(); + ++totalFiles; + } + else if(de.is_directory()) { + ++totalDirs; } } } @@ -41,6 +52,6 @@ int main(int argc, char* argv[]) std::cerr << "Error: " << fe.what() << std::endl; exit(1); } - std::cout << totalSize << std::endl; + std::cout << totalSize << " bytes in " << totalFiles << " files and " << totalDirs << " directories, maximum depth: " << maxDepth << std::endl; return 0; } diff --git a/include/ghc/filesystem.hpp b/include/ghc/filesystem.hpp index 602200f..3d8582f 100644 --- a/include/ghc/filesystem.hpp +++ b/include/ghc/filesystem.hpp @@ -129,6 +129,7 @@ #include #include #include +#include #include #include #include @@ -143,13 +144,23 @@ #include #endif // GHC_EXPAND_IMPL -// configure LWG conformance (see README.md) +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp): +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories +// configure LWG conformance () #define LWG_2682_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular +// file with that name, it is superceded by P1164R1, so only activate if really needed // #define LWG_2935_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) #define LWG_2937_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) -#define GHC_FILESYSTEM_VERSION 10103L +#define GHC_FILESYSTEM_VERSION 10105L namespace ghc { namespace filesystem { @@ -332,6 +343,8 @@ public: iterator end() const; private: + friend class directory_iterator; + void append_name(const char* name); static constexpr value_type generic_separator = '/'; template class input_iterator_range @@ -727,13 +740,14 @@ public: void swap(recursive_directory_iterator& rhs); private: - struct recursive_directory_iterator_impl { + struct recursive_directory_iterator_impl + { directory_options _options; bool _recursion_pending; std::stack _dir_iter_stack; recursive_directory_iterator_impl(directory_options options, bool recursion_pending) - : _options(options) - , _recursion_pending(recursion_pending) + : _options(options) + , _recursion_pending(recursion_pending) { } }; @@ -1042,7 +1056,11 @@ GHC_INLINE std::error_code make_error_code(portable_error err) case portable_error::invalid_argument: return std::error_code(ERROR_INVALID_PARAMETER, std::system_category()); case portable_error::is_a_directory: - return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category()); +#ifdef ERROR_DIRECTORY_NOT_SUPPORTED + return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category()); +#else + return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); +#endif } #else switch (err) { @@ -1198,7 +1216,7 @@ inline StringType fromUtf8(const std::string& utf8String, const typename StringT unsigned utf8_state = S_STRT; std::uint32_t codepoint = 0; while (iter < utf8String.end()) { - if (!(utf8_state = consumeUtf8Fragment(utf8_state, (uint8_t)*iter++, codepoint))) { + if ((utf8_state = consumeUtf8Fragment(utf8_state, (uint8_t)*iter++, codepoint)) == S_STRT) { if (sizeof(typename StringType::value_type) == 4) { result += codepoint; } @@ -1899,7 +1917,8 @@ inline path& path::assign(const Source& source) template <> inline path& path::assign(const path& source) { - return assign(source._path); + _path = source._path; + return *this; } template @@ -1949,6 +1968,19 @@ GHC_INLINE path& path::operator/=(const path& p) return *this; } +GHC_INLINE void path::append_name(const char* name) +{ + if (_path.empty()) { + this->operator/=(path(name)); + } + else { + if (_path.back() != path::generic_separator) { + _path.push_back(path::generic_separator); + } + _path += name; + } +} + #endif // GHC_EXPAND_IMPL template @@ -2401,7 +2433,7 @@ GHC_INLINE path path::lexically_normal() const continue; } else if (*(--dest.end()) != "..") { - if(dest._path.back() == generic_separator) { + if (dest._path.back() == generic_separator) { dest._path.pop_back(); } dest.remove_filename(); @@ -2988,7 +3020,7 @@ GHC_INLINE void copy(const path& from, const path& to, copy_options options, std } } #ifdef LWG_2682_BEHAVIOUR - else if(is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) { + else if (is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) { ec = detail::make_error_code(detail::portable_error::is_a_directory); } #endif @@ -4527,7 +4559,8 @@ public: if (_dirHandle != INVALID_HANDLE_VALUE) { do { if (FindNextFileW(_dirHandle, &_findData)) { - _current = _base / std::wstring(_findData.cFileName); + _current = _base; + _current.append_name(detail::toUtf8(_findData.cFileName).c_str()); copyToDirEntry(ec); } else { @@ -4574,32 +4607,16 @@ public: // POSIX implementation class directory_iterator::impl { - size_t directory_entry_buffer_size(DIR* d) - { - size_t result = std::max(sizeof(::dirent), sizeof(::dirent) - sizeof(::dirent::d_name) + NAME_MAX) + 1; - if (d) { - long rc = ::fpathconf(dirfd(d), _PC_NAME_MAX); - if (rc > long(result)) { - result = static_cast(rc); - } - } - return result; - } - public: impl(const path& path, directory_options options) : _base(path) , _options(options) - , _dir((path.empty() ? nullptr : ::opendir(path.native().c_str())), - [](DIR* d) { - if (d) { - ::closedir(d); - } - }) - , _bufferSize(directory_entry_buffer_size(_dir.get())) - , _buffer(new char[_bufferSize]) - , _entry(reinterpret_cast<::dirent*>(&_buffer[0])) + , _dir(nullptr) + , _entry(nullptr) { + if (!path.empty()) { + _dir = ::opendir(path.native().c_str()); + } if (!path.empty()) { if (!_dir) { auto error = errno; @@ -4614,40 +4631,30 @@ public: } } impl(const impl& other) = delete; - int i_readdir_r(DIR* dir, struct dirent* entry, struct dirent** result) + ~impl() { -#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24)) - errno = 0; - auto de = readdir(dir); - if (de) { - *entry = *de; - *result = entry; - return 0; + if (_dir) { + ::closedir(_dir); } - return errno; -#else - return ::readdir_r(dir, entry, result); -#endif } void increment(std::error_code& ec) { if (_dir) { do { - dirent* result = 0; - if (0 == i_readdir_r(_dir.get(), _entry, &result)) { - if (result) { - _current = _base / path(_entry->d_name); - _dir_entry = directory_entry(_current, ec); - } - else { - _dir.reset(); - _current = path(); - break; - } + errno = 0; + _entry = readdir(_dir); + if (_entry) { + _current = _base; + _current.append_name(_entry->d_name); + _dir_entry = directory_entry(_current, ec); } else { + ::closedir(_dir); + _dir = nullptr; _current = path(); - ec = std::error_code(errno, std::system_category()); + if (errno) { + ec = std::error_code(errno, std::system_category()); + } break; } } while (std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); @@ -4656,9 +4663,7 @@ public: path _base; directory_options _options; path _current; - std::shared_ptr _dir; - size_t _bufferSize; - std::unique_ptr _buffer; + DIR* _dir; struct ::dirent* _entry; directory_entry _dir_entry; std::error_code _ec; @@ -4883,9 +4888,14 @@ GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment else { _impl->_dir_iter_stack.top().increment(ec); } - while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { + if (!ec) { + while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { + _impl->_dir_iter_stack.pop(); + _impl->_dir_iter_stack.top().increment(ec); + } + } + else if (!_impl->_dir_iter_stack.empty()) { _impl->_dir_iter_stack.pop(); - _impl->_dir_iter_stack.top().increment(ec); } _impl->_recursion_pending = true; return *this; @@ -4906,10 +4916,10 @@ GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec) *this = recursive_directory_iterator(); } else { - while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { + do { _impl->_dir_iter_stack.pop(); _impl->_dir_iter_stack.top().increment(ec); - } + } while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()); } } diff --git a/include/ghc/fs_std.hpp b/include/ghc/fs_std.hpp index 2b500fb..9b54a0d 100644 --- a/include/ghc/fs_std.hpp +++ b/include/ghc/fs_std.hpp @@ -33,7 +33,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // //--------------------------------------------------------------------------------------- -// fs_std.hpp - The dynamic switching header for that includes std::filesystem if detected +// fs_std.hpp - The dynamic switching header that includes std::filesystem if detected // or ghc::filesystem if not, and makes the resulting API available in the // namespace fs. //--------------------------------------------------------------------------------------- diff --git a/test/filesystem_test.cpp b/test/filesystem_test.cpp index a0629ad..34cf108 100644 --- a/test/filesystem_test.cpp +++ b/test/filesystem_test.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -87,28 +88,34 @@ using fstream = ghc::filesystem::fstream; #endif #include "catch.hpp" +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Behaviour Switches (should match the config in ghc/filesystem.hpp): +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories #define TEST_LWG_2682_BEHAVIOUR -//#define TEST_LWG_2935_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular +// file with that name, it is superceded by P1164R1, so only activate if really needed +// #define TEST_LWG_2935_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) #define TEST_LWG_2937_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template std::time_t to_time_t(TP tp) { - // Based on trick from: Nico Josuttis, C++17 - The Complete Guide using namespace std::chrono; auto sctp = time_point_cast(tp - TP::clock::now() + system_clock::now()); - //system_clock::duration dt = duration_cast(tp - TP::clock::now()); return system_clock::to_time_t(sctp); } template TP from_time_t(std::time_t t) { - // Based on trick from: Nico Josuttis, C++17 - The Complete Guide using namespace std::chrono; auto sctp = system_clock::from_time_t(t); auto tp = time_point_cast(sctp - system_clock::now() + TP::clock::now()); - // system_clock::duration dt = duration_cast(tp - TP::clock::now()); return tp; } @@ -288,7 +295,7 @@ bool operator!=(TestAllocator const& x, TestAllocator const& y) noexcept return !(x == y); } -TEST_CASE("Temporary Directory", "[temp dir]") +TEST_CASE("Temporary Directory", "[fs.test.tempdir]") { fs::path tempPath; { @@ -300,6 +307,21 @@ TEST_CASE("Temporary Directory", "[temp dir]") REQUIRE(!fs::exists(tempPath)); } +#ifdef GHC_FILESYSTEM_VERSION +TEST_CASE("fs::detail::fromUf88", "[filesystem][fs.detail.utf8]") +{ + CHECK(fs::detail::fromUtf8("foobar").length() == 6); + CHECK(fs::detail::fromUtf8("foobar") == L"foobar"); + CHECK(fs::detail::fromUtf8(u8"föobar").length() == 6); + CHECK(fs::detail::fromUtf8(u8"föobar") == L"föobar"); + + CHECK(fs::detail::toUtf8(std::wstring(L"foobar")).length() == 6); + CHECK(fs::detail::toUtf8(std::wstring(L"foobar")) == "foobar"); + CHECK(fs::detail::toUtf8(std::wstring(L"föobar")).length() == 7); + CHECK(fs::detail::toUtf8(std::wstring(L"föobar")) == u8"föobar"); +} +#endif + #ifndef GHC_OS_WINDOWS TEST_CASE("30.10.8.1 path(\"//host\").has_root_name()", "[filesystem][path][fs.path.generic]") { @@ -1228,29 +1250,73 @@ TEST_CASE("30.10.14 class recursive_directory_iterator", "[filesystem][recursive fs::recursive_directory_iterator rd5; rd5 = rd4; } -/* - if(1) { - fs::path d = ".."; - int maxDepth = 2; - fs::recursive_directory_iterator dit(d); - std::cout << d << std::endl; - for(auto & f : dit) { -#if 1 - if(dit.depth()<=maxDepth) { - std::cout << dit.depth() << ": " << f.path() << std::endl; + { + TemporaryDirectory t(TempOpt::change_path); + generateFile("a"); + fs::create_directory("d1"); + fs::create_directory("d1/d2"); + generateFile("d1/b"); + generateFile("d1/c"); + generateFile("d1/d2/d"); + generateFile("e"); + auto iter = fs::recursive_directory_iterator("."); + std::multimap result; + while(iter != fs::recursive_directory_iterator()) { + result.insert(std::make_pair(iter->path().generic_string(), iter.depth())); + ++iter; + } + std::stringstream os; + for(auto p : result) { + os << "[" << p.first << "," << p.second << "],"; + } + CHECK(os.str() == "[./a,0],[./d1,0],[./d1/b,1],[./d1/c,1],[./d1/d2,1],[./d1/d2/d,2],[./e,0],"); + } + { + TemporaryDirectory t(TempOpt::change_path); + generateFile("a"); + fs::create_directory("d1"); + fs::create_directory("d1/d2"); + generateFile("d1/d2/b"); + generateFile("e"); + auto iter = fs::recursive_directory_iterator("."); + std::multimap result; + while(iter != fs::recursive_directory_iterator()) { + result.insert(std::make_pair(iter->path().generic_string(), iter.depth())); + if(iter->path() == "./d1/d2") { + iter.disable_recursion_pending(); + } + ++iter; + } + std::stringstream os; + for(auto p : result) { + os << "[" << p.first << "," << p.second << "],"; + } + CHECK(os.str() == "[./a,0],[./d1,0],[./d1/d2,1],[./e,0],"); + } + { + TemporaryDirectory t(TempOpt::change_path); + generateFile("a"); + fs::create_directory("d1"); + fs::create_directory("d1/d2"); + generateFile("d1/d2/b"); + generateFile("e"); + auto iter = fs::recursive_directory_iterator("."); + std::multimap result; + while(iter != fs::recursive_directory_iterator()) { + result.insert(std::make_pair(iter->path().generic_string(), iter.depth())); + if(iter->path() == "./d1/d2") { + iter.pop(); } else { - dit.pop(); + ++iter; } -#else - std::cout << dit.depth() << ": " << f.path() << std::endl; - if(dit.depth()>maxDepth) { - dit.disable_recursion_pending(); - } -#endif } + std::stringstream os; + for(auto p : result) { + os << "[" << p.first << "," << p.second << "],"; + } + CHECK(os.str() == "[./a,0],[./d1,0],[./d1/d2,1],[./e,0],"); } - */ } TEST_CASE("30.10.15.1 absolute", "[filesystem][operations][fs.op.absolute]") @@ -1447,7 +1513,7 @@ TEST_CASE("30.10.15.6 create_directories", "[filesystem][operations][fs.op.creat CHECK(!fs::is_directory(p)); CHECK(!fs::create_directories(p, ec)); #else - INFO("This test expects conformance predating LWG #2935 result. (As suggested by WG21 P1164R0, implemented by GCC with issue #86910.)"); + INFO("This test expects conformance with P1164R1. (implemented by GCC with issue #86910.)"); p = t.path() / "testfile"; generateFile(p); CHECK(fs::is_regular_file(p)); @@ -1491,7 +1557,7 @@ TEST_CASE("30.10.15.7 create_directory", "[filesystem][operations][fs.op.create_ CHECK(!fs::is_directory(p)); CHECK(!fs::create_directories(p, ec)); #else - INFO("This test expects conformance predating LWG #2935 result. (As suggested by WG21 P1164R0, implemented by GCC with issue #86910.)"); + INFO("This test expects conformance with P1164R1. (implemented by GCC with issue #86910.)"); p = t.path() / "testfile"; generateFile(p); CHECK(fs::is_regular_file(p));