[libcxx] r307461 - Fix filesystem build on platforms with weird time_t types.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 7 21:18:41 PDT 2017


Author: ericwf
Date: Fri Jul  7 21:18:41 2017
New Revision: 307461

URL: http://llvm.org/viewvc/llvm-project?rev=307461&view=rev
Log:
Fix filesystem build on platforms with weird time_t types.

32-bit powerpc provides a 64 bit time_t type and older ppc64 systems
provide time_t as a floating point type. This caused problems when building
operations.cpp since operations.cpp contained compile time tests for conversions
between time_t and filesystem time type.

When these tests failed they caused the libc++ build to fail as well. This is unfortunate.

This patch moves the tests out of the source file and into the test suite. It also
expands the tests to allow testing of the weird time_t configurations on all platforms.

Added:
    libcxx/trunk/src/experimental/filesystem/filesystem_time_helper.h
    libcxx/trunk/test/libcxx/experimental/filesystem/convert_file_time.sh.cpp
Modified:
    libcxx/trunk/src/experimental/filesystem/operations.cpp
    libcxx/trunk/utils/libcxx/test/config.py

Added: libcxx/trunk/src/experimental/filesystem/filesystem_time_helper.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/experimental/filesystem/filesystem_time_helper.h?rev=307461&view=auto
==============================================================================
--- libcxx/trunk/src/experimental/filesystem/filesystem_time_helper.h (added)
+++ libcxx/trunk/src/experimental/filesystem/filesystem_time_helper.h Fri Jul  7 21:18:41 2017
@@ -0,0 +1,173 @@
+//===----------------------------------------------------------------------===////
+//
+//                     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 FILESYSTEM_TIME_HELPER_H
+#define FILESYSTEM_TIME_HELPER_H
+
+#include "experimental/__config"
+#include "chrono"
+#include "cstdlib"
+#include "climits"
+
+#include <unistd.h>
+#include <sys/stat.h>
+#if !defined(UTIME_OMIT)
+#include <sys/time.h> // for ::utimes as used in __last_write_time
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+
+namespace time_detail { namespace {
+
+using namespace chrono;
+
+template <class FileTimeT,
+          bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
+struct fs_time_util_base {
+  static constexpr auto max_seconds =
+      duration_cast<seconds>(FileTimeT::duration::max()).count();
+
+  static constexpr auto max_nsec =
+      duration_cast<nanoseconds>(FileTimeT::duration::max() -
+                                 seconds(max_seconds))
+          .count();
+
+  static constexpr auto min_seconds =
+      duration_cast<seconds>(FileTimeT::duration::min()).count();
+
+  static constexpr auto min_nsec_timespec =
+      duration_cast<nanoseconds>(
+          (FileTimeT::duration::min() - seconds(min_seconds)) + seconds(1))
+          .count();
+
+  // 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)) ==
+                    FileTimeT::duration::min(),
+                "");
+};
+
+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>
+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))
+        .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, class TimeSpecT>
+struct fs_time_util : fs_time_util_base<FileTimeT> {
+  using Base = fs_time_util_base<FileTimeT>;
+  using Base::max_nsec;
+  using Base::max_seconds;
+  using Base::min_nsec_timespec;
+  using Base::min_seconds;
+
+public:
+  template <class CType, class ChronoType>
+  static bool checked_set(CType* out, ChronoType time) {
+    using Lim = numeric_limits<CType>;
+    if (time > Lim::max() || time < Lim::min())
+      return false;
+    *out = static_cast<CType>(time);
+    return true;
+  }
+
+  static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
+    if (tm.tv_sec >= 0) {
+      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);
+    }
+  }
+
+  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);
+    if (nsecs.count() < 0) {
+      secs = secs + seconds(1);
+      nsecs = nsecs + seconds(1);
+    }
+    using TLim = numeric_limits<TimeT>;
+    if (secs.count() >= 0)
+      return secs.count() <= TLim::max();
+    return secs.count() >= TLim::min();
+  }
+
+  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));
+    } 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;
+      return FileTimeT(Dur);
+    }
+  }
+
+  template <class SubSecDurT, class SubSecT>
+  static bool set_times_checked(TimeT* sec_out, SubSecT* subsec_out,
+                                FileTimeT tp) {
+    using namespace chrono;
+    auto dur = tp.time_since_epoch();
+    auto sec_dur = duration_cast<seconds>(dur);
+    auto subsec_dur = duration_cast<SubSecDurT>(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);
+      } else {
+        subsec_dur = SubSecDurT::zero();
+      }
+    }
+    return checked_set(sec_out, sec_dur.count()) &&
+           checked_set(subsec_out, subsec_dur.count());
+  }
+};
+
+} // end namespace
+} // end namespace time_detail
+
+using time_detail::fs_time_util;
+
+_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+
+#endif // FILESYSTEM_TIME_HELPER_H

