[libcxx] r337960 - [libc++] Use __int128_t to represent file_time_type.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 25 17:37:25 PDT 2018


On Wed, Jul 25, 2018 at 6:03 PM Alex L <arphaman at gmail.com> wrote:

> Hmm, looks like the added test is failing on Darwin even after your fixes.
>
> Do you have an idea of why that could be?
>

Not yet, working on it now.
I'm failing to reproduce it on my macbook though. If you can, any
information about what's going on would be helpful.
Like what are those actual values?


>
>
> http://lab.llvm.org:8080/green/job/libcxx_master_cmake/4784/testReport/junit/libc++/std_experimental_filesystem_fs_op_funcs_fs_op_last_write_time/last_write_time_pass_cpp/
>
> Compiled With:
> ['/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++',
> '-o',
> '/Users/buildslave/jenkins/sharedspace/libcxx/build/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/Output/last_write_time.pass.cpp.o',
> '-x', 'c++',
> '/Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp',
> '-c', '-v', '-arch', 'x86_64', '-mmacosx-version-min=10.13',
> '-D_LIBCPP_DISABLE_AVAILABILITY', '-ftemplate-depth=270',
> '-Werror=thread-safety', '-std=c++11', '-include',
> '/Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/support/nasty_macros.hpp',
> '-nostdinc++',
> '-I/Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/include',
> '-I/Users/buildslave/jenkins/sharedspace/libcxx/build/include/c++build',
> '-isysroot',
> '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk',
> '-I/Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/support',
> '-DLIBCXX_FILESYSTEM_STATIC_TEST_ROOT="/Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/Inputs/static_test_env"',
> '-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT="/Users/buildslave/jenkins/sharedspace/libcxx/build/test/filesystem/Output/dynamic_env"',
> '-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER="/usr/local/opt/python at 2/bin/python2.7
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/support/filesystem_dynamic_test_helper.py"',
> '-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER', '-Wall', '-Wextra', '-Werror',
> '-Wuser-defined-warnings', '-Wshadow', '-Wno-unused-command-line-argument',
> '-Wno-attributes', '-Wno-pessimizing-move', '-Wno-c++11-extensions',
> '-Wno-user-defined-literals', '-Wno-noexcept-type',
> '-Wno-aligned-allocation-unavailable', '-Wsign-compare',
> '-Wunused-variable', '-Wunused-parameter', '-Wunreachable-code',
> '-Wno-conversion', '-Wno-unused-local-typedef', '-c', '&&',
> '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++',
> '-o',
> '/Users/buildslave/jenkins/sharedspace/libcxx/build/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/Output/last_write_time.pass.cpp.exe',
> '/Users/buildslave/jenkins/sharedspace/libcxx/build/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/Output/last_write_time.pass.cpp.o',
> '-v', '-arch', 'x86_64', '-mmacosx-version-min=10.13',
> '-D_LIBCPP_DISABLE_AVAILABILITY', '-ftemplate-depth=270',
> '-L/Users/buildslave/jenkins/sharedspace/libcxx/build/lib',
> '-Wl,-rpath,/Users/buildslave/jenkins/sharedspace/libcxx/build/lib',
> '-nodefaultlibs', '-lc++experimental', '-lc++', '-lSystem']
> Command:
> ['/Users/buildslave/jenkins/sharedspace/libcxx/build/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/Output/last_write_time.pass.cpp.exe']
> Exit Code: 1
> Standard Error:
> --
> In set_last_write_time_dynamic_env_test():451 Assertion
> TEST_CHECK(CompareTime(got_time, TC.new_time)) failed.
>     in file:
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>
> In set_last_write_time_dynamic_env_test():451 Assertion
> TEST_CHECK(CompareTime(got_time, TC.new_time)) failed.
>     in file:
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>
> In set_last_write_time_dynamic_env_test():451 Assertion
> TEST_CHECK(CompareTime(got_time, TC.new_time)) failed.
>     in file:
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>
> In set_last_write_time_dynamic_env_test():451 Assertion
> TEST_CHECK(CompareTime(got_time, TC.new_time)) failed.
>     in file:
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>
> In set_last_write_time_dynamic_env_test():451 Assertion
> TEST_CHECK(CompareTime(got_time, TC.new_time)) failed.
>     in file:
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>
> In set_last_write_time_dynamic_env_test():451 Assertion
> TEST_CHECK(CompareTime(got_time, TC.new_time)) failed.
>     in file:
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>
> In set_last_write_time_dynamic_env_test():451 Assertion
> TEST_CHECK(CompareTime(got_time, TC.new_time)) failed.
>     in file:
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>
> In set_last_write_time_dynamic_env_test():451 Assertion
> TEST_CHECK(CompareTime(got_time, TC.new_time)) failed.
>     in file:
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>
> In last_write_time_symlink_test():477 Assertion TEST_CHECK(got_time ==
> new_time) failed.
>     in file:
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>
> In last_write_time_symlink_test():479 Assertion
> TEST_CHECK(CompareTime(LastWriteTime(file), new_time)) failed.
>     in file:
> /Users/buildslave/jenkins/sharedspace/libcxx/libcxx.src/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>
> Summary for testsuite last_write_time_test_suite:
>     7 of 9 test cases passed.
>     78 of 88 assertions passed.
>     0 unsupported test cases.
> --
>
> Compiled test failed unexpectedly!
>
> Thanks,
> Alex
>
>
> On 25 July 2018 at 17:00, Alex L <arphaman at gmail.com> wrote:
>
>> Sure! Fixed it up in r337984.
>>
>> On 25 July 2018 at 15:03, Eric Fiselier <eric at efcs.ca> wrote:
>>
>>>
>>>
>>> On Wed, Jul 25, 2018 at 3:39 PM Alex L <arphaman at gmail.com> wrote:
>>>
>>>> Looks like this works:
>>>>
>>>> +++ b/src/experimental/filesystem/filesystem_common.h
>>>> @@ -393,7 +393,7 @@ bool set_file_times(const path& p,
>>>> std::array<TimeSpec, 2> const& TS,
>>>>                      error_code& ec) {
>>>>  #if !defined(_LIBCPP_USE_UTIMENSAT)
>>>>    using namespace chrono;
>>>> -  auto Convert = [](long nsec) {
>>>> +  auto Convert = [](long nsec) ->
>>>> decltype(std::declval<::timeval>().tv_usec) {
>>>>      return duration_cast<microseconds>(nanoseconds(nsec)).count();
>>>>    };
>>>>    struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec,
>>>> Convert(TS[0].tv_nsec)},
>>>>
>>>> I will commit this fix in a couple of minutes.
>>>>
>>>
>>> I think I would prefer an explicit cast to an implicit one since the
>>> narrowing is intended, and should be safe.
>>>
>>> Maybe:
>>>
>>> auto Convert [](long nsec) {
>>>   using int_type = decltype(::timeval::tv_usec);
>>>   auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
>>>   return static_cast<int_type>(dur);
>>> };
>>>
>>> ?
>>>
>>>>
>>>> On 25 July 2018 at 14:27, Eric Fiselier <eric at efcs.ca> wrote:
>>>>
>>>>> Thanks. let me know if you want me to take over
>>>>>
>>>>> On Wed, Jul 25, 2018, 3:22 PM Alex L, <arphaman at gmail.com> wrote:
>>>>>
>>>>>>
>>>>>>
>>>>>> On 25 July 2018 at 13:51, Eric Fiselier via cfe-commits <
>>>>>> cfe-commits at lists.llvm.org> wrote:
>>>>>>
>>>>>>> Author: ericwf
>>>>>>> Date: Wed Jul 25 13:51:49 2018
>>>>>>> New Revision: 337960
>>>>>>>
>>>>>>> URL: http://llvm.org/viewvc/llvm-project?rev=337960&view=rev
>>>>>>> Log:
>>>>>>> [libc++] Use __int128_t to represent file_time_type.
>>>>>>>
>>>>>>> Summary:
>>>>>>> The ``file_time_type`` time point is used to represent the write
>>>>>>> times for files.
>>>>>>> Its job is to act as part of a C++ wrapper for less ideal system
>>>>>>> interfaces. The
>>>>>>> underlying filesystem uses the ``timespec`` struct for the same
>>>>>>> purpose.
>>>>>>>
>>>>>>> However, the initial implementation of ``file_time_type`` could not
>>>>>>> represent
>>>>>>> either the range or resolution of ``timespec``, making it
>>>>>>> unsuitable. Fixing
>>>>>>> this requires an implementation which uses more than 64 bits to
>>>>>>> store the
>>>>>>> time point.
>>>>>>>
>>>>>>> I primarily considered two solutions: Using ``__int128_t`` and using
>>>>>>> a
>>>>>>> arithmetic emulation of ``timespec``. Each has its pros and cons,
>>>>>>> and both
>>>>>>> come with more than one complication.
>>>>>>>
>>>>>>> However, after a lot of consideration, I decided on using
>>>>>>> `__int128_t`. This patch implements that change.
>>>>>>>
>>>>>>> Please see the [FileTimeType Design Document](
>>>>>>> http://libcxx.llvm.org/docs/DesignDocs/FileTimeType.html) for more
>>>>>>> information.
>>>>>>>
>>>>>>> Reviewers: mclow.lists, ldionne, joerg, arthur.j.odwyer, EricWF
>>>>>>>
>>>>>>> Reviewed By: EricWF
>>>>>>>
>>>>>>> Subscribers: christof, K-ballo, cfe-commits, BillyONeal
>>>>>>>
>>>>>>> Differential Revision: https://reviews.llvm.org/D49774
>>>>>>>
>>>>>>> Added:
>>>>>>>     libcxx/trunk/src/include/apple_availability.h
>>>>>>> Modified:
>>>>>>>     libcxx/trunk/include/experimental/filesystem
>>>>>>>     libcxx/trunk/src/chrono.cpp
>>>>>>>     libcxx/trunk/src/experimental/filesystem/filesystem_common.h
>>>>>>>     libcxx/trunk/src/experimental/filesystem/operations.cpp
>>>>>>>
>>>>>>> libcxx/trunk/test/libcxx/experimental/filesystem/class.directory_entry/directory_entry.mods/last_write_time.sh.cpp
>>>>>>>
>>>>>>> libcxx/trunk/test/libcxx/experimental/filesystem/convert_file_time.sh.cpp
>>>>>>>
>>>>>>> libcxx/trunk/test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp
>>>>>>>
>>>>>>> libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>>>>>>>
>>>>>>> Modified: libcxx/trunk/include/experimental/filesystem
>>>>>>> URL:
>>>>>>> http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/experimental/filesystem?rev=337960&r1=337959&r2=337960&view=diff
>>>>>>>
>>>>>>> ==============================================================================
>>>>>>> --- libcxx/trunk/include/experimental/filesystem (original)
>>>>>>> +++ libcxx/trunk/include/experimental/filesystem Wed Jul 25 13:51:49
>>>>>>> 2018
>>>>>>> @@ -260,7 +260,37 @@ _LIBCPP_PUSH_MACROS
>>>>>>>
>>>>>>>  _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
>>>>>>>
>>>>>>> -typedef chrono::time_point<std::chrono::system_clock>
>>>>>>> file_time_type;
>>>>>>> +struct _FilesystemClock {
>>>>>>> +#if !defined(_LIBCPP_HAS_NO_INT128)
>>>>>>> +  typedef __int128_t rep;
>>>>>>> +  typedef nano period;
>>>>>>> +#else
>>>>>>> +  typedef long long rep;
>>>>>>> +  typedef nano period;
>>>>>>> +#endif
>>>>>>> +
>>>>>>> +  typedef chrono::duration<rep, period> duration;
>>>>>>> +  typedef chrono::time_point<_FilesystemClock> time_point;
>>>>>>> +
>>>>>>> +  static _LIBCPP_CONSTEXPR_AFTER_CXX11 const bool is_steady = false;
>>>>>>> +
>>>>>>> +  _LIBCPP_FUNC_VIS static time_point now() noexcept;
>>>>>>> +
>>>>>>> +  _LIBCPP_INLINE_VISIBILITY
>>>>>>> +  static time_t to_time_t(const time_point& __t) noexcept {
>>>>>>> +    typedef chrono::duration<rep> __secs;
>>>>>>> +    return time_t(
>>>>>>> +
>>>>>>> chrono::duration_cast<__secs>(__t.time_since_epoch()).count());
>>>>>>> +  }
>>>>>>> +
>>>>>>> +  _LIBCPP_INLINE_VISIBILITY
>>>>>>> +  static time_point from_time_t(time_t __t) noexcept {
>>>>>>> +    typedef chrono::duration<rep> __secs;
>>>>>>> +    return time_point(__secs(__t));
>>>>>>> +  }
>>>>>>> +};
>>>>>>> +
>>>>>>> +typedef chrono::time_point<_FilesystemClock> file_time_type;
>>>>>>>
>>>>>>>  struct _LIBCPP_TYPE_VIS space_info
>>>>>>>  {
>>>>>>>
>>>>>>> Modified: libcxx/trunk/src/chrono.cpp
>>>>>>> URL:
>>>>>>> http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/chrono.cpp?rev=337960&r1=337959&r2=337960&view=diff
>>>>>>>
>>>>>>> ==============================================================================
>>>>>>> --- libcxx/trunk/src/chrono.cpp (original)
>>>>>>> +++ libcxx/trunk/src/chrono.cpp Wed Jul 25 13:51:49 2018
>>>>>>> @@ -11,27 +11,10 @@
>>>>>>>  #include "cerrno"        // errno
>>>>>>>  #include "system_error"  // __throw_system_error
>>>>>>>  #include <time.h>        // clock_gettime, CLOCK_MONOTONIC and
>>>>>>> CLOCK_REALTIME
>>>>>>> +#include "include/apple_availability.h"
>>>>>>>
>>>>>>> -#if (__APPLE__)
>>>>>>> -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
>>>>>>> -#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101200
>>>>>>> -#define _LIBCXX_USE_CLOCK_GETTIME
>>>>>>> -#endif
>>>>>>> -#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
>>>>>>> -#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 100000
>>>>>>> -#define _LIBCXX_USE_CLOCK_GETTIME
>>>>>>> -#endif
>>>>>>> -#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
>>>>>>> -#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 100000
>>>>>>> -#define _LIBCXX_USE_CLOCK_GETTIME
>>>>>>> -#endif
>>>>>>> -#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
>>>>>>> -#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 30000
>>>>>>> -#define _LIBCXX_USE_CLOCK_GETTIME
>>>>>>> -#endif
>>>>>>> -#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
>>>>>>> -#else
>>>>>>> -#define _LIBCXX_USE_CLOCK_GETTIME
>>>>>>> +#if !defined(__APPLE__)
>>>>>>> +#define _LIBCPP_USE_CLOCK_GETTIME
>>>>>>>  #endif // __APPLE__
>>>>>>>
>>>>>>>  #if defined(_LIBCPP_WIN32API)
>>>>>>> @@ -42,7 +25,7 @@
>>>>>>>  #include <winapifamily.h>
>>>>>>>  #endif
>>>>>>>  #else
>>>>>>> -#if !defined(CLOCK_REALTIME) || !defined(_LIBCXX_USE_CLOCK_GETTIME)
>>>>>>> +#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
>>>>>>>  #include <sys/time.h>        // for gettimeofday and timeval
>>>>>>>  #endif // !defined(CLOCK_REALTIME)
>>>>>>>  #endif // defined(_LIBCPP_WIN32API)
>>>>>>> @@ -92,16 +75,16 @@ system_clock::now() _NOEXCEPT
>>>>>>>                         static_cast<__int64>(ft.dwLowDateTime)};
>>>>>>>    return time_point(duration_cast<duration>(d - nt_to_unix_epoch));
>>>>>>>  #else
>>>>>>> -#if defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
>>>>>>> -    struct timespec tp;
>>>>>>> -    if (0 != clock_gettime(CLOCK_REALTIME, &tp))
>>>>>>> -        __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME)
>>>>>>> failed");
>>>>>>> -    return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec
>>>>>>> / 1000));
>>>>>>> +#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
>>>>>>> +  struct timespec tp;
>>>>>>> +  if (0 != clock_gettime(CLOCK_REALTIME, &tp))
>>>>>>> +    __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME)
>>>>>>> failed");
>>>>>>> +  return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec /
>>>>>>> 1000));
>>>>>>>  #else
>>>>>>>      timeval tv;
>>>>>>>      gettimeofday(&tv, 0);
>>>>>>>      return time_point(seconds(tv.tv_sec) +
>>>>>>> microseconds(tv.tv_usec));
>>>>>>> -#endif // _LIBCXX_USE_CLOCK_GETTIME && CLOCK_REALTIME
>>>>>>> +#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
>>>>>>>  #endif
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -129,7 +112,7 @@ const bool steady_clock::is_steady;
>>>>>>>  #if defined(__APPLE__)
>>>>>>>
>>>>>>>  // Darwin libc versions >= 1133 provide ns precision via
>>>>>>> CLOCK_UPTIME_RAW
>>>>>>> -#if defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
>>>>>>> +#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
>>>>>>>  steady_clock::time_point
>>>>>>>  steady_clock::now() _NOEXCEPT
>>>>>>>  {
>>>>>>> @@ -191,7 +174,7 @@ steady_clock::now() _NOEXCEPT
>>>>>>>      static FP fp = init_steady_clock();
>>>>>>>      return time_point(duration(fp()));
>>>>>>>  }
>>>>>>> -#endif // defined(_LIBCXX_USE_CLOCK_GETTIME) &&
>>>>>>> defined(CLOCK_UPTIME_RAW)
>>>>>>> +#endif // defined(_LIBCPP_USE_CLOCK_GETTIME) &&
>>>>>>> defined(CLOCK_UPTIME_RAW)
>>>>>>>
>>>>>>>  #elif defined(_LIBCPP_WIN32API)
>>>>>>>
>>>>>>>
>>>>>>> Modified:
>>>>>>> libcxx/trunk/src/experimental/filesystem/filesystem_common.h
>>>>>>> URL:
>>>>>>> http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/experimental/filesystem/filesystem_common.h?rev=337960&r1=337959&r2=337960&view=diff
>>>>>>>
>>>>>>> ==============================================================================
>>>>>>> --- libcxx/trunk/src/experimental/filesystem/filesystem_common.h
>>>>>>> (original)
>>>>>>> +++ libcxx/trunk/src/experimental/filesystem/filesystem_common.h Wed
>>>>>>> Jul 25 13:51:49 2018
>>>>>>> @@ -23,33 +23,17 @@
>>>>>>>
>>>>>>>  #include <experimental/filesystem>
>>>>>>>
>>>>>>> -#if (__APPLE__)
>>>>>>> -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
>>>>>>> -#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101300
>>>>>>> -#define _LIBCXX_USE_UTIMENSAT
>>>>>>> -#endif
>>>>>>> -#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
>>>>>>> -#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 110000
>>>>>>> -#define _LIBCXX_USE_UTIMENSAT
>>>>>>> -#endif
>>>>>>> -#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
>>>>>>> -#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 110000
>>>>>>> -#define _LIBCXX_USE_UTIMENSAT
>>>>>>> -#endif
>>>>>>> -#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
>>>>>>> -#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 40000
>>>>>>> -#define _LIBCXX_USE_UTIMENSAT
>>>>>>> -#endif
>>>>>>> -#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
>>>>>>> -#else
>>>>>>> +#include "../../include/apple_availability.h"
>>>>>>> +
>>>>>>> +#if !defined(__APPLE__)
>>>>>>>  // We can use the presence of UTIME_OMIT to detect platforms that
>>>>>>> provide
>>>>>>>  // utimensat.
>>>>>>>  #if defined(UTIME_OMIT)
>>>>>>> -#define _LIBCXX_USE_UTIMENSAT
>>>>>>> +#define _LIBCPP_USE_UTIMENSAT
>>>>>>> +#endif
>>>>>>>  #endif
>>>>>>> -#endif // __APPLE__
>>>>>>>
>>>>>>> -#if !defined(_LIBCXX_USE_UTIMENSAT)
>>>>>>> +#if !defined(_LIBCPP_USE_UTIMENSAT)
>>>>>>>  #include <sys/time.h> // for ::utimes as used in __last_write_time
>>>>>>>  #endif
>>>>>>>
>>>>>>> @@ -212,76 +196,119 @@ private:
>>>>>>>    ErrorHandler& operator=(ErrorHandler const&) = delete;
>>>>>>>  };
>>>>>>>
>>>>>>> -namespace time_util {
>>>>>>> +using chrono::duration;
>>>>>>> +using chrono::duration_cast;
>>>>>>>
>>>>>>> -using namespace chrono;
>>>>>>> +using TimeSpec = struct ::timespec;
>>>>>>> +using StatT = struct ::stat;
>>>>>>>
>>>>>>> -template <class FileTimeT,
>>>>>>> +template <class FileTimeT, class TimeT,
>>>>>>>            bool IsFloat = is_floating_point<typename
>>>>>>> FileTimeT::rep>::value>
>>>>>>> -struct fs_time_util_base {
>>>>>>> -  static constexpr seconds::rep max_seconds =
>>>>>>> -      duration_cast<seconds>(FileTimeT::duration::max()).count();
>>>>>>> -
>>>>>>> -  static constexpr nanoseconds::rep max_nsec =
>>>>>>> -      duration_cast<nanoseconds>(FileTimeT::duration::max() -
>>>>>>> -                                 seconds(max_seconds))
>>>>>>> +struct time_util_base {
>>>>>>> +  using rep = typename FileTimeT::rep;
>>>>>>> +  using fs_duration = typename FileTimeT::duration;
>>>>>>> +  using fs_seconds = duration<rep>;
>>>>>>> +  using fs_nanoseconds = duration<rep, nano>;
>>>>>>> +  using fs_microseconds = duration<rep, micro>;
>>>>>>> +
>>>>>>> +  static constexpr rep max_seconds =
>>>>>>> +      duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
>>>>>>> +
>>>>>>> +  static constexpr rep max_nsec =
>>>>>>> +      duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
>>>>>>> +                                    fs_seconds(max_seconds))
>>>>>>>            .count();
>>>>>>>
>>>>>>> -  static constexpr seconds::rep min_seconds =
>>>>>>> -      duration_cast<seconds>(FileTimeT::duration::min()).count();
>>>>>>> +  static constexpr rep min_seconds =
>>>>>>> +      duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
>>>>>>>
>>>>>>> -  static constexpr nanoseconds::rep min_nsec_timespec =
>>>>>>> -      duration_cast<nanoseconds>(
>>>>>>> -          (FileTimeT::duration::min() - seconds(min_seconds)) +
>>>>>>> seconds(1))
>>>>>>> +  static constexpr rep min_nsec_timespec =
>>>>>>> +      duration_cast<fs_nanoseconds>(
>>>>>>> +          (FileTimeT::duration::min() - fs_seconds(min_seconds)) +
>>>>>>> +          fs_seconds(1))
>>>>>>>            .count();
>>>>>>>
>>>>>>> +private:
>>>>>>> +#if _LIBCPP_STD_VER > 11
>>>>>>> +  static constexpr fs_duration get_min_nsecs() {
>>>>>>> +    return duration_cast<fs_duration>(
>>>>>>> +        fs_nanoseconds(min_nsec_timespec) -
>>>>>>> +        duration_cast<fs_nanoseconds>(fs_seconds(1)));
>>>>>>> +  }
>>>>>>>    // Static assert that these values properly round trip.
>>>>>>> -  static_assert((seconds(min_seconds) +
>>>>>>> -
>>>>>>>  duration_cast<microseconds>(nanoseconds(min_nsec_timespec))) -
>>>>>>> -                        duration_cast<microseconds>(seconds(1)) ==
>>>>>>> +  static_assert(fs_seconds(min_seconds) + get_min_nsecs() ==
>>>>>>>                      FileTimeT::duration::min(),
>>>>>>> -                "");
>>>>>>> +                "value doesn't roundtrip");
>>>>>>> +
>>>>>>> +  static constexpr bool check_range() {
>>>>>>> +    // This kinda sucks, but it's what happens when we don't have
>>>>>>> __int128_t.
>>>>>>> +    if (sizeof(TimeT) == sizeof(rep)) {
>>>>>>> +      typedef duration<long long, ratio<3600 * 24 * 365> > Years;
>>>>>>> +      return duration_cast<Years>(fs_seconds(max_seconds)) >
>>>>>>> Years(250) &&
>>>>>>> +             duration_cast<Years>(fs_seconds(min_seconds)) <
>>>>>>> Years(-250);
>>>>>>> +    }
>>>>>>> +    return max_seconds >= numeric_limits<TimeT>::max() &&
>>>>>>> +           min_seconds <= numeric_limits<TimeT>::min();
>>>>>>> +  }
>>>>>>> +  static_assert(check_range(), "the representable range is
>>>>>>> unacceptable small");
>>>>>>> +#endif
>>>>>>>  };
>>>>>>>
>>>>>>> -template <class FileTimeT>
>>>>>>> -struct fs_time_util_base<FileTimeT, true> {
>>>>>>> -  static const long long max_seconds;
>>>>>>> -  static const long long max_nsec;
>>>>>>> -  static const long long min_seconds;
>>>>>>> -  static const long long min_nsec_timespec;
>>>>>>> +template <class FileTimeT, class TimeT>
>>>>>>> +struct time_util_base<FileTimeT, TimeT, true> {
>>>>>>> +  using rep = typename FileTimeT::rep;
>>>>>>> +  using fs_duration = typename FileTimeT::duration;
>>>>>>> +  using fs_seconds = duration<rep>;
>>>>>>> +  using fs_nanoseconds = duration<rep, nano>;
>>>>>>> +  using fs_microseconds = duration<rep, micro>;
>>>>>>> +
>>>>>>> +  static const rep max_seconds;
>>>>>>> +  static const rep max_nsec;
>>>>>>> +  static const rep min_seconds;
>>>>>>> +  static const rep min_nsec_timespec;
>>>>>>>  };
>>>>>>>
>>>>>>> -template <class FileTimeT>
>>>>>>> -const long long fs_time_util_base<FileTimeT, true>::max_seconds =
>>>>>>> -    duration_cast<seconds>(FileTimeT::duration::max()).count();
>>>>>>> -
>>>>>>> -template <class FileTimeT>
>>>>>>> -const long long fs_time_util_base<FileTimeT, true>::max_nsec =
>>>>>>> -    duration_cast<nanoseconds>(FileTimeT::duration::max() -
>>>>>>> -                               seconds(max_seconds))
>>>>>>> +template <class FileTimeT, class TimeT>
>>>>>>> +const typename FileTimeT::rep
>>>>>>> +    time_util_base<FileTimeT, TimeT, true>::max_seconds =
>>>>>>> +
>>>>>>> duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
>>>>>>> +
>>>>>>> +template <class FileTimeT, class TimeT>
>>>>>>> +const typename FileTimeT::rep time_util_base<FileTimeT, TimeT,
>>>>>>> true>::max_nsec =
>>>>>>> +    duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
>>>>>>> +                                  fs_seconds(max_seconds))
>>>>>>>          .count();
>>>>>>>
>>>>>>> -template <class FileTimeT>
>>>>>>> -const long long fs_time_util_base<FileTimeT, true>::min_seconds =
>>>>>>> -    duration_cast<seconds>(FileTimeT::duration::min()).count();
>>>>>>> -
>>>>>>> -template <class FileTimeT>
>>>>>>> -const long long fs_time_util_base<FileTimeT,
>>>>>>> true>::min_nsec_timespec =
>>>>>>> -    duration_cast<nanoseconds>(
>>>>>>> -        (FileTimeT::duration::min() - seconds(min_seconds)) +
>>>>>>> seconds(1))
>>>>>>> -        .count();
>>>>>>> +template <class FileTimeT, class TimeT>
>>>>>>> +const typename FileTimeT::rep
>>>>>>> +    time_util_base<FileTimeT, TimeT, true>::min_seconds =
>>>>>>> +
>>>>>>> duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
>>>>>>> +
>>>>>>> +template <class FileTimeT, class TimeT>
>>>>>>> +const typename FileTimeT::rep
>>>>>>> +    time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec =
>>>>>>> +        duration_cast<fs_nanoseconds>((FileTimeT::duration::min() -
>>>>>>> +                                       fs_seconds(min_seconds)) +
>>>>>>> +                                      fs_seconds(1))
>>>>>>> +            .count();
>>>>>>>
>>>>>>>  template <class FileTimeT, class TimeT, class TimeSpecT>
>>>>>>> -struct fs_time_util : fs_time_util_base<FileTimeT> {
>>>>>>> -  using Base = fs_time_util_base<FileTimeT>;
>>>>>>> +struct time_util : time_util_base<FileTimeT, TimeT> {
>>>>>>> +  using Base = time_util_base<FileTimeT, TimeT>;
>>>>>>>    using Base::max_nsec;
>>>>>>>    using Base::max_seconds;
>>>>>>>    using Base::min_nsec_timespec;
>>>>>>>    using Base::min_seconds;
>>>>>>>
>>>>>>> +  using typename Base::fs_duration;
>>>>>>> +  using typename Base::fs_microseconds;
>>>>>>> +  using typename Base::fs_nanoseconds;
>>>>>>> +  using typename Base::fs_seconds;
>>>>>>> +
>>>>>>>  public:
>>>>>>>    template <class CType, class ChronoType>
>>>>>>> -  static bool checked_set(CType* out, ChronoType time) {
>>>>>>> +  static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out,
>>>>>>> +                                                        ChronoType
>>>>>>> time) {
>>>>>>>      using Lim = numeric_limits<CType>;
>>>>>>>      if (time > Lim::max() || time < Lim::min())
>>>>>>>        return false;
>>>>>>> @@ -291,21 +318,21 @@ public:
>>>>>>>
>>>>>>>    static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
>>>>>>> is_representable(TimeSpecT tm) {
>>>>>>>      if (tm.tv_sec >= 0) {
>>>>>>> -      return (tm.tv_sec < max_seconds) ||
>>>>>>> +      return tm.tv_sec < max_seconds ||
>>>>>>>               (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
>>>>>>>      } else if (tm.tv_sec == (min_seconds - 1)) {
>>>>>>>        return tm.tv_nsec >= min_nsec_timespec;
>>>>>>>      } else {
>>>>>>> -      return (tm.tv_sec >= min_seconds);
>>>>>>> +      return tm.tv_sec >= min_seconds;
>>>>>>>      }
>>>>>>>    }
>>>>>>>
>>>>>>>    static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
>>>>>>> is_representable(FileTimeT tm) {
>>>>>>> -    auto secs = duration_cast<seconds>(tm.time_since_epoch());
>>>>>>> -    auto nsecs = duration_cast<nanoseconds>(tm.time_since_epoch() -
>>>>>>> secs);
>>>>>>> +    auto secs = duration_cast<fs_seconds>(tm.time_since_epoch());
>>>>>>> +    auto nsecs =
>>>>>>> duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs);
>>>>>>>      if (nsecs.count() < 0) {
>>>>>>> -      secs = secs + seconds(1);
>>>>>>> -      nsecs = nsecs + seconds(1);
>>>>>>> +      secs = secs + fs_seconds(1);
>>>>>>> +      nsecs = nsecs + fs_seconds(1);
>>>>>>>      }
>>>>>>>      using TLim = numeric_limits<TimeT>;
>>>>>>>      if (secs.count() >= 0)
>>>>>>> @@ -314,49 +341,45 @@ public:
>>>>>>>    }
>>>>>>>
>>>>>>>    static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
>>>>>>> -  convert_timespec(TimeSpecT tm) {
>>>>>>> -    auto adj_msec =
>>>>>>> duration_cast<microseconds>(nanoseconds(tm.tv_nsec));
>>>>>>> -    if (tm.tv_sec >= 0) {
>>>>>>> -      auto Dur = seconds(tm.tv_sec) + microseconds(adj_msec);
>>>>>>> -      return FileTimeT(Dur);
>>>>>>> -    } else if
>>>>>>> (duration_cast<microseconds>(nanoseconds(tm.tv_nsec)).count() ==
>>>>>>> -               0) {
>>>>>>> -      return FileTimeT(seconds(tm.tv_sec));
>>>>>>> +  convert_from_timespec(TimeSpecT tm) {
>>>>>>> +    if (tm.tv_sec >= 0 || tm.tv_nsec == 0) {
>>>>>>> +      return FileTimeT(fs_seconds(tm.tv_sec) +
>>>>>>> +
>>>>>>>  duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec)));
>>>>>>>      } else { // tm.tv_sec < 0
>>>>>>> -      auto adj_subsec =
>>>>>>> -          duration_cast<microseconds>(seconds(1) -
>>>>>>> nanoseconds(tm.tv_nsec));
>>>>>>> -      auto Dur = seconds(tm.tv_sec + 1) - adj_subsec;
>>>>>>> +      auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) -
>>>>>>> +
>>>>>>>  fs_nanoseconds(tm.tv_nsec));
>>>>>>> +      auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec;
>>>>>>>        return FileTimeT(Dur);
>>>>>>>      }
>>>>>>>    }
>>>>>>>
>>>>>>> -  template <class SubSecDurT, class SubSecT>
>>>>>>> -  static bool set_times_checked(TimeT* sec_out, SubSecT* subsec_out,
>>>>>>> -                                FileTimeT tp) {
>>>>>>> +  template <class SubSecT>
>>>>>>> +  static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
>>>>>>> +  set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT
>>>>>>> tp) {
>>>>>>>      auto dur = tp.time_since_epoch();
>>>>>>> -    auto sec_dur = duration_cast<seconds>(dur);
>>>>>>> -    auto subsec_dur = duration_cast<SubSecDurT>(dur - sec_dur);
>>>>>>> +    auto sec_dur = duration_cast<fs_seconds>(dur);
>>>>>>> +    auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur);
>>>>>>>      // The tv_nsec and tv_usec fields must not be negative so
>>>>>>> adjust accordingly
>>>>>>>      if (subsec_dur.count() < 0) {
>>>>>>>        if (sec_dur.count() > min_seconds) {
>>>>>>> -        sec_dur -= seconds(1);
>>>>>>> -        subsec_dur += seconds(1);
>>>>>>> +        sec_dur -= fs_seconds(1);
>>>>>>> +        subsec_dur += fs_seconds(1);
>>>>>>>        } else {
>>>>>>> -        subsec_dur = SubSecDurT::zero();
>>>>>>> +        subsec_dur = fs_nanoseconds::zero();
>>>>>>>        }
>>>>>>>      }
>>>>>>>      return checked_set(sec_out, sec_dur.count()) &&
>>>>>>>             checked_set(subsec_out, subsec_dur.count());
>>>>>>>    }
>>>>>>> +  static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
>>>>>>> convert_to_timespec(TimeSpecT& dest,
>>>>>>> +
>>>>>>> FileTimeT tp) {
>>>>>>> +    if (!is_representable(tp))
>>>>>>> +      return false;
>>>>>>> +    return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);
>>>>>>> +  }
>>>>>>>  };
>>>>>>>
>>>>>>> -} // namespace time_util
>>>>>>> -
>>>>>>> -
>>>>>>> -using TimeSpec = struct ::timespec;
>>>>>>> -using StatT = struct ::stat;
>>>>>>> -
>>>>>>> -using FSTime = time_util::fs_time_util<file_time_type, time_t,
>>>>>>> struct timespec>;
>>>>>>> +using fs_time = time_util<file_time_type, time_t, TimeSpec>;
>>>>>>>
>>>>>>>  #if defined(__APPLE__)
>>>>>>>  TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
>>>>>>> @@ -366,20 +389,18 @@ TimeSpec extract_mtime(StatT const& st)
>>>>>>>  TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
>>>>>>>  #endif
>>>>>>>
>>>>>>> -#if !defined(_LIBCXX_USE_UTIMENSAT)
>>>>>>> -using TimeStruct = struct ::timeval;
>>>>>>> -using TimeStructArray = TimeStruct[2];
>>>>>>> -#else
>>>>>>> -using TimeStruct = TimeSpec;
>>>>>>> -using TimeStructArray = TimeStruct[2];
>>>>>>> -#endif
>>>>>>> -
>>>>>>> -bool SetFileTimes(const path& p, TimeStructArray const& TS,
>>>>>>> -                  error_code& ec) {
>>>>>>> -#if !defined(_LIBCXX_USE_UTIMENSAT)
>>>>>>> -  if (::utimes(p.c_str(), TS) == -1)
>>>>>>> +bool set_file_times(const path& p, std::array<TimeSpec, 2> const&
>>>>>>> TS,
>>>>>>> +                    error_code& ec) {
>>>>>>> +#if !defined(_LIBCPP_USE_UTIMENSAT)
>>>>>>> +  using namespace chrono;
>>>>>>> +  auto Convert = [](long nsec) {
>>>>>>> +    return duration_cast<microseconds>(nanoseconds(nsec)).count();
>>>>>>> +  };
>>>>>>> +  struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec,
>>>>>>> Convert(TS[0].tv_nsec)},
>>>>>>> +                                     {TS[1].tv_sec,
>>>>>>> Convert(TS[1].tv_nsec)}};
>>>>>>>
>>>>>>
>>>>>> This causes the '-Wc++11-narrowing' warning on Darwin:
>>>>>>
>>>>>> filesystem_common.h:399:53: error: non-constant-expression cannot be
>>>>>> narrowed from type 'long long' to '__darwin_suseconds_t' (aka 'int') in
>>>>>> initializer list [-Wc++11-narrowing] struct ::timeval ConvertedTS[2] =
>>>>>> {{TS[0].tv_sec, Convert(TS[0].tv_nsec)}, ^~~~~~~~~~~~~~~~~~~~~~
>>>>>> I'll work on a fix commit.
>>>>>>
>>>>>>
>>>>>>> +  if (::utimes(p.c_str(), ConvertedTS) == -1)
>>>>>>>  #else
>>>>>>> -  if (::utimensat(AT_FDCWD, p.c_str(), TS, 0) == -1)
>>>>>>> +  if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1)
>>>>>>>  #endif
>>>>>>>    {
>>>>>>>      ec = capture_errno();
>>>>>>> @@ -388,25 +409,9 @@ bool SetFileTimes(const path& p, TimeStr
>>>>>>>    return false;
>>>>>>>  }
>>>>>>>
>>>>>>> -void SetTimeStructTo(TimeStruct& TS, TimeSpec ToTS) {
>>>>>>> -  using namespace chrono;
>>>>>>> -  TS.tv_sec = ToTS.tv_sec;
>>>>>>> -#if !defined(_LIBCXX_USE_UTIMENSAT)
>>>>>>> -  TS.tv_usec =
>>>>>>> duration_cast<microseconds>(nanoseconds(ToTS.tv_nsec)).count();
>>>>>>> -#else
>>>>>>> -  TS.tv_nsec = ToTS.tv_nsec;
>>>>>>> -#endif
>>>>>>> -}
>>>>>>> -
>>>>>>> -bool SetTimeStructTo(TimeStruct& TS, file_time_type NewTime) {
>>>>>>> -  using namespace chrono;
>>>>>>> -#if !defined(_LIBCXX_USE_UTIMENSAT)
>>>>>>> -  return !FSTime::set_times_checked<microseconds>(&TS.tv_sec,
>>>>>>> &TS.tv_usec,
>>>>>>> -                                                  NewTime);
>>>>>>> -#else
>>>>>>> -  return !FSTime::set_times_checked<nanoseconds>(&TS.tv_sec,
>>>>>>> &TS.tv_nsec,
>>>>>>> -                                                 NewTime);
>>>>>>> -#endif
>>>>>>> +bool set_time_spec_to(TimeSpec& TS, file_time_type NewTime) {
>>>>>>> +  return !fs_time::set_times_checked(
>>>>>>> +      &TS.tv_sec, &TS.tv_nsec, NewTime);
>>>>>>>  }
>>>>>>>
>>>>>>>  } // namespace
>>>>>>>
>>>>>>> Modified: libcxx/trunk/src/experimental/filesystem/operations.cpp
>>>>>>> URL:
>>>>>>> http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/experimental/filesystem/operations.cpp?rev=337960&r1=337959&r2=337960&view=diff
>>>>>>>
>>>>>>> ==============================================================================
>>>>>>> --- libcxx/trunk/src/experimental/filesystem/operations.cpp
>>>>>>> (original)
>>>>>>> +++ libcxx/trunk/src/experimental/filesystem/operations.cpp Wed Jul
>>>>>>> 25 13:51:49 2018
>>>>>>> @@ -23,6 +23,7 @@
>>>>>>>  #include <unistd.h>
>>>>>>>  #include <sys/stat.h>
>>>>>>>  #include <sys/statvfs.h>
>>>>>>> +#include <time.h>
>>>>>>>  #include <fcntl.h>  /* values for fchmodat */
>>>>>>>
>>>>>>>  #if defined(__linux__)
>>>>>>> @@ -36,6 +37,14 @@
>>>>>>>  # define _LIBCPP_USE_COPYFILE
>>>>>>>  #endif
>>>>>>>
>>>>>>> +#if !defined(__APPLE__)
>>>>>>> +#define _LIBCPP_USE_CLOCK_GETTIME
>>>>>>> +#endif
>>>>>>> +
>>>>>>> +#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
>>>>>>> +#include <sys/time.h> // for gettimeofday and timeval
>>>>>>> +#endif                // !defined(CLOCK_REALTIME)
>>>>>>> +
>>>>>>>  #if defined(_LIBCPP_COMPILER_GCC)
>>>>>>>  #if _GNUC_VER < 500
>>>>>>>  #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
>>>>>>> @@ -44,9 +53,6 @@
>>>>>>>
>>>>>>>  _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
>>>>>>>
>>>>>>> -filesystem_error::~filesystem_error() {}
>>>>>>> -
>>>>>>> -
>>>>>>>  namespace { namespace parser
>>>>>>>  {
>>>>>>>
>>>>>>> @@ -355,7 +361,7 @@ private:
>>>>>>>    explicit FileDescriptor(const path* p, int fd = -1) : name(*p),
>>>>>>> fd(fd) {}
>>>>>>>  };
>>>>>>>
>>>>>>> -perms posix_get_perms(const struct ::stat& st) noexcept {
>>>>>>> +perms posix_get_perms(const StatT& st) noexcept {
>>>>>>>    return static_cast<perms>(st.st_mode) & perms::mask;
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -364,8 +370,7 @@ perms posix_get_perms(const struct ::sta
>>>>>>>  }
>>>>>>>
>>>>>>>  file_status create_file_status(error_code& m_ec, path const& p,
>>>>>>> -                               const struct ::stat& path_stat,
>>>>>>> -                               error_code* ec) {
>>>>>>> +                               const StatT& path_stat, error_code*
>>>>>>> ec) {
>>>>>>>    if (ec)
>>>>>>>      *ec = m_ec;
>>>>>>>    if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) {
>>>>>>> @@ -400,8 +405,7 @@ file_status create_file_status(error_cod
>>>>>>>    return fs_tmp;
>>>>>>>  }
>>>>>>>
>>>>>>> -file_status posix_stat(path const& p, struct ::stat& path_stat,
>>>>>>> -                       error_code* ec) {
>>>>>>> +file_status posix_stat(path const& p, StatT& path_stat, error_code*
>>>>>>> ec) {
>>>>>>>    error_code m_ec;
>>>>>>>    if (::stat(p.c_str(), &path_stat) == -1)
>>>>>>>      m_ec = detail::capture_errno();
>>>>>>> @@ -409,12 +413,11 @@ file_status posix_stat(path const& p, st
>>>>>>>  }
>>>>>>>
>>>>>>>  file_status posix_stat(path const& p, error_code* ec) {
>>>>>>> -  struct ::stat path_stat;
>>>>>>> +  StatT path_stat;
>>>>>>>    return posix_stat(p, path_stat, ec);
>>>>>>>  }
>>>>>>>
>>>>>>> -file_status posix_lstat(path const& p, struct ::stat& path_stat,
>>>>>>> -                        error_code* ec) {
>>>>>>> +file_status posix_lstat(path const& p, StatT& path_stat,
>>>>>>> error_code* ec) {
>>>>>>>    error_code m_ec;
>>>>>>>    if (::lstat(p.c_str(), &path_stat) == -1)
>>>>>>>      m_ec = detail::capture_errno();
>>>>>>> @@ -422,7 +425,7 @@ file_status posix_lstat(path const& p, s
>>>>>>>  }
>>>>>>>
>>>>>>>  file_status posix_lstat(path const& p, error_code* ec) {
>>>>>>> -  struct ::stat path_stat;
>>>>>>> +  StatT path_stat;
>>>>>>>    return posix_lstat(p, path_stat, ec);
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -464,10 +467,32 @@ file_status FileDescriptor::refresh_stat
>>>>>>>  using detail::capture_errno;
>>>>>>>  using detail::ErrorHandler;
>>>>>>>  using detail::StatT;
>>>>>>> +using detail::TimeSpec;
>>>>>>>  using parser::createView;
>>>>>>>  using parser::PathParser;
>>>>>>>  using parser::string_view_t;
>>>>>>>
>>>>>>> +const bool _FilesystemClock::is_steady;
>>>>>>> +
>>>>>>> +_FilesystemClock::time_point _FilesystemClock::now() noexcept {
>>>>>>> +  typedef chrono::duration<rep> __secs;
>>>>>>> +#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
>>>>>>> +  typedef chrono::duration<rep, nano> __nsecs;
>>>>>>> +  struct timespec tp;
>>>>>>> +  if (0 != clock_gettime(CLOCK_REALTIME, &tp))
>>>>>>> +    __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME)
>>>>>>> failed");
>>>>>>> +  return time_point(__secs(tp.tv_sec) +
>>>>>>> +
>>>>>>> chrono::duration_cast<duration>(__nsecs(tp.tv_nsec)));
>>>>>>> +#else
>>>>>>> +  typedef chrono::duration<rep, micro> __microsecs;
>>>>>>> +  timeval tv;
>>>>>>> +  gettimeofday(&tv, 0);
>>>>>>> +  return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec));
>>>>>>> +#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
>>>>>>> +}
>>>>>>> +
>>>>>>> +filesystem_error::~filesystem_error() {}
>>>>>>> +
>>>>>>>  void filesystem_error::__create_what(int __num_paths) {
>>>>>>>    const char* derived_what = system_error::what();
>>>>>>>    __storage_->__what_ = [&]() -> string {
>>>>>>> @@ -525,14 +550,14 @@ void __copy(const path& from, const path
>>>>>>>    const bool sym_status2 = bool(options &
>>>>>>> copy_options::copy_symlinks);
>>>>>>>
>>>>>>>    error_code m_ec1;
>>>>>>> -  struct ::stat f_st = {};
>>>>>>> +  StatT f_st = {};
>>>>>>>    const file_status f = sym_status || sym_status2
>>>>>>>                              ? detail::posix_lstat(from, f_st,
>>>>>>> &m_ec1)
>>>>>>>                              : detail::posix_stat(from, f_st,
>>>>>>> &m_ec1);
>>>>>>>    if (m_ec1)
>>>>>>>      return err.report(m_ec1);
>>>>>>>
>>>>>>> -  struct ::stat t_st = {};
>>>>>>> +  StatT t_st = {};
>>>>>>>    const file_status t = sym_status ? detail::posix_lstat(to, t_st,
>>>>>>> &m_ec1)
>>>>>>>                                     : detail::posix_stat(to, t_st,
>>>>>>> &m_ec1);
>>>>>>>
>>>>>>> @@ -916,7 +941,7 @@ uintmax_t __file_size(const path& p, err
>>>>>>>    ErrorHandler<uintmax_t> err("file_size", ec, &p);
>>>>>>>
>>>>>>>    error_code m_ec;
>>>>>>> -  struct ::stat st;
>>>>>>> +  StatT st;
>>>>>>>    file_status fst = detail::posix_stat(p, st, &m_ec);
>>>>>>>    if (!exists(fst) || !is_regular_file(fst)) {
>>>>>>>      errc error_kind =
>>>>>>> @@ -966,14 +991,14 @@ bool __fs_is_empty(const path& p, error_
>>>>>>>
>>>>>>>  static file_time_type __extract_last_write_time(const path& p,
>>>>>>> const StatT& st,
>>>>>>>                                                  error_code* ec) {
>>>>>>> -  using detail::FSTime;
>>>>>>> +  using detail::fs_time;
>>>>>>>    ErrorHandler<file_time_type> err("last_write_time", ec, &p);
>>>>>>>
>>>>>>>    auto ts = detail::extract_mtime(st);
>>>>>>> -  if (!FSTime::is_representable(ts))
>>>>>>> +  if (!fs_time::is_representable(ts))
>>>>>>>      return err.report(errc::value_too_large);
>>>>>>>
>>>>>>> -  return FSTime::convert_timespec(ts);
>>>>>>> +  return fs_time::convert_from_timespec(ts);
>>>>>>>  }
>>>>>>>
>>>>>>>  file_time_type __last_write_time(const path& p, error_code *ec)
>>>>>>> @@ -992,30 +1017,27 @@ file_time_type __last_write_time(const p
>>>>>>>  void __last_write_time(const path& p, file_time_type new_time,
>>>>>>>                         error_code *ec)
>>>>>>>  {
>>>>>>> -    using namespace chrono;
>>>>>>> -    using namespace detail;
>>>>>>> -
>>>>>>>      ErrorHandler<void> err("last_write_time", ec, &p);
>>>>>>>
>>>>>>>      error_code m_ec;
>>>>>>> -    TimeStructArray tbuf;
>>>>>>> -#if !defined(_LIBCXX_USE_UTIMENSAT)
>>>>>>> +    array<TimeSpec, 2> tbuf;
>>>>>>> +#if !defined(_LIBCPP_USE_UTIMENSAT)
>>>>>>>      // This implementation has a race condition between determining
>>>>>>> the
>>>>>>>      // last access time and attempting to set it to the same value
>>>>>>> using
>>>>>>>      // ::utimes
>>>>>>> -    struct ::stat st;
>>>>>>> +    StatT st;
>>>>>>>      file_status fst = detail::posix_stat(p, st, &m_ec);
>>>>>>> -    if (m_ec && !status_known(fst))
>>>>>>> +    if (m_ec)
>>>>>>>        return err.report(m_ec);
>>>>>>> -    SetTimeStructTo(tbuf[0], detail::extract_atime(st));
>>>>>>> +    tbuf[0] = detail::extract_atime(st);
>>>>>>>  #else
>>>>>>>      tbuf[0].tv_sec = 0;
>>>>>>>      tbuf[0].tv_nsec = UTIME_OMIT;
>>>>>>>  #endif
>>>>>>> -    if (SetTimeStructTo(tbuf[1], new_time))
>>>>>>> -      return err.report(errc::invalid_argument);
>>>>>>> +    if (detail::set_time_spec_to(tbuf[1], new_time))
>>>>>>> +      return err.report(errc::value_too_large);
>>>>>>>
>>>>>>> -    SetFileTimes(p, tbuf, m_ec);
>>>>>>> +    detail::set_file_times(p, tbuf, m_ec);
>>>>>>>      if (m_ec)
>>>>>>>        return err.report(m_ec);
>>>>>>>  }
>>>>>>> @@ -1591,7 +1613,7 @@ error_code directory_entry::__do_refresh
>>>>>>>    __data_.__reset();
>>>>>>>    error_code failure_ec;
>>>>>>>
>>>>>>> -  struct ::stat full_st;
>>>>>>> +  StatT full_st;
>>>>>>>    file_status st = detail::posix_lstat(__p_, full_st, &failure_ec);
>>>>>>>    if (!status_known(st)) {
>>>>>>>      __data_.__reset();
>>>>>>>
>>>>>>> Added: libcxx/trunk/src/include/apple_availability.h
>>>>>>> URL:
>>>>>>> http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/include/apple_availability.h?rev=337960&view=auto
>>>>>>>
>>>>>>> ==============================================================================
>>>>>>> --- libcxx/trunk/src/include/apple_availability.h (added)
>>>>>>> +++ libcxx/trunk/src/include/apple_availability.h Wed Jul 25
>>>>>>> 13:51:49 2018
>>>>>>> @@ -0,0 +1,52 @@
>>>>>>> +//===------------------------ apple_availability.h
>>>>>>> ------------------------===//
>>>>>>> +//
>>>>>>> +//                     The LLVM Compiler Infrastructure
>>>>>>> +//
>>>>>>> +// This file is dual licensed under the MIT and the University of
>>>>>>> Illinois Open
>>>>>>> +// Source Licenses. See LICENSE.TXT for details.
>>>>>>> +//
>>>>>>>
>>>>>>> +//===----------------------------------------------------------------------===//
>>>>>>> +#ifndef _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H
>>>>>>> +#define _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H
>>>>>>> +
>>>>>>> +#if defined(__APPLE__)
>>>>>>> +
>>>>>>> +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
>>>>>>> +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101300
>>>>>>> +#define _LIBCPP_USE_UTIMENSAT
>>>>>>> +#endif
>>>>>>> +#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
>>>>>>> +#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 110000
>>>>>>> +#define _LIBCPP_USE_UTIMENSAT
>>>>>>> +#endif
>>>>>>> +#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
>>>>>>> +#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 110000
>>>>>>> +#define _LIBCPP_USE_UTIMENSAT
>>>>>>> +#endif
>>>>>>> +#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
>>>>>>> +#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 40000
>>>>>>> +#define _LIBCPP_USE_UTIMENSAT
>>>>>>> +#endif
>>>>>>> +#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
>>>>>>> +
>>>>>>> +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
>>>>>>> +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101200
>>>>>>> +#define _LIBCPP_USE_CLOCK_GETTIME
>>>>>>> +#endif
>>>>>>> +#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
>>>>>>> +#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 100000
>>>>>>> +#define _LIBCPP_USE_CLOCK_GETTIME
>>>>>>> +#endif
>>>>>>> +#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
>>>>>>> +#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 100000
>>>>>>> +#define _LIBCPP_USE_CLOCK_GETTIME
>>>>>>> +#endif
>>>>>>> +#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
>>>>>>> +#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 30000
>>>>>>> +#define _LIBCPP_USE_CLOCK_GETTIME
>>>>>>> +#endif
>>>>>>> +#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
>>>>>>> +
>>>>>>> +#endif // __APPLE__
>>>>>>> +
>>>>>>> +#endif // _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H
>>>>>>>
>>>>>>> Modified:
>>>>>>> libcxx/trunk/test/libcxx/experimental/filesystem/class.directory_entry/directory_entry.mods/last_write_time.sh.cpp
>>>>>>> URL:
>>>>>>> http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/experimental/filesystem/class.directory_entry/directory_entry.mods/last_write_time.sh.cpp?rev=337960&r1=337959&r2=337960&view=diff
>>>>>>>
>>>>>>> ==============================================================================
>>>>>>> ---
>>>>>>> libcxx/trunk/test/libcxx/experimental/filesystem/class.directory_entry/directory_entry.mods/last_write_time.sh.cpp
>>>>>>> (original)
>>>>>>> +++
>>>>>>> libcxx/trunk/test/libcxx/experimental/filesystem/class.directory_entry/directory_entry.mods/last_write_time.sh.cpp
>>>>>>> Wed Jul 25 13:51:49 2018
>>>>>>> @@ -41,9 +41,7 @@ TEST_CASE(last_write_time_not_representa
>>>>>>>    ToTime.tv_sec =
>>>>>>> std::numeric_limits<decltype(ToTime.tv_sec)>::max();
>>>>>>>    ToTime.tv_nsec = duration_cast<nanoseconds>(seconds(1)).count() -
>>>>>>> 1;
>>>>>>>
>>>>>>> -  TimeStructArray TS;
>>>>>>> -  SetTimeStructTo(TS[0], ToTime);
>>>>>>> -  SetTimeStructTo(TS[1], ToTime);
>>>>>>> +  std::array<TimeSpec, 2> TS = {ToTime, ToTime};
>>>>>>>
>>>>>>>    file_time_type old_time = last_write_time(file);
>>>>>>>    directory_entry ent(file);
>>>>>>> @@ -57,9 +55,7 @@ TEST_CASE(last_write_time_not_representa
>>>>>>>    file_time_type rep_value;
>>>>>>>    {
>>>>>>>      std::error_code ec;
>>>>>>> -    if (SetFileTimes(file, TS, ec)) {
>>>>>>> -      TEST_REQUIRE(false && "unsupported");
>>>>>>> -    }
>>>>>>> +    TEST_REQUIRE(!set_file_times(file, TS, ec));
>>>>>>>      ec.clear();
>>>>>>>      rep_value = last_write_time(file, ec);
>>>>>>>      IsRepresentable = !bool(ec);
>>>>>>> @@ -82,7 +78,7 @@ TEST_CASE(last_write_time_not_representa
>>>>>>>
>>>>>>>      ExceptionChecker CheckExcept(file, expected_err,
>>>>>>>
>>>>>>> "directory_entry::last_write_time");
>>>>>>> -    TEST_CHECK_THROW_RESULT(fs::filesystem_error, CheckExcept,
>>>>>>> +    TEST_CHECK_THROW_RESULT(filesystem_error, CheckExcept,
>>>>>>>                              ent.last_write_time());
>>>>>>>
>>>>>>>    } else {
>>>>>>>
>>>>>>> Modified:
>>>>>>> libcxx/trunk/test/libcxx/experimental/filesystem/convert_file_time.sh.cpp
>>>>>>> URL:
>>>>>>> http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/experimental/filesystem/convert_file_time.sh.cpp?rev=337960&r1=337959&r2=337960&view=diff
>>>>>>>
>>>>>>> ==============================================================================
>>>>>>> ---
>>>>>>> libcxx/trunk/test/libcxx/experimental/filesystem/convert_file_time.sh.cpp
>>>>>>> (original)
>>>>>>> +++
>>>>>>> libcxx/trunk/test/libcxx/experimental/filesystem/convert_file_time.sh.cpp
>>>>>>> Wed Jul 25 13:51:49 2018
>>>>>>> @@ -25,15 +25,23 @@
>>>>>>>
>>>>>>>  #include "filesystem_common.h"
>>>>>>>
>>>>>>> +#ifndef __SIZEOF_INT128__
>>>>>>> +#define TEST_HAS_NO_INT128_T
>>>>>>> +#endif
>>>>>>> +
>>>>>>>  using namespace std::chrono;
>>>>>>>  namespace fs = std::experimental::filesystem;
>>>>>>>  using fs::file_time_type;
>>>>>>> -using fs::detail::time_util::fs_time_util;
>>>>>>> +using fs::detail::time_util;
>>>>>>> +
>>>>>>> +#ifdef TEST_HAS_NO_INT128_T
>>>>>>> +static_assert(sizeof(fs::file_time_type::rep) <= 8, "");
>>>>>>> +#endif
>>>>>>>
>>>>>>> -enum TestKind { TK_64Bit, TK_32Bit, TK_FloatingPoint };
>>>>>>> +enum TestKind { TK_128Bit, TK_64Bit, TK_32Bit, TK_FloatingPoint };
>>>>>>>
>>>>>>> -template <class FileTimeT, class TimeT, class TimeSpec>
>>>>>>> -constexpr TestKind getTestKind() {
>>>>>>> +template <class TimeT>
>>>>>>> +constexpr TestKind getTimeTTestKind() {
>>>>>>>    if (sizeof(TimeT) == 8 && !std::is_floating_point<TimeT>::value)
>>>>>>>      return TK_64Bit;
>>>>>>>    else if (sizeof(TimeT) == 4 &&
>>>>>>> !std::is_floating_point<TimeT>::value)
>>>>>>> @@ -43,17 +51,99 @@ constexpr TestKind getTestKind() {
>>>>>>>    else
>>>>>>>      assert(false && "test kind not supported");
>>>>>>>  }
>>>>>>> +template <class FileTimeT>
>>>>>>> +constexpr TestKind getFileTimeTestKind() {
>>>>>>> +  using Rep = typename FileTimeT::rep;
>>>>>>> +  if (std::is_floating_point<Rep>::value)
>>>>>>> +    return TK_FloatingPoint;
>>>>>>> +  if (sizeof(Rep) == 16)
>>>>>>> +    return TK_128Bit;
>>>>>>> +  if (sizeof(Rep) == 8)
>>>>>>> +    return TK_64Bit;
>>>>>>> +  assert(false && "test kind not supported");
>>>>>>> +}
>>>>>>>
>>>>>>>  template <class FileTimeT, class TimeT, class TimeSpecT,
>>>>>>> -          class Base = fs_time_util<FileTimeT, TimeT, TimeSpecT>,
>>>>>>> -          TestKind = getTestKind<FileTimeT, TimeT, TimeSpecT>()>
>>>>>>> -struct check_is_representable;
>>>>>>> +          class Base = time_util<FileTimeT, TimeT, TimeSpecT>,
>>>>>>> +          TestKind = getTimeTTestKind<TimeT>(),
>>>>>>> +          TestKind = getFileTimeTestKind<FileTimeT>()>
>>>>>>> +struct test_case;
>>>>>>>
>>>>>>>  template <class FileTimeT, class TimeT, class TimeSpecT, class Base>
>>>>>>> -struct check_is_representable<FileTimeT, TimeT, TimeSpecT, Base,
>>>>>>> TK_64Bit>
>>>>>>> +struct test_case<FileTimeT, TimeT, TimeSpecT, Base, TK_64Bit,
>>>>>>> TK_128Bit>
>>>>>>>      : public Base {
>>>>>>>
>>>>>>> -  using Base::convert_timespec;
>>>>>>> +  using Base::convert_from_timespec;
>>>>>>> +  using Base::convert_to_timespec;
>>>>>>> +  using Base::is_representable;
>>>>>>> +  using Base::max_nsec;
>>>>>>> +  using Base::max_seconds;
>>>>>>> +  using Base::min_nsec_timespec;
>>>>>>> +  using Base::min_seconds;
>>>>>>> +
>>>>>>> +  static constexpr auto max_time_t =
>>>>>>> std::numeric_limits<TimeT>::max();
>>>>>>> +  static constexpr auto min_time_t =
>>>>>>> std::numeric_limits<TimeT>::min();
>>>>>>> +
>>>>>>> +  static constexpr bool test_timespec() {
>>>>>>> +    static_assert(is_representable(TimeSpecT{max_time_t, 0}), "");
>>>>>>> +    static_assert(is_representable(TimeSpecT{max_time_t,
>>>>>>> 999999999}), "");
>>>>>>> +    static_assert(is_representable(TimeSpecT{max_time_t,
>>>>>>> 1000000000}), "");
>>>>>>> +    static_assert(is_representable(TimeSpecT{max_time_t,
>>>>>>> max_nsec}), "");
>>>>>>> +
>>>>>>> +    static_assert(is_representable(TimeSpecT{min_time_t, 0}), "");
>>>>>>> +    static_assert(is_representable(TimeSpecT{min_time_t,
>>>>>>> 999999999}), "");
>>>>>>> +    static_assert(is_representable(TimeSpecT{min_time_t,
>>>>>>> 1000000000}), "");
>>>>>>> +    static_assert(is_representable(TimeSpecT{min_time_t,
>>>>>>> min_nsec_timespec}),
>>>>>>> +                  "");
>>>>>>> +
>>>>>>> +    return true;
>>>>>>> +  }
>>>>>>> +
>>>>>>> +  static constexpr bool test_file_time_type() {
>>>>>>> +    // This kinda sucks. Oh well.
>>>>>>> +    static_assert(!Base::is_representable(FileTimeT::max()), "");
>>>>>>> +    static_assert(!Base::is_representable(FileTimeT::min()), "");
>>>>>>> +    return true;
>>>>>>> +  }
>>>>>>> +
>>>>>>> +  static constexpr bool check_round_trip(TimeSpecT orig) {
>>>>>>> +    TimeSpecT new_ts = {};
>>>>>>> +    FileTimeT out = convert_from_timespec(orig);
>>>>>>> +    assert(convert_to_timespec(new_ts, out));
>>>>>>> +    return new_ts.tv_sec == orig.tv_sec && new_ts.tv_nsec ==
>>>>>>> orig.tv_nsec;
>>>>>>> +  }
>>>>>>> +
>>>>>>> +  static constexpr bool test_convert_timespec() {
>>>>>>> +    static_assert(check_round_trip({0, 0}), "");
>>>>>>> +    static_assert(check_round_trip({0, 1}), "");
>>>>>>> +    static_assert(check_round_trip({1, 1}), "");
>>>>>>> +    static_assert(check_round_trip({-1, 1}), "");
>>>>>>> +    static_assert(check_round_trip({max_time_t, max_nsec}), "");
>>>>>>> +    static_assert(check_round_trip({max_time_t, 123}), "");
>>>>>>> +    static_assert(check_round_trip({min_time_t,
>>>>>>> min_nsec_timespec}), "");
>>>>>>> +    static_assert(check_round_trip({min_time_t, 123}), "");
>>>>>>> +    return true;
>>>>>>> +  }
>>>>>>> +
>>>>>>> +  static bool test() {
>>>>>>> +    static_assert(test_timespec(), "");
>>>>>>> +    static_assert(test_file_time_type(), "");
>>>>>>> +    static_assert(test_convert_timespec(), "");
>>>>>>> +    return true;
>>>>>>> +  }
>>>>>>> +};
>>>>>>> +
>>>>>>> +template <class FileTimeT, class TimeT, class TimeSpecT, class Base>
>>>>>>> +struct test_case<FileTimeT, TimeT, TimeSpecT, Base, TK_32Bit,
>>>>>>> TK_128Bit>
>>>>>>> +    : public test_case<FileTimeT, TimeT, TimeSpecT, Base, TK_64Bit,
>>>>>>> TK_128Bit> {
>>>>>>> +
>>>>>>> +};
>>>>>>> +
>>>>>>> +template <class FileTimeT, class TimeT, class TimeSpecT, class Base>
>>>>>>> +struct test_case<FileTimeT, TimeT, TimeSpecT, Base, TK_64Bit,
>>>>>>> TK_64Bit>
>>>>>>> +    : public Base {
>>>>>>> +
>>>>>>> +  using Base::convert_from_timespec;
>>>>>>>    using Base::is_representable;
>>>>>>>    using Base::max_nsec;
>>>>>>>    using Base::max_seconds;
>>>>>>> @@ -88,24 +178,25 @@ struct check_is_representable<FileTimeT,
>>>>>>>    }
>>>>>>>
>>>>>>>    static constexpr bool test_convert_timespec() {
>>>>>>> -    static_assert(convert_timespec(TimeSpecT{max_seconds,
>>>>>>> max_nsec}) ==
>>>>>>> +    static_assert(convert_from_timespec(TimeSpecT{max_seconds,
>>>>>>> max_nsec}) ==
>>>>>>>                        FileTimeT::max(),
>>>>>>>                    "");
>>>>>>> -    static_assert(convert_timespec(TimeSpecT{max_seconds, max_nsec
>>>>>>> - 1}) <
>>>>>>> +    static_assert(convert_from_timespec(TimeSpecT{max_seconds,
>>>>>>> max_nsec - 1}) <
>>>>>>>                        FileTimeT::max(),
>>>>>>>                    "");
>>>>>>> -    static_assert(convert_timespec(TimeSpecT{max_seconds - 1,
>>>>>>> 999999999}) <
>>>>>>> +    static_assert(convert_from_timespec(TimeSpecT{max_seconds - 1,
>>>>>>> 999999999}) <
>>>>>>>                        FileTimeT::max(),
>>>>>>>                    "");
>>>>>>> -    static_assert(convert_timespec(TimeSpecT{
>>>>>>> +    static_assert(convert_from_timespec(TimeSpecT{
>>>>>>>                        min_seconds - 1, min_nsec_timespec}) ==
>>>>>>> FileTimeT::min(),
>>>>>>>                    "");
>>>>>>> -    static_assert(
>>>>>>> -        convert_timespec(TimeSpecT{min_seconds - 1,
>>>>>>> min_nsec_timespec + 1}) >
>>>>>>> -            FileTimeT::min(),
>>>>>>> -        "");
>>>>>>> -    static_assert(
>>>>>>> -        convert_timespec(TimeSpecT{min_seconds, 0}) >
>>>>>>> FileTimeT::min(), "");
>>>>>>> +    static_assert(convert_from_timespec(
>>>>>>> +                      TimeSpecT{min_seconds - 1, min_nsec_timespec
>>>>>>> + 1}) >
>>>>>>> +                      FileTimeT::min(),
>>>>>>> +                  "");
>>>>>>> +    static_assert(convert_from_timespec(TimeSpecT{min_seconds, 0}) >
>>>>>>> +                      FileTimeT::min(),
>>>>>>> +                  "");
>>>>>>>      return true;
>>>>>>>    }
>>>>>>>
>>>>>>> @@ -118,12 +209,12 @@ struct check_is_representable<FileTimeT,
>>>>>>>  };
>>>>>>>
>>>>>>>  template <class FileTimeT, class TimeT, class TimeSpecT, class Base>
>>>>>>> -struct check_is_representable<FileTimeT, TimeT, TimeSpecT, Base,
>>>>>>> TK_32Bit>
>>>>>>> +struct test_case<FileTimeT, TimeT, TimeSpecT, Base, TK_32Bit,
>>>>>>> TK_64Bit>
>>>>>>>      : public Base {
>>>>>>>    static constexpr auto max_time_t =
>>>>>>> std::numeric_limits<TimeT>::max();
>>>>>>>    static constexpr auto min_time_t =
>>>>>>> std::numeric_limits<TimeT>::min();
>>>>>>>
>>>>>>> -  using Base::convert_timespec;
>>>>>>> +  using Base::convert_from_timespec;
>>>>>>>    using Base::is_representable;
>>>>>>>    using Base::max_nsec;
>>>>>>>    using Base::max_seconds;
>>>>>>> @@ -158,9 +249,10 @@ struct check_is_representable<FileTimeT,
>>>>>>>    }
>>>>>>>  };
>>>>>>>
>>>>>>> -template <class FileTimeT, class TimeT, class TimeSpec, class Base>
>>>>>>> -struct check_is_representable<FileTimeT, TimeT, TimeSpec, Base,
>>>>>>> -                              TK_FloatingPoint> : public Base {
>>>>>>> +template <class FileTimeT, class TimeT, class TimeSpec, class Base,
>>>>>>> +          TestKind FileTimeTKind>
>>>>>>> +struct test_case<FileTimeT, TimeT, TimeSpec, Base, TK_FloatingPoint,
>>>>>>> +                 FileTimeTKind> : public Base {
>>>>>>>
>>>>>>>    static bool test() { return true; }
>>>>>>>  };
>>>>>>> @@ -182,19 +274,33 @@ struct TestClock {
>>>>>>>    static time_point now() noexcept { return {}; }
>>>>>>>  };
>>>>>>>
>>>>>>> -template <class IntType, class Dur = duration<IntType, std::micro> >
>>>>>>> -using TestFileTimeT = time_point<TestClock<Dur> >;
>>>>>>> +template <class IntType, class Period = std::micro>
>>>>>>> +using TestFileTimeT = time_point<TestClock<duration<IntType,
>>>>>>> Period> > >;
>>>>>>>
>>>>>>>  int main() {
>>>>>>> -  assert((
>>>>>>> -      check_is_representable<file_time_type, time_t, struct
>>>>>>> timespec>::test()));
>>>>>>> -  assert((check_is_representable<TestFileTimeT<int64_t>, int64_t,
>>>>>>> -                                 TestTimeSpec<int64_t, long>
>>>>>>> >::test()));
>>>>>>> -  assert((check_is_representable<TestFileTimeT<long long>, int32_t,
>>>>>>> -                                 TestTimeSpec<int32_t, int32_t>
>>>>>>> >::test()));
>>>>>>> -
>>>>>>> -  // Test that insane platforms like ppc64 linux, which use long
>>>>>>> double as time_t,
>>>>>>> -  // at least compile.
>>>>>>> -  assert((check_is_representable<TestFileTimeT<long double>, double,
>>>>>>> -                                 TestTimeSpec<long double, long>
>>>>>>> >::test()));
>>>>>>> +  { assert((test_case<file_time_type, time_t, struct
>>>>>>> timespec>::test())); }
>>>>>>> +  {
>>>>>>> +    assert((test_case<TestFileTimeT<int64_t>, int64_t,
>>>>>>> +                      TestTimeSpec<int64_t, long> >::test()));
>>>>>>> +  }
>>>>>>> +  {
>>>>>>> +    assert((test_case<TestFileTimeT<long long>, int32_t,
>>>>>>> +                      TestTimeSpec<int32_t, int32_t> >::test()));
>>>>>>> +  }
>>>>>>> +  {
>>>>>>> +    // Test that insane platforms like ppc64 linux, which use long
>>>>>>> double as time_t,
>>>>>>> +    // at least compile.
>>>>>>> +    assert((test_case<TestFileTimeT<long double>, double,
>>>>>>> +                      TestTimeSpec<long double, long> >::test()));
>>>>>>> +  }
>>>>>>> +#ifndef TEST_HAS_NO_INT128_T
>>>>>>> +  {
>>>>>>> +    assert((test_case<TestFileTimeT<__int128_t, std::nano>, int64_t,
>>>>>>> +                      TestTimeSpec<int64_t, long> >::test()));
>>>>>>> +  }
>>>>>>> +  {
>>>>>>> +    assert((test_case<TestFileTimeT<__int128_t, std::nano>, int32_t,
>>>>>>> +                      TestTimeSpec<int32_t, int32_t> >::test()));
>>>>>>> +  }
>>>>>>> +#endif
>>>>>>>  }
>>>>>>>
>>>>>>> Modified:
>>>>>>> libcxx/trunk/test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp
>>>>>>> URL:
>>>>>>> http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp?rev=337960&r1=337959&r2=337960&view=diff
>>>>>>>
>>>>>>> ==============================================================================
>>>>>>> ---
>>>>>>> libcxx/trunk/test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp
>>>>>>> (original)
>>>>>>> +++
>>>>>>> libcxx/trunk/test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp
>>>>>>> Wed Jul 25 13:51:49 2018
>>>>>>> @@ -17,15 +17,30 @@
>>>>>>>  #include <chrono>
>>>>>>>  #include <type_traits>
>>>>>>>
>>>>>>> +#include "test_macros.h"
>>>>>>> +
>>>>>>>  // system_clock is used because it meets the requirements of
>>>>>>> TrivialClock,
>>>>>>>  // and the resolution and range of system_clock should match the
>>>>>>> operating
>>>>>>>  // system's file time type.
>>>>>>> -typedef std::chrono::system_clock              ExpectedClock;
>>>>>>> -typedef std::chrono::time_point<ExpectedClock> ExpectedTimePoint;
>>>>>>> +
>>>>>>> +void test_trivial_clock() {
>>>>>>> +  using namespace fs;
>>>>>>> +  using Clock = file_time_type::clock;
>>>>>>> +  ASSERT_NOEXCEPT(Clock::now());
>>>>>>> +  ASSERT_SAME_TYPE(decltype(Clock::now()), file_time_type);
>>>>>>> +  ASSERT_SAME_TYPE(Clock::time_point, file_time_type);
>>>>>>> +  volatile auto* odr_use = &Clock::is_steady;
>>>>>>> +  ((void)odr_use);
>>>>>>> +}
>>>>>>> +
>>>>>>> +void test_time_point_resolution_and_range() {
>>>>>>> +  using namespace fs;
>>>>>>> +  using Dur = file_time_type::duration;
>>>>>>> +  using Period = Dur::period;
>>>>>>> +  ASSERT_SAME_TYPE(Period, std::nano);
>>>>>>> +}
>>>>>>>
>>>>>>>  int main() {
>>>>>>> -  static_assert(std::is_same<
>>>>>>> -          fs::file_time_type,
>>>>>>> -          ExpectedTimePoint
>>>>>>> -      >::value, "");
>>>>>>> +  test_trivial_clock();
>>>>>>> +  test_time_point_resolution_and_range();
>>>>>>>  }
>>>>>>>
>>>>>>> Modified:
>>>>>>> libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>>>>>>> URL:
>>>>>>> http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp?rev=337960&r1=337959&r2=337960&view=diff
>>>>>>>
>>>>>>> ==============================================================================
>>>>>>> ---
>>>>>>> libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>>>>>>> (original)
>>>>>>> +++
>>>>>>> libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp
>>>>>>> Wed Jul 25 13:51:49 2018
>>>>>>> @@ -30,13 +30,86 @@
>>>>>>>  #include <sys/stat.h>
>>>>>>>  #include <iostream>
>>>>>>>
>>>>>>> +#include <fcntl.h>
>>>>>>> +#include <sys/time.h>
>>>>>>> +
>>>>>>>  using namespace fs;
>>>>>>>
>>>>>>> -struct Times { std::time_t access, write; };
>>>>>>> +using TimeSpec = struct ::timespec;
>>>>>>> +using StatT = struct ::stat;
>>>>>>> +
>>>>>>> +using Sec = std::chrono::duration<file_time_type::rep>;
>>>>>>> +using Hours = std::chrono::hours;
>>>>>>> +using Minutes = std::chrono::minutes;
>>>>>>> +using MicroSec = std::chrono::duration<file_time_type::rep,
>>>>>>> std::micro>;
>>>>>>> +using NanoSec = std::chrono::duration<file_time_type::rep,
>>>>>>> std::nano>;
>>>>>>> +using std::chrono::duration_cast;
>>>>>>> +
>>>>>>> +#if defined(__APPLE__)
>>>>>>> +TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
>>>>>>> +TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
>>>>>>> +#else
>>>>>>> +TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
>>>>>>> +TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
>>>>>>> +#endif
>>>>>>> +
>>>>>>> +bool ConvertToTimeSpec(TimeSpec& ts, file_time_type ft) {
>>>>>>> +  using SecFieldT = decltype(TimeSpec::tv_sec);
>>>>>>> +  using NSecFieldT = decltype(TimeSpec::tv_nsec);
>>>>>>> +  using SecLim = std::numeric_limits<SecFieldT>;
>>>>>>> +  using NSecLim = std::numeric_limits<NSecFieldT>;
>>>>>>> +
>>>>>>> +  auto secs = duration_cast<Sec>(ft.time_since_epoch());
>>>>>>> +  auto nsecs = duration_cast<NanoSec>(ft.time_since_epoch() - secs);
>>>>>>> +  if (nsecs.count() < 0) {
>>>>>>> +    if (Sec::min().count() > SecLim::min()) {
>>>>>>> +      secs += Sec(1);
>>>>>>> +      nsecs -= Sec(1);
>>>>>>> +    } else {
>>>>>>> +      nsecs = NanoSec(0);
>>>>>>> +    }
>>>>>>> +  }
>>>>>>> +  if (SecLim::max() < secs.count() || SecLim::min() > secs.count())
>>>>>>> +    return false;
>>>>>>> +  if (NSecLim::max() < nsecs.count() || NSecLim::min() >
>>>>>>> nsecs.count())
>>>>>>> +    return false;
>>>>>>> +  ts.tv_sec = secs.count();
>>>>>>> +  ts.tv_nsec = nsecs.count();
>>>>>>> +  return true;
>>>>>>> +}
>>>>>>> +
>>>>>>> +bool ConvertFromTimeSpec(file_time_type& ft, TimeSpec ts) {
>>>>>>> +  auto secs_part =
>>>>>>> duration_cast<file_time_type::duration>(Sec(ts.tv_sec));
>>>>>>> +  if (duration_cast<Sec>(secs_part).count() != ts.tv_sec)
>>>>>>> +    return false;
>>>>>>> +  auto subsecs =
>>>>>>> duration_cast<file_time_type::duration>(NanoSec(ts.tv_nsec));
>>>>>>> +  auto dur = secs_part + subsecs;
>>>>>>> +  if (dur < secs_part && subsecs.count() >= 0)
>>>>>>> +    return false;
>>>>>>> +  ft = file_time_type(dur);
>>>>>>> +  return true;
>>>>>>> +}
>>>>>>> +
>>>>>>> +bool CompareTimeExact(TimeSpec ts, TimeSpec ts2) {
>>>>>>> +  return ts2.tv_sec == ts.tv_sec && ts2.tv_nsec == ts.tv_nsec;
>>>>>>> +}
>>>>>>> +bool CompareTimeExact(file_time_type ft, TimeSpec ts) {
>>>>>>> +  TimeSpec ts2 = {};
>>>>>>> +  if (!ConvertToTimeSpec(ts2, ft))
>>>>>>> +    return false;
>>>>>>> +  return CompareTimeExact(ts, ts2);
>>>>>>> +}
>>>>>>> +bool CompareTimeExact(TimeSpec ts, file_time_type ft) {
>>>>>>> +  return CompareTimeExact(ft, ts);
>>>>>>> +}
>>>>>>> +
>>>>>>> +struct Times {
>>>>>>> +  TimeSpec access, write;
>>>>>>> +};
>>>>>>>
>>>>>>>  Times GetTimes(path const& p) {
>>>>>>>      using Clock = file_time_type::clock;
>>>>>>> -    struct ::stat st;
>>>>>>> +    StatT st;
>>>>>>>      if (::stat(p.c_str(), &st) == -1) {
>>>>>>>          std::error_code ec(errno, std::generic_category());
>>>>>>>  #ifndef TEST_HAS_NO_EXCEPTIONS
>>>>>>> @@ -46,22 +119,18 @@ Times GetTimes(path const& p) {
>>>>>>>          std::exit(EXIT_FAILURE);
>>>>>>>  #endif
>>>>>>>      }
>>>>>>> -    return {st.st_atime, st.st_mtime};
>>>>>>> +    return {extract_atime(st), extract_mtime(st)};
>>>>>>>  }
>>>>>>>
>>>>>>> -std::time_t LastAccessTime(path const& p) {
>>>>>>> -    return GetTimes(p).access;
>>>>>>> -}
>>>>>>> +TimeSpec LastAccessTime(path const& p) { return GetTimes(p).access;
>>>>>>> }
>>>>>>>
>>>>>>> -std::time_t LastWriteTime(path const& p) {
>>>>>>> -    return GetTimes(p).write;
>>>>>>> -}
>>>>>>> +TimeSpec LastWriteTime(path const& p) { return GetTimes(p).write; }
>>>>>>>
>>>>>>> -std::pair<std::time_t, std::time_t> GetSymlinkTimes(path const& p) {
>>>>>>> -    using Clock = file_time_type::clock;
>>>>>>> -    struct ::stat st;
>>>>>>> -    if (::lstat(p.c_str(), &st) == -1) {
>>>>>>> -        std::error_code ec(errno, std::generic_category());
>>>>>>> +std::pair<TimeSpec, TimeSpec> GetSymlinkTimes(path const& p) {
>>>>>>> +  using Clock = file_time_type::clock;
>>>>>>> +  StatT st;
>>>>>>> +  if (::lstat(p.c_str(), &st) == -1) {
>>>>>>> +    std::error_code ec(errno, std::generic_category());
>>>>>>>  #ifndef TEST_HAS_NO_EXCEPTIONS
>>>>>>>          throw ec;
>>>>>>>  #else
>>>>>>> @@ -69,24 +138,10 @@ std::pair<std::time_t, std::time_t> GetS
>>>>>>>          std::exit(EXIT_FAILURE);
>>>>>>>  #endif
>>>>>>>      }
>>>>>>> -    return {st.st_atime, st.st_mtime};
>>>>>>> +    return {extract_atime(st), extract_mtime(st)};
>>>>>>>  }
>>>>>>>
>>>>>>>  namespace {
>>>>>>> -bool TestSupportsNegativeTimes() {
>>>>>>> -    using namespace std::chrono;
>>>>>>> -    std::error_code ec;
>>>>>>> -    std::time_t old_write_time, new_write_time;
>>>>>>> -    { // WARNING: Do not assert in this scope.
>>>>>>> -        scoped_test_env env;
>>>>>>> -        const path file = env.create_file("file", 42);
>>>>>>> -        old_write_time = LastWriteTime(file);
>>>>>>> -        file_time_type tp(seconds(-5));
>>>>>>> -        fs::last_write_time(file, tp, ec);
>>>>>>> -        new_write_time = LastWriteTime(file);
>>>>>>> -    }
>>>>>>> -    return !ec && new_write_time <= -5;
>>>>>>> -}
>>>>>>>
>>>>>>>  // In some configurations, the comparison is tautological and the
>>>>>>> test is valid.
>>>>>>>  // We disable the warning so that we can actually test it
>>>>>>> regardless. Also, that
>>>>>>> @@ -98,61 +153,131 @@ bool TestSupportsNegativeTimes() {
>>>>>>>  #pragma clang diagnostic ignored "-Wtautological-constant-compare"
>>>>>>>  #endif
>>>>>>>
>>>>>>> -bool TestSupportsMaxTime() {
>>>>>>> -    using namespace std::chrono;
>>>>>>> -    using Lim = std::numeric_limits<std::time_t>;
>>>>>>> -    auto max_sec =
>>>>>>> duration_cast<seconds>(file_time_type::max().time_since_epoch()).count();
>>>>>>> -    if (max_sec > Lim::max()) return false;
>>>>>>> -    std::error_code ec;
>>>>>>> -    std::time_t old_write_time, new_write_time;
>>>>>>> -    { // WARNING: Do not assert in this scope.
>>>>>>> -        scoped_test_env env;
>>>>>>> -        const path file = env.create_file("file", 42);
>>>>>>> -        old_write_time = LastWriteTime(file);
>>>>>>> -        file_time_type tp = file_time_type::max();
>>>>>>> -        fs::last_write_time(file, tp, ec);
>>>>>>> -        new_write_time = LastWriteTime(file);
>>>>>>> -    }
>>>>>>> -    return !ec && new_write_time > max_sec - 1;
>>>>>>> -}
>>>>>>> -
>>>>>>> -bool TestSupportsMinTime() {
>>>>>>> -    using namespace std::chrono;
>>>>>>> -    using Lim = std::numeric_limits<std::time_t>;
>>>>>>> -    auto min_sec =
>>>>>>> duration_cast<seconds>(file_time_type::min().time_since_epoch()).count();
>>>>>>> -    if (min_sec < Lim::min()) return false;
>>>>>>> -    std::error_code ec;
>>>>>>> -    std::time_t old_write_time, new_write_time;
>>>>>>> -    { // WARNING: Do not assert in this scope.
>>>>>>> -      scoped_test_env env;
>>>>>>> -      const path file = env.create_file("file", 42);
>>>>>>> -      old_write_time = LastWriteTime(file);
>>>>>>> -      file_time_type tp = file_time_type::min();
>>>>>>> -      fs::last_write_time(file, tp, ec);
>>>>>>> -      new_write_time = LastWriteTime(file);
>>>>>>> -    }
>>>>>>> -    return !ec && new_write_time < min_sec + 1;
>>>>>>> -}
>>>>>>> -
>>>>>>> -#if defined(__clang__)
>>>>>>> -#pragma clang diagnostic pop
>>>>>>> -#endif
>>>>>>> -
>>>>>>> -static const bool SupportsNegativeTimes =
>>>>>>> TestSupportsNegativeTimes();
>>>>>>> -static const bool SupportsMaxTime = TestSupportsMaxTime();
>>>>>>> -static const bool SupportsMinTime = TestSupportsMinTime();
>>>>>>> +static const bool SupportsNegativeTimes = [] {
>>>>>>> +  using namespace std::chrono;
>>>>>>> +  std::error_code ec;
>>>>>>> +  TimeSpec old_write_time, new_write_time;
>>>>>>> +  { // WARNING: Do not assert in this scope.
>>>>>>> +    scoped_test_env env;
>>>>>>> +    const path file = env.create_file("file", 42);
>>>>>>> +    old_write_time = LastWriteTime(file);
>>>>>>> +    file_time_type tp(seconds(-5));
>>>>>>> +    fs::last_write_time(file, tp, ec);
>>>>>>> +    new_write_time = LastWriteTime(file);
>>>>>>> +  }
>>>>>>> +
>>>>>>> +  return !ec && new_write_time.tv_sec < 0;
>>>>>>> +}();
>>>>>>> +
>>>>>>> +static const bool SupportsMaxTime = [] {
>>>>>>> +  using namespace std::chrono;
>>>>>>> +  TimeSpec max_ts = {};
>>>>>>> +  if (!ConvertToTimeSpec(max_ts, file_time_type::max()))
>>>>>>> +    return false;
>>>>>>> +
>>>>>>> +  std::error_code ec;
>>>>>>> +  TimeSpec old_write_time, new_write_time;
>>>>>>> +  { // WARNING: Do not assert in this scope.
>>>>>>> +    scoped_test_env env;
>>>>>>> +    const path file = env.create_file("file", 42);
>>>>>>> +    old_write_time = LastWriteTime(file);
>>>>>>> +    file_time_type tp = file_time_type::max();
>>>>>>> +    fs::last_write_time(file, tp, ec);
>>>>>>> +    new_write_time = LastWriteTime(file);
>>>>>>> +  }
>>>>>>> +  return !ec && new_write_time.tv_sec > max_ts.tv_sec - 1;
>>>>>>> +}();
>>>>>>> +
>>>>>>> +static const bool SupportsMinTime = [] {
>>>>>>> +  using namespace std::chrono;
>>>>>>> +  TimeSpec min_ts = {};
>>>>>>> +  if (!ConvertToTimeSpec(min_ts, file_time_type::min()))
>>>>>>> +    return false;
>>>>>>> +  std::error_code ec;
>>>>>>> +  TimeSpec old_write_time, new_write_time;
>>>>>>> +  { // WARNING: Do not assert in this scope.
>>>>>>> +    scoped_test_env env;
>>>>>>> +    const path file = env.create_file("file", 42);
>>>>>>> +    old_write_time = LastWriteTime(file);
>>>>>>> +    file_time_type tp = file_time_type::min();
>>>>>>> +    fs::last_write_time(file, tp, ec);
>>>>>>> +    new_write_time = LastWriteTime(file);
>>>>>>> +  }
>>>>>>> +  return !ec && new_write_time.tv_sec < min_ts.tv_sec + 1;
>>>>>>> +}();
>>>>>>> +
>>>>>>> +static const bool SupportsNanosecondRoundTrip = [] {
>>>>>>> +  NanoSec ns(3);
>>>>>>> +
>>>>>>> +  // Test if the file_time_type period is less than that of
>>>>>>> nanoseconds.
>>>>>>> +  auto ft_dur = duration_cast<file_time_type::duration>(ns);
>>>>>>> +  if (duration_cast<NanoSec>(ft_dur) != ns)
>>>>>>> +    return false;
>>>>>>> +
>>>>>>> +  // Test that the system call we use to set the times also
>>>>>>> supports nanosecond
>>>>>>> +  // resolution. (utimes does not)
>>>>>>> +  file_time_type ft(ft_dur);
>>>>>>> +  {
>>>>>>> +    scoped_test_env env;
>>>>>>> +    const path p = env.create_file("file", 42);
>>>>>>> +    last_write_time(p, ft);
>>>>>>> +    return last_write_time(p) == ft;
>>>>>>> +  }
>>>>>>> +}();
>>>>>>> +
>>>>>>> +static const bool SupportsMinRoundTrip = [] {
>>>>>>> +  TimeSpec ts = {};
>>>>>>> +  if (!ConvertToTimeSpec(ts, file_time_type::min()))
>>>>>>> +    return false;
>>>>>>> +  file_time_type min_val = {};
>>>>>>> +  if (!ConvertFromTimeSpec(min_val, ts))
>>>>>>> +    return false;
>>>>>>> +  return min_val == file_time_type::min();
>>>>>>> +}();
>>>>>>>
>>>>>>>  } // end namespace
>>>>>>>
>>>>>>> -// In some configurations, the comparison is tautological and the
>>>>>>> test is valid.
>>>>>>> -// We disable the warning so that we can actually test it
>>>>>>> regardless. Also, that
>>>>>>> -// diagnostic is pretty new, so also don't fail if old clang does
>>>>>>> not support it
>>>>>>> -#if defined(__clang__)
>>>>>>> -#pragma clang diagnostic push
>>>>>>> -#pragma clang diagnostic ignored "-Wunknown-warning-option"
>>>>>>> -#pragma clang diagnostic ignored "-Wunknown-pragmas"
>>>>>>> -#pragma clang diagnostic ignored "-Wtautological-constant-compare"
>>>>>>> -#endif
>>>>>>> +static bool CompareTime(TimeSpec t1, TimeSpec t2) {
>>>>>>> +  if (SupportsNanosecondRoundTrip)
>>>>>>> +    return CompareTimeExact(t1, t2);
>>>>>>> +  if (t1.tv_sec != t2.tv_sec)
>>>>>>> +    return false;
>>>>>>> +
>>>>>>> +  auto diff = std::abs(t1.tv_nsec - t2.tv_nsec);
>>>>>>> +
>>>>>>> +  return diff < duration_cast<NanoSec>(MicroSec(1)).count();
>>>>>>> +}
>>>>>>> +
>>>>>>> +static bool CompareTime(file_time_type t1, TimeSpec t2) {
>>>>>>> +  TimeSpec ts1 = {};
>>>>>>> +  if (!ConvertToTimeSpec(ts1, t1))
>>>>>>> +    return false;
>>>>>>> +  return CompareTime(ts1, t2);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static bool CompareTime(TimeSpec t1, file_time_type t2) {
>>>>>>> +  return CompareTime(t2, t1);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static bool CompareTime(file_time_type t1, file_time_type t2) {
>>>>>>> +  auto min_secs =
>>>>>>> duration_cast<Sec>(file_time_type::min().time_since_epoch());
>>>>>>> +  bool IsMin =
>>>>>>> +      t1.time_since_epoch() < min_secs || t2.time_since_epoch() <
>>>>>>> min_secs;
>>>>>>> +
>>>>>>> +  if (SupportsNanosecondRoundTrip && (!IsMin ||
>>>>>>> SupportsMinRoundTrip))
>>>>>>> +    return t1 == t2;
>>>>>>> +  if (IsMin) {
>>>>>>> +    return duration_cast<Sec>(t1.time_since_epoch()) ==
>>>>>>> +           duration_cast<Sec>(t2.time_since_epoch());
>>>>>>> +  }
>>>>>>> +  file_time_type::duration dur;
>>>>>>> +  if (t1 > t2)
>>>>>>> +    dur = t1 - t2;
>>>>>>> +  else
>>>>>>> +    dur = t2 - t1;
>>>>>>> +
>>>>>>> +  return duration_cast<MicroSec>(dur).count() < 1;
>>>>>>> +}
>>>>>>>
>>>>>>>  // Check if a time point is representable on a given filesystem.
>>>>>>> Check that:
>>>>>>>  // (A) 'tp' is representable as a time_t
>>>>>>> @@ -162,22 +287,33 @@ static const bool SupportsMinTime = Test
>>>>>>>  // (D) 'tp' is not 'file_time_type::min()' or the filesystem
>>>>>>> supports the min
>>>>>>>  //     value.
>>>>>>>  inline bool TimeIsRepresentableByFilesystem(file_time_type tp) {
>>>>>>> -    using namespace std::chrono;
>>>>>>> -    using Lim = std::numeric_limits<std::time_t>;
>>>>>>> -    auto sec =
>>>>>>> duration_cast<seconds>(tp.time_since_epoch()).count();
>>>>>>> -    auto microsec =
>>>>>>> duration_cast<microseconds>(tp.time_since_epoch()).count();
>>>>>>> -    if (sec < Lim::min() || sec > Lim::max())   return false;
>>>>>>> -    else if (microsec < 0 && !SupportsNegativeTimes) return false;
>>>>>>> -    else if (tp == file_time_type::max() && !SupportsMaxTime)
>>>>>>> return false;
>>>>>>> -    else if (tp == file_time_type::min() && !SupportsMinTime)
>>>>>>> return false;
>>>>>>> -    return true;
>>>>>>> +  TimeSpec ts = {};
>>>>>>> +  if (!ConvertToTimeSpec(ts, tp))
>>>>>>> +    return false;
>>>>>>> +  else if (tp.time_since_epoch().count() < 0 &&
>>>>>>> !SupportsNegativeTimes)
>>>>>>> +    return false;
>>>>>>> +  else if (tp == file_time_type::max() && !SupportsMaxTime)
>>>>>>> +    return false;
>>>>>>> +  else if (tp == file_time_type::min() && !SupportsMinTime)
>>>>>>> +    return false;
>>>>>>> +  return true;
>>>>>>>  }
>>>>>>>
>>>>>>>  #if defined(__clang__)
>>>>>>>  #pragma clang diagnostic pop
>>>>>>>  #endif
>>>>>>>
>>>>>>> -TEST_SUITE(exists_test_suite)
>>>>>>> +// Create a sub-second duration using the smallest period the
>>>>>>> filesystem supports.
>>>>>>> +file_time_type::duration SubSec(long long val) {
>>>>>>> +  using SubSecT = file_time_type::duration;
>>>>>>> +  if (SupportsNanosecondRoundTrip) {
>>>>>>> +    return duration_cast<SubSecT>(NanoSec(val));
>>>>>>> +  } else {
>>>>>>> +    return duration_cast<SubSecT>(MicroSec(val));
>>>>>>> +  }
>>>>>>> +}
>>>>>>> +
>>>>>>> +TEST_SUITE(last_write_time_test_suite)
>>>>>>>
>>>>>>>  TEST_CASE(signature_test)
>>>>>>>  {
>>>>>>> @@ -202,21 +338,21 @@ TEST_CASE(read_last_write_time_static_en
>>>>>>>          file_time_type ret = last_write_time(StaticEnv::File);
>>>>>>>          TEST_CHECK(ret != min);
>>>>>>>          TEST_CHECK(ret < C::now());
>>>>>>> -        TEST_CHECK(C::to_time_t(ret) ==
>>>>>>> LastWriteTime(StaticEnv::File));
>>>>>>> +        TEST_CHECK(CompareTime(ret,
>>>>>>> LastWriteTime(StaticEnv::File)));
>>>>>>>
>>>>>>>          file_time_type ret2 =
>>>>>>> last_write_time(StaticEnv::SymlinkToFile);
>>>>>>> -        TEST_CHECK(ret == ret2);
>>>>>>> -        TEST_CHECK(C::to_time_t(ret2) ==
>>>>>>> LastWriteTime(StaticEnv::SymlinkToFile));
>>>>>>> +        TEST_CHECK(CompareTime(ret, ret2));
>>>>>>> +        TEST_CHECK(CompareTime(ret2,
>>>>>>> LastWriteTime(StaticEnv::SymlinkToFile)));
>>>>>>>      }
>>>>>>>      {
>>>>>>>          file_time_type ret = last_write_time(StaticEnv::Dir);
>>>>>>>          TEST_CHECK(ret != min);
>>>>>>>          TEST_CHECK(ret < C::now());
>>>>>>> -        TEST_CHECK(C::to_time_t(ret) ==
>>>>>>> LastWriteTime(StaticEnv::Dir));
>>>>>>> +        TEST_CHECK(CompareTime(ret, LastWriteTime(StaticEnv::Dir)));
>>>>>>>
>>>>>>>          file_time_type ret2 =
>>>>>>> last_write_time(StaticEnv::SymlinkToDir);
>>>>>>> -        TEST_CHECK(ret == ret2);
>>>>>>> -        TEST_CHECK(C::to_time_t(ret2) ==
>>>>>>> LastWriteTime(StaticEnv::SymlinkToDir));
>>>>>>> +        TEST_CHECK(CompareTime(ret, ret2));
>>>>>>> +        TEST_CHECK(CompareTime(ret2,
>>>>>>> LastWriteTime(StaticEnv::SymlinkToDir)));
>>>>>>>      }
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -230,15 +366,17 @@ TEST_CASE(get_last_write_time_dynamic_en
>>>>>>>      const path dir = env.create_dir("dir");
>>>>>>>
>>>>>>>      const auto file_times = GetTimes(file);
>>>>>>> -    const std::time_t file_write_time = file_times.write;
>>>>>>> +    const TimeSpec file_write_time = file_times.write;
>>>>>>>      const auto dir_times = GetTimes(dir);
>>>>>>> -    const std::time_t dir_write_time = dir_times.write;
>>>>>>> +    const TimeSpec dir_write_time = dir_times.write;
>>>>>>>
>>>>>>>      file_time_type ftime = last_write_time(file);
>>>>>>> -    TEST_CHECK(Clock::to_time_t(ftime) == file_write_time);
>>>>>>> +    TEST_CHECK(Clock::to_time_t(ftime) == file_write_time.tv_sec);
>>>>>>> +    TEST_CHECK(CompareTime(ftime, file_write_time));
>>>>>>>
>>>>>>>      file_time_type dtime = last_write_time(dir);
>>>>>>> -    TEST_CHECK(Clock::to_time_t(dtime) == dir_write_time);
>>>>>>> +    TEST_CHECK(Clock::to_time_t(dtime) == dir_write_time.tv_sec);
>>>>>>> +    TEST_CHECK(CompareTime(dtime, dir_write_time));
>>>>>>>
>>>>>>>      SleepFor(Sec(2));
>>>>>>>
>>>>>>> @@ -253,18 +391,15 @@ TEST_CASE(get_last_write_time_dynamic_en
>>>>>>>
>>>>>>>      TEST_CHECK(ftime2 > ftime);
>>>>>>>      TEST_CHECK(dtime2 > dtime);
>>>>>>> -    TEST_CHECK(LastWriteTime(file) == Clock::to_time_t(ftime2));
>>>>>>> -    TEST_CHECK(LastWriteTime(dir) == Clock::to_time_t(dtime2));
>>>>>>> +    TEST_CHECK(CompareTime(LastWriteTime(file), ftime2));
>>>>>>> +    TEST_CHECK(CompareTime(LastWriteTime(dir), dtime2));
>>>>>>>  }
>>>>>>>
>>>>>>>
>>>>>>>  TEST_CASE(set_last_write_time_dynamic_env_test)
>>>>>>>  {
>>>>>>>      using Clock = file_time_type::clock;
>>>>>>> -    using Sec = std::chrono::seconds;
>>>>>>> -    using Hours = std::chrono::hours;
>>>>>>> -    using Minutes = std::chrono::minutes;
>>>>>>> -    using MicroSec = std::chrono::microseconds;
>>>>>>> +    using SubSecT = file_time_type::duration;
>>>>>>>      scoped_test_env env;
>>>>>>>
>>>>>>>      const path file = env.create_file("file", 42);
>>>>>>> @@ -272,15 +407,17 @@ TEST_CASE(set_last_write_time_dynamic_en
>>>>>>>      const auto now = Clock::now();
>>>>>>>      const file_time_type epoch_time = now - now.time_since_epoch();
>>>>>>>
>>>>>>> -    const file_time_type future_time = now + Hours(3) + Sec(42) +
>>>>>>> MicroSec(17);
>>>>>>> -    const file_time_type past_time = now - Minutes(3) - Sec(42) -
>>>>>>> MicroSec(17);
>>>>>>> -    const file_time_type before_epoch_time = epoch_time -
>>>>>>> Minutes(3) - Sec(42) - MicroSec(17);
>>>>>>> +    const file_time_type future_time = now + Hours(3) + Sec(42) +
>>>>>>> SubSec(17);
>>>>>>> +    const file_time_type past_time = now - Minutes(3) - Sec(42) -
>>>>>>> SubSec(17);
>>>>>>> +    const file_time_type before_epoch_time =
>>>>>>> +        epoch_time - Minutes(3) - Sec(42) - SubSec(17);
>>>>>>>      // FreeBSD has a bug in their utimes implementation where the
>>>>>>> time is not update
>>>>>>>      // when the number of seconds is '-1'.
>>>>>>>  #if defined(__FreeBSD__)
>>>>>>> -    const file_time_type just_before_epoch_time = epoch_time -
>>>>>>> Sec(2) - MicroSec(17);
>>>>>>> +    const file_time_type just_before_epoch_time =
>>>>>>> +        epoch_time - Sec(2) - SubSec(17);
>>>>>>>  #else
>>>>>>> -    const file_time_type just_before_epoch_time = epoch_time -
>>>>>>> MicroSec(17);
>>>>>>> +    const file_time_type just_before_epoch_time = epoch_time -
>>>>>>> SubSec(17);
>>>>>>>  #endif
>>>>>>>
>>>>>>>      struct TestCase {
>>>>>>> @@ -300,7 +437,8 @@ TEST_CASE(set_last_write_time_dynamic_en
>>>>>>>      };
>>>>>>>      for (const auto& TC : cases) {
>>>>>>>          const auto old_times = GetTimes(TC.p);
>>>>>>> -        file_time_type old_time(Sec(old_times.write));
>>>>>>> +        file_time_type old_time;
>>>>>>> +        TEST_REQUIRE(ConvertFromTimeSpec(old_time,
>>>>>>> old_times.write));
>>>>>>>
>>>>>>>          std::error_code ec = GetTestEC();
>>>>>>>          last_write_time(TC.p, TC.new_time, ec);
>>>>>>> @@ -310,14 +448,8 @@ TEST_CASE(set_last_write_time_dynamic_en
>>>>>>>
>>>>>>>          if (TimeIsRepresentableByFilesystem(TC.new_time)) {
>>>>>>>              TEST_CHECK(got_time != old_time);
>>>>>>> -            if (TC.new_time < epoch_time) {
>>>>>>> -                TEST_CHECK(got_time <= TC.new_time);
>>>>>>> -                TEST_CHECK(got_time > TC.new_time - Sec(1));
>>>>>>> -            } else {
>>>>>>> -                TEST_CHECK(got_time <= TC.new_time + Sec(1));
>>>>>>> -                TEST_CHECK(got_time >= TC.new_time - Sec(1));
>>>>>>> -            }
>>>>>>> -            TEST_CHECK(LastAccessTime(TC.p) == old_times.access);
>>>>>>> +            TEST_CHECK(CompareTime(got_time, TC.new_time));
>>>>>>> +            TEST_CHECK(CompareTime(LastAccessTime(TC.p),
>>>>>>> old_times.access));
>>>>>>>          }
>>>>>>>      }
>>>>>>>  }
>>>>>>> @@ -325,9 +457,6 @@ TEST_CASE(set_last_write_time_dynamic_en
>>>>>>>  TEST_CASE(last_write_time_symlink_test)
>>>>>>>  {
>>>>>>>      using Clock = file_time_type::clock;
>>>>>>> -    using Sec = std::chrono::seconds;
>>>>>>> -    using Hours = std::chrono::hours;
>>>>>>> -    using Minutes = std::chrono::minutes;
>>>>>>>
>>>>>>>      scoped_test_env env;
>>>>>>>
>>>>>>> @@ -343,77 +472,75 @@ TEST_CASE(last_write_time_symlink_test)
>>>>>>>      last_write_time(sym, new_time, ec);
>>>>>>>      TEST_CHECK(!ec);
>>>>>>>
>>>>>>> -    const std::time_t new_time_t = Clock::to_time_t(new_time);
>>>>>>>      file_time_type  got_time = last_write_time(sym);
>>>>>>> -    std::time_t got_time_t = Clock::to_time_t(got_time);
>>>>>>> +    TEST_CHECK(!CompareTime(got_time, old_times.write));
>>>>>>> +    TEST_CHECK(got_time == new_time);
>>>>>>>
>>>>>>> -    TEST_CHECK(got_time_t != old_times.write);
>>>>>>> -    TEST_CHECK(got_time_t == new_time_t);
>>>>>>> -    TEST_CHECK(LastWriteTime(file) == new_time_t);
>>>>>>> -    TEST_CHECK(LastAccessTime(sym) == old_times.access);
>>>>>>> -    TEST_CHECK(GetSymlinkTimes(sym) == old_sym_times);
>>>>>>> +    TEST_CHECK(CompareTime(LastWriteTime(file), new_time));
>>>>>>> +    TEST_CHECK(CompareTime(LastAccessTime(sym), old_times.access));
>>>>>>> +    std::pair<TimeSpec, TimeSpec> sym_times = GetSymlinkTimes(sym);
>>>>>>> +    TEST_CHECK(CompareTime(sym_times.first, old_sym_times.first));
>>>>>>> +    TEST_CHECK(CompareTime(sym_times.second, old_sym_times.second));
>>>>>>>  }
>>>>>>>
>>>>>>>
>>>>>>>  TEST_CASE(test_write_min_time)
>>>>>>>  {
>>>>>>>      using Clock = file_time_type::clock;
>>>>>>> -    using Sec = std::chrono::seconds;
>>>>>>> -    using MicroSec = std::chrono::microseconds;
>>>>>>> -    using Lim = std::numeric_limits<std::time_t>;
>>>>>>>      scoped_test_env env;
>>>>>>>      const path p = env.create_file("file", 42);
>>>>>>> -
>>>>>>> -    std::error_code ec = GetTestEC();
>>>>>>> +    const file_time_type old_time = last_write_time(p);
>>>>>>>      file_time_type new_time = file_time_type::min();
>>>>>>>
>>>>>>> +    std::error_code ec = GetTestEC();
>>>>>>>      last_write_time(p, new_time, ec);
>>>>>>>      file_time_type tt = last_write_time(p);
>>>>>>>
>>>>>>>      if (TimeIsRepresentableByFilesystem(new_time)) {
>>>>>>>          TEST_CHECK(!ec);
>>>>>>> -        TEST_CHECK(tt >= new_time);
>>>>>>> -        TEST_CHECK(tt < new_time + Sec(1));
>>>>>>> -
>>>>>>> -        ec = GetTestEC();
>>>>>>> -        last_write_time(p, Clock::now());
>>>>>>> +        TEST_CHECK(CompareTime(tt, new_time));
>>>>>>>
>>>>>>> -        new_time = file_time_type::min() + MicroSec(1);
>>>>>>> +        last_write_time(p, old_time);
>>>>>>> +        new_time = file_time_type::min() + SubSec(1);
>>>>>>>
>>>>>>> +        ec = GetTestEC();
>>>>>>>          last_write_time(p, new_time, ec);
>>>>>>>          tt = last_write_time(p);
>>>>>>>
>>>>>>>          if (TimeIsRepresentableByFilesystem(new_time)) {
>>>>>>>              TEST_CHECK(!ec);
>>>>>>> -            TEST_CHECK(tt >= new_time);
>>>>>>> -            TEST_CHECK(tt < new_time + Sec(1));
>>>>>>> +            TEST_CHECK(CompareTime(tt, new_time));
>>>>>>> +        } else {
>>>>>>> +          TEST_CHECK(ErrorIs(ec, std::errc::value_too_large));
>>>>>>> +          TEST_CHECK(tt == old_time);
>>>>>>>          }
>>>>>>> +    } else {
>>>>>>> +      TEST_CHECK(ErrorIs(ec, std::errc::value_too_large));
>>>>>>> +      TEST_CHECK(tt == old_time);
>>>>>>>      }
>>>>>>>  }
>>>>>>>
>>>>>>> +TEST_CASE(test_write_max_time) {
>>>>>>> +  using Clock = file_time_type::clock;
>>>>>>> +  using Sec = std::chrono::seconds;
>>>>>>> +  using Hours = std::chrono::hours;
>>>>>>> +
>>>>>>> +  scoped_test_env env;
>>>>>>> +  const path p = env.create_file("file", 42);
>>>>>>> +  const file_time_type old_time = last_write_time(p);
>>>>>>> +  file_time_type new_time = file_time_type::max();
>>>>>>> +
>>>>>>> +  std::error_code ec = GetTestEC();
>>>>>>> +  last_write_time(p, new_time, ec);
>>>>>>> +  file_time_type tt = last_write_time(p);
>>>>>>>
>>>>>>> -
>>>>>>> -TEST_CASE(test_write_min_max_time)
>>>>>>> -{
>>>>>>> -    using Clock = file_time_type::clock;
>>>>>>> -    using Sec = std::chrono::seconds;
>>>>>>> -    using Hours = std::chrono::hours;
>>>>>>> -    using Lim = std::numeric_limits<std::time_t>;
>>>>>>> -    scoped_test_env env;
>>>>>>> -    const path p = env.create_file("file", 42);
>>>>>>> -
>>>>>>> -    std::error_code ec = GetTestEC();
>>>>>>> -    file_time_type new_time = file_time_type::max();
>>>>>>> -
>>>>>>> -    ec = GetTestEC();
>>>>>>> -    last_write_time(p, new_time, ec);
>>>>>>> -    file_time_type tt = last_write_time(p);
>>>>>>> -
>>>>>>> -    if (TimeIsRepresentableByFilesystem(new_time)) {
>>>>>>> -        TEST_CHECK(!ec);
>>>>>>> -        TEST_CHECK(tt > new_time - Sec(1));
>>>>>>> -        TEST_CHECK(tt <= new_time);
>>>>>>> -    }
>>>>>>> +  if (TimeIsRepresentableByFilesystem(new_time)) {
>>>>>>> +    TEST_CHECK(!ec);
>>>>>>> +    TEST_CHECK(CompareTime(tt, new_time));
>>>>>>> +  } else {
>>>>>>> +    TEST_CHECK(ErrorIs(ec, std::errc::value_too_large));
>>>>>>> +    TEST_CHECK(tt == old_time);
>>>>>>> +  }
>>>>>>>  }
>>>>>>>
>>>>>>>  TEST_CASE(test_value_on_failure)
>>>>>>> @@ -421,8 +548,7 @@ TEST_CASE(test_value_on_failure)
>>>>>>>      const path p = StaticEnv::DNE;
>>>>>>>      std::error_code ec = GetTestEC();
>>>>>>>      TEST_CHECK(last_write_time(p, ec) == file_time_type::min());
>>>>>>> -    TEST_CHECK(ec);
>>>>>>> -    TEST_CHECK(ec != GetTestEC());
>>>>>>> +    TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
>>>>>>>  }
>>>>>>>
>>>>>>>  TEST_CASE(test_exists_fails)
>>>>>>> @@ -434,10 +560,30 @@ TEST_CASE(test_exists_fails)
>>>>>>>
>>>>>>>      std::error_code ec = GetTestEC();
>>>>>>>      TEST_CHECK(last_write_time(file, ec) == file_time_type::min());
>>>>>>> -    TEST_CHECK(ec);
>>>>>>> -    TEST_CHECK(ec != GetTestEC());
>>>>>>> +    TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
>>>>>>>
>>>>>>> -    TEST_CHECK_THROW(filesystem_error, last_write_time(file));
>>>>>>> +    ExceptionChecker Checker(file, std::errc::permission_denied,
>>>>>>> +                             "last_write_time");
>>>>>>> +    TEST_CHECK_THROW_RESULT(filesystem_error, Checker,
>>>>>>> last_write_time(file));
>>>>>>> +}
>>>>>>> +
>>>>>>> +TEST_CASE(my_test) {
>>>>>>> +  scoped_test_env env;
>>>>>>> +  const path p = env.create_file("file", 42);
>>>>>>> +  using namespace std::chrono;
>>>>>>> +  using TimeSpec = struct ::timespec;
>>>>>>> +  TimeSpec ts[2];
>>>>>>> +  ts[0].tv_sec = 0;
>>>>>>> +  ts[0].tv_nsec = UTIME_OMIT;
>>>>>>> +  ts[1].tv_sec = -1;
>>>>>>> +  ts[1].tv_nsec =
>>>>>>> +      duration_cast<nanoseconds>(seconds(1) -
>>>>>>> nanoseconds(13)).count();
>>>>>>> +  if (::utimensat(AT_FDCWD, p.c_str(), ts, 0) == -1) {
>>>>>>> +    TEST_CHECK(false);
>>>>>>> +  }
>>>>>>> +  TimeSpec new_ts = LastWriteTime(p);
>>>>>>> +  TEST_CHECK(ts[1].tv_sec == new_ts.tv_sec);
>>>>>>> +  TEST_CHECK(ts[1].tv_nsec == new_ts.tv_nsec);
>>>>>>>  }
>>>>>>>
>>>>>>>  TEST_SUITE_END()
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> cfe-commits mailing list
>>>>>>> cfe-commits at lists.llvm.org
>>>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>>>>
>>>>>>
>>>>>>
>>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180725/7f99b503/attachment-0001.html>


More information about the cfe-commits mailing list