Bug #14431
openCompilation (still) fails with C++17 filesystem and Clang in C++20 mode (or higher)
0%
Description
First reported as #14352, but the chosen solution does not actually solve the problem, only a rounding issue mentioned as part of the report.
I suggested a reduction of lines 71–83 in src/web/FileUtils.C to:
#ifdef WT_FILESYSTEM_IMPL_STD
auto ftime = Wt::cpp17::filesystem::last_write_time(file);
auto systime = decltype(ftime)::clock::to_sys(ftime);
return std::chrono::time_point_cast<std::chrono::system_clock::duration>(systime);
#else // !WT_FILESYSTEM_IMPL_STD
return std::chrono::system_clock::from_time_t(Wt::cpp17::filesystem::last_write_time(file));
#endif // WT_FILESYSTEM_IMPL_STD
In my suggestion I pointed out that time_point_cast is a C++11 feature, but I missed that file_clock::to_sys is a C++20 feature, so I acknowledge the need for the WT_FILESYSTEM_IMPL_STD_CLOCK_17 macro to stay.
The relevant block of code is now lines 71–81 and looks like this:
#ifdef WT_FILESYSTEM_IMPL_STD
#ifndef WT_FILESYSTEM_IMPL_STD_CLOCK_17
return std::chrono::clock_cast<std::chrono::system_clock>(Wt::cpp17::filesystem::last_write_time(file));
#else // WT_FILESYSTEM_IMPL_STD_CLOCK_17
LOG_DEBUG("When using cpp17 or lower with std::filesystem, the result of this function is an approximation. Use boost::filesystem, instead of std::filesystem (see WT_CPP17_FILESYSTEM_IMPLEMENTATION) if this is a problem for your application.");
auto ftime = Wt::cpp17::filesystem::last_write_time(file);
return std::chrono::time_point_cast<std::chrono::system_clock::duration>(ftime - Wt::cpp17::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());
#endif //WT_FILESYSTEM_IMPL_STD_CLOCK_17
#else // !WT_FILESYSTEM_IMPL_STD
return std::chrono::system_clock::from_time_t(Wt::cpp17::filesystem::last_write_time(file));
#endif // WT_FILESYSTEM_IMPL_STD
The problem is that Clang/libc++ lacks clock_cast (even in the recently released LLVM/Clang 22). I think that clock_cast represents an improvement per se, but since it does not work with Clang, the problem is not at all gone. Therefore I would like to suggest a slightly different solution this time:
#ifdef WT_FILESYSTEM_IMPL_STD
#ifndef WT_FILESYSTEM_IMPL_STD_CLOCK_17
#if __cpp_lib_chrono >= 201803L
return std::chrono::clock_cast<std::chrono::system_clock>(Wt::cpp17::filesystem::last_write_time(file));
#else
auto ftime = Wt::cpp17::filesystem::last_write_time(file);
auto systime = decltype(ftime)::clock::to_sys(ftime);
return std::chrono::time_point_cast<std::chrono::system_clock::duration>(systime);
#endif
#else // WT_FILESYSTEM_IMPL_STD_CLOCK_17
LOG_DEBUG("When using cpp17 or lower with std::filesystem, the result of this function is an approximation. Use boost::filesystem, instead of std::filesystem (see WT_CPP17_FILESYSTEM_IMPLEMENTATION) if this is a problem for your application.");
auto ftime = Wt::cpp17::filesystem::last_write_time(file);
return std::chrono::time_point_cast<std::chrono::system_clock::duration>(ftime - Wt::cpp17::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());
#endif //WT_FILESYSTEM_IMPL_STD_CLOCK_17
#else // !WT_FILESYSTEM_IMPL_STD
return std::chrono::system_clock::from_time_t(Wt::cpp17::filesystem::last_write_time(file));
#endif // WT_FILESYSTEM_IMPL_STD
That is, inside the #ifndef WT_FILESYSTEM_IMPL_STD_CLOCK_17 block, use clock_cast if it is available (using the feature test macro __cpp_lib_chrono) and fall back on time_point_cast with the code modification I suggested if it is not.
The __cpp_lib_chrono macro will have the value 201803L or higher if and only if the standard library implements P0355R7 (that is where clock_cast came in) in full. As mentioned, libc++ does not do that, and thus we can see in libcxx/include/version (line 60) of libc++ on the main branch of the llvm-project repo that __cpp_lib_chrono is defined to 201611L.
No data to display