Modified: libcxx/trunk/src/experimental/filesystem/operations.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/experimental/filesystem/operations.cpp?rev=307461&r1=307460&r2=307461&view=diff
==============================================================================
--- libcxx/trunk/src/experimental/filesystem/operations.cpp (original)
+++ libcxx/trunk/src/experimental/filesystem/operations.cpp Fri Jul  7 21:18:41 2017
@@ -15,6 +15,8 @@
 #include "cstdlib"
 #include "climits"
 
+#include "filesystem_time_helper.h"
+
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
@@ -505,17 +507,6 @@ bool __fs_is_empty(const path& p, std::e
 
 namespace detail { namespace {
 
-using namespace std::chrono;
-
-template <class CType, class ChronoType>
-bool checked_set(CType* out, ChronoType time) {
-    using Lim = numeric_limits<CType>;
-    if (time > Lim::max() || time < Lim::min())
-        return false;
-    *out = static_cast<CType>(time);
-    return true;
-}
-
 using TimeSpec = struct timespec;
 using StatT =  struct stat;
 
@@ -528,137 +519,10 @@ __attribute__((unused)) // Suppress warn
 TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
 #endif
 
-constexpr auto max_seconds = duration_cast<seconds>(
-    file_time_type::duration::max()).count();
-
-constexpr auto max_nsec = duration_cast<nanoseconds>(
-    file_time_type::duration::max() - seconds(max_seconds)).count();
-
-constexpr auto min_seconds = duration_cast<seconds>(
-    file_time_type::duration::min()).count();
-
-constexpr auto min_nsec_timespec = duration_cast<nanoseconds>(
-    (file_time_type::duration::min() - seconds(min_seconds)) + seconds(1)).count();
-
-// 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))
-                  == file_time_type::duration::min(), "");
-
-constexpr auto max_time_t = numeric_limits<time_t>::max();
-constexpr auto min_time_t = numeric_limits<time_t>::min();
-
-#if !defined(__LP64__) && defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
-#endif
-
-_LIBCPP_CONSTEXPR_AFTER_CXX11
-bool is_representable(TimeSpec const& tm) {
-  if (tm.tv_sec >= 0) {
-    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);
-  }
-}
-#ifndef _LIBCPP_HAS_NO_CXX14_CONSTEXPR
-#if defined(__LP64__)
-static_assert(is_representable({max_seconds, max_nsec}), "");
-static_assert(!is_representable({max_seconds + 1, 0}), "");
-static_assert(!is_representable({max_seconds, max_nsec + 1}), "");
-static_assert(!is_representable({max_time_t, 0}), "");
-static_assert(is_representable({min_seconds, 0}), "");
-static_assert(is_representable({min_seconds - 1, min_nsec_timespec}), "");
-static_assert(is_representable({min_seconds - 1, min_nsec_timespec + 1}), "");
-static_assert(!is_representable({min_seconds - 1, min_nsec_timespec - 1}), "");
-static_assert(!is_representable({min_time_t, 999999999}), "");
-#else
-static_assert(is_representable({max_time_t, 999999999}), "");
-static_assert(is_representable({max_time_t, 1000000000}), "");
-static_assert(is_representable({min_time_t, 0}), "");
-#endif
-#endif
-
-_LIBCPP_CONSTEXPR_AFTER_CXX11
-bool is_representable(file_time_type const& tm) {
-  auto secs = duration_cast<seconds>(tm.time_since_epoch());
-  auto nsecs = duration_cast<nanoseconds>(tm.time_since_epoch() - secs);
-  if (nsecs.count() < 0) {
-    secs = secs +  seconds(1);
-    nsecs = nsecs + seconds(1);
-  }
-  using TLim = numeric_limits<time_t>;
-  if (secs.count() >= 0)
-    return secs.count() <= TLim::max();
-  return secs.count() >= TLim::min();
-}
-#ifndef _LIBCPP_HAS_NO_CXX14_CONSTEXPR
-#if defined(__LP64__)
-static_assert(is_representable(file_time_type::max()), "");
-static_assert(is_representable(file_time_type::min()), "");
-#else
-static_assert(!is_representable(file_time_type::max()), "");
-static_assert(!is_representable(file_time_type::min()), "");
-static_assert(is_representable(file_time_type(seconds(max_time_t))), "");
-static_assert(is_representable(file_time_type(seconds(min_time_t))), "");
-#endif
-#endif
-
-_LIBCPP_CONSTEXPR_AFTER_CXX11
-file_time_type convert_timespec(TimeSpec const& 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 file_time_type(Dur);
-  } else if (duration_cast<microseconds>(nanoseconds(tm.tv_nsec)).count() == 0) {
-    return file_time_type(seconds(tm.tv_sec));
-  } 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;
-    return file_time_type(Dur);
-  }
-}
-#ifndef _LIBCPP_HAS_NO_CXX14_CONSTEXPR
-#if defined(__LP64__)
-static_assert(convert_timespec({max_seconds, max_nsec}) == file_time_type::max(), "");
-static_assert(convert_timespec({max_seconds, max_nsec - 1}) < file_time_type::max(), "");
-static_assert(convert_timespec({max_seconds - 1, 999999999}) < file_time_type::max(), "");
-static_assert(convert_timespec({min_seconds - 1, min_nsec_timespec}) == file_time_type::min(), "");
-static_assert(convert_timespec({min_seconds - 1, min_nsec_timespec + 1}) > file_time_type::min(), "");
-static_assert(convert_timespec({min_seconds , 0}) > file_time_type::min(), "");
-#else
-// FIXME add tests for 32 bit builds
-#endif
-#endif
-
-#if !defined(__LP64__) && defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-template <class SubSecDurT, class SubSecT>
-bool set_times_checked(time_t* sec_out, SubSecT* subsec_out, file_time_type tp) {
-    using namespace chrono;
-    auto dur = tp.time_since_epoch();
-    auto sec_dur = duration_cast<seconds>(dur);
-    auto subsec_dur = duration_cast<SubSecDurT>(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);
-        } else {
-            subsec_dur = SubSecDurT::zero();
-        }
-    }
-    return checked_set(sec_out, sec_dur.count())
-        && checked_set(subsec_out, subsec_dur.count());
-}
-
 }} // end namespace detail
 
