Project

General

Profile

Actions

Bug #14352

closed

Compilation fails with C++17 filesystem and Clang in C++20 mode (or higher)

Added by Erik Solem about 1 month ago. Updated about 6 hours ago.

Status:
Closed
Priority:
Normal
Target version:
Start date:
02/23/2026
Due date:
% Done:

0%

Estimated time:

Description

When building with -DWT_CPP17_FILESYSTEM_IMPLEMENTATION="std" and compiling with Clang in C++20 mode (or higher), FileUtils.C fails to compile. The reason is the function lastWriteTime starting at line 69. The relevant lines are (I cannot add line numbers without ruining the formatting, but the first line in this snippet is line 71):

#ifdef WT_FILESYSTEM_IMPL_STD
  #ifndef WT_FILESYSTEM_IMPL_STD_CLOCK_17
      auto ftime = Wt::cpp17::filesystem::last_write_time(file);
      auto systime = decltype(ftime)::clock::to_sys(ftime);
      return std::chrono::system_clock::from_time_t(decltype(systime)::clock::to_time_t(systime));
  #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

Clang fails on line 75:

error: no viable conversion from 'time_point<[...], duration<__int128, ratio<[...], 1000000000>>>' to 'const
      time_point<[...], duration<long long, ratio<[...], 1000000>>>'
   75 |       return std::chrono::system_clock::from_time_t(decltype(systime)::clock::to_time_t(systime));
      |

I target Clang’s “native” libc++ standard library implementation, not GCC’s libstdc++, which I believe would not be affected by this issue.

After looking into this code, I have questions. First of all, why convert via time_t at all? A simple time_point_cast should be enough:

return std::chrono::time_point_cast<std::chrono::system_clock::duration>(systime);

This will, however, keep the sub-second precision that is lost in the current implementation. In my example, the file timestamp was 2026-02-23 22:03:01.145992113. The current code rounds down to the nearest whole second, giving 2026-02-23 22:03:01.000000000 (nanosecond precision) with GCC. Is this intentional? If it is, an explicit chrono::floor on line 74 solves the Clang problem without having to change the return statement on line 75 (though I would still argue that conversion via time_t is unnecessary):

-      auto systime = decltype(ftime)::clock::to_sys(ftime);
+      auto systime = std::chrono::floor<std::chrono::seconds>(decltype(ftime)::clock::to_sys(ftime));

(the program compiled with Clang will print six zeros instead of nine, as libc++ uses microsecond precision for system_clock whereas GNU libstdc++ has nanosecond precision)

I compile with C++20/C++23, so WT_FILESYSTEM_IMPL_STD_CLOCK_17 is not defined by default. If overriding this, Clang succeeds, using the return statement on line 79 instead. According to the LOG_DEBUG message, the function will then return “an approximation”, but in reality I seem to get a more accurate timestamp (although less precise), namely 2026-02-23 22:03:01.145992. This value is indeed less precise than ftime, but for Clang that precision was lost anyway when converting to system_clock. With GCC the precision is kept in the C++20 case, but it is rounded down to the nearest second, so while 01.000000000 is more precise than 01.145992, the value itself is further from 01.145992113.

As time_point_cast has been around since C++11 (long before <filesystem>), is it not better to skip the WT_FILESYSTEM_IMPL_STD_CLOCK_17 macro altogether, just keep the #ifndef case and use time_point_cast instead of conversion via time_t? That is, simplify the block of code above to (patch suggestion attached):

#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

(If rounding is desired, std::chrono::floor<std::chrono::seconds>(...) must be added to the definition of systime.)

(In my opinion the code would also be clearer if defining ftime above the #ifdef and using it in both cases, but that is not directly relevant to this issue and not part of my patch. It just looks a bit confusing when Wt::cpp17::filesystem is used inside the feature test macro used to define it.)


Files

FileUtils.C.patch (1.67 KB) FileUtils.C.patch Suggested patch Erik Solem, 02/24/2026 12:32 AM
Actions #1

Updated by Romain Mardulyn about 1 month ago

  • Assignee set to Romain Mardulyn
  • Target version set to 4.12.4
Actions #2

Updated by Romain Mardulyn about 1 month ago

  • Target version deleted (4.12.4)
Actions #3

Updated by Romain Mardulyn 25 days ago

  • Status changed from New to InProgress
  • Target version set to 4.12.6
Actions #4

Updated by Romain Mardulyn 25 days ago

  • Status changed from InProgress to Review
  • Assignee deleted (Romain Mardulyn)
Actions #5

Updated by Romain Mardulyn 22 days ago

  • Assignee set to Raf Pauwels
Actions #6

Updated by Raf Pauwels 19 days ago

  • Status changed from Review to Resolved
  • Assignee changed from Raf Pauwels to Romain Mardulyn
Actions #7

Updated by Romain Mardulyn 18 days ago

  • Status changed from Resolved to Implemented @Emweb
Actions #8

Updated by Romain Mardulyn 14 days ago

  • Status changed from Implemented @Emweb to Closed
Actions #9

Updated by Erik Solem 9 days ago

The code simplification implemented is an improvement, but it does not solve the problem, which is that compilation fails with Clang, because libc++ does not yet implement clock_cast from C++20.

Actions #10

Updated by Romain Mardulyn about 6 hours ago

  • Target version changed from 4.12.6 to 4.13.0
Actions #11

Updated by Romain Mardulyn about 6 hours ago

Hi Eric,

We will add a workaround for Clang in the next version.

Actions

Also available in: Atom PDF