diff options
author | Eric Fiselier <eric@efcs.ca> | 2017-07-08 04:18:41 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2017-07-08 04:18:41 +0000 |
commit | 433c2f08599eab3a3756646b65b17c1315e9fde3 (patch) | |
tree | 7a93dad55920a0e68c9369312d0cb06068a0c18e /libcxx/src/experimental/filesystem/operations.cpp | |
parent | c8dba240b1c66a552789980016ff761a3db398dd (diff) | |
download | bcm5719-llvm-433c2f08599eab3a3756646b65b17c1315e9fde3.tar.gz bcm5719-llvm-433c2f08599eab3a3756646b65b17c1315e9fde3.zip |
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.
llvm-svn: 307461
Diffstat (limited to 'libcxx/src/experimental/filesystem/operations.cpp')
-rw-r--r-- | libcxx/src/experimental/filesystem/operations.cpp | 152 |
1 files changed, 8 insertions, 144 deletions
diff --git a/libcxx/src/experimental/filesystem/operations.cpp b/libcxx/src/experimental/filesystem/operations.cpp index f7e6cc794fe..641a3c53636 100644 --- a/libcxx/src/experimental/filesystem/operations.cpp +++ b/libcxx/src/experimental/filesystem/operations.cpp @@ -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::error_code *ec) 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 warning 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 path& p, std::error_code *ec) } 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, file_time_type new_time, 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, file_time_type new_time, 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), |