+using FSTime = fs_time_util<file_time_type, time_t, struct timespec>;
+
 file_time_type __last_write_time(const path& p, std::error_code *ec)
 {
     using namespace ::std::chrono;
@@ -671,12 +535,12 @@ file_time_type __last_write_time(const p
     }
     if (ec) ec->clear();
     auto ts = detail::extract_mtime(st);
-    if (!detail::is_representable(ts)) {
+    if (!FSTime::is_representable(ts)) {
         set_or_throw(error_code(EOVERFLOW, generic_category()), ec,
                      "last_write_time", p);
         return file_time_type::min();
     }
-    return detail::convert_timespec(ts);
+    return FSTime::convert_timespec(ts);
 }
 
 void __last_write_time(const path& p, file_time_type new_time,
@@ -701,7 +565,7 @@ void __last_write_time(const path& p, fi
     struct ::timeval tbuf[2];
     tbuf[0].tv_sec = atime.tv_sec;
     tbuf[0].tv_usec = duration_cast<microseconds>(nanoseconds(atime.tv_nsec)).count();
-    const bool overflowed = !detail::set_times_checked<microseconds>(
+    const bool overflowed = !FSTime::set_times_checked<microseconds>(
         &tbuf[1].tv_sec, &tbuf[1].tv_usec, new_time);
 
     if (overflowed) {
@@ -717,7 +581,7 @@ void __last_write_time(const path& p, fi
     tbuf[0].tv_sec = 0;
     tbuf[0].tv_nsec = UTIME_OMIT;
 
-    const bool overflowed = !detail::set_times_checked<nanoseconds>(
+    const bool overflowed = !FSTime::set_times_checked<nanoseconds>(
         &tbuf[1].tv_sec, &tbuf[1].tv_nsec, new_time);
     if (overflowed) {
         set_or_throw(make_error_code(errc::invalid_argument),

Added: 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=307461&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/experimental/filesystem/convert_file_time.sh.cpp (added)
+++ libcxx/trunk/test/libcxx/experimental/filesystem/convert_file_time.sh.cpp Fri Jul  7 21:18:41 2017
@@ -0,0 +1,200 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+
+// <experimental/filesystem>
+
+// typedef TrivialClock file_time_type;
+
+// RUN: %build -I%libcxx_src_root/src/experimental/filesystem
+// RUN: %run
+
+#include <experimental/filesystem>
+#include <chrono>
+#include <type_traits>
+#include <limits>
+#include <cstddef>
+#include <cassert>
+
+#include "filesystem_time_helper.h"
+
+using namespace std::chrono;
+namespace fs = std::experimental::filesystem;
+using fs::file_time_type;
+using fs::fs_time_util;
+
+enum TestKind { TK_64Bit, TK_32Bit, TK_FloatingPoint };
+
+template <class FileTimeT, class TimeT, class TimeSpec>
+constexpr TestKind getTestKind() {
+  if (sizeof(TimeT) == 8 && !std::is_floating_point<TimeT>::value)
+    return TK_64Bit;
+  else if (sizeof(TimeT) == 4 && !std::is_floating_point<TimeT>::value)
+    return TK_32Bit;
+  else if (std::is_floating_point<TimeT>::value)
+    return TK_FloatingPoint;
+  else
+    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;
+
+template <class FileTimeT, class TimeT, class TimeSpecT, class Base>
+struct check_is_representable<FileTimeT, TimeT, TimeSpecT, Base, TK_64Bit>
+    : public Base {
+
+  using Base::convert_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_seconds, max_nsec}), "");
+    static_assert(!is_representable(TimeSpecT{max_seconds + 1, 0}), "");
+    static_assert(!is_representable(TimeSpecT{max_seconds, max_nsec + 1}), "");
+    static_assert(!is_representable(TimeSpecT{max_time_t, 0}), "");
+    static_assert(is_representable(TimeSpecT{min_seconds, 0}), "");
+    static_assert(
+        is_representable(TimeSpecT{min_seconds - 1, min_nsec_timespec}), "");
+    static_assert(
+        is_representable(TimeSpecT{min_seconds - 1, min_nsec_timespec + 1}),
+        "");
+    static_assert(
+        !is_representable(TimeSpecT{min_seconds - 1, min_nsec_timespec - 1}),
+        "");
+    static_assert(!is_representable(TimeSpecT{min_time_t, 999999999}), "");
+    return true;
+  }
+
+  static constexpr bool test_file_time_type() {
+    static_assert(Base::is_representable(FileTimeT::max()), "");
+    static_assert(Base::is_representable(FileTimeT::min()), "");
+    return true;
+  }
+
+  static constexpr bool test_convert_timespec() {
+    static_assert(convert_timespec(TimeSpecT{max_seconds, max_nsec}) ==
+                      FileTimeT::max(),
+                  "");
+    static_assert(convert_timespec(TimeSpecT{max_seconds, max_nsec - 1}) <
+                      FileTimeT::max(),
+                  "");
+    static_assert(convert_timespec(TimeSpecT{max_seconds - 1, 999999999}) <
+                      FileTimeT::max(),
+                  "");
+    static_assert(convert_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(), "");
+    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 check_is_representable<FileTimeT, TimeT, TimeSpecT, Base, TK_32Bit>
+    : 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::is_representable;
+  using Base::max_nsec;
+  using Base::max_seconds;
+  using Base::min_nsec_timespec;
+  using Base::min_seconds;
+
+  static constexpr bool test_timespec() {
+    static_assert(is_representable(TimeSpecT{max_time_t, 999999999}), "");
+    static_assert(is_representable(TimeSpecT{max_time_t, 1000000000}), "");
+    static_assert(is_representable(TimeSpecT{min_time_t, 0}), "");
+    return true;
+  }
+
+  static constexpr bool test_file_time_type() {
+    static_assert(!is_representable(FileTimeT::max()), "");
+    static_assert(!is_representable(FileTimeT::min()), "");
+    static_assert(is_representable(FileTimeT(seconds(max_time_t))), "");
+    static_assert(is_representable(FileTimeT(seconds(min_time_t))), "");
+    return true;
+  }
+
+  static constexpr bool test_convert_timespec() {
+    // FIXME add tests for 32 bit builds
+    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 TimeSpec, class Base>
+struct check_is_representable<FileTimeT, TimeT, TimeSpec, Base,
+                              TK_FloatingPoint> : public Base {
+
+  static bool test() { return true; }
+};
+
+template <class TimeT, class NSecT = long>
+struct TestTimeSpec {
+  TimeT tv_sec;
+  NSecT tv_nsec;
+};
+
+template <class Dur>
+struct TestClock {
+  typedef Dur duration;
+  typedef typename duration::rep rep;
+  typedef typename duration::period period;
+  typedef std::chrono::time_point<TestClock> time_point;
+  static constexpr const bool is_steady = false;
+
+  static time_point now() noexcept { return {}; }
+};
+
+template <class IntType, class Dur = duration<IntType, std::micro> >
+using TestFileTimeT = time_point<TestClock<Dur> >;
+
+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()));
+}

Modified: libcxx/trunk/utils/libcxx/test/config.py
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/utils/libcxx/test/config.py?rev=307461&r1=307460&r2=307461&view=diff
==============================================================================
--- libcxx/trunk/utils/libcxx/test/config.py (original)
+++ libcxx/trunk/utils/libcxx/test/config.py Fri Jul  7 21:18:41 2017
@@ -1019,6 +1019,7 @@ class Configuration(object):
         cxx_path = pipes.quote(self.cxx.path)
         # Configure compiler substitutions
         sub.append(('%cxx', cxx_path))
+        sub.append(('%libcxx_src_root', self.libcxx_src_root))
         # Configure flags substitutions
         flags_str = ' '.join([pipes.quote(f) for f in self.cxx.flags])
         compile_flags_str = ' '.join([pipes.quote(f) for f in self.cxx.compile_flags])




More information about the cfe-commits mailing list