diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/algorithm.cpp | 2 | ||||
-rw-r--r-- | src/any.cpp | 9 | ||||
-rw-r--r-- | src/chrono.cpp | 83 | ||||
-rw-r--r-- | src/condition_variable.cpp | 6 | ||||
-rw-r--r-- | src/debug.cpp | 100 | ||||
-rw-r--r-- | src/exception.cpp | 4 | ||||
-rw-r--r-- | src/experimental/filesystem/directory_iterator.cpp | 4 | ||||
-rw-r--r-- | src/experimental/filesystem/operations.cpp | 184 | ||||
-rw-r--r-- | src/experimental/filesystem/path.cpp | 550 | ||||
-rw-r--r-- | src/experimental/memory_resource.cpp | 17 | ||||
-rw-r--r-- | src/include/atomic_support.h | 2 | ||||
-rw-r--r-- | src/include/config_elast.h | 2 | ||||
-rw-r--r-- | src/ios.cpp | 18 | ||||
-rw-r--r-- | src/locale.cpp | 311 | ||||
-rw-r--r-- | src/memory.cpp | 46 | ||||
-rw-r--r-- | src/mutex.cpp | 9 | ||||
-rw-r--r-- | src/new.cpp | 170 | ||||
-rw-r--r-- | src/optional.cpp | 12 | ||||
-rw-r--r-- | src/random.cpp | 2 | ||||
-rw-r--r-- | src/stdexcept.cpp | 3 | ||||
-rw-r--r-- | src/string.cpp | 8 | ||||
-rw-r--r-- | src/strstream.cpp | 3 | ||||
-rw-r--r-- | src/support/solaris/xlocale.cpp (renamed from src/support/solaris/xlocale.c) | 5 | ||||
-rw-r--r-- | src/support/win32/locale_win32.cpp | 5 | ||||
-rw-r--r-- | src/system_error.cpp | 3 | ||||
-rw-r--r-- | src/thread.cpp | 10 | ||||
-rw-r--r-- | src/typeinfo.cpp | 4 | ||||
-rw-r--r-- | src/variant.cpp | 18 |
28 files changed, 1052 insertions, 538 deletions
diff --git a/src/algorithm.cpp b/src/algorithm.cpp index e9752b0653e03..f036eb7abe1c5 100644 --- a/src/algorithm.cpp +++ b/src/algorithm.cpp @@ -48,7 +48,7 @@ template bool __insertion_sort_incomplete<__less<long double>&, long double*>(lo template unsigned __sort5<__less<long double>&, long double*>(long double*, long double*, long double*, long double*, long double*, __less<long double>&); #ifndef _LIBCPP_HAS_NO_THREADS -static __libcpp_mutex_t __rs_mut = _LIBCPP_MUTEX_INITIALIZER; +_LIBCPP_SAFE_STATIC static __libcpp_mutex_t __rs_mut = _LIBCPP_MUTEX_INITIALIZER; #endif unsigned __rs_default::__c_ = 0; diff --git a/src/any.cpp b/src/any.cpp index f77684578905b..45b2337eb353f 100644 --- a/src/any.cpp +++ b/src/any.cpp @@ -7,12 +7,17 @@ // //===----------------------------------------------------------------------===// +#include "any" #include "experimental/any" -_LIBCPP_BEGIN_NAMESPACE_LFTS - +namespace std { const char* bad_any_cast::what() const _NOEXCEPT { return "bad any cast"; } +} +_LIBCPP_BEGIN_NAMESPACE_LFTS +const char* bad_any_cast::what() const _NOEXCEPT { + return "bad any cast"; +} _LIBCPP_END_NAMESPACE_LFTS diff --git a/src/chrono.cpp b/src/chrono.cpp index 62149fbf420cd..b9d6bf97be33a 100644 --- a/src/chrono.cpp +++ b/src/chrono.cpp @@ -12,14 +12,23 @@ #include "system_error" // __throw_system_error #include <time.h> // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#include <Windows.h> +#if _WIN32_WINNT >= _WIN32_WINNT_WIN8 +#include <winapifamily.h> +#endif +#else #if !defined(CLOCK_REALTIME) #include <sys/time.h> // for gettimeofday and timeval #endif +#endif -#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) && !defined(CLOCK_MONOTONIC) +#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) #if __APPLE__ #include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t -#else +#elif !defined(_WIN32) && !defined(CLOCK_MONOTONIC) #error "Monotonic clock not implemented" #endif #endif @@ -36,6 +45,32 @@ const bool system_clock::is_steady; system_clock::time_point system_clock::now() _NOEXCEPT { +#if defined(_WIN32) + // FILETIME is in 100ns units + using filetime_duration = + _VSTD::chrono::duration<__int64, + _VSTD::ratio_multiply<_VSTD::ratio<100, 1>, + nanoseconds::period>>; + + // The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970. + static _LIBCPP_CONSTEXPR const filetime_duration + nt_to_unix_epoch{11644473600}; + + FILETIME ft; +#if _WIN32_WINNT >= _WIN32_WINNT_WIN8 +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + GetSystemTimePreciseAsFileTime(&ft); +#else + GetSystemTimeAsFileTime(&ft); +#endif +#else + GetSystemTimeAsFileTime(&ft); +#endif + + filetime_duration d{(static_cast<__int64>(ft.dwHighDateTime) << 32) | + static_cast<__int64>(ft.dwLowDateTime)}; + return time_point(duration_cast<duration>(d - nt_to_unix_epoch)); +#else #ifdef CLOCK_REALTIME struct timespec tp; if (0 != clock_gettime(CLOCK_REALTIME, &tp)) @@ -46,6 +81,7 @@ system_clock::now() _NOEXCEPT gettimeofday(&tv, 0); return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); #endif // CLOCK_REALTIME +#endif } time_t @@ -69,18 +105,7 @@ system_clock::from_time_t(time_t t) _NOEXCEPT const bool steady_clock::is_steady; -#ifdef CLOCK_MONOTONIC - -steady_clock::time_point -steady_clock::now() _NOEXCEPT -{ - struct timespec tp; - if (0 != clock_gettime(CLOCK_MONOTONIC, &tp)) - __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed"); - return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec)); -} - -#elif defined(__APPLE__) +#if defined(__APPLE__) // mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of // nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom @@ -90,8 +115,6 @@ steady_clock::now() _NOEXCEPT // MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize // for that case as an optimization. -#pragma GCC visibility push(hidden) - static steady_clock::rep steady_simplified() @@ -129,8 +152,6 @@ init_steady_clock() return &steady_full; } -#pragma GCC visibility pop - steady_clock::time_point steady_clock::now() _NOEXCEPT { @@ -138,6 +159,32 @@ steady_clock::now() _NOEXCEPT return time_point(duration(fp())); } +#elif defined(_WIN32) + +steady_clock::time_point +steady_clock::now() _NOEXCEPT +{ + static LARGE_INTEGER freq; + static BOOL initialized = FALSE; + if (!initialized) + initialized = QueryPerformanceFrequency(&freq); // always succceeds + + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return time_point(duration(counter.QuadPart * nano::den / freq.QuadPart)); +} + +#elif defined(CLOCK_MONOTONIC) + +steady_clock::time_point +steady_clock::now() _NOEXCEPT +{ + struct timespec tp; + if (0 != clock_gettime(CLOCK_MONOTONIC, &tp)) + __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed"); + return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec)); +} + #else #error "Monotonic clock not implemented" #endif diff --git a/src/condition_variable.cpp b/src/condition_variable.cpp index bfb4bf3925f7e..25e66038eec0b 100644 --- a/src/condition_variable.cpp +++ b/src/condition_variable.cpp @@ -79,6 +79,12 @@ condition_variable::__do_timed_wait(unique_lock<mutex>& lk, void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk) { + auto& tl_ptr = __thread_local_data(); + // If this thread was not created using std::thread then it will not have + // previously allocated. + if (tl_ptr.get() == nullptr) { + tl_ptr.set_pointer(new __thread_struct); + } __thread_local_data()->notify_all_at_thread_exit(&cond, lk.release()); } diff --git a/src/debug.cpp b/src/debug.cpp index b1a16e6e72d48..f2fc1ceb495a8 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -7,16 +7,79 @@ // //===----------------------------------------------------------------------===// -#define _LIBCPP_DEBUG 1 #include "__config" #include "__debug" #include "functional" #include "algorithm" +#include "string" +#include "cstdio" #include "__hash_table" #include "mutex" _LIBCPP_BEGIN_NAMESPACE_STD +static std::string make_what_str(__libcpp_debug_info const& info) { + string msg = info.__file_; + msg += ":" + to_string(info.__line_) + ": _LIBCPP_ASSERT '"; + msg += info.__pred_; + msg += "' failed. "; + msg += info.__msg_; + return msg; +} + +_LIBCPP_SAFE_STATIC __libcpp_debug_function_type + __libcpp_debug_function = __libcpp_abort_debug_function; + +bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) { + __libcpp_debug_function = __func; + return true; +} + +_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) { + std::fprintf(stderr, "%s\n", make_what_str(info).c_str()); + std::abort(); +} + +_LIBCPP_NORETURN void __libcpp_throw_debug_function(__libcpp_debug_info const& info) { +#ifndef _LIBCPP_NO_EXCEPTIONS + throw __libcpp_debug_exception(info); +#else + __libcpp_abort_debug_function(info); +#endif +} + +struct __libcpp_debug_exception::__libcpp_debug_exception_imp { + __libcpp_debug_info __info_; + std::string __what_str_; +}; + +__libcpp_debug_exception::__libcpp_debug_exception() _NOEXCEPT + : __imp_(nullptr) { +} + +__libcpp_debug_exception::__libcpp_debug_exception( + __libcpp_debug_info const& info) : __imp_(new __libcpp_debug_exception_imp) +{ + __imp_->__info_ = info; + __imp_->__what_str_ = make_what_str(info); +} +__libcpp_debug_exception::__libcpp_debug_exception( + __libcpp_debug_exception const& other) : __imp_(nullptr) { + if (other.__imp_) + __imp_ = new __libcpp_debug_exception_imp(*other.__imp_); +} + +__libcpp_debug_exception::~__libcpp_debug_exception() _NOEXCEPT { + if (__imp_) + delete __imp_; +} + +const char* __libcpp_debug_exception::what() const _NOEXCEPT { + if (__imp_) + return __imp_->__what_str_.c_str(); + return "__libcpp_debug_exception"; +} + _LIBCPP_FUNC_VIS __libcpp_db* __get_db() @@ -152,11 +215,8 @@ __libcpp_db::__insert_c(void* __c) size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1); __c_node** cbeg = static_cast<__c_node**>(calloc(nc, sizeof(void*))); if (cbeg == nullptr) -#ifndef _LIBCPP_NO_EXCEPTIONS - throw bad_alloc(); -#else - abort(); -#endif + __throw_bad_alloc(); + for (__c_node** p = __cbeg_; p != __cend_; ++p) { __c_node* q = *p; @@ -178,11 +238,8 @@ __libcpp_db::__insert_c(void* __c) __c_node* r = __cbeg_[hc] = static_cast<__c_node*>(malloc(sizeof(__c_node))); if (__cbeg_[hc] == nullptr) -#ifndef _LIBCPP_NO_EXCEPTIONS - throw bad_alloc(); -#else - abort(); -#endif + __throw_bad_alloc(); + r->__c_ = __c; r->__next_ = p; ++__csz_; @@ -475,11 +532,8 @@ __c_node::__add(__i_node* i) __i_node** beg = static_cast<__i_node**>(malloc(nc * sizeof(__i_node*))); if (beg == nullptr) -#ifndef _LIBCPP_NO_EXCEPTIONS - throw bad_alloc(); -#else - abort(); -#endif + __throw_bad_alloc(); + if (nc > 1) memcpy(beg, beg_, nc/2*sizeof(__i_node*)); free(beg_); @@ -501,11 +555,8 @@ __libcpp_db::__insert_iterator(void* __i) size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1); __i_node** ibeg = static_cast<__i_node**>(calloc(nc, sizeof(void*))); if (ibeg == nullptr) -#ifndef _LIBCPP_NO_EXCEPTIONS - throw bad_alloc(); -#else - abort(); -#endif + __throw_bad_alloc(); + for (__i_node** p = __ibeg_; p != __iend_; ++p) { __i_node* q = *p; @@ -527,11 +578,8 @@ __libcpp_db::__insert_iterator(void* __i) __i_node* r = __ibeg_[hi] = static_cast<__i_node*>(malloc(sizeof(__i_node))); if (r == nullptr) -#ifndef _LIBCPP_NO_EXCEPTIONS - throw bad_alloc(); -#else - abort(); -#endif + __throw_bad_alloc(); + ::new(r) __i_node(__i, p, nullptr); ++__isz_; return r; diff --git a/src/exception.cpp b/src/exception.cpp index e172f642d4830..96bd7ee59a02b 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -32,8 +32,8 @@ #define HAVE_DEPENDENT_EH_ABI 1 #endif #elif !defined(__GLIBCXX__) // defined(LIBCXX_BUILDING_LIBCXXABI) - static std::terminate_handler __terminate_handler; - static std::unexpected_handler __unexpected_handler; + _LIBCPP_SAFE_STATIC static std::terminate_handler __terminate_handler; + _LIBCPP_SAFE_STATIC static std::unexpected_handler __unexpected_handler; #endif // defined(LIBCXX_BUILDING_LIBCXXABI) namespace std diff --git a/src/experimental/filesystem/directory_iterator.cpp b/src/experimental/filesystem/directory_iterator.cpp index fa217ba7a12ce..a888dcfa1190e 100644 --- a/src/experimental/filesystem/directory_iterator.cpp +++ b/src/experimental/filesystem/directory_iterator.cpp @@ -20,7 +20,7 @@ inline bool capture_error_or_throw(std::error_code* user_ec, *user_ec = my_ec; return true; } - __libcpp_throw(filesystem_error(msg, std::forward<Args>(args)..., my_ec)); + __throw_filesystem_error(msg, std::forward<Args>(args)..., my_ec); return false; } @@ -33,7 +33,7 @@ inline bool set_or_throw(std::error_code& my_ec, *user_ec = my_ec; return true; } - __libcpp_throw(filesystem_error(msg, std::forward<Args>(args)..., my_ec)); + __throw_filesystem_error(msg, std::forward<Args>(args)..., my_ec); return false; } diff --git a/src/experimental/filesystem/operations.cpp b/src/experimental/filesystem/operations.cpp index 369996fcbe62d..6c7e4cf24888b 100644 --- a/src/experimental/filesystem/operations.cpp +++ b/src/experimental/filesystem/operations.cpp @@ -51,7 +51,7 @@ void set_or_throw(std::error_code const& m_ec, std::error_code* ec, } else { string msg_s("std::experimental::filesystem::"); msg_s += msg; - __libcpp_throw(filesystem_error(msg_s, p, p2, m_ec)); + __throw_filesystem_error(msg_s, p, p2, m_ec); } } @@ -236,12 +236,11 @@ void __copy(const path& from, const path& to, copy_options options, } return; } - else if (is_directory(f)) { - if (not bool(copy_options::recursive & options) && - bool(copy_options::__in_recursive_copy & options)) - { - return; - } + else if (is_directory(f) && bool(copy_options::create_symlinks & options)) { + return set_or_throw(make_error_code(errc::is_a_directory), ec, "copy"); + } + else if (is_directory(f) && (bool(copy_options::recursive & options) || + copy_options::none == options)) { if (!exists(t)) { // create directory to with attributes from 'from'. @@ -283,6 +282,10 @@ bool __copy_file(const path& from, const path& to, copy_options options, } const bool to_exists = exists(to_st); + if (to_exists && !is_regular_file(to_st)) { + set_or_throw(make_error_code(errc::not_supported), ec, "copy_file", from, to); + return false; + } if (to_exists && bool(copy_options::skip_existing & options)) { return false; } @@ -303,6 +306,8 @@ bool __copy_file(const path& from, const path& to, copy_options options, set_or_throw(make_error_code(errc::file_exists), ec, "copy", from, to); return false; } + + _LIBCPP_UNREACHABLE(); } void __copy_symlink(const path& existing_symlink, const path& new_symlink, @@ -476,18 +481,32 @@ bool __fs_is_empty(const path& p, std::error_code *ec) std::error_code m_ec; struct ::stat pst; auto st = detail::posix_stat(p, pst, &m_ec); - if (is_directory(st)) - return directory_iterator(p) == directory_iterator{}; + if (m_ec) { + set_or_throw(m_ec, ec, "is_empty", p); + return false; + } + else if (!is_directory(st) && !is_regular_file(st)) { + m_ec = make_error_code(errc::not_supported); + set_or_throw(m_ec, ec, "is_empty"); + return false; + } + else if (is_directory(st)) { + auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p); + if (ec && *ec) + return false; + return it == directory_iterator{}; + } else if (is_regular_file(st)) return static_cast<std::uintmax_t>(pst.st_size) == 0; - // else - set_or_throw(m_ec, ec, "is_empty", p); - return false; + + _LIBCPP_UNREACHABLE(); } namespace detail { namespace { +using namespace std::chrono; + template <class CType, class ChronoType> bool checked_set(CType* out, ChronoType time) { using Lim = numeric_limits<CType>; @@ -497,8 +516,127 @@ bool checked_set(CType* out, ChronoType time) { return true; } -constexpr long long min_seconds = file_time_type::duration::min().count() - / file_time_type::period::den; +using TimeSpec = struct ::timespec; +using StatT = struct ::stat; + +#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; } +__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) { @@ -509,7 +647,6 @@ bool set_times_checked(time_t* sec_out, SubSecT* subsec_out, file_time_type tp) // 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 { @@ -522,9 +659,9 @@ bool set_times_checked(time_t* sec_out, SubSecT* subsec_out, file_time_type tp) }} // end namespace detail - file_time_type __last_write_time(const path& p, std::error_code *ec) { + using namespace ::std::chrono; std::error_code m_ec; struct ::stat st; detail::posix_stat(p, st, &m_ec); @@ -533,7 +670,13 @@ file_time_type __last_write_time(const path& p, std::error_code *ec) return file_time_type::min(); } if (ec) ec->clear(); - return file_time_type::clock::from_time_t(st.st_mtime); + auto ts = detail::extract_mtime(st); + if (!detail::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); } void __last_write_time(const path& p, file_time_type new_time, @@ -554,9 +697,10 @@ void __last_write_time(const path& p, file_time_type new_time, set_or_throw(m_ec, ec, "last_write_time", p); return; } + auto atime = detail::extract_atime(st); struct ::timeval tbuf[2]; - tbuf[0].tv_sec = st.st_atime; - tbuf[0].tv_usec = 0; + 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>( &tbuf[1].tv_sec, &tbuf[1].tv_usec, new_time); @@ -720,7 +864,7 @@ space_info __space(const path& p, std::error_code *ec) { // Multiply with overflow checking. auto do_mult = [&](std::uintmax_t& out, std::uintmax_t other) { out = other * m_svfs.f_frsize; - if (out / other != m_svfs.f_frsize || other == 0) + if (other == 0 || out / other != m_svfs.f_frsize) out = static_cast<std::uintmax_t>(-1); }; do_mult(si.capacity, m_svfs.f_blocks); diff --git a/src/experimental/filesystem/path.cpp b/src/experimental/filesystem/path.cpp index 38c449832f6ec..96b81f7b0a70e 100644 --- a/src/experimental/filesystem/path.cpp +++ b/src/experimental/filesystem/path.cpp @@ -6,242 +6,279 @@ // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +#undef NDEBUG #include "experimental/filesystem" -#include "experimental/string_view" +#include "string_view" #include "utility" - -_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM - -_LIBCPP_CONSTEXPR path::value_type path::preferred_separator; +#include "cassert" namespace { namespace parser { +using namespace std; +using namespace std::experimental::filesystem; + +using string_view_t = path::__string_view; +using string_view_pair = pair<string_view_t, string_view_t>; +using PosPtr = path::value_type const*; + +struct PathParser { + enum ParserState : unsigned char { + // Zero is a special sentinel value used by default constructed iterators. + PS_BeforeBegin = 1, + PS_InRootName, + PS_InRootDir, + PS_InFilenames, + PS_InTrailingSep, + PS_AtEnd + }; -using string_type = string_view; -using value_type = path::value_type; - -using string_view_pair = pair<string_view, string_view>; - -// status reporting -constexpr size_t npos = static_cast<size_t>(-1); - -inline bool good(size_t pos) { return pos != npos; } - -// lexical elements -constexpr value_type preferred_separator = path::preferred_separator; -constexpr value_type const * preferred_separator_str = "/"; -constexpr value_type const * dot = "."; - -// forward // -bool is_separator(string_type const &, size_t); -bool is_root_name(const string_type&, size_t); -bool is_root_directory(string_type const &, size_t); -bool is_trailing_separator(string_type const &, size_t); - -size_t start_of(string_type const &, size_t); -size_t end_of(string_type const &, size_t); - -size_t root_name_start(const string_type& s); -size_t root_name_end(const string_type&); - -size_t root_directory_start(string_type const &); -size_t root_directory_end(string_type const &); + const string_view_t Path; + string_view_t RawEntry; + ParserState State; -string_view_pair separate_filename(string_type const &); -string_view extract_raw(string_type const &, size_t); -string_view extract_preferred(string_type const &, size_t); +private: + PathParser(string_view_t P, ParserState State) noexcept + : Path(P), State(State) {} -inline bool is_separator(const string_type& s, size_t pos) { - return (pos < s.size() && s[pos] == preferred_separator); -} +public: + PathParser(string_view_t P, string_view_t E, unsigned char S) + : Path(P), RawEntry(E), State(static_cast<ParserState>(S)) { + // S cannot be '0' or PS_BeforeBegin. + } -inline bool is_root_name(const string_type& s, size_t pos) { - return good(pos) && pos == 0 ? root_name_start(s) == pos : false; -} + static PathParser CreateBegin(string_view_t P) noexcept { + PathParser PP(P, PS_BeforeBegin); + PP.increment(); + return PP; + } -inline bool is_root_directory(const string_type& s, size_t pos) { - return good(pos) ? root_directory_start(s) == pos : false; -} + static PathParser CreateEnd(string_view_t P) noexcept { + PathParser PP(P, PS_AtEnd); + return PP; + } -inline bool is_trailing_separator(const string_type& s, size_t pos) { - return (pos < s.size() && is_separator(s, pos) && - end_of(s, pos) == s.size()-1 && - !is_root_directory(s, pos) && !is_root_name(s, pos)); -} + PosPtr peek() const noexcept { + auto End = &Path.back() + 1; + auto TkEnd = getNextTokenStartPos(); + return TkEnd == End ? nullptr : TkEnd; + } -size_t start_of(const string_type& s, size_t pos) { - if (pos >= s.size()) return npos; - bool in_sep = (s[pos] == preferred_separator); - while (pos - 1 < s.size() && - (s[pos-1] == preferred_separator) == in_sep) - { --pos; } - if (pos == 2 && !in_sep && s[0] == preferred_separator && - s[1] == preferred_separator) - { return 0; } - return pos; -} + void increment() noexcept { + const PosPtr End = &Path.back() + 1; + const PosPtr Start = getNextTokenStartPos(); + if (Start == End) + return makeState(PS_AtEnd); + + switch (State) { + case PS_BeforeBegin: { + PosPtr TkEnd = consumeSeparator(Start, End); + // If we consumed exactly two separators we have a root name. + if (TkEnd && TkEnd == Start + 2) { + // FIXME Do we need to consume a name or is '//' a root name on its own? + // what about '//.', '//..', '//...'? + auto NameEnd = consumeName(TkEnd, End); + if (NameEnd) + TkEnd = NameEnd; + return makeState(PS_InRootName, Start, TkEnd); + } + else if (TkEnd) + return makeState(PS_InRootDir, Start, TkEnd); + else + return makeState(PS_InFilenames, Start, consumeName(Start, End)); + } -size_t end_of(const string_type& s, size_t pos) { - if (pos >= s.size()) return npos; - // special case for root name - if (pos == 0 && is_root_name(s, pos)) return root_name_end(s); - bool in_sep = (s[pos] == preferred_separator); - while (pos + 1 < s.size() && (s[pos+1] == preferred_separator) == in_sep) - { ++pos; } - return pos; -} + case PS_InRootName: + return makeState(PS_InRootDir, Start, consumeSeparator(Start, End)); + case PS_InRootDir: + return makeState(PS_InFilenames, Start, consumeName(Start, End)); + + case PS_InFilenames: { + PosPtr SepEnd = consumeSeparator(Start, End); + if (SepEnd != End) { + PosPtr TkEnd = consumeName(SepEnd, End); + if (TkEnd) + return makeState(PS_InFilenames, SepEnd, TkEnd); + } + return makeState(PS_InTrailingSep, Start, SepEnd); + } -inline size_t root_name_start(const string_type& s) { - return good(root_name_end(s)) ? 0 : npos; -} + case PS_InTrailingSep: + return makeState(PS_AtEnd); -size_t root_name_end(const string_type& s) { - if (s.size() < 2 || s[0] != preferred_separator - || s[1] != preferred_separator) { - return npos; + case PS_AtEnd: + _LIBCPP_UNREACHABLE(); } - if (s.size() == 2) { - return 1; + } + + void decrement() noexcept { + const PosPtr REnd = &Path.front() - 1; + const PosPtr RStart = getCurrentTokenStartPos() - 1; + assert(RStart != REnd); + + switch (State) { + case PS_AtEnd: { + // Try to consume a trailing separator or root directory first. + if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) { + if (SepEnd == REnd) + return makeState((RStart == REnd + 2) ? PS_InRootName : PS_InRootDir, + Path.data(), RStart + 1); + // Check if we're seeing the root directory separator + auto PP = CreateBegin(Path); + bool InRootDir = PP.State == PS_InRootName && + &PP.RawEntry.back() == SepEnd; + return makeState(InRootDir ? PS_InRootDir : PS_InTrailingSep, + SepEnd + 1, RStart + 1); + } else { + PosPtr TkStart = consumeName(RStart, REnd); + if (TkStart == REnd + 2 && consumeSeparator(TkStart, REnd) == REnd) + return makeState(PS_InRootName, Path.data(), RStart + 1); + else + return makeState(PS_InFilenames, TkStart + 1, RStart + 1); + } } - size_t index = 2; // current position - if (s[index] == preferred_separator) { - return npos; + case PS_InTrailingSep: + return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1, RStart + 1); + case PS_InFilenames: { + PosPtr SepEnd = consumeSeparator(RStart, REnd); + if (SepEnd == REnd) + return makeState((RStart == REnd + 2) ? PS_InRootName : PS_InRootDir, + Path.data(), RStart + 1); + PosPtr TkEnd = consumeName(SepEnd, REnd); + if (TkEnd == REnd + 2 && consumeSeparator(TkEnd, REnd) == REnd) + return makeState(PS_InRootDir, SepEnd + 1, RStart + 1); + return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1); } - while (index + 1 < s.size() && s[index+1] != preferred_separator) { - ++index; + case PS_InRootDir: + return makeState(PS_InRootName, Path.data(), RStart + 1); + case PS_InRootName: + case PS_BeforeBegin: + _LIBCPP_UNREACHABLE(); } - return index; -} - -size_t root_directory_start(const string_type& s) { - size_t e = root_name_end(s); - if (!good(e)) - return is_separator(s, 0) ? 0 : npos; - return is_separator(s, e + 1) ? e + 1 : npos; -} - -size_t root_directory_end(const string_type& s) { - size_t st = root_directory_start(s); - if (!good(st)) return npos; - size_t index = st; - while (index + 1 < s.size() && s[index + 1] == preferred_separator) - { ++index; } - return index; -} - -string_view_pair separate_filename(string_type const & s) { - if (s == "." || s == ".." || s.empty()) return string_view_pair{s, ""}; - auto pos = s.find_last_of('.'); - if (pos == string_type::npos) return string_view_pair{s, string_view{}}; - return string_view_pair{s.substr(0, pos), s.substr(pos)}; -} - -inline string_view extract_raw(const string_type& s, size_t pos) { - size_t end_i = end_of(s, pos); - if (!good(end_i)) return string_view{}; - return string_view(s).substr(pos, end_i - pos + 1); -} - -string_view extract_preferred(const string_type& s, size_t pos) { - string_view raw = extract_raw(s, pos); - if (raw.empty()) - return raw; - if (is_trailing_separator(s, pos)) - return string_view{dot}; - if (is_separator(s, pos) && !is_root_name(s, pos)) - return string_view(preferred_separator_str); - return raw; -} - -}} // namespace parser - - -//////////////////////////////////////////////////////////////////////////////// -// path_view_iterator -//////////////////////////////////////////////////////////////////////////////// -namespace { - -struct path_view_iterator { - const string_view __s_; - size_t __pos_; + } - explicit path_view_iterator(string_view const& __s) : __s_(__s), __pos_(__s_.empty() ? parser::npos : 0) {} - explicit path_view_iterator(string_view const& __s, size_t __p) : __s_(__s), __pos_(__p) {} + /// \brief Return a view with the "preferred representation" of the current + /// element. For example trailing separators are represented as a '.' + string_view_t operator*() const noexcept { + switch (State) { + case PS_BeforeBegin: + case PS_AtEnd: + return ""; + case PS_InRootDir: + return "/"; + case PS_InTrailingSep: + return "."; + case PS_InRootName: + case PS_InFilenames: + return RawEntry; + } + _LIBCPP_UNREACHABLE(); + } - string_view operator*() const { - return parser::extract_preferred(__s_, __pos_); + explicit operator bool() const noexcept { + return State != PS_BeforeBegin && State != PS_AtEnd; } - path_view_iterator& operator++() { + PathParser& operator++() noexcept { increment(); return *this; } - path_view_iterator& operator--() { + PathParser& operator--() noexcept { decrement(); return *this; } - void increment() { - if (__pos_ == parser::npos) return; - while (! set_position(parser::end_of(__s_, __pos_)+1)) - ; - return; +private: + void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept { + State = NewState; + RawEntry = string_view_t(Start, End - Start); + } + void makeState(ParserState NewState) noexcept { + State = NewState; + RawEntry = {}; } - void decrement() { - if (__pos_ == 0) { - set_position(0); - } - else if (__pos_ == parser::npos) { - auto const str_size = __s_.size(); - set_position(parser::start_of( - __s_, str_size != 0 ? str_size - 1 : str_size)); - } else { - while (!set_position(parser::start_of(__s_, __pos_-1))) - ; + /// \brief Return a pointer to the first character after the currently + /// lexed element. + PosPtr getNextTokenStartPos() const noexcept { + switch (State) { + case PS_BeforeBegin: + return &Path.front(); + case PS_InRootName: + case PS_InRootDir: + case PS_InFilenames: + return &RawEntry.back() + 1; + case PS_InTrailingSep: + case PS_AtEnd: + return &Path.back() + 1; } + _LIBCPP_UNREACHABLE(); } - bool set_position(size_t pos) { - if (pos >= __s_.size()) { - __pos_ = parser::npos; - } else { - __pos_ = pos; + /// \brief Return a pointer to the first character in the currently lexed + /// element. + PosPtr getCurrentTokenStartPos() const noexcept { + switch (State) { + case PS_BeforeBegin: + case PS_InRootName: + return &Path.front(); + case PS_InRootDir: + case PS_InFilenames: + case PS_InTrailingSep: + return &RawEntry.front(); + case PS_AtEnd: + return &Path.back() + 1; } - return valid_iterator_position(); + _LIBCPP_UNREACHABLE(); } - bool valid_iterator_position() const { - if (__pos_ == parser::npos) return true; // end position is valid - return (!parser::is_separator (__s_, __pos_) || - parser::is_root_directory (__s_, __pos_) || - parser::is_trailing_separator(__s_, __pos_) || - parser::is_root_name (__s_, __pos_)); + PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept { + if (P == End || *P != '/') + return nullptr; + const int Inc = P < End ? 1 : -1; + P += Inc; + while (P != End && *P == '/') + P += Inc; + return P; } - bool is_end() const { return __pos_ == parser::npos; } - - inline bool operator==(path_view_iterator const& __p) { - return __pos_ == __p.__pos_; + PosPtr consumeName(PosPtr P, PosPtr End) const noexcept { + if (P == End || *P == '/') + return nullptr; + const int Inc = P < End ? 1 : -1; + P += Inc; + while (P != End && *P != '/') + P += Inc; + return P; } }; -path_view_iterator pbegin(path const& p) { - return path_view_iterator(p.native()); +string_view_pair separate_filename(string_view_t const & s) { + if (s == "." || s == ".." || s.empty()) return string_view_pair{s, ""}; + auto pos = s.find_last_of('.'); + if (pos == string_view_t::npos) return string_view_pair{s, string_view{}}; + return string_view_pair{s.substr(0, pos), s.substr(pos)}; } -path_view_iterator pend(path const& p) { - path_view_iterator __p(p.native()); - __p.__pos_ = parser::npos; - return __p; +string_view_t createView(PosPtr S, PosPtr E) noexcept { + return {S, static_cast<size_t>(E - S) + 1}; } -} // end namespace +}} // namespace parser + +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM + +using parser::string_view_t; +using parser::string_view_pair; +using parser::PathParser; +using parser::createView; + /////////////////////////////////////////////////////////////////////////////// // path definitions /////////////////////////////////////////////////////////////////////////////// +constexpr path::value_type path::preferred_separator; + path & path::replace_extension(path const & replacement) { path p = extension(); @@ -260,131 +297,146 @@ path & path::replace_extension(path const & replacement) /////////////////////////////////////////////////////////////////////////////// // path.decompose -string_view path::__root_name() const +string_view_t path::__root_name() const { - return parser::is_root_name(__pn_, 0) - ? parser::extract_preferred(__pn_, 0) - : string_view{}; + auto PP = PathParser::CreateBegin(__pn_); + if (PP.State == PathParser::PS_InRootName) + return *PP; + return {}; } -string_view path::__root_directory() const +string_view_t path::__root_directory() const { - auto start_i = parser::root_directory_start(__pn_); - if(!parser::good(start_i)) { - return {}; - } - return parser::extract_preferred(__pn_, start_i); + auto PP = PathParser::CreateBegin(__pn_); + if (PP.State == PathParser::PS_InRootName) + ++PP; + if (PP.State == PathParser::PS_InRootDir) + return *PP; + return {}; } -string_view path::__relative_path() const +string_view_t path::__root_path_raw() const { - if (empty()) { - return {__pn_}; - } - auto end_i = parser::root_directory_end(__pn_); - if (not parser::good(end_i)) { - end_i = parser::root_name_end(__pn_); + auto PP = PathParser::CreateBegin(__pn_); + if (PP.State == PathParser::PS_InRootName) { + auto NextCh = PP.peek(); + if (NextCh && *NextCh == '/') { + ++PP; + assert(PP.State == PathParser::PS_InRootDir); + return createView(__pn_.data(), &PP.RawEntry.back()); + } + return PP.RawEntry; } - if (not parser::good(end_i)) { - return {__pn_}; - } - return string_view(__pn_).substr(end_i+1); + if (PP.State == PathParser::PS_InRootDir) + return *PP; + return {}; } -string_view path::__parent_path() const +string_view_t path::__relative_path() const { - if (empty() || pbegin(*this) == --pend(*this)) { - return {}; - } - auto end_it = --(--pend(*this)); - auto end_i = parser::end_of(__pn_, end_it.__pos_); - return string_view(__pn_).substr(0, end_i+1); + auto PP = PathParser::CreateBegin(__pn_); + while (PP.State <= PathParser::PS_InRootDir) + ++PP; + if (PP.State == PathParser::PS_AtEnd) + return {}; + return createView(PP.RawEntry.data(), &__pn_.back()); } -string_view path::__filename() const +string_view_t path::__parent_path() const { - return empty() ? string_view{} : *--pend(*this); + if (empty()) + return {}; + auto PP = PathParser::CreateEnd(__pn_); + --PP; + if (PP.RawEntry.data() == __pn_.data()) + return {}; + --PP; + return createView(__pn_.data(), &PP.RawEntry.back()); } -string_view path::__stem() const +string_view_t path::__filename() const +{ + if (empty()) return {}; + return *(--PathParser::CreateEnd(__pn_)); +} + +string_view_t path::__stem() const { return parser::separate_filename(__filename()).first; } -string_view path::__extension() const +string_view_t path::__extension() const { return parser::separate_filename(__filename()).second; } //////////////////////////////////////////////////////////////////////////// // path.comparisons -int path::__compare(const value_type* __s) const { - path_view_iterator thisIter(this->native()); - path_view_iterator sIter(__s); - while (!thisIter.is_end() && !sIter.is_end()) { - int res = (*thisIter).compare(*sIter); +int path::__compare(string_view_t __s) const { + auto PP = PathParser::CreateBegin(__pn_); + auto PP2 = PathParser::CreateBegin(__s); + while (PP && PP2) { + int res = (*PP).compare(*PP2); if (res != 0) return res; - ++thisIter; ++sIter; + ++PP; ++PP2; } - if (thisIter.is_end() && sIter.is_end()) + if (PP.State == PP2.State && PP.State == PathParser::PS_AtEnd) return 0; - if (thisIter.is_end()) + if (PP.State == PathParser::PS_AtEnd) return -1; return 1; } //////////////////////////////////////////////////////////////////////////// // path.nonmembers -size_t hash_value(const path& __p) _NOEXCEPT { - path_view_iterator thisIter(__p.native()); - struct HashPairT { - size_t first; - size_t second; - }; - HashPairT hp = {0, 0}; +size_t hash_value(const path& __p) noexcept { + auto PP = PathParser::CreateBegin(__p.native()); + size_t hash_value = 0; std::hash<string_view> hasher; - std::__scalar_hash<decltype(hp)> pair_hasher; - while (!thisIter.is_end()) { - hp.second = hasher(*thisIter); - hp.first = pair_hasher(hp); - ++thisIter; + while (PP) { + hash_value = __hash_combine(hash_value, hasher(*PP)); + ++PP; } - return hp.first; + return hash_value; } //////////////////////////////////////////////////////////////////////////// // path.itr path::iterator path::begin() const { - path_view_iterator pit = pbegin(*this); + auto PP = PathParser::CreateBegin(__pn_); iterator it; it.__path_ptr_ = this; - it.__pos_ = pit.__pos_; - it.__elem_.__assign_view(*pit); + it.__state_ = PP.State; + it.__entry_ = PP.RawEntry; + it.__stashed_elem_.__assign_view(*PP); return it; } path::iterator path::end() const { iterator it{}; + it.__state_ = PathParser::PS_AtEnd; it.__path_ptr_ = this; - it.__pos_ = parser::npos; return it; } path::iterator& path::iterator::__increment() { - path_view_iterator it(__path_ptr_->native(), __pos_); - it.increment(); - __pos_ = it.__pos_; - __elem_.__assign_view(*it); + static_assert(__at_end == PathParser::PS_AtEnd, ""); + PathParser PP(__path_ptr_->native(), __entry_, __state_); + ++PP; + __state_ = PP.State; + __entry_ = PP.RawEntry; + __stashed_elem_.__assign_view(*PP); return *this; } path::iterator& path::iterator::__decrement() { - path_view_iterator it(__path_ptr_->native(), __pos_); - it.decrement(); - __pos_ = it.__pos_; - __elem_.__assign_view(*it); + PathParser PP(__path_ptr_->native(), __entry_, __state_); + --PP; + __state_ = PP.State; + __entry_ = PP.RawEntry; + __stashed_elem_.__assign_view(*PP); return *this; } diff --git a/src/experimental/memory_resource.cpp b/src/experimental/memory_resource.cpp index c01eb0823baee..3e87a2dedded2 100644 --- a/src/experimental/memory_resource.cpp +++ b/src/experimental/memory_resource.cpp @@ -50,11 +50,7 @@ public: protected: virtual void* do_allocate(size_t, size_t) { -#ifndef _LIBCPP_NO_EXCEPTIONS - throw std::bad_alloc(); -#else - abort(); -#endif + __throw_bad_alloc(); } virtual void do_deallocate(void *, size_t, size_t) {} virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT @@ -74,7 +70,10 @@ union ResourceInitHelper { }; // When compiled in C++14 this initialization should be a constant expression. // Only in C++11 is "init_priority" needed to ensure initialization order. -ResourceInitHelper res_init __attribute__((init_priority (101))); +#if _LIBCPP_STD_VER > 11 +_LIBCPP_SAFE_STATIC +#endif +ResourceInitHelper res_init __attribute__((init_priority (101))); } // end namespace @@ -93,7 +92,7 @@ static memory_resource * __default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT { #ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER - static atomic<memory_resource*> __res = + _LIBCPP_SAFE_STATIC static atomic<memory_resource*> __res = ATOMIC_VAR_INIT(&res_init.resources.new_delete_res); if (set) { new_res = new_res ? new_res : new_delete_resource(); @@ -106,7 +105,7 @@ __default_memory_resource(bool set = false, memory_resource * new_res = nullptr) &__res, memory_order::memory_order_acquire); } #elif !defined(_LIBCPP_HAS_NO_THREADS) - static memory_resource * res = &res_init.resources.new_delete_res; + _LIBCPP_SAFE_STATIC static memory_resource * res = &res_init.resources.new_delete_res; static mutex res_lock; if (set) { new_res = new_res ? new_res : new_delete_resource(); @@ -119,7 +118,7 @@ __default_memory_resource(bool set = false, memory_resource * new_res = nullptr) return res; } #else - static memory_resource* res = &res_init.resources.new_delete_res; + _LIBCPP_SAFE_STATIC static memory_resource* res = &res_init.resources.new_delete_res; if (set) { new_res = new_res ? new_res : new_delete_resource(); memory_resource * old_res = res; diff --git a/src/include/atomic_support.h b/src/include/atomic_support.h index 8b719c5f22148..af0f5f505ea54 100644 --- a/src/include/atomic_support.h +++ b/src/include/atomic_support.h @@ -45,7 +45,7 @@ namespace { enum __libcpp_atomic_order { _AO_Relaxed = __ATOMIC_RELAXED, _AO_Consume = __ATOMIC_CONSUME, - _AO_Aquire = __ATOMIC_ACQUIRE, + _AO_Acquire = __ATOMIC_ACQUIRE, _AO_Release = __ATOMIC_RELEASE, _AO_Acq_Rel = __ATOMIC_ACQ_REL, _AO_Seq = __ATOMIC_SEQ_CST diff --git a/src/include/config_elast.h b/src/include/config_elast.h index 9d6a76b0c004e..53b3184d4c173 100644 --- a/src/include/config_elast.h +++ b/src/include/config_elast.h @@ -20,6 +20,8 @@ #define _LIBCPP_ELAST ELAST #elif defined(_NEWLIB_VERSION) #define _LIBCPP_ELAST __ELASTERROR +#elif defined(__Fuchsia__) +// No _LIBCPP_ELAST needed on Fuchsia #elif defined(__linux__) #define _LIBCPP_ELAST 4095 #elif defined(__APPLE__) diff --git a/src/ios.cpp b/src/ios.cpp index 23e3ee0ca044e..7c76ca258b264 100644 --- a/src/ios.cpp +++ b/src/ios.cpp @@ -25,19 +25,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template class basic_ios<char>; -template class basic_ios<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<wchar_t>; -template class basic_streambuf<char>; -template class basic_streambuf<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<wchar_t>; -template class basic_istream<char>; -template class basic_istream<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<wchar_t>; -template class basic_ostream<char>; -template class basic_ostream<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<wchar_t>; -template class basic_iostream<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_iostream<char>; class _LIBCPP_HIDDEN __iostream_category : public __do_message diff --git a/src/locale.cpp b/src/locale.cpp index da2fd11678d60..5d6ccd5fb02ec 100644 --- a/src/locale.cpp +++ b/src/locale.cpp @@ -28,7 +28,7 @@ #include "__sso_allocator" #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__) #include "support/win32/locale_win32.h" -#elif !defined(__ANDROID__) +#elif !defined(__BIONIC__) #include <langinfo.h> #endif #include <stdlib.h> @@ -107,6 +107,16 @@ countof(const T * const begin, const T * const end) return static_cast<size_t>(end - begin); } +_LIBCPP_NORETURN static void __throw_runtime_error(const string &msg) +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + throw runtime_error(msg); +#else + (void)msg; + _VSTD::abort(); +#endif +} + } #if defined(_AIX) @@ -646,22 +656,18 @@ collate_byname<char>::collate_byname(const char* n, size_t refs) : collate<char>(refs), __l(newlocale(LC_ALL_MASK, n, 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) - throw runtime_error("collate_byname<char>::collate_byname" + __throw_runtime_error("collate_byname<char>::collate_byname" " failed to construct for " + string(n)); -#endif // _LIBCPP_NO_EXCEPTIONS } collate_byname<char>::collate_byname(const string& name, size_t refs) : collate<char>(refs), __l(newlocale(LC_ALL_MASK, name.c_str(), 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) - throw runtime_error("collate_byname<char>::collate_byname" + __throw_runtime_error("collate_byname<char>::collate_byname" " failed to construct for " + name); -#endif // _LIBCPP_NO_EXCEPTIONS } collate_byname<char>::~collate_byname() @@ -698,22 +704,18 @@ collate_byname<wchar_t>::collate_byname(const char* n, size_t refs) : collate<wchar_t>(refs), __l(newlocale(LC_ALL_MASK, n, 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) - throw runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)" + __throw_runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)" " failed to construct for " + string(n)); -#endif // _LIBCPP_NO_EXCEPTIONS } collate_byname<wchar_t>::collate_byname(const string& name, size_t refs) : collate<wchar_t>(refs), __l(newlocale(LC_ALL_MASK, name.c_str(), 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) - throw runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)" + __throw_runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)" " failed to construct for " + name); -#endif // _LIBCPP_NO_EXCEPTIONS } collate_byname<wchar_t>::~collate_byname() @@ -1172,22 +1174,18 @@ ctype_byname<char>::ctype_byname(const char* name, size_t refs) : ctype<char>(0, false, refs), __l(newlocale(LC_ALL_MASK, name, 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) - throw runtime_error("ctype_byname<char>::ctype_byname" + __throw_runtime_error("ctype_byname<char>::ctype_byname" " failed to construct for " + string(name)); -#endif // _LIBCPP_NO_EXCEPTIONS } ctype_byname<char>::ctype_byname(const string& name, size_t refs) : ctype<char>(0, false, refs), __l(newlocale(LC_ALL_MASK, name.c_str(), 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) - throw runtime_error("ctype_byname<char>::ctype_byname" + __throw_runtime_error("ctype_byname<char>::ctype_byname" " failed to construct for " + name); -#endif // _LIBCPP_NO_EXCEPTIONS } ctype_byname<char>::~ctype_byname() @@ -1229,22 +1227,18 @@ ctype_byname<wchar_t>::ctype_byname(const char* name, size_t refs) : ctype<wchar_t>(refs), __l(newlocale(LC_ALL_MASK, name, 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) - throw runtime_error("ctype_byname<wchar_t>::ctype_byname" + __throw_runtime_error("ctype_byname<wchar_t>::ctype_byname" " failed to construct for " + string(name)); -#endif // _LIBCPP_NO_EXCEPTIONS } ctype_byname<wchar_t>::ctype_byname(const string& name, size_t refs) : ctype<wchar_t>(refs), __l(newlocale(LC_ALL_MASK, name.c_str(), 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) - throw runtime_error("ctype_byname<wchar_t>::ctype_byname" + __throw_runtime_error("ctype_byname<wchar_t>::ctype_byname" " failed to construct for " + name); -#endif // _LIBCPP_NO_EXCEPTIONS } ctype_byname<wchar_t>::~ctype_byname() @@ -1504,11 +1498,9 @@ codecvt<wchar_t, char, mbstate_t>::codecvt(const char* nm, size_t refs) : locale::facet(refs), __l(newlocale(LC_ALL_MASK, nm, 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) - throw runtime_error("codecvt_byname<wchar_t, char, mbstate_t>::codecvt_byname" + __throw_runtime_error("codecvt_byname<wchar_t, char, mbstate_t>::codecvt_byname" " failed to construct for " + string(nm)); -#endif // _LIBCPP_NO_EXCEPTIONS } codecvt<wchar_t, char, mbstate_t>::~codecvt() @@ -4191,6 +4183,54 @@ __widen_from_utf8<32>::~__widen_from_utf8() { } + +static bool checked_string_to_wchar_convert(wchar_t& dest, + const char* ptr, + __locale_struct* loc) { + if (*ptr == '\0') + return false; + mbstate_t mb = {}; + wchar_t out; + size_t ret = __libcpp_mbrtowc_l(&out, ptr, strlen(ptr), &mb, loc); + if (ret == static_cast<size_t>(-1) || ret == static_cast<size_t>(-2)) { + return false; + } + dest = out; + return true; +} + +static bool checked_string_to_char_convert(char& dest, + const char* ptr, + __locale_struct* __loc) { + if (*ptr == '\0') + return false; + if (!ptr[1]) { + dest = *ptr; + return true; + } + // First convert the MBS into a wide char then attempt to narrow it using + // wctob_l. + wchar_t wout; + if (!checked_string_to_wchar_convert(wout, ptr, __loc)) + return false; + int res; + if ((res = __libcpp_wctob_l(wout, __loc)) != char_traits<char>::eof()) { + dest = res; + return true; + } + // FIXME: Work around specific multibyte sequences that we can reasonable + // translate into a different single byte. + switch (wout) { + case L'\u00A0': // non-breaking space + dest = ' '; + return true; + default: + return false; + } + _LIBCPP_UNREACHABLE(); +} + + // numpunct<char> && numpunct<wchar_t> locale::id numpunct< char >::id; @@ -4257,16 +4297,15 @@ numpunct_byname<char>::__init(const char* nm) if (strcmp(nm, "C") != 0) { __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); -#ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) - throw runtime_error("numpunct_byname<char>::numpunct_byname" + __throw_runtime_error("numpunct_byname<char>::numpunct_byname" " failed to construct for " + string(nm)); -#endif // _LIBCPP_NO_EXCEPTIONS + lconv* lc = __libcpp_localeconv_l(loc.get()); - if (*lc->decimal_point) - __decimal_point_ = *lc->decimal_point; - if (*lc->thousands_sep) - __thousands_sep_ = *lc->thousands_sep; + checked_string_to_char_convert(__decimal_point_, lc->decimal_point, + loc.get()); + checked_string_to_char_convert(__thousands_sep_, lc->thousands_sep, + loc.get()); __grouping_ = lc->grouping; // localization for truename and falsename is not available } @@ -4296,18 +4335,17 @@ numpunct_byname<wchar_t>::__init(const char* nm) if (strcmp(nm, "C") != 0) { __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); -#ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) - throw runtime_error("numpunct_byname<char>::numpunct_byname" + __throw_runtime_error("numpunct_byname<wchar_t>::numpunct_byname" " failed to construct for " + string(nm)); -#endif // _LIBCPP_NO_EXCEPTIONS + lconv* lc = __libcpp_localeconv_l(loc.get()); - if (*lc->decimal_point) - __decimal_point_ = *lc->decimal_point; - if (*lc->thousands_sep) - __thousands_sep_ = *lc->thousands_sep; + checked_string_to_wchar_convert(__decimal_point_, lc->decimal_point, + loc.get()); + checked_string_to_wchar_convert(__thousands_sep_, lc->thousands_sep, + loc.get()); __grouping_ = lc->grouping; - // locallization for truename and falsename is not available + // localization for truename and falsename is not available } } @@ -4703,21 +4741,17 @@ __time_get_c_storage<wchar_t>::__r() const __time_get::__time_get(const char* nm) : __loc_(newlocale(LC_ALL_MASK, nm, 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__loc_ == 0) - throw runtime_error("time_get_byname" + __throw_runtime_error("time_get_byname" " failed to construct for " + string(nm)); -#endif // _LIBCPP_NO_EXCEPTIONS } __time_get::__time_get(const string& nm) : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__loc_ == 0) - throw runtime_error("time_get_byname" + __throw_runtime_error("time_get_byname" " failed to construct for " + nm); -#endif // _LIBCPP_NO_EXCEPTIONS } __time_get::~__time_get() @@ -5363,21 +5397,17 @@ __time_get_storage<wchar_t>::__do_date_order() const __time_put::__time_put(const char* nm) : __loc_(newlocale(LC_ALL_MASK, nm, 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__loc_ == 0) - throw runtime_error("time_put_byname" + __throw_runtime_error("time_put_byname" " failed to construct for " + string(nm)); -#endif // _LIBCPP_NO_EXCEPTIONS } __time_put::__time_put(const string& nm) : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0)) { -#ifndef _LIBCPP_NO_EXCEPTIONS if (__loc_ == 0) - throw runtime_error("time_put_byname" + __throw_runtime_error("time_put_byname" " failed to construct for " + nm); -#endif // _LIBCPP_NO_EXCEPTIONS } __time_put::~__time_put() @@ -5792,20 +5822,20 @@ moneypunct_byname<char, false>::init(const char* nm) { typedef moneypunct<char, false> base; __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); -#ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) - throw runtime_error("moneypunct_byname" + __throw_runtime_error("moneypunct_byname" " failed to construct for " + string(nm)); -#endif // _LIBCPP_NO_EXCEPTIONS + lconv* lc = __libcpp_localeconv_l(loc.get()); - if (*lc->mon_decimal_point) - __decimal_point_ = *lc->mon_decimal_point; - else - __decimal_point_ = base::do_decimal_point(); - if (*lc->mon_thousands_sep) - __thousands_sep_ = *lc->mon_thousands_sep; - else - __thousands_sep_ = base::do_thousands_sep(); + if (!checked_string_to_char_convert(__decimal_point_, + lc->mon_decimal_point, + loc.get())) + __decimal_point_ = base::do_decimal_point(); + if (!checked_string_to_char_convert(__thousands_sep_, + lc->mon_thousands_sep, + loc.get())) + __thousands_sep_ = base::do_thousands_sep(); + __grouping_ = lc->mon_grouping; __curr_symbol_ = lc->currency_symbol; if (lc->frac_digits != CHAR_MAX) @@ -5836,20 +5866,19 @@ moneypunct_byname<char, true>::init(const char* nm) { typedef moneypunct<char, true> base; __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); -#ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) - throw runtime_error("moneypunct_byname" + __throw_runtime_error("moneypunct_byname" " failed to construct for " + string(nm)); -#endif // _LIBCPP_NO_EXCEPTIONS + lconv* lc = __libcpp_localeconv_l(loc.get()); - if (*lc->mon_decimal_point) - __decimal_point_ = *lc->mon_decimal_point; - else - __decimal_point_ = base::do_decimal_point(); - if (*lc->mon_thousands_sep) - __thousands_sep_ = *lc->mon_thousands_sep; - else - __thousands_sep_ = base::do_thousands_sep(); + if (!checked_string_to_char_convert(__decimal_point_, + lc->mon_decimal_point, + loc.get())) + __decimal_point_ = base::do_decimal_point(); + if (!checked_string_to_char_convert(__thousands_sep_, + lc->mon_thousands_sep, + loc.get())) + __thousands_sep_ = base::do_thousands_sep(); __grouping_ = lc->mon_grouping; __curr_symbol_ = lc->int_curr_symbol; if (lc->int_frac_digits != CHAR_MAX) @@ -5897,20 +5926,18 @@ moneypunct_byname<wchar_t, false>::init(const char* nm) { typedef moneypunct<wchar_t, false> base; __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); -#ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) - throw runtime_error("moneypunct_byname" + __throw_runtime_error("moneypunct_byname" " failed to construct for " + string(nm)); -#endif // _LIBCPP_NO_EXCEPTIONS lconv* lc = __libcpp_localeconv_l(loc.get()); - if (*lc->mon_decimal_point) - __decimal_point_ = static_cast<wchar_t>(*lc->mon_decimal_point); - else - __decimal_point_ = base::do_decimal_point(); - if (*lc->mon_thousands_sep) - __thousands_sep_ = static_cast<wchar_t>(*lc->mon_thousands_sep); - else - __thousands_sep_ = base::do_thousands_sep(); + if (!checked_string_to_wchar_convert(__decimal_point_, + lc->mon_decimal_point, + loc.get())) + __decimal_point_ = base::do_decimal_point(); + if (!checked_string_to_wchar_convert(__thousands_sep_, + lc->mon_thousands_sep, + loc.get())) + __thousands_sep_ = base::do_thousands_sep(); __grouping_ = lc->mon_grouping; wchar_t wbuf[100]; mbstate_t mb = {0}; @@ -5964,20 +5991,19 @@ moneypunct_byname<wchar_t, true>::init(const char* nm) { typedef moneypunct<wchar_t, true> base; __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); -#ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) - throw runtime_error("moneypunct_byname" + __throw_runtime_error("moneypunct_byname" " failed to construct for " + string(nm)); -#endif // _LIBCPP_NO_EXCEPTIONS + lconv* lc = __libcpp_localeconv_l(loc.get()); - if (*lc->mon_decimal_point) - __decimal_point_ = static_cast<wchar_t>(*lc->mon_decimal_point); - else - __decimal_point_ = base::do_decimal_point(); - if (*lc->mon_thousands_sep) - __thousands_sep_ = static_cast<wchar_t>(*lc->mon_thousands_sep); - else - __thousands_sep_ = base::do_thousands_sep(); + if (!checked_string_to_wchar_convert(__decimal_point_, + lc->mon_decimal_point, + loc.get())) + __decimal_point_ = base::do_decimal_point(); + if (!checked_string_to_wchar_convert(__thousands_sep_, + lc->mon_thousands_sep, + loc.get())) + __thousands_sep_ = base::do_thousands_sep(); __grouping_ = lc->mon_grouping; wchar_t wbuf[100]; mbstate_t mb = {0}; @@ -6050,69 +6076,70 @@ void __throw_runtime_error(const char* msg) throw runtime_error(msg); #else (void)msg; + _VSTD::abort(); #endif } -template class collate<char>; -template class collate<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>; -template class num_get<char>; -template class num_get<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<wchar_t>; -template struct __num_get<char>; -template struct __num_get<wchar_t>; +template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<char>; +template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<wchar_t>; -template class num_put<char>; -template class num_put<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<wchar_t>; -template struct __num_put<char>; -template struct __num_put<wchar_t>; +template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<char>; +template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<wchar_t>; -template class time_get<char>; -template class time_get<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<wchar_t>; -template class time_get_byname<char>; -template class time_get_byname<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<wchar_t>; -template class time_put<char>; -template class time_put<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<wchar_t>; -template class time_put_byname<char>; -template class time_put_byname<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<wchar_t>; -template class moneypunct<char, false>; -template class moneypunct<char, true>; -template class moneypunct<wchar_t, false>; -template class moneypunct<wchar_t, true>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, false>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, true>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, false>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, true>; -template class moneypunct_byname<char, false>; -template class moneypunct_byname<char, true>; -template class moneypunct_byname<wchar_t, false>; -template class moneypunct_byname<wchar_t, true>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, false>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, true>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, false>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, true>; -template class money_get<char>; -template class money_get<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<wchar_t>; -template class __money_get<char>; -template class __money_get<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<wchar_t>; -template class money_put<char>; -template class money_put<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<wchar_t>; -template class __money_put<char>; -template class __money_put<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<wchar_t>; -template class messages<char>; -template class messages<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<wchar_t>; -template class messages_byname<char>; -template class messages_byname<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<wchar_t>; -template class codecvt_byname<char, char, mbstate_t>; -template class codecvt_byname<wchar_t, char, mbstate_t>; -template class codecvt_byname<char16_t, char, mbstate_t>; -template class codecvt_byname<char32_t, char, mbstate_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char, char, mbstate_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<wchar_t, char, mbstate_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char, mbstate_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char, mbstate_t>; -template class __vector_base_common<true>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>; _LIBCPP_END_NAMESPACE_STD diff --git a/src/memory.cpp b/src/memory.cpp index 15e947fc0ff8c..514a2ce226670 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -96,7 +96,35 @@ __shared_weak_count::__release_shared() _NOEXCEPT void __shared_weak_count::__release_weak() _NOEXCEPT { - if (decrement(__shared_weak_owners_) == -1) + // NOTE: The acquire load here is an optimization of the very + // common case where a shared pointer is being destructed while + // having no other contended references. + // + // BENEFIT: We avoid expensive atomic stores like XADD and STREX + // in a common case. Those instructions are slow and do nasty + // things to caches. + // + // IS THIS SAFE? Yes. During weak destruction, if we see that we + // are the last reference, we know that no-one else is accessing + // us. If someone were accessing us, then they would be doing so + // while the last shared / weak_ptr was being destructed, and + // that's undefined anyway. + // + // If we see anything other than a 0, then we have possible + // contention, and need to use an atomicrmw primitive. + // The same arguments don't apply for increment, where it is legal + // (though inadvisable) to share shared_ptr references between + // threads, and have them all get copied at once. The argument + // also doesn't apply for __release_shared, because an outstanding + // weak_ptr::lock() could read / modify the shared count. + if (__libcpp_atomic_load(&__shared_weak_owners_, _AO_Acquire) == 0) + { + // no need to do this store, because we are about + // to destroy everything. + //__libcpp_atomic_store(&__shared_weak_owners_, -1, _AO_Release); + __on_zero_shared_weak(); + } + else if (decrement(__shared_weak_owners_) == -1) __on_zero_shared_weak(); } @@ -126,8 +154,8 @@ __shared_weak_count::__get_deleter(const type_info&) const _NOEXCEPT #if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER) -static const std::size_t __sp_mut_count = 16; -static __libcpp_mutex_t mut_back_imp[__sp_mut_count] = +_LIBCPP_SAFE_STATIC static const std::size_t __sp_mut_count = 16; +_LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut_back[__sp_mut_count] = { _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, @@ -135,8 +163,6 @@ static __libcpp_mutex_t mut_back_imp[__sp_mut_count] = _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER }; -static mutex* mut_back = reinterpret_cast<std::mutex*>(mut_back_imp); - _LIBCPP_CONSTEXPR __sp_mut::__sp_mut(void* p) _NOEXCEPT : __lx(p) { @@ -145,13 +171,13 @@ _LIBCPP_CONSTEXPR __sp_mut::__sp_mut(void* p) _NOEXCEPT void __sp_mut::lock() _NOEXCEPT { - mutex& m = *static_cast<mutex*>(__lx); + auto m = static_cast<__libcpp_mutex_t*>(__lx); unsigned count = 0; - while (!m.try_lock()) + while (__libcpp_mutex_trylock(m) != 0) { if (++count > 16) { - m.lock(); + __libcpp_mutex_lock(m); break; } this_thread::yield(); @@ -161,13 +187,13 @@ __sp_mut::lock() _NOEXCEPT void __sp_mut::unlock() _NOEXCEPT { - static_cast<mutex*>(__lx)->unlock(); + __libcpp_mutex_unlock(static_cast<__libcpp_mutex_t*>(__lx)); } __sp_mut& __get_sp_mut(const void* p) { - static __sp_mut muts[__sp_mut_count] + static __sp_mut muts[__sp_mut_count] { &mut_back[ 0], &mut_back[ 1], &mut_back[ 2], &mut_back[ 3], &mut_back[ 4], &mut_back[ 5], &mut_back[ 6], &mut_back[ 7], diff --git a/src/mutex.cpp b/src/mutex.cpp index 9f808ca5076c5..dc530ceeac0df 100644 --- a/src/mutex.cpp +++ b/src/mutex.cpp @@ -195,13 +195,10 @@ recursive_timed_mutex::unlock() _NOEXCEPT // keep in sync with: 7741191. #ifndef _LIBCPP_HAS_NO_THREADS -static __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER; -static __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER; +_LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER; +_LIBCPP_SAFE_STATIC static __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER; #endif -/// NOTE: Changes to flag are done via relaxed atomic stores -/// even though the accesses are protected by a mutex because threads -/// just entering 'call_once` concurrently read from flag. void __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*)) { @@ -238,7 +235,7 @@ __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*)) __libcpp_mutex_unlock(&mut); func(arg); __libcpp_mutex_lock(&mut); - __libcpp_relaxed_store(&flag, ~0ul); + __libcpp_atomic_store(&flag, ~0ul, _AO_Release); __libcpp_mutex_unlock(&mut); __libcpp_condvar_broadcast(&cv); #ifndef _LIBCPP_NO_EXCEPTIONS diff --git a/src/new.cpp b/src/new.cpp index f4f73d86803d3..3d8b2a9d8a660 100644 --- a/src/new.cpp +++ b/src/new.cpp @@ -37,12 +37,9 @@ // in this shared library, so that they can be overridden by programs // that define non-weak copies of the functions. -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS +_LIBCPP_WEAK void * -operator new(std::size_t size) -#if !__has_feature(cxx_noexcept) - throw(std::bad_alloc) -#endif +operator new(std::size_t size) _THROW_BAD_ALLOC { if (size == 0) size = 1; @@ -64,7 +61,39 @@ operator new(std::size_t size) return p; } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS +_LIBCPP_WEAK +void * +operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC +{ + if (size == 0) + size = 1; + if (static_cast<size_t>(alignment) < sizeof(void*)) + alignment = std::align_val_t(sizeof(void*)); + void* p; +#if defined(_WIN32) + while ((p = _aligned_malloc(size, static_cast<size_t>(alignment))) == nullptr) +#else + while (::posix_memalign(&p, static_cast<size_t>(alignment), size) != 0) +#endif + { + // If posix_memalign fails and there is a new_handler, + // call it to try free up memory. + std::new_handler nh = std::get_new_handler(); + if (nh) + nh(); + else { +#ifndef _LIBCPP_NO_EXCEPTIONS + throw std::bad_alloc(); +#else + p = nullptr; // posix_memalign doesn't initialize 'p' on failure + break; +#endif + } + } + return p; +} + +_LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) _NOEXCEPT { @@ -83,17 +112,40 @@ operator new(size_t size, const std::nothrow_t&) _NOEXCEPT return p; } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS +_LIBCPP_WEAK void* -operator new[](size_t size) -#if !__has_feature(cxx_noexcept) - throw(std::bad_alloc) -#endif +operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT +{ + void* p = 0; +#ifndef _LIBCPP_NO_EXCEPTIONS + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + p = ::operator new(size, alignment); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + } +#endif // _LIBCPP_NO_EXCEPTIONS + return p; +} + +_LIBCPP_WEAK +void* +operator new[](size_t size) _THROW_BAD_ALLOC { return ::operator new(size); } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS +_LIBCPP_WEAK +void* +operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC +{ + return ::operator new(size, alignment); +} + +_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) _NOEXCEPT { @@ -112,7 +164,26 @@ operator new[](size_t size, const std::nothrow_t&) _NOEXCEPT return p; } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS +_LIBCPP_WEAK +void* +operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT +{ + void* p = 0; +#ifndef _LIBCPP_NO_EXCEPTIONS + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + p = ::operator new[](size, alignment); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + } +#endif // _LIBCPP_NO_EXCEPTIONS + return p; +} + +_LIBCPP_WEAK void operator delete(void* ptr) _NOEXCEPT { @@ -120,41 +191,84 @@ operator delete(void* ptr) _NOEXCEPT ::free(ptr); } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS +_LIBCPP_WEAK +void +operator delete(void* ptr, std::align_val_t) _NOEXCEPT +{ + if (ptr) + ::free(ptr); +} + +_LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT { ::operator delete(ptr); } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS +_LIBCPP_WEAK +void +operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT +{ + ::operator delete(ptr, alignment); +} + +_LIBCPP_WEAK void operator delete(void* ptr, size_t) _NOEXCEPT { ::operator delete(ptr); } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS +_LIBCPP_WEAK +void +operator delete(void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT +{ + ::operator delete(ptr, alignment); +} + +_LIBCPP_WEAK void operator delete[] (void* ptr) _NOEXCEPT { ::operator delete(ptr); } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS +_LIBCPP_WEAK +void +operator delete[] (void* ptr, std::align_val_t alignment) _NOEXCEPT +{ + ::operator delete(ptr, alignment); +} + +_LIBCPP_WEAK void operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT { ::operator delete[](ptr); } -_LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS +_LIBCPP_WEAK +void +operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT +{ + ::operator delete[](ptr, alignment); +} + +_LIBCPP_WEAK void operator delete[] (void* ptr, size_t) _NOEXCEPT { ::operator delete[](ptr); } +_LIBCPP_WEAK +void +operator delete[] (void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT +{ + ::operator delete[](ptr, alignment); +} + #endif // !__GLIBCXX__ namespace std @@ -206,6 +320,8 @@ bad_array_new_length::bad_array_new_length() _NOEXCEPT { } +#ifndef __GLIBCXX__ + bad_array_new_length::~bad_array_new_length() _NOEXCEPT { } @@ -216,22 +332,28 @@ bad_array_new_length::what() const _NOEXCEPT return "bad_array_new_length"; } +#endif // !__GLIBCXX__ + #endif //LIBCXXRT -const char* -bad_array_length::what() const _NOEXCEPT +bad_array_length::bad_array_length() _NOEXCEPT { - return "bad_array_length"; } -bad_array_length::bad_array_length() _NOEXCEPT +#ifndef __GLIBCXX__ + +bad_array_length::~bad_array_length() _NOEXCEPT { } -bad_array_length::~bad_array_length() _NOEXCEPT +const char* +bad_array_length::what() const _NOEXCEPT { + return "bad_array_length"; } +#endif // !__GLIBCXX__ + #endif // _LIBCPPABI_VERSION #ifndef LIBSTDCXX @@ -241,6 +363,8 @@ __throw_bad_alloc() { #ifndef _LIBCPP_NO_EXCEPTIONS throw bad_alloc(); +#else + _VSTD::abort(); #endif } diff --git a/src/optional.cpp b/src/optional.cpp index 8c5dd76d86d6b..f2fbfdfec1cee 100644 --- a/src/optional.cpp +++ b/src/optional.cpp @@ -7,18 +7,18 @@ // //===----------------------------------------------------------------------===// +#include "optional" #include "experimental/optional" -_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL +namespace std +{ -#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +bad_optional_access::~bad_optional_access() _NOEXCEPT = default; -bad_optional_access::~bad_optional_access() _NOEXCEPT {} +} // std -#else +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL bad_optional_access::~bad_optional_access() _NOEXCEPT = default; -#endif - _LIBCPP_END_NAMESPACE_EXPERIMENTAL diff --git a/src/random.cpp b/src/random.cpp index 4ab424eaa6e58..eb2510a48c85e 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -7,6 +7,8 @@ // //===----------------------------------------------------------------------===// +#include <__config> + #if defined(_LIBCPP_USING_WIN32_RANDOM) // Must be defined before including stdlib.h to enable rand_s(). #define _CRT_RAND_S diff --git a/src/stdexcept.cpp b/src/stdexcept.cpp index 0a08bfec27ec9..90d8a34b82deb 100644 --- a/src/stdexcept.cpp +++ b/src/stdexcept.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "__refstring" #include "stdexcept" #include "new" #include "string" #include "system_error" +#include "__refstring" /* For _LIBCPPABI_VERSION */ #if defined(LIBCXX_BUILDING_LIBCXXABI) || defined(__APPLE__) || defined(LIBCXXRT) @@ -20,6 +20,7 @@ static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), ""); + namespace std // purposefully not using versioning namespace { diff --git a/src/string.cpp b/src/string.cpp index d3f29df639f48..cd644330b3a77 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -20,10 +20,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template class __basic_string_common<true>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>; -template class basic_string<char>; -template class basic_string<wchar_t>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>; +template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<wchar_t>; template string @@ -40,7 +40,7 @@ void throw_helper( const string& msg ) throw T( msg ); #else fprintf(stderr, "%s\n", msg.c_str()); - abort(); + _VSTD::abort(); #endif } diff --git a/src/strstream.cpp b/src/strstream.cpp index 0e2d7ff21bb97..be94f9c89e837 100644 --- a/src/strstream.cpp +++ b/src/strstream.cpp @@ -11,6 +11,7 @@ #include "algorithm" #include "climits" #include "cstring" +#include "cstdlib" #include "__debug" _LIBCPP_BEGIN_NAMESPACE_STD @@ -266,6 +267,8 @@ strstreambuf::seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmod case ios::end: newoff = seekhigh - eback(); break; + default: + _LIBCPP_UNREACHABLE(); } newoff += __off; if (0 <= newoff && newoff <= seekhigh - eback()) diff --git a/src/support/solaris/xlocale.c b/src/support/solaris/xlocale.cpp index 9125eea73777f..6eaf317c768a3 100644 --- a/src/support/solaris/xlocale.c +++ b/src/support/solaris/xlocale.cpp @@ -14,12 +14,13 @@ #include <stdio.h> #include <sys/localedef.h> +extern "C" { int isxdigit_l(int __c, locale_t __l) { return isxdigit(__c); } -int iswxdigit_l(wchar_t __c, locale_t __l) { +int iswxdigit_l(wint_t __c, locale_t __l) { return isxdigit(__c); } @@ -63,4 +64,6 @@ struct lconv *localeconv_l(locale_t __l) { return localeconv(); } +}; + #endif // __sun__ diff --git a/src/support/win32/locale_win32.cpp b/src/support/win32/locale_win32.cpp index 5a43743470d53..7300451101ebd 100644 --- a/src/support/win32/locale_win32.cpp +++ b/src/support/win32/locale_win32.cpp @@ -10,6 +10,11 @@ #include <locale> #include <cstdarg> // va_start, va_end +#include <memory> +#include <type_traits> + +typedef _VSTD::remove_pointer<locale_t>::type __locale_struct; +typedef _VSTD::unique_ptr<__locale_struct, decltype(&uselocale)> __locale_raii; // FIXME: base currently unused. Needs manual work to construct the new locale locale_t newlocale( int mask, const char * locale, locale_t /*base*/ ) diff --git a/src/system_error.cpp b/src/system_error.cpp index 87f35ae37f391..3a2255425f092 100644 --- a/src/system_error.cpp +++ b/src/system_error.cpp @@ -55,6 +55,7 @@ error_category::equivalent(const error_code& code, int condition) const _NOEXCEP return *this == code.category() && code.value() == condition; } +#if !defined(_LIBCPP_HAS_NO_THREADS) namespace { // GLIBC also uses 1024 as the maximum buffer size internally. @@ -96,6 +97,7 @@ string do_strerror_r(int ev) { #endif } // end namespace +#endif string __do_message::message(int ev) const @@ -258,6 +260,7 @@ __throw_system_error(int ev, const char* what_arg) #else (void)ev; (void)what_arg; + _VSTD::abort(); #endif } diff --git a/src/thread.cpp b/src/thread.cpp index 467402b6b423a..4775e10f6ab55 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -53,10 +53,9 @@ thread::join() if (ec == 0) __t_ = 0; } -#ifndef _LIBCPP_NO_EXCEPTIONS + if (ec) - throw system_error(error_code(ec, system_category()), "thread::join failed"); -#endif // _LIBCPP_NO_EXCEPTIONS + __throw_system_error(ec, "thread::join failed"); } void @@ -69,10 +68,9 @@ thread::detach() if (ec == 0) __t_ = 0; } -#ifndef _LIBCPP_NO_EXCEPTIONS + if (ec) - throw system_error(error_code(ec, system_category()), "thread::detach failed"); -#endif // _LIBCPP_NO_EXCEPTIONS + __throw_system_error(ec, "thread::detach failed"); } unsigned diff --git a/src/typeinfo.cpp b/src/typeinfo.cpp index 5c0a609b5e5ca..3033c9800f180 100644 --- a/src/typeinfo.cpp +++ b/src/typeinfo.cpp @@ -54,12 +54,16 @@ std::bad_typeid::what() const _NOEXCEPT { #ifndef _LIBCPP_NO_EXCEPTIONS throw std::bad_typeid(); +#else + _VSTD::abort(); #endif } void __cxxabiv1::__cxa_bad_cast() { #ifndef _LIBCPP_NO_EXCEPTIONS throw std::bad_cast(); +#else + _VSTD::abort(); #endif } #endif diff --git a/src/variant.cpp b/src/variant.cpp new file mode 100644 index 0000000000000..5bb508c3f4676 --- /dev/null +++ b/src/variant.cpp @@ -0,0 +1,18 @@ +//===------------------------ variant.cpp ---------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "variant" + +namespace std { + +const char* bad_variant_access::what() const noexcept { + return "bad_variant_access"; +} + +} // namespace std |