Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -26,10 +26,10 @@ project(libcxx CXX C) set(PACKAGE_NAME libcxx) - set(PACKAGE_VERSION trunk-svn) + set(PACKAGE_VERSION 4.0.0svn) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") -endif () +endif() if (LIBCXX_BUILT_STANDALONE AND NOT LLVM_FOUND) message(WARNING "UNSUPPORTED LIBCXX CONFIGURATION DETECTED: " @@ -52,6 +52,7 @@ # Basic options --------------------------------------------------------------- option(LIBCXX_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON) option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON) +option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON) option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON) option(LIBCXX_ENABLE_FILESYSTEM "Build filesystem as part of libc++experimental.a" ${LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY}) @@ -68,6 +69,10 @@ set(LIBCXX_ABI_VERSION 1 CACHE STRING "ABI version of libc++.") option(LIBCXX_ABI_UNSTABLE "Unstable ABI of libc++." OFF) +if (NOT LIBCXX_ENABLE_SHARED AND NOT LIBCXX_ENABLE_STATIC) + message(FATAL_ERROR "libc++ must be built as either a shared or static library.") +endif() + # ABI Library options --------------------------------------------------------- set(LIBCXX_CXX_ABI "${LIBCXX_CXX_ABI}" CACHE STRING "Specify C++ ABI library to use." FORCE) @@ -81,12 +86,12 @@ set(LIBCXX_CXX_ABI_LIBNAME "libcxxabi") set(LIBCXX_CXX_ABI_INCLUDE_PATHS "${CMAKE_SOURCE_DIR}/projects/libcxxabi/include") set(LIBCXX_CXX_ABI_INTREE 1) - else () + else() set(LIBCXX_CXX_ABI_LIBNAME "none") - endif () -else () + endif() +else() set(LIBCXX_CXX_ABI_LIBNAME "${LIBCXX_CXX_ABI}") -endif () +endif() # Use a static copy of the ABI library when linking libc++. This option # cannot be used with LIBCXX_ENABLE_ABI_LINKER_SCRIPT. @@ -296,9 +301,9 @@ remove_flags(-Wno-pedantic -pedantic-errors -pedantic) # Required flags ============================================================== -add_compile_flags_if_supported(-std=c++11) +add_compile_flags_if_supported(-std=c++14) if (NOT MSVC AND NOT LIBCXX_SUPPORTS_STD_EQ_CXX11_FLAG) - message(FATAL_ERROR "C++11 is required but the compiler does not support -std=c++11") + message(FATAL_ERROR "C++14 is required but the compiler does not support -std=c++14") endif() # On all systems the system c++ standard library headers need to be excluded. @@ -307,7 +312,6 @@ # headers add_compile_flags_if_supported(-nostdinc++) - # Warning flags =============================================================== add_definitions(-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) add_compile_flags_if_supported( Index: benchmarks/CMakeLists.txt =================================================================== --- benchmarks/CMakeLists.txt +++ benchmarks/CMakeLists.txt @@ -87,7 +87,12 @@ add_executable(${libcxx_target} EXCLUDE_FROM_ALL ${source_file}) add_dependencies(${libcxx_target} cxx google-benchmark-libcxx) add_dependencies(libcxx-benchmarks ${libcxx_target}) - target_link_libraries(${libcxx_target} cxx -lbenchmark) + if (LIBCXX_ENABLE_SHARED) + target_link_libraries(${libcxx_target} cxx_shared) + else() + target_link_libraries(${libcxx_target} cxx_static) + endif() + target_link_libraries(${libcxx_target} -lbenchmark) set_target_properties(${libcxx_target} PROPERTIES OUTPUT_NAME "${name}.libcxx.out" Index: benchmarks/ContainerBenchmarks.hpp =================================================================== --- benchmarks/ContainerBenchmarks.hpp +++ benchmarks/ContainerBenchmarks.hpp @@ -10,7 +10,7 @@ template void BM_ConstructIterIter(benchmark::State& st, Container, GenInputs gen) { - auto in = gen(st.range_x()); + auto in = gen(st.range(0)); const auto end = in.end(); benchmark::DoNotOptimize(&in); while (st.KeepRunning()) { @@ -21,7 +21,7 @@ template void BM_InsertValue(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range_x()); + auto in = gen(st.range(0)); const auto end = in.end(); while (st.KeepRunning()) { c.clear(); @@ -34,7 +34,7 @@ template void BM_InsertValueRehash(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range_x()); + auto in = gen(st.range(0)); const auto end = in.end(); while (st.KeepRunning()) { c.clear(); @@ -49,7 +49,7 @@ template void BM_InsertDuplicate(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range_x()); + auto in = gen(st.range(0)); const auto end = in.end(); c.insert(in.begin(), in.end()); benchmark::DoNotOptimize(&c); @@ -65,7 +65,7 @@ template void BM_EmplaceDuplicate(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range_x()); + auto in = gen(st.range(0)); const auto end = in.end(); c.insert(in.begin(), in.end()); benchmark::DoNotOptimize(&c); @@ -80,7 +80,7 @@ template static void BM_Find(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range_x()); + auto in = gen(st.range(0)); c.insert(in.begin(), in.end()); benchmark::DoNotOptimize(&(*c.begin())); const auto end = in.data() + in.size(); @@ -95,7 +95,7 @@ template static void BM_FindRehash(benchmark::State& st, Container c, GenInputs gen) { c.rehash(8); - auto in = gen(st.range_x()); + auto in = gen(st.range(0)); c.insert(in.begin(), in.end()); benchmark::DoNotOptimize(&(*c.begin())); const auto end = in.data() + in.size(); Index: benchmarks/algorithms.bench.cpp =================================================================== --- benchmarks/algorithms.bench.cpp +++ benchmarks/algorithms.bench.cpp @@ -10,7 +10,7 @@ template void BM_Sort(benchmark::State& st, GenInputs gen) { using ValueType = typename decltype(gen(0))::value_type; - const auto in = gen(st.range_x()); + const auto in = gen(st.range(0)); std::vector inputs[5]; auto reset_inputs = [&]() { for (auto& C : inputs) { Index: benchmarks/unordered_set_operations.bench.cpp =================================================================== --- benchmarks/unordered_set_operations.bench.cpp +++ benchmarks/unordered_set_operations.bench.cpp @@ -109,7 +109,7 @@ template void BM_Hash(benchmark::State& st, HashFn fn, GenInputs gen) { - auto in = gen(st.range_x()); + auto in = gen(st.range(0)); const auto end = in.data() + in.size(); std::size_t last_hash = 0; benchmark::DoNotOptimize(&last_hash); Index: docs/BuildingLibcxx.rst =================================================================== --- docs/BuildingLibcxx.rst +++ docs/BuildingLibcxx.rst @@ -150,8 +150,15 @@ **Default**: ``ON`` - Build libc++ as a shared library. If ``OFF`` is specified then libc++ is - built as a static library. + Build libc++ as a shared library. Either :option:`LIBCXX_ENABLE_SHARED` or + :option:`LIBCXX_ENABLE_STATIC` has to be enabled. + +.. option:: LIBCXX_ENABLE_STATIC:BOOL + + **Default**: ``ON`` + + Build libc++ as a static library. Either :option:`LIBCXX_ENABLE_SHARED` or + :option:`LIBCXX_ENABLE_STATIC` has to be enabled. .. option:: LIBCXX_LIBDIR_SUFFIX:STRING Index: include/variant =================================================================== --- /dev/null +++ include/variant @@ -0,0 +1,1599 @@ +// -*- C++ -*- +//===------------------------------ variant -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_VARIANT +#define _LIBCPP_VARIANT + +/* + variant synopsis + +namespace std { + + // 20.7.2, variant of value types + template + class variant { + public: + + // 20.7.2.1, constructors + constexpr variant() noexcept(see below); + variant(const variant&); + variant(variant&&) noexcept(see below); + + template constexpr variant(T&&) noexcept(see below); + + template + constexpr explicit variant(in_place_index_t, Args&&...); + + template + constexpr explicit variant( + in_place_index_t, initializer_list, Args&&...); + + template + constexpr explicit variant(in_place_type_t, Args&&...); + + template + constexpr explicit variant( + in_place_type_t, initializer_list, Args&&...); + + // allocator-extended constructors + template + variant(allocator_arg_t, const Alloc&); + + template + variant(allocator_arg_t, const Alloc&, const variant&); + + template + variant(allocator_arg_t, const Alloc&, variant&&); + + template + variant(allocator_arg_t, const Alloc&, T&&); + + template + variant(allocator_arg_t, const Alloc&, in_place_index_t, Args&&...); + + template + variant(allocator_arg_t, + const Alloc&, + in_place_index_t, + initializer_list, + Args&&...); + + template + variant(allocator_arg_t, const Alloc&, in_place_type_t, Args&&...); + + template + variant(allocator_arg_t, + const Alloc&, + in_place_type_t, + initializer_list, + Args&&...); + + // 20.7.2.2, destructor + ~variant(); + + // 20.7.2.3, assignment + variant& operator=(const variant&); + variant& operator=(variant&&) noexcept(see below); + + template variant& operator=(T&&) noexcept(see below); + + // 20.7.2.4, modifiers + template + void emplace(Args&&...); + + template + void emplace(initializer_list, Args&&...); + + template + void emplace(Args&&...); + + template + void emplace(initializer_list, Args&&...); + + // 20.7.2.5, value status + constexpr bool valueless_by_exception() const noexcept; + constexpr size_t index() const noexcept; + + // 20.7.2.6, swap + void swap(variant&) noexcept(see below); + }; + + // 20.7.3, variant helper classes + template struct variant_size; // undefined + + template + constexpr size_t variant_size_v = variant_size::value; + + template struct variant_size; + template struct variant_size; + template struct variant_size; + + template + struct variant_size>; + + template struct variant_alternative; // undefined + + template + using variant_alternative_t = typename variant_alternative::type; + + template struct variant_alternative; + template struct variant_alternative; + template struct variant_alternative; + + template + struct variant_alternative>; + + constexpr size_t variant_npos = -1; + + // 20.7.4, value access + template + constexpr bool holds_alternative(const variant&) noexcept; + + template + constexpr variant_alternative_t>& + get(variant&); + + template + constexpr variant_alternative_t>&& + get(variant&&); + + template + constexpr variant_alternative_t> const& + get(const variant&); + + template + constexpr variant_alternative_t> const&& + get(const variant&&); + + template + constexpr T& get(variant&); + + template + constexpr T&& get(variant&&); + + template + constexpr const T& get(const variant&); + + template + constexpr const T&& get(const variant&&); + + template + constexpr add_pointer_t>> + get_if(variant*) noexcept; + + template + constexpr add_pointer_t>> + get_if(const variant*) noexcept; + + template + constexpr add_pointer_t + get_if(variant*) noexcept; + + template + constexpr add_pointer_t + get_if(const variant*) noexcept; + + // 20.7.5, relational operators + template + constexpr bool operator==(const variant&, const variant&); + + template + constexpr bool operator!=(const variant&, const variant&); + + template + constexpr bool operator<(const variant&, const variant&); + + template + constexpr bool operator>(const variant&, const variant&); + + template + constexpr bool operator<=(const variant&, const variant&); + + template + constexpr bool operator>=(const variant&, const variant&); + + // 20.7.6, visitation + template + constexpr see below visit(Visitor&&, Variants&&...); + + // 20.7.7, class monostate + struct monostate; + + // 20.7.8, monostate relational operators + constexpr bool operator<(monostate, monostate) noexcept; + constexpr bool operator>(monostate, monostate) noexcept; + constexpr bool operator<=(monostate, monostate) noexcept; + constexpr bool operator>=(monostate, monostate) noexcept; + constexpr bool operator==(monostate, monostate) noexcept; + constexpr bool operator!=(monostate, monostate) noexcept; + + // 20.7.9, specialized algorithms + template + void swap(variant&, variant&) noexcept(see below); + + // 20.7.10, class bad_variant_access + class bad_variant_access; + + // 20.7.11, hash support + template struct hash; + template struct hash>; + template <> struct hash; + + // 20.7.12, allocator-related traits + template struct uses_allocator; + template + struct uses_allocator, Alloc>; + +} // namespace std + +*/ + +#include <__config> +#include <__tuple> +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +#define _LIBCPP_NOEXCEPT_SFINAE_RETURN(...) \ + noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { \ + return __VA_ARGS__; \ + } + +#define _LIBCPP_NOEXCEPT_INIT(base, ...) \ + noexcept(noexcept(base##_type(__VA_ARGS__))) : base(__VA_ARGS__) + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +constexpr bool __all_v = __all::value; + +template +using __size_constant = integral_constant; + +class _LIBCPP_EXCEPTION_ABI bad_variant_access : public exception { +public: + virtual ~bad_variant_access(); + virtual const char* what() const noexcept; +}; + +#if _LIBCPP_STD_VER > 14 + +template +class variant; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_size; + +template +constexpr size_t variant_size_v = variant_size<_Tp>::value; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_size + : variant_size<_Tp> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_size + : variant_size<_Tp> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_size + : variant_size<_Tp> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_size> + : __size_constant {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_alternative; + +template +using variant_alternative_t = typename variant_alternative<_Ip, _Tp>::type; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_alternative<_Ip, const _Tp> + : __identity>> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_alternative<_Ip, volatile _Tp> + : __identity>> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_alternative<_Ip, const volatile _Tp> + : __identity>> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_alternative<_Ip, variant<_Types...>> + : __identity<__type_pack_element<_Ip, _Types...>> {}; + +constexpr size_t variant_npos = static_cast(-1); + +struct __variant_valueless_t {}; +constexpr __variant_valueless_t __variant_valueless = __variant_valueless_t{}; + +struct __variant_void { + __variant_void() = delete; + __variant_void(const __variant_void&) = default; + __variant_void(__variant_void&&) = default; + __variant_void& operator=(const __variant_void&) = default; + __variant_void& operator=(__variant_void&&) = default; +}; + +namespace __find_detail { + + template + constexpr size_t __find_index() { + constexpr bool __matches[] = {is_same_v<_Tp, _Types>...}; + size_t __result = __not_found; + for (size_t __i = 0; __i < sizeof...(_Types); ++__i) { + if (__matches[__i]) { + if (__result != __not_found) { + return __ambiguous; + } + __result = __i; + } + } + return __result; + } + + template + struct __find_unambiguous_index_sfinae_impl : __size_constant<__index> {}; + + template <> + struct __find_unambiguous_index_sfinae_impl<__not_found> {}; + + template <> + struct __find_unambiguous_index_sfinae_impl<__ambiguous> {}; + + template + struct __find_unambiguous_index_sfinae + : __find_unambiguous_index_sfinae_impl<__find_index<_Tp, _Types...>()> {}; + +} // namespace __find_detail + +using __find_detail::__find_unambiguous_index_sfinae; + +template +class __variant_overload; + +template <> +class __variant_overload<> { +public: + void operator()() const; +}; + +template +class __variant_overload<_Tp, _Types...> + : public __variant_overload<_Types...> { + using __base_type = __variant_overload<_Types...>; + +public: + using __base_type::operator(); + _Tp operator()(_Tp) const; + + template , int> = 0> + void operator()(remove_reference_t<_Tp>&&) const = delete; +}; + +template +using __variant_best_match = result_of_t<__variant_overload<_Types...>(_Tp)>; + +struct __variant_union_access { + template + static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<0>) { + return _VSTD::forward<_Vp>(__v).__head; + } + + template + static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<_Ip>) { + return __get_alt(_VSTD::forward<_Vp>(__v).__tail, in_place<_Ip - 1>); + } +}; + +struct __variant_impl_access { + template + static constexpr auto&& __get_alt(_Vp&& __v) { + return __variant_union_access::__get_alt(_VSTD::forward<_Vp>(__v).__data, + in_place<_Ip>); + } +}; + +struct __variant_access { + template + static constexpr auto&& __get_alt(_Vp&& __v) { + return __variant_impl_access::__get_alt<_Ip>( + _VSTD::forward<_Vp>(__v).__impl); + } +}; + +namespace __variant_impl_visitation_detail { + + template + constexpr const _Tp& __at_impl(const _Tp& __elem, const size_t*) { + return __elem; + } + + template + constexpr auto&& __at_impl(const array<_Tp, _Np>& __elems, + const size_t* __index) { + return __at_impl(__elems[*__index], __index + 1); + } + + template + constexpr auto&& __at(const array<_Tp, _Np>& __elems, + const size_t (&__indices)[_Ip]) { + return __at_impl(__elems, begin(__indices)); + } + + template + struct __all_same : __all...> {}; + + template + constexpr void __variant_visit_has_same_return_types(true_type) {} + + template + constexpr void __variant_visit_has_same_return_types(false_type) = delete; + + template + constexpr array...>, sizeof...(_Args)> + __make_array(_Args&&... __args) { + using __all_same = __all_same...>; + __variant_visit_has_same_return_types...>(__all_same{}); + return {{_VSTD::forward<_Args>(__args)...}}; + } + + template + constexpr auto __make_dispatch(index_sequence<_Is...>) { + struct __dispatcher { + static constexpr decltype(auto) __dispatch(_Fp __f, _Vs... __vs) { + return __invoke_constexpr( + static_cast<_Fp>(__f), + __variant_impl_access::__get_alt<_Is>(static_cast<_Vs>(__vs))...); + } + }; + return _VSTD::addressof(__dispatcher::__dispatch); + } + + template + constexpr auto __make_fdiagonal_impl() { + return __make_dispatch<_Fp, _Vs...>( + index_sequence<(__identity<_Vs>{}, _Ip)...>{}); + } + + template + constexpr auto __make_fdiagonal_impl(index_sequence<_Is...>) { + return __make_array(__make_fdiagonal_impl<_Is, _Fp, _Vs...>()...); + } + + template + constexpr auto __make_fdiagonal() { + constexpr size_t _Np = decay_t<_Vp>::__size(); + static_assert(__all_v<(_Np == decay_t<_Vs>::__size())...>); + return __make_fdiagonal_impl<_Fp, _Vp, _Vs...>(make_index_sequence<_Np>{}); + } + + template + constexpr auto __make_fmatrix_impl(index_sequence<_Is...> __is) { + return __make_dispatch<_Fp, _Vs...>(__is); + } + + template + constexpr auto __make_fmatrix_impl(index_sequence<_Is...>, + index_sequence<_Js...>, + _Ls... __ls) { + return __make_array(__make_fmatrix_impl<_Fp, _Vs...>( + index_sequence<_Is..., _Js>{}, __ls...)...); + } + + template + constexpr auto __make_fmatrix() { + return __make_fmatrix_impl<_Fp, _Vs...>( + index_sequence<>{}, make_index_sequence::__size()>{}...); + } + +} // namespace __variant_impl_visitation_detail + +struct __variant_impl_visitation { + template + static constexpr decltype(auto) __visit_alt_at(size_t __index, + _Visitor&& __visitor, + _Vs&&... __vs) { + using namespace __variant_impl_visitation_detail; + constexpr auto __fdiagonal = __make_fdiagonal< + _Visitor&&, + decltype(_VSTD::forward<_Vs>(__vs).__as_variant_base())...>(); + return __fdiagonal[__index]( + _VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__as_variant_base()...); + } + + template + static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, + _Vs&&... __vs) { + using namespace __variant_impl_visitation_detail; + constexpr auto __fmatrix = __make_fmatrix< + _Visitor&&, + decltype(_VSTD::forward<_Vs>(__vs).__as_variant_base())...>(); + const size_t __indices[] = {__vs.index()...}; + return __at(__fmatrix, __indices)( + _VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__as_variant_base()...); + } +}; + +struct __variant_visitation { + template + static constexpr decltype(auto) __visit_alt_at(size_t __index, + _Visitor&& __visitor, + _Vs&&... __vs) { + return __variant_impl_visitation::__visit_alt_at( + __index, + _VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__impl...); + } + + template + static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, + _Vs&&... __vs) { + return __variant_impl_visitation::__visit_alt( + _VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__impl...); + } + + template + struct __value_visitor { + template + constexpr decltype(auto) operator()(_Alts&&... __alts) const { + return __invoke_constexpr(static_cast<_Visitor>(__visitor), + _VSTD::forward<_Alts>(__alts).__get_value()...); + } + + _Visitor __visitor; + }; + + template + static constexpr auto __make_value_visitor(_Visitor&& __visitor) { + return __value_visitor<_Visitor&&>{_VSTD::forward<_Visitor>(__visitor)}; + } + + template + static constexpr decltype(auto) __visit_value_at(size_t __index, + _Visitor&& __visitor, + _Vs&&... __vs) { + return __visit_alt_at( + __index, + __make_value_visitor(_VSTD::forward<_Visitor>(__visitor)), + _VSTD::forward<_Vs>(__vs)...); + } + + template + static constexpr decltype(auto) __visit_value(_Visitor&& __visitor, + _Vs&&... __vs) { + return __visit_alt( + __make_value_visitor(_VSTD::forward<_Visitor>(__visitor)), + _VSTD::forward<_Vs>(__vs)...); + } +}; + +template +struct _LIBCPP_TYPE_VIS_ONLY __variant_alt { + using __value_type = _Tp; + + __variant_alt() = delete; + __variant_alt(const __variant_alt&) = delete; + __variant_alt(__variant_alt&&) = delete; + __variant_alt& operator=(const __variant_alt&) = delete; + __variant_alt& operator=(__variant_alt&&) = delete; + + template + explicit constexpr __variant_alt(in_place_t, _Args&&... __args) + : __value(_VSTD::forward<_Args>(__args)...) {} + + template + explicit __variant_alt(allocator_arg_t, + const _Alloc&, + integral_constant, + _Args&&... __args) + : __value(_VSTD::forward<_Args>(__args)...) {} + + template + explicit __variant_alt(allocator_arg_t, + const _Alloc& __alloc, + integral_constant, + _Args&&... __args) + : __value(allocator_arg, __alloc, _VSTD::forward<_Args>(__args)...) {} + + template + explicit __variant_alt(allocator_arg_t, + const _Alloc& __alloc, + integral_constant, + _Args&&... __args) + : __value(_VSTD::forward<_Args>(__args)..., __alloc) {} + + constexpr auto&& __get_value() & { + return static_cast<__value_type&>(__value); + } + + constexpr auto&& __get_value() && { + return static_cast<__value_type&&>(__value); + } + + constexpr auto&& __get_value() const & { + return static_cast(__value); + } + + constexpr auto&& __get_value() const && { + return static_cast(__value); + } + +private: + __value_type __value; +}; + +template +union __variant_union; + +template +union __variant_union<__trivially_destructible, __index> {}; + +#define _LIBCPP_VARIANT_UNION(__trivially_destructible, dtor) \ + template \ + union __variant_union<__trivially_destructible, __index, _Tp, _Types...> { \ + public: \ + explicit constexpr __variant_union(__variant_valueless_t) noexcept \ + : __dummy{} {} \ + \ + template \ + explicit constexpr __variant_union(in_place_index_t<0>, _Args&&... __args) \ + : __head(in_place, _VSTD::forward<_Args>(__args)...) {} \ + \ + template \ + explicit constexpr __variant_union(in_place_index_t<_Ip>, \ + _Args&&... __args) \ + : __tail(in_place<_Ip - 1>, _VSTD::forward<_Args>(__args)...) {} \ + \ + template \ + explicit constexpr __variant_union(allocator_arg_t, \ + const _Alloc& __alloc, \ + in_place_index_t<0>, \ + _Args&&... __args) \ + : __head(allocator_arg, \ + __alloc, \ + __uses_alloc_ctor<_Tp, _Alloc, _Args&&...>{}, \ + _VSTD::forward<_Args>(__args)...) {} \ + \ + template \ + explicit constexpr __variant_union(allocator_arg_t, \ + const _Alloc& __alloc, \ + in_place_index_t<_Ip>, \ + _Args&&... __args) \ + : __tail(allocator_arg, \ + __alloc, \ + in_place<_Ip - 1>, \ + _VSTD::forward<_Args>(__args)...) {} \ + \ + dtor \ + \ + private: \ + char __dummy; \ + __variant_alt<__index, _Tp> __head; \ + __variant_union<__trivially_destructible, __index + 1, _Types...> __tail; \ + \ + friend struct __variant_union_access; \ + } + +_LIBCPP_VARIANT_UNION(true , ~__variant_union() = default;); +_LIBCPP_VARIANT_UNION(false, ~__variant_union() {}); + +#undef _LIBCPP_VARIANT_UNION + +template +class __variant_base { +public: + static constexpr size_t __size() { return sizeof...(_Types); } + + explicit constexpr __variant_base(__variant_valueless_t) noexcept + : __index(variant_npos), __data(__variant_valueless) {} + + template = 0, + class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, + enable_if_t, int> = 0> + explicit constexpr __variant_base( + in_place_index_t<_Ip>, + _Args&&... __args) noexcept(is_nothrow_constructible_v<_Tp, _Args&&...>) + : __index(_Ip), __data(in_place<_Ip>, _VSTD::forward<_Args>(__args)...) {} + + template = 0, + class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, + enable_if_t, int> = 0> + explicit __variant_base(allocator_arg_t, + const _Alloc& __alloc, + in_place_index_t<_Ip>, + _Args&&... __args) + : __index(_Ip), + __data(allocator_arg, + __alloc, + in_place<_Ip>, + _VSTD::forward<_Args>(__args)...) {} + + constexpr bool valueless_by_exception() const noexcept { + return index() == variant_npos; + } + + constexpr size_t index() const noexcept { return __index; } + +protected: + constexpr auto&& __as_variant_base() & { return *this; } + constexpr auto&& __as_variant_base() && { return _VSTD::move(*this); } + constexpr auto&& __as_variant_base() const & { return *this; } + constexpr auto&& __as_variant_base() const && { return _VSTD::move(*this); } + + size_t __index; + __variant_union<__trivially_destructible, 0, _Types...> __data; + + friend struct __variant_impl_access; + friend struct __variant_impl_visitation; +}; + +// Provides the appropriate destructor and a `__destroy` function based on +// whether all types of alternatives are `__trivially_destructible`. +template +class __variant_dtor; + +template +class __variant_dtor + : public __variant_base { + using __base_type = __variant_base; + +public: + using __base_type::__base_type; + ~__variant_dtor() = default; + +protected: + void __destroy() noexcept { this->__index = variant_npos; } +}; + +template +class __variant_dtor + : public __variant_base { + using __base_type = __variant_base; + +public: + using __base_type::__base_type; + ~__variant_dtor() { __destroy(); } + +protected: + void __destroy() noexcept { + if (!this->valueless_by_exception()) { + __variant_impl_visitation::__visit_alt( + [](auto& __alt) noexcept { + using __alt_type = decay_t; + __alt.~__alt_type(); + }, + *this); + } + this->__index = variant_npos; + } +}; + +template +struct __variant_impl + : public __variant_dtor<__all_v...>, + _Types...> { + using __base_type = + __variant_dtor<__all_v...>, + _Types...>; + +public: + using __base_type::__base_type; + + __variant_impl( + const conditional_t<__all_v...>, + __variant_impl, + __nat>& __that) + : __variant_impl(__variant_valueless) { + static_assert(!is_same_v, __nat>); + __generic_construct(*this, __that); + } + + __variant_impl( + conditional_t<__all_v...>, + __variant_impl, + __nat>&& + __that) noexcept(__all_v...>) + : __variant_impl(__variant_valueless) { + static_assert(!is_same_v, __nat>); + __generic_construct(*this, _VSTD::move(__that)); + } + + template , + __dummy>::value...>, + int> = 0> + __variant_impl(allocator_arg_t, + const _Alloc& __alloc, + const __variant_impl& __that) + : __variant_impl(__variant_valueless) { + __generic_construct(*this, allocator_arg, __alloc, __that); + } + + template , + __dummy>::value...>, + int> = 0> + __variant_impl(allocator_arg_t, + const _Alloc& __alloc, + __variant_impl&& __that) + : __variant_impl(__variant_valueless) { + __generic_construct(*this, allocator_arg, __alloc, _VSTD::move(__that)); + } + + __variant_impl& operator=( + const conditional_t<__all_v<(is_copy_constructible_v<_Types> && + is_move_constructible_v<_Types> && + is_copy_assignable_v<_Types>)...>, + __variant_impl, + __nat>& __that) { + static_assert(!is_same_v, __nat>); + return __generic_assign(__that); + } + + __variant_impl& operator=( + conditional_t<__all_v<(is_move_constructible_v<_Types> && + is_move_assignable_v<_Types>)...>, + __variant_impl, + __nat>&& + __that) noexcept(__all_v<(is_nothrow_move_constructible_v<_Types> && + is_nothrow_move_assignable_v<_Types>)...>) { + static_assert(!is_same_v, __nat>); + return __generic_assign(_VSTD::move(__that)); + } + + template = 0, + class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, + enable_if_t<(is_assignable_v<_Tp&, _Arg&&> && + is_constructible_v<_Tp, _Arg&&>), + int> = 0> + void __assign(_Arg&& __arg) noexcept( + (is_nothrow_assignable_v<_Tp&, _Arg&&> && + is_nothrow_constructible_v<_Tp, _Arg&&>)) { + __assign_alt(__variant_impl_access::__get_alt<_Ip>(*this), + _VSTD::forward<_Arg>(__arg), + false_type{}); + } + + template = 0, + class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, + enable_if_t, int> = 0> + void emplace(_Args&&... __args) { + this->__destroy(); + __construct_alt(__variant_impl_access::__get_alt<_Ip>(*this), + in_place, + _VSTD::forward<_Args>(__args)...); + this->__index = _Ip; + } + + template < + bool __dummy = false, + enable_if_t< + __all_v<( + __dependent_type, __dummy>::value && + __dependent_type, __dummy>::value)...>, + int> = 0> + void swap(__variant_impl& __that) noexcept( + __all_v<(is_nothrow_move_constructible_v<_Types> && + is_nothrow_swappable_v<_Types>)...>) { + if (this->valueless_by_exception() && __that.valueless_by_exception()) { + // do nothing. + } else if (this->index() == __that.index()) { + __variant_impl_visitation::__visit_alt_at( + this->index(), + [](auto& __this_alt, auto& __that_alt) { + using _VSTD::swap; + swap(__this_alt.__get_value(), __that_alt.__get_value()); + }, + *this, + __that); + } else { + __variant_impl* __lhs = this; + __variant_impl* __rhs = _VSTD::addressof(__that); + if (__lhs->__is_nothrow_move_constructible() && + !__rhs->__is_nothrow_move_constructible()) { + _VSTD::swap(__lhs, __rhs); + } + __variant_impl __tmp(_VSTD::move(*__rhs)); +#ifndef _LIBCPP_NO_EXCEPTIONS + // EXTENSION: When the move construction of `__lhs` into `__rhs` throws + // and `__tmp` is nothrow move constructible then we move `__tmp` back + // into `__rhs` and provide the strong exception safety guarentee. + try { + __generic_construct(*__rhs, _VSTD::move(*__lhs)); + } catch (...) { + if (__tmp.__is_nothrow_move_constructible()) { + __generic_construct(*__rhs, _VSTD::move(__tmp)); + } + throw; + } +#else + __generic_construct(*__rhs, _VSTD::move(*__lhs)); +#endif + __generic_construct(*__lhs, _VSTD::move(__tmp)); + } + } + +private: + bool __is_nothrow_move_constructible() const { + constexpr bool __results[] = {is_nothrow_move_constructible_v<_Types>...}; + return this->valueless_by_exception() || __results[this->index()]; + } + + template + void __assign_alt(__variant_alt<_Ip, _Tp>& __alt, + _Arg&& __arg, + bool_constant<__copy_assign> __tag) { + if (this->index() == _Ip) { + __alt.__get_value() = _VSTD::forward<_Arg>(__arg); + } else { + struct { + void operator()(true_type) const { + __this->emplace<_Ip>(_Tp(static_cast<_Arg&&>(__arg))); + } + void operator()(false_type) const { + __this->emplace<_Ip>(static_cast<_Arg&&>(__arg)); + } + __variant_impl* __this; + _Arg&& __arg; + } __impl{this, _VSTD::forward<_Arg>(__arg)}; + __impl(__tag); + } + } + + template + __variant_impl& __generic_assign(_That&& __that) { + static_assert(is_same_v, __variant_impl>); + if (this->valueless_by_exception() && __that.valueless_by_exception()) { + // do nothing. + } else if (__that.valueless_by_exception()) { + this->__destroy(); + } else { + __variant_impl_visitation::__visit_alt_at( + __that.index(), + [this](auto& __this_alt, auto&& __that_alt) { + __assign_alt( + __this_alt, + _VSTD::forward(__that_alt).__get_value(), + is_lvalue_reference<_That&&>{}); + }, + *this, + _VSTD::forward<_That>(__that)); + } + return *this; + } + + template + static void __construct_alt(__variant_alt<_Ip, _Tp>& __alt, + in_place_t, + _Args&&... __args) { + ::new (_VSTD::addressof(__alt)) + __variant_alt<_Ip, _Tp>(in_place, _VSTD::forward<_Args>(__args)...); + } + + template + static void __construct_alt(__variant_alt<_Ip, _Tp>& __alt, + allocator_arg_t, + const _Alloc& __alloc, + _Args&&... __args) { + ::new (_VSTD::addressof(__alt)) + __variant_alt<_Ip, _Tp>(allocator_arg, + __alloc, + __uses_alloc_ctor<_Tp, _Alloc, _Args&&...>{}, + _VSTD::forward<_Args>(__args)...); + } + + template + static void __generic_construct(__variant_impl& __lhs, _Rhs&& __rhs) { + static_assert(is_same_v, __variant_impl>); + __lhs.__destroy(); + if (!__rhs.valueless_by_exception()) { + __variant_impl_visitation::__visit_alt_at( + __rhs.index(), + [](auto& __lhs_alt, auto&& __rhs_alt) { + __construct_alt( + __lhs_alt, + in_place, + _VSTD::forward(__rhs_alt).__get_value()); + }, + __lhs, + _VSTD::forward<_Rhs>(__rhs)); + __lhs.__index = __rhs.index(); + } + } + + template + static void __generic_construct(__variant_impl& __lhs, + allocator_arg_t, + const _Alloc& __alloc, + _Rhs&& __rhs) { + static_assert(is_same_v, __variant_impl>); + __lhs.__destroy(); + if (!__rhs.valueless_by_exception()) { + __variant_impl_visitation::__visit_alt_at( + __rhs.index(), + [&__alloc](auto& __lhs_alt, auto&& __rhs_alt) { + __construct_alt( + __lhs_alt, + allocator_arg, + __alloc, + _VSTD::forward(__rhs_alt).__get_value()); + }, + __lhs, + _VSTD::forward<_Rhs>(__rhs)); + __lhs.__index = __rhs.index(); + } + } +}; + +template <> +class variant<> { + variant() = delete; + variant(const variant&) = delete; + variant(variant&&) = delete; + variant& operator=(const variant&) = delete; + variant& operator=(variant&&) = delete; +}; + +template +class variant { + template + using __transform = conditional_t, __variant_void, _Tp>; + + template + using __variant_best_match = + __variant_best_match<_Arg, __transform<_Types>...>; + + template + using __find_unambiguous_index_sfinae = + __find_unambiguous_index_sfinae<_Tp, __transform<_Types>...>; + + using __impl_type = __variant_impl<__transform<_Types>...>; + + __impl_type __impl; + +public: + template < + class _Impl = __impl_type, + enable_if_t>, int> = 0> + constexpr variant() _LIBCPP_NOEXCEPT_INIT(__impl, in_place<0>) {} + + variant(const variant&) = default; + variant(variant&&) = default; + + template , variant>, int> = 0, + class _Tp = __variant_best_match<_Arg&&>, + size_t _Ip = __find_unambiguous_index_sfinae<_Tp>::value, + enable_if_t< + is_constructible_v<__impl_type, in_place_index_t<_Ip>, _Arg&&>, + int> = 0> + constexpr variant(_Arg&& __arg) + _LIBCPP_NOEXCEPT_INIT(__impl, + in_place<_Ip>, + _VSTD::forward<_Arg>(__arg)) {} + + template < + size_t _Ip, + class... _Args, + enable_if_t< + is_constructible_v<__impl_type, in_place_index_t<_Ip>, _Args&&...>, + int> = 0> + explicit constexpr variant(in_place_index_t<_Ip>, _Args&&... __args) + _LIBCPP_NOEXCEPT_INIT(__impl, + in_place<_Ip>, + _VSTD::forward<_Args>(__args)...) {} + + template , + initializer_list<_Up>&, + _Args&&...>, + int> = 0> + explicit constexpr variant(in_place_index_t<_Ip>, + initializer_list<_Up> __il, + _Args&&... __args) + _LIBCPP_NOEXCEPT_INIT(__impl, + in_place<_Ip>, + __il, + _VSTD::forward<_Args>(__args)...) {} + + template < + class _Tp, + class... _Args, + size_t _Ip = __find_unambiguous_index_sfinae<_Tp>::value, + enable_if_t< + is_constructible_v<__impl_type, in_place_index_t<_Ip>, _Args&&...>, + int> = 0> + explicit constexpr variant(in_place_type_t<_Tp>, _Args&&... __args) + _LIBCPP_NOEXCEPT_INIT(__impl, + in_place<_Ip>, + _VSTD::forward<_Args>(__args)...) {} + + template ::value, + enable_if_t, + initializer_list<_Up>&, + _Args&&...>, + int> = 0> + explicit constexpr variant(in_place_type_t<_Tp>, + initializer_list<_Up> __il, + _Args&&... __args) + _LIBCPP_NOEXCEPT_INIT(__impl, + in_place<_Ip>, + __il, + _VSTD::forward<_Args>(__args)...) {} + + template >, + int> = 0> + variant(allocator_arg_t, const _Alloc& __alloc) + _LIBCPP_NOEXCEPT_INIT(__impl, allocator_arg, __alloc, in_place<0>) {} + + template , + int> = 0> + variant(allocator_arg_t, const _Alloc& __alloc, const variant& __that) + _LIBCPP_NOEXCEPT_INIT(__impl, allocator_arg, __alloc, __that.__impl) {} + + template , + int> = 0> + variant(allocator_arg_t, const _Alloc& __alloc, variant&& __that) + _LIBCPP_NOEXCEPT_INIT(__impl, + allocator_arg, + __alloc, + _VSTD::move(__that).__impl) {} + + template , variant>, int> = 0, + class _Tp = __variant_best_match<_Arg&&>, + size_t _Ip = __find_unambiguous_index_sfinae<_Tp>::value, + enable_if_t, + _Arg&&>, + int> = 0> + variant(allocator_arg_t, const _Alloc& __alloc, _Arg&& __arg) + _LIBCPP_NOEXCEPT_INIT(__impl, + allocator_arg, + __alloc, + in_place<_Ip>, + _VSTD::forward<_Arg>(__arg)) {} + + template , + _Args&&...>, + int> = 0> + variant(allocator_arg_t, + const _Alloc& __alloc, + in_place_index_t<_Ip>, + _Args&&... __args) + _LIBCPP_NOEXCEPT_INIT(__impl, + allocator_arg, + __alloc, + in_place<_Ip>, + _VSTD::forward<_Args>(__args)...) {} + + template , + initializer_list<_Up>&, + _Args&&...>, + int> = 0> + variant(allocator_arg_t, + const _Alloc& __alloc, + in_place_index_t<_Ip>, + initializer_list<_Up> __il, + _Args&&... __args) + _LIBCPP_NOEXCEPT_INIT(__impl, + allocator_arg, + __alloc, + in_place<_Ip>, + __il, + _VSTD::forward<_Args>(__args)...) {} + + template ::value, + enable_if_t, + _Args&&...>, + int> = 0> + variant(allocator_arg_t, + const _Alloc& __alloc, + in_place_type_t<_Tp>, + _Args&&... __args) + _LIBCPP_NOEXCEPT_INIT(__impl, + allocator_arg, + __alloc, + in_place<_Ip>, + _VSTD::forward<_Args>(__args)...) {} + + template ::value, + enable_if_t, + initializer_list<_Up>&, + _Args&&...>, + int> = 0> + variant(allocator_arg_t, + const _Alloc& __alloc, + in_place_type_t<_Tp>, + initializer_list<_Up> __il, + _Args&&... __args) + _LIBCPP_NOEXCEPT_INIT(__impl, + allocator_arg, + __alloc, + in_place<_Ip>, + __il, + _VSTD::forward<_Args>(__args)...) {} + + ~variant() = default; + + variant& operator=(const variant&) = default; + variant& operator=(variant&&) = default; + + template , variant>, int> = 0, + class _Tp = __variant_best_match<_Arg&&>, + size_t _Ip = __find_unambiguous_index_sfinae<_Tp>::value> + auto operator=(_Arg&& __arg) + _LIBCPP_NOEXCEPT_SFINAE_RETURN( + __impl.template __assign<_Ip>(_VSTD::forward<_Arg>(__arg))) + + template + auto emplace(_Args&&... __args) + _LIBCPP_NOEXCEPT_SFINAE_RETURN( + __impl.template emplace<_Ip>(_VSTD::forward<_Args>(__args)...)) + + template + auto emplace(initializer_list<_Up> __il, _Args&&... __args) + _LIBCPP_NOEXCEPT_SFINAE_RETURN( + __impl.template emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...)) + + template ::value> + auto emplace(_Args&&... __args) + _LIBCPP_NOEXCEPT_SFINAE_RETURN( + __impl.template emplace<_Ip>(_VSTD::forward<_Args>(__args)...)) + + template ::value> + auto emplace(initializer_list<_Up> __il, _Args&&... __args) + _LIBCPP_NOEXCEPT_SFINAE_RETURN( + __impl.template emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...)) + + constexpr bool valueless_by_exception() const noexcept { + return __impl.valueless_by_exception(); + } + + constexpr size_t index() const noexcept { return __impl.index(); } + + template + auto swap(_Vp& __that) + _LIBCPP_NOEXCEPT_SFINAE_RETURN(__impl.swap(__that.__impl)) + +private: + friend struct __variant_access; + friend struct __variant_visitation; +}; + +template +constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept { + return __v.index() == _Ip; +} + +template +constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept { + return __holds_alternative<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +static constexpr auto&& __generic_get(_Vp&& __v) { + return __holds_alternative<_Ip>(__v) + ? __variant_access::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v)) + .__get_value() + : throw bad_variant_access{}; +} + +template +constexpr variant_alternative_t<_Ip, variant<_Types...>>& get( + variant<_Types...>& __v) { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get<_Ip>(__v); +} + +template +constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get( + variant<_Types...>&& __v) { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get<_Ip>(_VSTD::move(__v)); +} + +template +constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get( + const variant<_Types...>& __v) { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get<_Ip>(__v); +} + +template +constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get( + const variant<_Types...>&& __v) { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get<_Ip>(_VSTD::move(__v)); +} + +template +constexpr _Tp& get(variant<_Types...>& __v) { + static_assert(!is_void_v<_Tp>); + return _VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +constexpr _Tp&& get(variant<_Types...>&& __v) { + static_assert(!is_void_v<_Tp>); + return _VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>( + _VSTD::move(__v)); +} + +template +constexpr const _Tp& get(const variant<_Types...>& __v) { + static_assert(!is_void_v<_Tp>); + return _VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +constexpr const _Tp&& get(const variant<_Types...>&& __v) { + static_assert(!is_void_v<_Tp>); + return _VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>( + _VSTD::move(__v)); +} + +template +constexpr auto* __generic_get_if(_Vp* __v) noexcept { + return __v && __holds_alternative<_Ip>(*__v) + ? _VSTD::addressof( + __variant_access::__get_alt<_Ip>(*__v).__get_value()) + : nullptr; +} + +template +constexpr add_pointer_t>> +get_if(variant<_Types...>* __v) noexcept { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get_if<_Ip>(__v); +} + +template +constexpr add_pointer_t>> +get_if(const variant<_Types...>* __v) noexcept { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get_if<_Ip>(__v); +} + +template +constexpr add_pointer_t<_Tp> +get_if(variant<_Types...>* __v) noexcept { + static_assert(!is_void_v<_Tp>); + return _VSTD::get_if<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +constexpr add_pointer_t +get_if(const variant<_Types...>* __v) noexcept { + static_assert(!is_void_v<_Tp>); + return _VSTD::get_if<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +constexpr bool operator==(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__lhs.index() != __rhs.index()) return false; + if (__lhs.valueless_by_exception()) return true; + return __variant_visitation::__visit_value_at( + __lhs.index(), equal_to<>{}, __lhs, __rhs); +} + +template +constexpr bool operator!=(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__lhs.index() != __rhs.index()) return true; + if (__lhs.valueless_by_exception()) return false; + return __variant_visitation::__visit_value_at( + __lhs.index(), not_equal_to<>{}, __lhs, __rhs); +} + +template +constexpr bool operator<(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__rhs.valueless_by_exception()) return false; + if (__lhs.valueless_by_exception()) return true; + if (__lhs.index() < __rhs.index()) return true; + if (__lhs.index() > __rhs.index()) return false; + return __variant_visitation::__visit_value_at( + __lhs.index(), less<>{}, __lhs, __rhs); +} + +template +constexpr bool operator>(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__lhs.valueless_by_exception()) return false; + if (__rhs.valueless_by_exception()) return true; + if (__lhs.index() > __rhs.index()) return true; + if (__lhs.index() < __rhs.index()) return false; + return __variant_visitation::__visit_value_at( + __lhs.index(), greater<>{}, __lhs, __rhs); +} + +template +constexpr bool operator<=(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__lhs.valueless_by_exception()) return true; + if (__rhs.valueless_by_exception()) return false; + if (__lhs.index() < __rhs.index()) return true; + if (__lhs.index() > __rhs.index()) return false; + return __variant_visitation::__visit_value_at( + __lhs.index(), less_equal<>{}, __lhs, __rhs); +} + +template +constexpr bool operator>=(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__rhs.valueless_by_exception()) return true; + if (__lhs.valueless_by_exception()) return false; + if (__lhs.index() > __rhs.index()) return true; + if (__lhs.index() < __rhs.index()) return false; + return __variant_visitation::__visit_value_at( + __lhs.index(), greater_equal<>{}, __lhs, __rhs); +} + +template +constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { + bool __results[] = {__vs.valueless_by_exception()...}; + for (bool __result : __results) { + if (__result) { + throw bad_variant_access{}; + } + } + return __variant_visitation::__visit_value( + _VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); +} + +struct _LIBCPP_TYPE_VIS_ONLY monostate {}; + +constexpr bool operator<(monostate, monostate) noexcept { return false; } +constexpr bool operator>(monostate, monostate) noexcept { return false; } +constexpr bool operator<=(monostate, monostate) noexcept { return true; } +constexpr bool operator>=(monostate, monostate) noexcept { return true; } +constexpr bool operator==(monostate, monostate) noexcept { return true; } +constexpr bool operator!=(monostate, monostate) noexcept { return false; } + +template +auto swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) + _LIBCPP_NOEXCEPT_SFINAE_RETURN(__lhs.swap(__rhs)) + +template <> +struct _LIBCPP_TYPE_VIS_ONLY hash> { + hash() = delete; + hash(const hash&) = delete; + hash(hash&&) = delete; + hash& operator=(const hash&) = delete; + hash& operator=(hash&&) = delete; +}; + +template +struct _LIBCPP_TYPE_VIS_ONLY hash> { + using argument_type = variant<_Types...>; + using result_type = size_t; + + result_type operator()(const argument_type& __v) const { + return __v.valueless_by_exception() + ? variant_npos + : __variant_visitation::__visit_alt( + [](const auto& __alt) { + using __alt_type = decay_t; + using __value_type = typename __alt_type::__value_type; + return hash<__value_type>{}(__alt.__get_value()); + }, + __v); + } +}; + +template <> +struct _LIBCPP_TYPE_VIS_ONLY hash { + using argument_type = monostate; + using result_type = size_t; + + result_type operator()(const argument_type&) const { return 0; } +}; + +template +struct _LIBCPP_TYPE_VIS_ONLY uses_allocator, _Alloc> + : true_type {}; + +#endif // _LIBCPP_STD_VER > 14 + +_LIBCPP_END_NAMESPACE_STD + +#undef _LIBCPP_NOEXCEPT_INIT +#undef _LIBCPP_NOEXCEPT_SFINAE_RETURN + +#endif // _LIBCPP_VARIANT Index: lib/CMakeLists.txt =================================================================== --- lib/CMakeLists.txt +++ lib/CMakeLists.txt @@ -28,16 +28,6 @@ set(exclude_from_all EXCLUDE_FROM_ALL) endif() -if (LIBCXX_ENABLE_SHARED) - add_library(cxx SHARED ${exclude_from_all} ${LIBCXX_SOURCES} ${LIBCXX_HEADERS}) -else() - add_library(cxx STATIC ${exclude_from_all} ${LIBCXX_SOURCES} ${LIBCXX_HEADERS}) -endif() - -if (DEFINED LIBCXX_CXX_ABI_DEPS) - add_dependencies(cxx LIBCXX_CXX_ABI_DEPS) -endif() - #if LIBCXX_CXX_ABI_LIBRARY_PATH is defined we want to add it to the search path. add_link_flags_if(LIBCXX_CXX_ABI_LIBRARY_PATH "-L${LIBCXX_CXX_ABI_LIBRARY_PATH}") @@ -139,18 +129,51 @@ endif() endif() -target_link_libraries(cxx ${LIBCXX_LIBRARIES}) split_list(LIBCXX_COMPILE_FLAGS) split_list(LIBCXX_LINK_FLAGS) -set_target_properties(cxx +# Add a object library that contains the compiled source files. +add_library(cxx_objects OBJECT ${exclude_from_all} ${LIBCXX_SOURCES} ${LIBCXX_HEADERS}) + +set_target_properties(cxx_objects PROPERTIES COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}" - LINK_FLAGS "${LIBCXX_LINK_FLAGS}" - OUTPUT_NAME "c++" - VERSION "${LIBCXX_ABI_VERSION}.0" - SOVERSION "${LIBCXX_ABI_VERSION}" +) + +set(LIBCXX_TARGETS) + +# Build the shared library. +if (LIBCXX_ENABLE_SHARED) + add_library(cxx_shared SHARED $) + target_link_libraries(cxx_shared ${LIBCXX_LIBRARIES}) + set_target_properties(cxx_shared + PROPERTIES + LINK_FLAGS "${LIBCXX_LINK_FLAGS}" + OUTPUT_NAME "c++" + VERSION "${LIBCXX_ABI_VERSION}.0" + SOVERSION "${LIBCXX_ABI_VERSION}" ) + list(APPEND LIBCXX_TARGETS "cxx_shared") +endif() + +# Build the static library. +if (LIBCXX_ENABLE_STATIC) + add_library(cxx_static STATIC $) + target_link_libraries(cxx_static ${LIBCXX_LIBRARIES}) + set_target_properties(cxx_static + PROPERTIES + LINK_FLAGS "${LIBCXX_LINK_FLAGS}" + OUTPUT_NAME "c++" + ) + list(APPEND LIBCXX_TARGETS "cxx_static") +endif() + +# Add a meta-target for both libraries. +add_custom_target(cxx DEPENDS ${LIBCXX_TARGETS}) + +if (DEFINED LIBCXX_CXX_ABI_DEPS) + add_dependencies(cxx LIBCXX_CXX_ABI_DEPS) +endif() if (LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY) file(GLOB LIBCXX_EXPERIMENTAL_SOURCES ../src/experimental/*.cpp) @@ -158,7 +181,11 @@ file(GLOB LIBCXX_FILESYSTEM_SOURCES ../src/experimental/filesystem/*.cpp) endif() add_library(cxx_experimental STATIC ${LIBCXX_EXPERIMENTAL_SOURCES} ${LIBCXX_FILESYSTEM_SOURCES}) - target_link_libraries(cxx_experimental cxx) + if (LIBCXX_ENABLE_SHARED) + target_link_libraries(cxx_experimental cxx_shared) + else() + target_link_libraries(cxx_experimental cxx_static) + endif() set(experimental_flags "${LIBCXX_COMPILE_FLAGS}") check_flag_supported(-std=c++14) @@ -174,7 +201,7 @@ # Generate a linker script inplace of a libc++.so symlink. Rerun this command # after cxx builds. -if (LIBCXX_ENABLE_ABI_LINKER_SCRIPT) +if (LIBCXX_ENABLE_SHARED AND LIBCXX_ENABLE_ABI_LINKER_SCRIPT) # Get the name of the ABI library and handle the case where CXXABI_LIBNAME # is a target name and not a library. Ex cxxabi_shared. set(SCRIPT_ABI_LIBNAME "${LIBCXX_CXX_ABI_LIBRARY}") @@ -183,11 +210,11 @@ endif() # Generate a linker script inplace of a libc++.so symlink. Rerun this command # after cxx builds. - add_custom_command(TARGET cxx POST_BUILD + add_custom_command(TARGET cxx_shared POST_BUILD COMMAND ${PYTHON_EXECUTABLE} ${LIBCXX_SOURCE_DIR}/utils/gen_link_script/gen_link_script.py ARGS - "$" + "$" "${SCRIPT_ABI_LIBNAME}" WORKING_DIRECTORY ${LIBCXX_BUILD_DIR} ) @@ -197,13 +224,13 @@ if (LIBCXX_INSTALL_EXPERIMENTAL_LIBRARY) set(experimental_lib cxx_experimental) endif() - install(TARGETS cxx ${experimental_lib} + install(TARGETS ${LIBCXX_TARGETS} ${experimental_lib} LIBRARY DESTINATION lib${LIBCXX_LIBDIR_SUFFIX} COMPONENT libcxx ARCHIVE DESTINATION lib${LIBCXX_LIBDIR_SUFFIX} COMPONENT libcxx ) # NOTE: This install command must go after the cxx install command otherwise # it will not be executed after the library symlinks are installed. - if (LIBCXX_ENABLE_ABI_LINKER_SCRIPT) + if (LIBCXX_ENABLE_SHARED AND LIBCXX_ENABLE_ABI_LINKER_SCRIPT) # Replace the libc++ filename with $ # after we required CMake 3.0. install(FILES "${LIBCXX_LIBRARY_DIR}/libc++${CMAKE_SHARED_LIBRARY_SUFFIX}" Index: src/variant.cpp =================================================================== --- /dev/null +++ src/variant.cpp @@ -0,0 +1,20 @@ +//===------------------------ 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" + +_LIBCPP_BEGIN_NAMESPACE_STD + +bad_variant_access::~bad_variant_access() = default; + +const char* bad_variant_access::what() const noexcept { + return "bad_variant_access"; +} + +_LIBCPP_END_NAMESPACE_STD Index: test/std/experimental/filesystem/fs.op.funcs/fs.op.hard_lk_ct/hard_link_count.pass.cpp =================================================================== --- test/std/experimental/filesystem/fs.op.funcs/fs.op.hard_lk_ct/hard_link_count.pass.cpp +++ test/std/experimental/filesystem/fs.op.funcs/fs.op.hard_lk_ct/hard_link_count.pass.cpp @@ -45,18 +45,27 @@ TEST_CASE(hard_link_count_for_directory) { - uintmax_t DirExpect = 3; - uintmax_t Dir3Expect = 2; + uintmax_t DirExpect = 3; // hard link from . .. and Dir2 + uintmax_t Dir3Expect = 2; // hard link from . .. + uintmax_t DirExpectAlt = DirExpect; + uintmax_t Dir3ExpectAlt = Dir3Expect; #if defined(__APPLE__) - DirExpect += 2; - Dir3Expect += 1; + // Filesystems formatted with case sensitive hfs+ behave unixish as + // expected. Normal hfs+ filesystems report the number of directory + // entries instead. + DirExpectAlt = 5; // . .. Dir2 file1 file2 + Dir3Expect = 3; // . .. file5 #endif - TEST_CHECK(hard_link_count(StaticEnv::Dir) == DirExpect); - TEST_CHECK(hard_link_count(StaticEnv::Dir3) == Dir3Expect); + TEST_CHECK(hard_link_count(StaticEnv::Dir) == DirExpect || + hard_link_count(StaticEnv::Dir) == DirExpectAlt); + TEST_CHECK(hard_link_count(StaticEnv::Dir3) == Dir3Expect || + hard_link_count(StaticEnv::Dir3) == Dir3ExpectAlt); std::error_code ec; - TEST_CHECK(hard_link_count(StaticEnv::Dir, ec) == DirExpect); - TEST_CHECK(hard_link_count(StaticEnv::Dir3, ec) == Dir3Expect); + TEST_CHECK(hard_link_count(StaticEnv::Dir, ec) == DirExpect || + hard_link_count(StaticEnv::Dir, ec) == DirExpectAlt); + TEST_CHECK(hard_link_count(StaticEnv::Dir3, ec) == Dir3Expect || + hard_link_count(StaticEnv::Dir3, ec) == Dir3ExpectAlt); } TEST_CASE(hard_link_count_increments_test) { Index: test/std/variant/variant.hash/hash.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.hash/hash.pass.cpp @@ -0,0 +1,94 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template struct hash>; +// template <> struct hash; + +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +#ifndef TEST_HAS_NO_EXCEPTIONS +namespace std { + template <> + struct hash<::MakeEmptyT> { + size_t operator()(::MakeEmptyT const&) const { assert(false); return 0; } + }; +} +#endif + +void test_hash_variant() +{ + { + using V = std::variant; + using H = std::hash; + const V v(42); + V v2(100); + const H h{}; + assert(h(v) == std::hash{}(42)); + assert(h(v2) == std::hash{}(100)); + { + ASSERT_SAME_TYPE(decltype(h(v)), std::size_t); + static_assert(std::is_copy_constructible::value, ""); + } + } + { + using V = std::variant; + using H = std::hash; + const char* str = "hello"; + const V v0; + const V v1(42); + V v2(100l); + V v3(str); + const H h{}; + assert(h(v0) == std::hash{}(std::monostate{})); + assert(h(v1) == std::hash{}(42)); + assert(h(v2) == std::hash{}(100)); + assert(h(v3) == std::hash{}(str)); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + using H = std::hash; + V v; makeEmpty(v); + V v2; makeEmpty(v2); + const H h{}; + assert(h(v) == h(v2)); + } +#endif +} + +void test_hash_monostate() +{ + using H = std::hash; + const H h{}; + std::monostate m1{}; + const std::monostate m2{}; + assert(h(m1) == h(m1)); + assert(h(m2) == h(m2)); + assert(h(m1) == h(m2)); + { + ASSERT_SAME_TYPE(decltype(h(m1)), std::size_t); + static_assert(std::is_copy_constructible::value, ""); + } +} + +int main() +{ + test_hash_variant(); + test_hash_monostate(); +} Index: test/std/variant/variant.helpers/variant_alternative.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.helpers/variant_alternative.pass.cpp @@ -0,0 +1,57 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template struct variant_alternative; // undefined +// template struct variant_alternative; +// template struct variant_alternative; +// template struct variant_alternative; +// template +// using variant_alternative_t = typename variant_alternative::type; +// +// template +// struct variant_alternative>; + +#include +#include + +template +void test() { + static_assert(std::is_same_v< + typename std::variant_alternative::type, E>, ""); + static_assert(std::is_same_v< + typename std::variant_alternative::type, const E>, ""); + static_assert(std::is_same_v< + typename std::variant_alternative::type, volatile E>, ""); + static_assert(std::is_same_v< + typename std::variant_alternative::type, const volatile E>, ""); + static_assert(std::is_same_v< + std::variant_alternative_t, E>, ""); + static_assert(std::is_same_v< + std::variant_alternative_t, const E>, ""); + static_assert(std::is_same_v< + std::variant_alternative_t, volatile E>, ""); + static_assert(std::is_same_v< + std::variant_alternative_t, const volatile E>, ""); +} + +int main() +{ + test, 0, void>(); + using V = std::variant; + test(); + test(); + test(); + test(); + test(); +} Index: test/std/variant/variant.helpers/variant_size.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.helpers/variant_size.pass.cpp @@ -0,0 +1,44 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template struct variant_size; // undefined +// template struct variant_size; +// template struct variant_size; +// template struct variant_size; +// template constexpr size_t variant_size_v +// = variant_size::value; + +#include +#include + +template +void test() { + static_assert(std::variant_size::value == E, ""); + static_assert(std::variant_size::value == E, ""); + static_assert(std::variant_size::value == E, ""); + static_assert(std::variant_size::value == E, ""); + static_assert(std::variant_size_v == E, ""); + static_assert(std::variant_size_v == E, ""); + static_assert(std::variant_size_v == E, ""); + static_assert(std::variant_size_v == E, ""); + static_assert(std::is_base_of, + std::variant_size>::value, ""); +}; + +int main() +{ + test, 0>(); + test, 1>(); + test, 4>(); +} Index: test/std/variant/variant.bad_variant_access/bad_variant_access.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.bad_variant_access/bad_variant_access.pass.cpp @@ -0,0 +1,38 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +/* + + class bad_variant_access : public exception { +public: + bad_variant_access() noexcept; + virtual const char* what() const noexcept; +}; + +*/ + +#include +#include +#include +#include + +int main() +{ + static_assert(std::is_base_of::value, ""); + static_assert(noexcept(std::bad_variant_access{}), "must be noexcept"); + static_assert(noexcept(std::bad_variant_access{}.what()), "must be noexcept"); + std::bad_variant_access ex; + assert(ex.what()); + +} Index: test/std/variant/variant.general/nothing_to_do.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.general/nothing_to_do.pass.cpp @@ -0,0 +1,13 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +int main() +{ +} Index: test/std/variant/variant.get/get_if_index.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.get/get_if_index.pass.cpp @@ -0,0 +1,126 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template +// constexpr add_pointer_t>> +// get_if(variant* v) noexcept; +// template +// constexpr add_pointer_t>> +// get_if(const variant* v) noexcept; + +#include +#include +#include "test_macros.h" + +void test_const_get_if() { + { + using V = std::variant; + constexpr const V* v = nullptr; + static_assert(std::get_if<0>(v) == nullptr, ""); + } + { + using V = std::variant; + constexpr V v(42); + ASSERT_NOEXCEPT(std::get_if<0>(&v)); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), int const*); + static_assert(*std::get_if<0>(&v) == 42, ""); + static_assert(std::get_if<1>(&v) == nullptr, ""); + } + { + using V = std::variant; + constexpr V v(42l); + ASSERT_SAME_TYPE(decltype(std::get_if<1>(&v)), long const*); + static_assert(*std::get_if<1>(&v) == 42, ""); + static_assert(std::get_if<0>(&v) == nullptr, ""); + } + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), const int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } +} + +void test_get_if() +{ + { + using V = std::variant; + V* v = nullptr; + assert(std::get_if<0>(v) == nullptr); + } + { + using V = std::variant; + V v(42); + ASSERT_NOEXCEPT(std::get_if<0>(std::addressof(v))); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), int*); + assert(*std::get_if<0>(std::addressof(v)) == 42); + assert(std::get_if<1>(std::addressof(v)) == nullptr); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get_if<1>(std::addressof(v))), long*); + assert(*std::get_if<1>(std::addressof(v)) == 42); + assert(std::get_if<0>(std::addressof(v)) == nullptr); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), const int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), const int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } +} + +int main() +{ + test_const_get_if(); + test_get_if(); +} Index: test/std/variant/variant.get/get_if_type.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.get/get_if_type.pass.cpp @@ -0,0 +1,124 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template +// constexpr add_pointer_t get_if(variant* v) noexcept; +// template +// constexpr add_pointer_t get_if(const variant* v) noexcept; + +#include +#include +#include "test_macros.h" + +void test_const_get_if() { + { + using V = std::variant; + constexpr const V* v = nullptr; + static_assert(std::get_if(v) == nullptr, ""); + } + { + using V = std::variant; + constexpr V v(42); + ASSERT_NOEXCEPT(std::get_if(&v)); + ASSERT_SAME_TYPE(decltype(std::get_if(&v)), int const*); + static_assert(*std::get_if(&v) == 42, ""); + static_assert(std::get_if(&v) == nullptr, ""); + } + { + using V = std::variant; + constexpr V v(42l); + ASSERT_SAME_TYPE(decltype(std::get_if(&v)), long const*); + static_assert(*std::get_if(&v) == 42, ""); + static_assert(std::get_if(&v) == nullptr, ""); + } + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), int*); + assert(std::get_if(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), int*); + assert(std::get_if(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), const int*); + assert(std::get_if(std::addressof(v)) == &x); + } +} + +void test_get_if() +{ + { + using V = std::variant; + V* v = nullptr; + assert(std::get_if(v) == nullptr); + } + { + using V = std::variant; + V v(42); + ASSERT_NOEXCEPT(std::get_if(std::addressof(v))); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), int*); + assert(*std::get_if(std::addressof(v)) == 42); + assert(std::get_if(std::addressof(v)) == nullptr); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), long*); + assert(*std::get_if(std::addressof(v)) == 42); + assert(std::get_if(std::addressof(v)) == nullptr); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), int*); + assert(std::get_if(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), const int*); + assert(std::get_if(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), int*); + assert(std::get_if(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), const int*); + assert(std::get_if(std::addressof(v)) == &x); + } +} + +int main() +{ + test_const_get_if(); + test_get_if(); +} Index: test/std/variant/variant.get/get_index.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.get/get_index.pass.cpp @@ -0,0 +1,256 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template +// constexpr variant_alternative_t>& get(variant& v); +// template +// constexpr variant_alternative_t>&& get(variant&& v); +// template +// constexpr variant_alternative_t> const& get(const variant& v); +// template +// constexpr variant_alternative_t> const&& get(const variant&& v); + +#include +#include +#include "test_macros.h" + +void test_const_lvalue_get() { + { + using V = std::variant; + constexpr V v(42); + //ASSERT_NOT_NOEXCEPT(std::get<0>(v)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int const&); + static_assert(std::get<0>(v) == 42, ""); + } + { + using V = std::variant; + constexpr V v(42l); + ASSERT_SAME_TYPE(decltype(std::get<1>(v)), long const&); + static_assert(std::get<1>(v) == 42, ""); + } + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int&); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int&); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int&); + assert(&std::get<0>(v) == &x); + } +} + +void test_lvalue_get() +{ + { + using V = std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(std::get<0>(v)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int&); + assert(std::get<0>(v) == 42); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get<1>(v)), long&); + assert(std::get<1>(v) == 42); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int&); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int&); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int&); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int&); + assert(&std::get<0>(v) == &x); + } +} + + +void test_rvalue_get() +{ + { + using V = std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(std::get<0>(std::move(v))); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int&&); + assert(std::get<0>(std::move(v)) == 42); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get<1>(std::move(v))), long&&); + assert(std::get<1>(std::move(v)) == 42); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int&); + assert(&std::get<0>(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int&); + assert(&std::get<0>(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int&&); + int&& xref = std::get<0>(std::move(v)); + assert(&xref == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int&&); + const int&& xref = std::get<0>(std::move(v)); + assert(&xref == &x); + } +} + + +void test_const_rvalue_get() +{ + { + using V = std::variant; + const V v(42); + ASSERT_NOT_NOEXCEPT(std::get<0>(std::move(v))); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int&&); + assert(std::get<0>(std::move(v)) == 42); + } + { + using V = std::variant; + const V v(42l); + ASSERT_SAME_TYPE(decltype(std::get<1>(std::move(v))), const long&&); + assert(std::get<1>(std::move(v)) == 42); + } + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int&); + assert(&std::get<0>(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int&); + assert(&std::get<0>(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int&&); + int&& xref = std::get<0>(std::move(v)); + assert(&xref == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int&&); + const int&& xref = std::get<0>(std::move(v)); + assert(&xref == &x); + } +} + +template +using Idx = std::integral_constant; + +void test_throws_for_all_value_categories() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + V v0(42); + const V& cv0 = v0; + assert(v0.index() == 0); + V v1(42l); + const V& cv1 = v1; + assert(v1.index() == 1); + std::integral_constant zero; + std::integral_constant one; + auto test = [](auto idx, auto&& v) { + using Idx = decltype(idx); + try { + std::get(std::forward(v)); + } catch (std::bad_variant_access const&) { + return true; + } catch (...) { /* ... */ } + return false; + }; + { // lvalue test cases + assert(test(one, v0)); + assert(test(zero, v1)); + } + { // const lvalue test cases + assert(test(one, cv0)); + assert(test(zero, cv1)); + } + { // rvalue test cases + assert(test(one, std::move(v0))); + assert(test(zero, std::move(v1))); + } + { // const rvalue test cases + assert(test(one, std::move(cv0))); + assert(test(zero, std::move(cv1))); + } +#endif +} + +int main() +{ + test_const_lvalue_get(); + test_lvalue_get(); + test_rvalue_get(); + test_const_rvalue_get(); + test_throws_for_all_value_categories(); +} Index: test/std/variant/variant.get/get_type.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.get/get_type.pass.cpp @@ -0,0 +1,251 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template constexpr T& get(variant& v); +// template constexpr T&& get(variant&& v); +// template constexpr const T& get(const variant& v); +// template constexpr const T&& get(const variant&& v); + +#include +#include +#include "test_macros.h" + +void test_const_lvalue_get() { + { + using V = std::variant; + constexpr V v(42); + //ASSERT_NOT_NOEXCEPT(std::get(v)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int const&); + static_assert(std::get(v) == 42, ""); + } + { + using V = std::variant; + constexpr V v(42l); + ASSERT_SAME_TYPE(decltype(std::get(v)), long const&); + static_assert(std::get(v) == 42, ""); + } + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get(v)), int&); + assert(&std::get(v) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(v)), int&); + assert(&std::get(v) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(v)), const int&); + assert(&std::get(v) == &x); + } +} + +void test_lvalue_get() +{ + { + using V = std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(std::get(v)); + ASSERT_SAME_TYPE(decltype(std::get(v)), int&); + assert(std::get(v) == 42); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get(v)), long&); + assert(std::get(v) == 42); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get(v)), int&); + assert(&std::get(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get(v)), const int&); + assert(&std::get(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(v)), int&); + assert(&std::get(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(v)), const int&); + assert(&std::get(v) == &x); + } +} + + +void test_rvalue_get() +{ + { + using V = std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(std::get(std::move(v))); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), int&&); + assert(std::get(std::move(v)) == 42); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), long&&); + assert(std::get(std::move(v)) == 42); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), int&); + assert(&std::get(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const int&); + assert(&std::get(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), int&&); + int&& xref = std::get(std::move(v)); + assert(&xref == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const int&&); + const int&& xref = std::get(std::move(v)); + assert(&xref == &x); + } +} + + +void test_const_rvalue_get() +{ + { + using V = std::variant; + const V v(42); + ASSERT_NOT_NOEXCEPT(std::get(std::move(v))); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const int&&); + assert(std::get(std::move(v)) == 42); + } + { + using V = std::variant; + const V v(42l); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const long&&); + assert(std::get(std::move(v)) == 42); + } + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), int&); + assert(&std::get(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const int&); + assert(&std::get(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), int&&); + int&& xref = std::get(std::move(v)); + assert(&xref == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const int&&); + const int&& xref = std::get(std::move(v)); + assert(&xref == &x); + } +} + +template struct identity { using type = Tp; }; + +void test_throws_for_all_value_categories() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + V v0(42); + const V& cv0 = v0; + assert(v0.index() == 0); + V v1(42l); + const V& cv1 = v1; + assert(v1.index() == 1); + identity zero; + identity one; + auto test = [](auto idx, auto&& v) { + using Idx = decltype(idx); + try { + std::get(std::forward(v)); + } catch (std::bad_variant_access const&) { + return true; + } catch (...) { /* ... */ } + return false; + }; + { // lvalue test cases + assert(test(one, v0)); + assert(test(zero, v1)); + } + { // const lvalue test cases + assert(test(one, cv0)); + assert(test(zero, cv1)); + } + { // rvalue test cases + assert(test(one, std::move(v0))); + assert(test(zero, std::move(v1))); + } + { // const rvalue test cases + assert(test(one, std::move(cv0))); + assert(test(zero, std::move(cv1))); + } +#endif +} + +int main() +{ + test_const_lvalue_get(); + test_lvalue_get(); + test_rvalue_get(); + test_const_rvalue_get(); + test_throws_for_all_value_categories(); +} Index: test/std/variant/variant.get/holds_alternative.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.get/holds_alternative.pass.cpp @@ -0,0 +1,38 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template +// constexpr bool holds_alternative(const variant& v) noexcept; + +#include + +int main() +{ + { + using V = std::variant; + constexpr V v; + static_assert(std::holds_alternative(v), ""); + } + { + using V = std::variant; + constexpr V v; + static_assert(std::holds_alternative(v), ""); + static_assert(!std::holds_alternative(v), ""); + } + { // noexcept test + using V = std::variant; + const V v; + static_assert(noexcept(std::holds_alternative(v)), "must be noexcept"); + } +} Index: test/std/variant/variant.monostate.relops/relops.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.monostate.relops/relops.pass.cpp @@ -0,0 +1,55 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// constexpr bool operator<(monostate, monostate) noexcept { return false; } +// constexpr bool operator>(monostate, monostate) noexcept { return false; } +// constexpr bool operator<=(monostate, monostate) noexcept { return true; } +// constexpr bool operator>=(monostate, monostate) noexcept { return true; } +// constexpr bool operator==(monostate, monostate) noexcept { return true; } +// constexpr bool operator!=(monostate, monostate) noexcept { return false; } + +#include +#include +#include + +int main() +{ + using M = std::monostate; + constexpr M m1{}; + constexpr M m2{}; + { + static_assert((m1 < m2) == false, ""); + static_assert(noexcept(m1 < m2), ""); + } + { + static_assert((m1 > m2) == false, ""); + static_assert(noexcept(m1 > m2), ""); + } + { + static_assert((m1 <= m2) == true, ""); + static_assert(noexcept(m1 <= m2), ""); + } + { + static_assert((m1 >= m2) == true, ""); + static_assert(noexcept(m1 >= m2), ""); + } + { + static_assert((m1 == m2) == true, ""); + static_assert(noexcept(m1 == m2), ""); + } + { + static_assert((m1 != m2) == false, ""); + static_assert(noexcept(m1 != m2), ""); + } +} Index: test/std/variant/variant.monostate/monostate.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.monostate/monostate.pass.cpp @@ -0,0 +1,31 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// struct monostate {}; + + +#include +#include +#include + +int main() +{ + using M = std::monostate; + static_assert(std::is_trivially_default_constructible::value, ""); + static_assert(std::is_trivially_copy_constructible::value, ""); + static_assert(std::is_trivially_copy_assignable::value, ""); + static_assert(std::is_trivially_destructible::value, ""); + constexpr M m{}; + ((void)m); +} Index: test/std/variant/variant.relops/relops.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.relops/relops.pass.cpp @@ -0,0 +1,209 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template +// constexpr bool +// operator==(variant const&, variant const&) noexcept; +// +// template +// constexpr bool +// operator!=(variant const&, variant const&) noexcept; +// +// template +// constexpr bool +// operator<(variant const&, variant const&) noexcept; +// +// template +// constexpr bool +// operator>(variant const&, variant const&) noexcept; +// +// template +// constexpr bool +// operator<=(variant const&, variant const&) noexcept; +// +// template +// constexpr bool +// operator>=(variant const&, variant const&) noexcept; + +#include +#include +#include + +#include "test_macros.h" + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct MakeEmptyT { + MakeEmptyT() = default; + MakeEmptyT(MakeEmptyT&&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } +}; +inline bool operator==(MakeEmptyT const&, MakeEmptyT const&) { assert(false); } +inline bool operator!=(MakeEmptyT const&, MakeEmptyT const&) { assert(false); } +inline bool operator< (MakeEmptyT const&, MakeEmptyT const&) { assert(false); } +inline bool operator<=(MakeEmptyT const&, MakeEmptyT const&) { assert(false); } +inline bool operator>(MakeEmptyT const&, MakeEmptyT const&) { assert(false); } +inline bool operator>=(MakeEmptyT const&, MakeEmptyT const&) { assert(false); } + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place); + try { + v = std::move(v2); + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +void test_equality() +{ + { + using V = std::variant; + constexpr V v1(42); + constexpr V v2(42); + static_assert(v1 == v2, ""); + static_assert(v2 == v1, ""); + static_assert(!(v1 != v2), ""); + static_assert(!(v2 != v1), ""); + } + { + using V = std::variant; + constexpr V v1(42); + constexpr V v2(43); + static_assert(!(v1 == v2), ""); + static_assert(!(v2 == v1), ""); + static_assert(v1 != v2, ""); + static_assert(v2 != v1, ""); + } + { + using V = std::variant; + constexpr V v1(42); + constexpr V v2(42l); + static_assert(!(v1 == v2), ""); + static_assert(!(v2 == v1), ""); + static_assert(v1 != v2, ""); + static_assert(v2 != v1, ""); + } + { + using V = std::variant; + constexpr V v1(42l); + constexpr V v2(42l); + static_assert(v1 == v2, ""); + static_assert(v2 == v1, ""); + static_assert(!(v1 != v2), ""); + static_assert(!(v2 != v1), ""); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + V v1; + V v2; makeEmpty(v2); + assert(!(v1 == v2)); + assert(!(v2 == v1)); + assert(v1 != v2); + assert(v2 != v1); + } + { + using V = std::variant; + V v1; makeEmpty(v1); + V v2; + assert(!(v1 == v2)); + assert(!(v2 == v1)); + assert(v1 != v2); + assert(v2 != v1); + } + { + using V = std::variant; + V v1; makeEmpty(v1); + V v2; makeEmpty(v2); + assert(v1 == v2); + assert(v2 == v1); + assert(!(v1 != v2)); + assert(!(v2 != v1)); + } +#endif +} + +template +constexpr bool test_less(Var const& l, Var const& r, bool expect_less, + bool expect_greater) { + return ((l < r) == expect_less) + && (!(l >= r) == expect_less) + && ((l > r) == expect_greater) + && (!(l <= r) == expect_greater); +} + +void test_relational() +{ + { // same index, same value + using V = std::variant; + constexpr V v1(1); + constexpr V v2(1); + static_assert(test_less(v1, v2, false, false), ""); + } + { // same index, value < other_value + using V = std::variant; + constexpr V v1(0); + constexpr V v2(1); + static_assert(test_less(v1, v2, true, false), ""); + } + { // same index, value > other_value + using V = std::variant; + constexpr V v1(1); + constexpr V v2(0); + static_assert(test_less(v1, v2, false, true), ""); + } + { // LHS.index() < RHS.index() + using V = std::variant; + constexpr V v1(0); + constexpr V v2(0l); + static_assert(test_less(v1, v2, true, false), ""); + } + { // LHS.index() > RHS.index() + using V = std::variant; + constexpr V v1(0l); + constexpr V v2(0); + static_assert(test_less(v1, v2, false, true), ""); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { // LHS.index() < RHS.index(), RHS is empty + using V = std::variant; + V v1; + V v2; makeEmpty(v2); + assert(test_less(v1, v2, false, true)); + } + { // LHS.index() > RHS.index(), LHS is empty + using V = std::variant; + V v1; makeEmpty(v1); + V v2; + assert(test_less(v1, v2, true, false)); + } + { // LHS.index() == RHS.index(), LHS and RHS are empty + using V = std::variant; + V v1; makeEmpty(v1); + V v2; makeEmpty(v2); + assert(test_less(v1, v2, false, false)); + } +#endif +} + +int main() { + test_equality(); + test_relational(); +} Index: test/std/variant/variant.synopsis/variant_npos.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.synopsis/variant_npos.pass.cpp @@ -0,0 +1,22 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// constexpr size_t variant_npos = -1; + +#include + +int main() +{ + static_assert(std::variant_npos == static_cast(-1), ""); +} Index: test/std/variant/variant.traits/uses_allocator.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.traits/uses_allocator.pass.cpp @@ -0,0 +1,25 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template +// struct uses_allocator, Alloc>; + +#include +#include + +int main() +{ + using T = std::variant; + static_assert(std::uses_allocator>::value, ""); +} Index: test/std/variant/variant.variant/variant.assign/T.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.assign/T.pass.cpp @@ -0,0 +1,222 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// variant& operator=(T&&) noexcept(see below); + +#include +#include +#include +#include + +#include "test_macros.h" + +namespace MetaHelpers { + +struct Dummy { + Dummy() = default; +}; + +struct ThrowsCtorT { + ThrowsCtorT(int) noexcept(false) {} + ThrowsCtorT& operator=(int) noexcept { return *this; } +}; + +struct ThrowsAssignT { + ThrowsAssignT(int) noexcept {} + ThrowsAssignT& operator=(int) noexcept(false) { return *this; } +}; + +struct NoThrowT { + NoThrowT(int) noexcept {} + NoThrowT& operator=(int) noexcept { return *this; } +}; + +} // namespace MetaHelpers + +namespace RuntimeHelpers { +#ifndef TEST_HAS_NO_EXCEPTIONS + +struct ThrowsCtorT { + int value; + ThrowsCtorT() : value(0) {} + ThrowsCtorT(int) noexcept(false) { throw 42; } + ThrowsCtorT& operator=(int v) noexcept { value = v; return *this; } +}; + +struct ThrowsAssignT { + int value; + ThrowsAssignT() : value(0) {} + ThrowsAssignT(int v) noexcept : value(v) {} + ThrowsAssignT& operator=(int) noexcept(false) { throw 42; } +}; + +struct NoThrowT { + int value; + NoThrowT() : value(0) {} + NoThrowT(int v) noexcept : value(v) {} + NoThrowT& operator=(int v) noexcept { value = v; return *this; } +}; + +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) +} // namespace RuntimeHelpers + +void test_T_assignment_noexcept() { + using namespace MetaHelpers; + { + using V = std::variant; + static_assert(std::is_nothrow_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_assignable::value, ""); + } +} + +void test_T_assignment_sfinae() { + { + using V = std::variant; + static_assert(!std::is_assignable::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_assignable::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_assignable::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_assignable::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_assignable::value, "no matching operator="); + } +} + +void test_T_assignment_basic() +{ + { + std::variant v(43); + v = 42; + assert(v.index() == 0); + assert(std::get<0>(v) == 42); + } + { + std::variant v(43l); + v = 42; + assert(v.index() == 0); + assert(std::get<0>(v) == 42); + v = 43l; + assert(v.index() == 1); + assert(std::get<1>(v) == 43); + } + { + using V = std::variant; + int x = 42; + V v(43l); + v = x; + assert(v.index() == 0); + assert(&std::get<0>(v) == &x); + v = std::move(x); + assert(v.index() == 1); + assert(&std::get<1>(v) == &x); + // 'long' is selected by FUN(int const&) since 'int const&' cannot bind + // to 'int&'. + int const& cx = x; + v = cx; + assert(v.index() == 2); + assert(std::get<2>(v) == 42); + } +} + +void test_T_assignment_performs_construction() +{ +using namespace RuntimeHelpers; +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + V v(std::in_place, "hello"); + try { + v = 42; + } catch (...) { /* ... */ } + assert(v.valueless_by_exception()); + } + { + using V = std::variant; + V v(std::in_place, "hello"); + v = 42; + assert(v.index() == 0); + assert(std::get<0>(v).value == 42); + } +#endif +} + +void test_T_assignment_performs_assignment() +{ + using namespace RuntimeHelpers; +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + V v; + v = 42; + assert(v.index() == 0); + assert(std::get<0>(v).value == 42); + } + { + using V = std::variant; + V v; + v = 42; + assert(v.index() == 0); + assert(std::get<0>(v).value == 42); + } + { + using V = std::variant; + V v(100); + try { + v = 42; + assert(false); + } catch(...) { /* ... */ } + assert(v.index() == 0); + assert(std::get<0>(v).value == 100); + } + { + using V = std::variant; + V v(100); + try { + v = 42; + assert(false); + } catch(...) { /* ... */ } + assert(v.index() == 1); + assert(std::get<1>(v).value == 100); + } +#endif +} + +int main() +{ + test_T_assignment_basic(); + test_T_assignment_performs_construction(); + test_T_assignment_performs_assignment(); + test_T_assignment_noexcept(); + test_T_assignment_sfinae(); +} \ No newline at end of file Index: test/std/variant/variant.variant/variant.assign/copy.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.assign/copy.pass.cpp @@ -0,0 +1,386 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// variant& operator=(variant const&); + + +#include +#include +#include +#include + +#include "test_macros.h" + +struct NoCopy { + NoCopy(NoCopy const&) = delete; + NoCopy& operator=(NoCopy const&) = default; +}; + +struct NothrowCopy { + NothrowCopy(NothrowCopy const&) noexcept = default; + NothrowCopy& operator=(NothrowCopy const&) noexcept = default; +}; + +struct CopyOnly { + CopyOnly(CopyOnly const&) = default; + CopyOnly(CopyOnly&&) = delete; + CopyOnly& operator=(CopyOnly const&) = default; + CopyOnly& operator=(CopyOnly&&) = delete; +}; + +struct MoveOnly { + MoveOnly(MoveOnly const&) = delete; + MoveOnly(MoveOnly&&) = default; + MoveOnly& operator=(MoveOnly const&) = default; +}; + +struct MoveOnlyNT { + MoveOnlyNT(MoveOnlyNT const&) = delete; + MoveOnlyNT(MoveOnlyNT&&) {} + MoveOnlyNT& operator=(MoveOnlyNT const&) = default; +}; + +struct CopyAssign { + static int alive; + static int copy_construct; + static int copy_assign; + static int move_construct; + static int move_assign; + static void reset() { + copy_construct = copy_assign = move_construct = move_assign = alive = 0; + } + CopyAssign(int v) : value(v) { ++alive; } + CopyAssign(CopyAssign const& o) : value(o.value) { ++alive; ++copy_construct; } + CopyAssign(CopyAssign&& o) : value(o.value) { o.value = -1; ++alive; ++move_construct; } + CopyAssign& operator=(CopyAssign const& o) { value = o.value; ++copy_assign; return *this; } + CopyAssign& operator=(CopyAssign&& o) { value = o.value; o.value = -1; ++move_assign; return *this; } + ~CopyAssign() { --alive; } + int value; +}; + +int CopyAssign::alive = 0; +int CopyAssign::copy_construct = 0; +int CopyAssign::copy_assign = 0; +int CopyAssign::move_construct = 0; +int CopyAssign::move_assign = 0; + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct CopyThrows { + CopyThrows() = default; + CopyThrows(CopyThrows const&) { throw 42; } + CopyThrows& operator=(CopyThrows const&) { throw 42; } +}; + +struct MoveThrows { + static int alive; + MoveThrows() { ++alive; } + MoveThrows(MoveThrows const&) {++alive;} + MoveThrows(MoveThrows&&) { throw 42; } + MoveThrows& operator=(MoveThrows const&) { return *this; } + MoveThrows& operator=(MoveThrows&&) { throw 42; } + ~MoveThrows() { --alive; } +}; + +int MoveThrows::alive = 0; + +struct MakeEmptyT { + static int alive; + MakeEmptyT() { ++alive; } + MakeEmptyT(MakeEmptyT const&) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + MakeEmptyT(MakeEmptyT &&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT const&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } + ~MakeEmptyT() { --alive; } +}; + +int MakeEmptyT::alive = 0; + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place); + try { + v = v2; + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +void test_copy_assignment_not_noexcept() { + { + using V = std::variant; + static_assert(!std::is_nothrow_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_copy_assignable::value, ""); + } +} + +void test_copy_assignment_sfinae() { + { + using V = std::variant; + static_assert(std::is_copy_assignable::value, ""); + } + { + // variant only provides copy assignment when beth the copy and move + // constructors are well formed + using V = std::variant; + static_assert(!std::is_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_assignable::value, ""); + } +} + +void test_copy_assignment_empty_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place<0>); makeEmpty(v1); + V v2(std::in_place<0>); makeEmpty(v2); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } +#endif +} + +void test_copy_assignment_non_empty_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place<0>, 42); + V v2(std::in_place<0>); makeEmpty(v2); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } + { + using V = std::variant; + V v1(std::in_place<2>, "hello"); + V v2(std::in_place<0>); makeEmpty(v2); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } +#endif +} + + +void test_copy_assignment_empty_non_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place<0>); makeEmpty(v1); + V v2(std::in_place<0>, 42); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(std::get<0>(v1) == 42); + } + { + using V = std::variant; + V v1(std::in_place<0>); makeEmpty(v1); + V v2(std::in_place, "hello"); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + } +#endif +} + +void test_copy_assignment_same_index() +{ + { + using V = std::variant; + V v1(43); + V v2(42); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(std::get<0>(v1) == 42); + } + { + using V = std::variant; + V v1(43l); + V v2(42l); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1) == 42); + } + { + using V = std::variant; + V v1(std::in_place, 43); + V v2(std::in_place, 42); + CopyAssign::reset(); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1).value == 42); + assert(CopyAssign::copy_construct == 0); + assert(CopyAssign::move_construct == 0); + assert(CopyAssign::copy_assign == 1); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place); + MET& mref = std::get<1>(v1); + V v2(std::in_place); + try { + v1 = v2; + assert(false); + } catch (...) { + } + assert(v1.index() == 1); + assert(&std::get<1>(v1) == &mref); + } +#endif +} + +void test_copy_assignment_different_index() +{ + { + using V = std::variant; + V v1(43); + V v2(42l); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1) == 42); + } + { + using V = std::variant; + CopyAssign::reset(); + V v1(std::in_place, 43); + V v2(std::in_place, 42); + assert(CopyAssign::copy_construct == 0); + assert(CopyAssign::move_construct == 0); + assert(CopyAssign::alive == 1); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1).value == 42); + assert(CopyAssign::alive == 2); + assert(CopyAssign::copy_construct == 1); + assert(CopyAssign::move_construct == 1); + assert(CopyAssign::copy_assign == 0); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + // Test that if copy construction throws then original value is + // unchanged. + using V = std::variant; + V v1(std::in_place, "hello"); + V v2(std::in_place); + try { + v1 = v2; + assert(false); + } catch (...) { /* ... */ } + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + } + { + // Test that if move construction throws then the variant is left + // valueless by exception. + using V = std::variant; + V v1(std::in_place, "hello"); + V v2(std::in_place); + assert(MoveThrows::alive == 1); + try { + v1 = v2; + assert(false); + } catch (...) { /* ... */ } + assert(v1.valueless_by_exception()); + assert(v2.index() == 1); + assert(MoveThrows::alive == 1); + } + { + using V = std::variant; + V v1(std::in_place); + V v2(std::in_place, "hello"); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + assert(v2.index() == 2); + assert(std::get<2>(v2) == "hello"); + } + { + using V = std::variant; + V v1(std::in_place); + V v2(std::in_place, "hello"); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + assert(v2.index() == 2); + assert(std::get<2>(v2) == "hello"); + } +#endif +} + +int main() +{ + test_copy_assignment_empty_empty(); + test_copy_assignment_non_empty_empty(); + test_copy_assignment_empty_non_empty(); + test_copy_assignment_same_index(); + test_copy_assignment_different_index(); + test_copy_assignment_sfinae(); + test_copy_assignment_not_noexcept(); +} Index: test/std/variant/variant.variant/variant.assign/move.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.assign/move.pass.cpp @@ -0,0 +1,314 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// variant& operator=(variant&&) noexcept(see below); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +struct NoCopy { + NoCopy(NoCopy const&) = delete; + NoCopy& operator=(NoCopy const&) = default; +}; + +struct CopyOnly { + CopyOnly(CopyOnly const&) = default; + CopyOnly(CopyOnly&&) = delete; + CopyOnly& operator=(CopyOnly const&) = default; + CopyOnly& operator=(CopyOnly&&) = delete; +}; + +struct MoveOnly { + MoveOnly(MoveOnly const&) = delete; + MoveOnly(MoveOnly&&) = default; + MoveOnly& operator=(MoveOnly const&) = delete; + MoveOnly& operator=(MoveOnly&&) = default; +}; + +struct MoveOnlyNT { + MoveOnlyNT(MoveOnlyNT const&) = delete; + MoveOnlyNT(MoveOnlyNT&&) {} + MoveOnlyNT& operator=(MoveOnlyNT const&) = delete; + MoveOnlyNT& operator=(MoveOnlyNT&&) = default; +}; + +struct MoveOnlyOddNothrow { + MoveOnlyOddNothrow(MoveOnlyOddNothrow&&) noexcept(false) {} + MoveOnlyOddNothrow(MoveOnlyOddNothrow const&) = delete; + MoveOnlyOddNothrow& operator=(MoveOnlyOddNothrow&&) noexcept = default; + MoveOnlyOddNothrow& operator=(MoveOnlyOddNothrow const&) = delete; +}; + +struct MoveAssignOnly { + MoveAssignOnly(MoveAssignOnly &&) = delete; + MoveAssignOnly& operator=(MoveAssignOnly&&) = default; +}; + +struct MoveAssign { + static int move_construct; + static int move_assign; + static void reset() { + move_construct = move_assign = 0; + } + MoveAssign(int v) : value(v) {} + MoveAssign(MoveAssign&& o) : value(o.value) { ++move_construct; o.value = -1; } + MoveAssign& operator=(MoveAssign&& o) { value = o.value; ++move_assign; o.value = -1; return *this; } + int value; +}; + +int MoveAssign::move_construct = 0; +int MoveAssign::move_assign = 0; + + +void test_move_assignment_noexcept() { + { + using V = std::variant; + static_assert(std::is_nothrow_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_nothrow_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_nothrow_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_nothrow_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_move_assignable::value, ""); + } +} + +void test_move_assignment_sfinae() { + { + using V = std::variant; + static_assert(std::is_move_assignable::value, ""); + } + { + // variant only provides move assignment when beth the move and move + // constructors are well formed + using V = std::variant; + static_assert(!std::is_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_move_assignable::value, ""); + } + { + // variant only provides move assignment when the types also provide + // a move constructor. + using V = std::variant; + static_assert(!std::is_move_assignable::value, ""); + } +} + +void test_move_assignment_empty_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place<0>); makeEmpty(v1); + V v2(std::in_place<0>); makeEmpty(v2); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } +#endif +} + +void test_move_assignment_non_empty_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place<0>, 42); + V v2(std::in_place<0>); makeEmpty(v2); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } + { + using V = std::variant; + V v1(std::in_place<2>, "hello"); + V v2(std::in_place<0>); makeEmpty(v2); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } +#endif +} + + +void test_move_assignment_empty_non_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place<0>); makeEmpty(v1); + V v2(std::in_place<0>, 42); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(std::get<0>(v1) == 42); + } + { + using V = std::variant; + V v1(std::in_place<0>); makeEmpty(v1); + V v2(std::in_place, "hello"); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + } +#endif +} + +void test_move_assignment_same_index() +{ + { + using V = std::variant; + V v1(43); + V v2(42); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(std::get<0>(v1) == 42); + } + { + using V = std::variant; + V v1(43l); + V v2(42l); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1) == 42); + } + { + using V = std::variant; + V v1(std::in_place, 43); + V v2(std::in_place, 42); + MoveAssign::reset(); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1).value == 42); + assert(MoveAssign::move_construct == 0); + assert(MoveAssign::move_assign == 1); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place); + MET& mref = std::get<1>(v1); + V v2(std::in_place); + try { + v1 = std::move(v2); + assert(false); + } catch (...) { + } + assert(v1.index() == 1); + assert(&std::get<1>(v1) == &mref); + } +#endif +} + +void test_move_assignment_different_index() +{ + { + using V = std::variant; + V v1(43); + V v2(42l); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1) == 42); + } + { + using V = std::variant; + V v1(std::in_place, 43); + V v2(std::in_place, 42); + MoveAssign::reset(); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1).value == 42); + assert(MoveAssign::move_construct == 1); + assert(MoveAssign::move_assign == 0); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place); + V v2(std::in_place); + try { + v1 = std::move(v2); + assert(false); + } catch (...) { + } + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } + { + using V = std::variant; + V v1(std::in_place); + V v2(std::in_place, "hello"); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + } +#endif +} + +int main() +{ + test_move_assignment_empty_empty(); + test_move_assignment_non_empty_empty(); + test_move_assignment_empty_non_empty(); + test_move_assignment_same_index(); + test_move_assignment_different_index(); + test_move_assignment_sfinae(); + test_move_assignment_noexcept(); +} Index: test/std/variant/variant.variant/variant.ctor/Alloc_T.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/Alloc_T.pass.cpp @@ -0,0 +1,166 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template variant(allocator_arg_t, Alloc const&, T&&); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" +#include "uses_alloc_types.hpp" + +struct Dummy { + Dummy() = default; +}; + +struct ThrowsT { + ThrowsT(int) noexcept(false) {} +}; + +struct NoThrowT { + NoThrowT(int) noexcept(true) {} +}; + + +void test_T_ctor_sfinae() { + using Tag = std::allocator_arg_t const&; + using A = std::allocator const&; + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambigious"); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambigious"); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambigious"); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, "no matching constructor"); + } +} + +void test_T_ctor_basic() +{ + using Tag = std::allocator_arg_t const&; + using A = std::allocator const&; + const auto atag = std::allocator_arg; + std::allocator a; + { + using V = std::variant; + static_assert(test_convertible(), "must be implicit"); + V v(atag, a,42); + assert(v.index() == 0); + assert(std::get<0>(v) == 42); + } + { + using V = std::variant; + V v(atag, a,42l); + static_assert(test_convertible(), "must be implicit"); + assert(v.index() == 1); + assert(std::get<1>(v) == 42); + } + { + using V = std::variant; + static_assert(test_convertible(), "must be implicit"); + int x = 42; + V v(atag, a,x); + assert(v.index() == 0); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + static_assert(test_convertible(), "must be implicit"); + int x = 42; + V v(atag, a,std::move(x)); + assert(v.index() == 1); + assert(&std::get<1>(v) == &x); + } +} + +void test_T_ctor_uses_alloc() +{ + using A = std::allocator; + using A2 = std::allocator; + using UA1 = UsesAllocatorV1; + using UA2 = UsesAllocatorV2; + using UA3 = UsesAllocatorV3; + using NUA = NotUsesAllocator; + const A a; + const A2 a2; + { + using V = std::variant; + V v(std::allocator_arg, a, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_AllocArg)); + } + { + using V = std::variant; + V v(std::allocator_arg, a2, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_None)); + } + { + using V = std::variant; + V v(std::allocator_arg, a, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_AllocLast)); + } + { + using V = std::variant; + V v(std::allocator_arg, a2, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_None)); + } + { + using V = std::variant; + V v(std::allocator_arg, a, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_AllocArg)); + } + { + using V = std::variant; + V v(std::allocator_arg, a2, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_None)); + } + { + using V = std::variant; + V v(std::allocator_arg, a, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_None)); + } + { + using V = std::variant; + V v(std::allocator_arg, a2, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_None)); + } +} + +int main() +{ + test_T_ctor_basic(); + test_T_ctor_uses_alloc(); + test_T_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/Alloc_copy.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/Alloc_copy.pass.cpp @@ -0,0 +1,171 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// variant(allocator_arg_t, Alloc const&, variant const&); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "uses_alloc_types.hpp" + +struct NonT { + NonT(int v) : value(v) {} + NonT(NonT const& o) : value(o.value) {} + int value; +}; +static_assert(!std::is_trivially_copy_constructible::value, ""); + + +struct NoCopy { + NoCopy(NoCopy const&) = delete; +}; + +struct MoveOnly { + MoveOnly(MoveOnly const&) = delete; + MoveOnly(MoveOnly&&) = default; +}; + +struct MoveOnlyNT { + MoveOnlyNT(MoveOnlyNT const&) = delete; + MoveOnlyNT(MoveOnlyNT&&) {} +}; + +void test_copy_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_constructible const&, V const&>::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_constructible const&, V const&>::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_constructible const&, V const&>::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_constructible const&, V const&>::value, ""); + } +} + +void test_copy_ctor_basic() +{ + { + std::variant v(std::in_place<0>, 42); + std::variant v2(std::allocator_arg, std::allocator{}, v); + assert(v2.index() == 0); + assert(std::get<0>(v2) == 42); + } + { + std::variant v(std::in_place<1>, 42); + std::variant v2(std::allocator_arg, std::allocator{}, v); + assert(v2.index() == 1); + assert(std::get<1>(v2) == 42); + } + { + std::variant v(std::in_place<0>, 42); + assert(v.index() == 0); + std::variant v2(std::allocator_arg, std::allocator{}, v); + assert(v2.index() == 0); + assert(std::get<0>(v2).value == 42); + } + { + std::variant v(std::in_place<1>, 42); + assert(v.index() == 1); + std::variant v2(std::allocator_arg, std::allocator{}, v); + assert(v2.index() == 1); + assert(std::get<1>(v2).value == 42); + } +} + + +void test_copy_ctor_uses_alloc() +{ + using A = std::allocator; + using A2 = std::allocator; + using UA1 = UsesAllocatorV1; + using UA2 = UsesAllocatorV2; + using UA3 = UsesAllocatorV3; + using NUA = NotUsesAllocator; + using V = std::variant; + const A a; + const A2 a2; + { + V v(std::in_place<0>); + V v2(std::allocator_arg, a, v); + assert(v2.index() == 0); + assert(checkConstruct(std::get<0>(v2), UA_AllocArg)); + } + { + V v(std::in_place<0>); + V v2(std::allocator_arg, a2, v); + assert(v2.index() == 0); + assert(checkConstruct(std::get<0>(v2), UA_None)); + } + { + V v(std::in_place<1>); + V v2(std::allocator_arg, a, v); + assert(v2.index() == 1); + assert(checkConstruct(std::get<1>(v2), UA_AllocLast)); + } + { + V v(std::in_place<1>); + V v2(std::allocator_arg, a2, v); + assert(v2.index() == 1); + assert(checkConstruct(std::get<1>(v2), UA_None)); + } + { + V v(std::in_place<2>); + V v2(std::allocator_arg, a, v); + assert(v2.index() == 2); + assert(checkConstruct(std::get<2>(v2), UA_AllocArg)); + } + { + V v(std::in_place<2>); + V v2(std::allocator_arg, a2, v); + assert(v2.index() == 2); + assert(checkConstruct(std::get<2>(v2), UA_None)); + } + { + V v(std::in_place<3>); + V v3(std::allocator_arg, a, v); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } + { + V v(std::in_place<3>); + V v3(std::allocator_arg, a2, v); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } +} + +int main() +{ + test_copy_ctor_basic(); + test_copy_ctor_uses_alloc(); + test_copy_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/Alloc_in_place_index_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/Alloc_in_place_index_Args.pass.cpp @@ -0,0 +1,162 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// variant(allocator_arg_t, Alloc const&, in_place_index_t, Args&&...); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" +#include "uses_alloc_types.hpp" + +void test_ctor_sfinae() { + using Tag = std::allocator_arg_t const; + using A = std::allocator const&; + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int*>::value, ""); + static_assert(test_convertible, int*>(), ""); + } + { // args not convertible to type + using V = std::variant; + static_assert(!std::is_constructible, int*>::value, ""); + static_assert(!test_convertible, int*>(), ""); + } + { // index out of range + using V = std::variant; + static_assert(!std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } +} + +void test_ctor_basic() +{ + using Tag = std::allocator_arg_t const; + using A = std::allocator const&; + Tag atag{}; + std::allocator a{}; + { + std::variant v(atag, a, std::in_place<0>, 42); + assert(v.index() == 0); + assert(std::get<0>(v) == 42); + } + { + std::variant v(atag, a, std::in_place<1>, 42); + assert(v.index() == 1); + assert(std::get<1>(v) == 42); + } + { + std::variant v(atag, a, std::in_place<1>, 42); + assert(v.index() == 1); + assert(std::get<1>(v) == 42); + } + { + using V = std::variant; + int x = 42; + V v(atag, a, std::in_place<0>, x); + assert(v.index() == 0); + assert(std::get<0>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(atag, a, std::in_place<1>, x); + assert(v.index() == 1); + assert(std::get<1>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(atag, a, std::in_place<2>, x); + assert(v.index() == 2); + assert(std::get<2>(v) == x); + } +} + + +void test_ctor_uses_alloc() +{ + using A = std::allocator; + using A2 = std::allocator; + using UA1 = UsesAllocatorV1; + using UA2 = UsesAllocatorV2; + using UA3 = UsesAllocatorV3; + using NUA = NotUsesAllocator; + using V = std::variant; + const A a; + const A2 a2; + { + V v(std::allocator_arg, a, std::in_place<0>, 42); + assert(v.index() == 0); + assert(checkConstruct(std::get<0>(v), UA_AllocArg)); + } + { + V v(std::allocator_arg, a2, std::in_place<0>, 42); + assert(v.index() == 0); + assert(checkConstruct(std::get<0>(v), UA_None)); + } + { + V v(std::allocator_arg, a, std::in_place<1>, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_AllocLast)); + } + { + V v(std::allocator_arg, a2, std::in_place<1>, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_None)); + } + { + V v(std::allocator_arg, a, std::in_place<2>, 42); + assert(v.index() == 2); + assert(checkConstruct(std::get<2>(v), UA_AllocArg)); + } + { + V v(std::allocator_arg, a2, std::in_place<2>, 42); + assert(v.index() == 2); + assert(checkConstruct(std::get<2>(v), UA_None)); + } + { + V v3(std::allocator_arg, a, std::in_place<3>, 42); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } + { + V v3(std::allocator_arg, a2, std::in_place<3>, 42); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } +} + +int main() +{ + test_ctor_basic(); + test_ctor_uses_alloc(); + test_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/Alloc_in_place_index_init_list_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/Alloc_in_place_index_init_list_Args.pass.cpp @@ -0,0 +1,212 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// variant(allocator_arg_t, Alloc const&, in_place_index_t, initializer_list, Args&&...); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" +#include "uses_alloc_types.hpp" + +struct InitList { + std::size_t size; + constexpr InitList(std::initializer_list il) : size(il.size()){} +}; + +struct InitListArg { + std::size_t size; + int value; + constexpr InitListArg(std::initializer_list il, int v) : size(il.size()), value(v) {} +}; + +void test_ctor_sfinae() { + using Tag = std::allocator_arg_t const&; + using A = std::allocator const&; + using IL = std::initializer_list; + { // just init list + using V = std::variant; + static_assert(std::is_constructible, IL>::value, ""); + static_assert(test_convertible, IL>(), ""); + } + { // too many arguments + using V = std::variant; + static_assert(!std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } + { // too few arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // init list and arguments + using V = std::variant; + static_assert(std::is_constructible, IL, int>::value, ""); + static_assert(test_convertible, IL, int>(), ""); + } + { // not constructible from arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // index out of range + using V = std::variant; + static_assert(!std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } +} + +void test_ctor_basic() +{ + std::allocator_arg_t const atag{}; + std::allocator a{}; + { + std::variant v(atag, a, std::in_place<0>, {1, 2, 3}); + assert(v.index() == 0); + assert(std::get<0>(v).size == 3); + } + { + std::variant v(atag, a, std::in_place<1>, {1, 2, 3, 4}, 42); + assert(v.index() == 1); + assert(std::get<1>(v).size == 4); + assert(std::get<1>(v).value == 42); + } +} + + +void test_no_args_ctor_uses_alloc() +{ + using IL = std::initializer_list; + using A = std::allocator; + using A2 = std::allocator; + using UA1 = UsesAllocatorV1; + using UA2 = UsesAllocatorV2; + using UA3 = UsesAllocatorV3; + using NUA = NotUsesAllocator; + using V = std::variant; + const A a; + const A2 a2; + { + V v(std::allocator_arg, a, std::in_place<0>, {1, 2, 3}); + assert(v.index() == 0); + assert(checkConstruct(std::get<0>(v), UA_AllocArg)); + } + { + V v(std::allocator_arg, a2, std::in_place<0>, {1, 2, 3}); + assert(v.index() == 0); + assert(checkConstruct(std::get<0>(v), UA_None)); + } + { + V v(std::allocator_arg, a, std::in_place<1>, {1, 2, 3}); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_AllocLast)); + } + { + V v(std::allocator_arg, a2, std::in_place<1>, {1, 2, 3}); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_None)); + } + { + V v(std::allocator_arg, a, std::in_place<2>, {1, 2, 3}); + assert(v.index() == 2); + assert(checkConstruct(std::get<2>(v), UA_AllocArg)); + } + { + V v(std::allocator_arg, a2, std::in_place<2>, {1, 2, 3}); + assert(v.index() == 2); + assert(checkConstruct(std::get<2>(v), UA_None)); + } + { + V v3(std::allocator_arg, a, std::in_place<3>, {1, 2, 3}); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } + { + V v3(std::allocator_arg, a2, std::in_place<3>, {1, 2, 3}); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } +} + + +void test_additional_args_ctor_uses_alloc() +{ + using IL = std::initializer_list; + using A = std::allocator; + using A2 = std::allocator; + using UA1 = UsesAllocatorV1; + using UA2 = UsesAllocatorV2; + using UA3 = UsesAllocatorV3; + using NUA = NotUsesAllocator; + using V = std::variant; + const A a; + const A2 a2; + const int x = 42; + { + V v(std::allocator_arg, a, std::in_place<0>, {1, 2, 3}, 42, x); + assert((v.index() == 0)); + assert((checkConstruct(std::get<0>(v), UA_AllocArg))); + } + { + V v(std::allocator_arg, a2, std::in_place<0>, {1, 2, 3}, 42, x); + assert((v.index() == 0)); + assert((checkConstruct(std::get<0>(v), UA_None))); + } + { + V v(std::allocator_arg, a, std::in_place<1>, {1, 2, 3}, 42, x); + assert((v.index() == 1)); + assert((checkConstruct(std::get<1>(v), UA_AllocLast))); + } + { + V v(std::allocator_arg, a2, std::in_place<1>, {1, 2, 3}, 42, x); + assert((v.index() == 1)); + assert((checkConstruct(std::get<1>(v), UA_None))); + } + { + V v(std::allocator_arg, a, std::in_place<2>, {1, 2, 3}, 42, x); + assert((v.index() == 2)); + assert((checkConstruct(std::get<2>(v), UA_AllocArg))); + } + { + V v(std::allocator_arg, a2, std::in_place<2>, {1, 2, 3}, 42, x); + assert((v.index() == 2)); + assert((checkConstruct(std::get<2>(v), UA_None))); + } + { + V v3(std::allocator_arg, a, std::in_place<3>, {1, 2, 3}, 42, x); + assert((v3.index() == 3)); + assert((checkConstruct(std::get<3>(v3), UA_None))); + } + { + V v3(std::allocator_arg, a2, std::in_place<3>, {1, 2, 3}, 42, x); + assert((v3.index() == 3)); + assert((checkConstruct(std::get<3>(v3), UA_None))); + } +} + + +int main() +{ + test_ctor_basic(); + test_no_args_ctor_uses_alloc(); + test_additional_args_ctor_uses_alloc(); + test_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/Alloc_in_place_type_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/Alloc_in_place_type_Args.pass.cpp @@ -0,0 +1,167 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// variant(allocator_arg_t, Alloc const&, in_place_type_t, Args&&...); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" +#include "uses_alloc_types.hpp" + +void test_ctor_sfinae() { + using Tag = std::allocator_arg_t const; + using A = std::allocator const&; + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int*>::value, ""); + static_assert(test_convertible, int*>(), ""); + } + { // duplicate type + using V = std::variant; + static_assert(!std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { // args not convertible to type + using V = std::variant; + static_assert(!std::is_constructible, int*>::value, ""); + static_assert(!test_convertible, int*>(), ""); + } + { // type not in variant + using V = std::variant; + static_assert(!std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } +} + +void test_ctor_basic() +{ + using Tag = std::allocator_arg_t const; + using A = std::allocator const&; + Tag atag{}; + std::allocator a{}; + { + std::variant v(atag, a, std::in_place, 42); + assert(v.index() == 0); + assert(std::get<0>(v) == 42); + } + { + std::variant v(atag, a, std::in_place, 42); + assert(v.index() == 1); + assert(std::get<1>(v) == 42); + } + { + std::variant v(atag, a, std::in_place, 42); + assert(v.index() == 1); + assert(std::get<1>(v) == 42); + } + { + using V = std::variant; + int x = 42; + V v(atag, a, std::in_place, x); + assert(v.index() == 0); + assert(std::get<0>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(atag, a, std::in_place, x); + assert(v.index() == 1); + assert(std::get<1>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(atag, a, std::in_place, x); + assert(v.index() == 2); + assert(std::get<2>(v) == x); + } +} + + +void test_ctor_uses_alloc() +{ + using A = std::allocator; + using A2 = std::allocator; + using UA1 = UsesAllocatorV1; + using UA2 = UsesAllocatorV2; + using UA3 = UsesAllocatorV3; + using NUA = NotUsesAllocator; + using V = std::variant; + const A a; + const A2 a2; + { + V v(std::allocator_arg, a, std::in_place, 42); + assert(v.index() == 0); + assert(checkConstruct(std::get<0>(v), UA_AllocArg)); + } + { + V v(std::allocator_arg, a2, std::in_place, 42); + assert(v.index() == 0); + assert(checkConstruct(std::get<0>(v), UA_None)); + } + { + V v(std::allocator_arg, a, std::in_place, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_AllocLast)); + } + { + V v(std::allocator_arg, a2, std::in_place, 42); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_None)); + } + { + V v(std::allocator_arg, a, std::in_place, 42); + assert(v.index() == 2); + assert(checkConstruct(std::get<2>(v), UA_AllocArg)); + } + { + V v(std::allocator_arg, a2, std::in_place, 42); + assert(v.index() == 2); + assert(checkConstruct(std::get<2>(v), UA_None)); + } + { + V v3(std::allocator_arg, a, std::in_place, 42); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } + { + V v3(std::allocator_arg, a2, std::in_place, 42); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } +} + +int main() +{ + test_ctor_basic(); + test_ctor_uses_alloc(); + test_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/Alloc_in_place_types_init_list_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/Alloc_in_place_types_init_list_Args.pass.cpp @@ -0,0 +1,212 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// variant(allocator_arg_t, Alloc const&, in_place_type_t, initializer_list, Args&&...); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" +#include "uses_alloc_types.hpp" + +struct InitList { + std::size_t size; + constexpr InitList(std::initializer_list il) : size(il.size()){} +}; + +struct InitListArg { + std::size_t size; + int value; + constexpr InitListArg(std::initializer_list il, int v) : size(il.size()), value(v) {} +}; + +void test_ctor_sfinae() { + using Tag = std::allocator_arg_t const&; + using A = std::allocator const&; + using IL = std::initializer_list; + { // just init list + using V = std::variant; + static_assert(std::is_constructible, IL>::value, ""); + static_assert(test_convertible, IL>(), ""); + } + { // too many arguments + using V = std::variant; + static_assert(!std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } + { // too few arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // init list and arguments + using V = std::variant; + static_assert(std::is_constructible, IL, int>::value, ""); + static_assert(test_convertible, IL, int>(), ""); + } + { // not constructible from arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // duplicate types in variant + using V = std::variant; + static_assert(!std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } +} + +void test_ctor_basic() +{ + std::allocator_arg_t const atag{}; + std::allocator a{}; + { + std::variant v(atag, a, std::in_place, {1, 2, 3}); + assert(v.index() == 0); + assert(std::get<0>(v).size == 3); + } + { + std::variant v(atag, a, std::in_place, {1, 2, 3, 4}, 42); + assert(v.index() == 1); + assert(std::get<1>(v).size == 4); + assert(std::get<1>(v).value == 42); + } +} + + +void test_no_args_ctor_uses_alloc() +{ + using IL = std::initializer_list; + using A = std::allocator; + using A2 = std::allocator; + using UA1 = UsesAllocatorV1; + using UA2 = UsesAllocatorV2; + using UA3 = UsesAllocatorV3; + using NUA = NotUsesAllocator; + using V = std::variant; + const A a; + const A2 a2; + { + V v(std::allocator_arg, a, std::in_place, {1, 2, 3}); + assert(v.index() == 0); + assert(checkConstruct(std::get<0>(v), UA_AllocArg)); + } + { + V v(std::allocator_arg, a2, std::in_place, {1, 2, 3}); + assert(v.index() == 0); + assert(checkConstruct(std::get<0>(v), UA_None)); + } + { + V v(std::allocator_arg, a, std::in_place, {1, 2, 3}); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_AllocLast)); + } + { + V v(std::allocator_arg, a2, std::in_place, {1, 2, 3}); + assert(v.index() == 1); + assert(checkConstruct(std::get<1>(v), UA_None)); + } + { + V v(std::allocator_arg, a, std::in_place, {1, 2, 3}); + assert(v.index() == 2); + assert(checkConstruct(std::get<2>(v), UA_AllocArg)); + } + { + V v(std::allocator_arg, a2, std::in_place, {1, 2, 3}); + assert(v.index() == 2); + assert(checkConstruct(std::get<2>(v), UA_None)); + } + { + V v3(std::allocator_arg, a, std::in_place, {1, 2, 3}); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } + { + V v3(std::allocator_arg, a2, std::in_place, {1, 2, 3}); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } +} + + +void test_additional_args_ctor_uses_alloc() +{ + using IL = std::initializer_list; + using A = std::allocator; + using A2 = std::allocator; + using UA1 = UsesAllocatorV1; + using UA2 = UsesAllocatorV2; + using UA3 = UsesAllocatorV3; + using NUA = NotUsesAllocator; + using V = std::variant; + const A a; + const A2 a2; + const int x = 42; + { + V v(std::allocator_arg, a, std::in_place, {1, 2, 3}, 42, x); + assert((v.index() == 0)); + assert((checkConstruct(std::get<0>(v), UA_AllocArg))); + } + { + V v(std::allocator_arg, a2, std::in_place, {1, 2, 3}, 42, x); + assert((v.index() == 0)); + assert((checkConstruct(std::get<0>(v), UA_None))); + } + { + V v(std::allocator_arg, a, std::in_place, {1, 2, 3}, 42, x); + assert((v.index() == 1)); + assert((checkConstruct(std::get<1>(v), UA_AllocLast))); + } + { + V v(std::allocator_arg, a2, std::in_place, {1, 2, 3}, 42, x); + assert((v.index() == 1)); + assert((checkConstruct(std::get<1>(v), UA_None))); + } + { + V v(std::allocator_arg, a, std::in_place, {1, 2, 3}, 42, x); + assert((v.index() == 2)); + assert((checkConstruct(std::get<2>(v), UA_AllocArg))); + } + { + V v(std::allocator_arg, a2, std::in_place, {1, 2, 3}, 42, x); + assert((v.index() == 2)); + assert((checkConstruct(std::get<2>(v), UA_None))); + } + { + V v3(std::allocator_arg, a, std::in_place, {1, 2, 3}, 42, x); + assert((v3.index() == 3)); + assert((checkConstruct(std::get<3>(v3), UA_None))); + } + { + V v3(std::allocator_arg, a2, std::in_place, {1, 2, 3}, 42, x); + assert((v3.index() == 3)); + assert((checkConstruct(std::get<3>(v3), UA_None))); + } +} + + +int main() +{ + test_ctor_basic(); + test_no_args_ctor_uses_alloc(); + test_additional_args_ctor_uses_alloc(); + test_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/Alloc_move.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/Alloc_move.pass.cpp @@ -0,0 +1,187 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// variant(allocator_arg_t, Alloc const&, variant &&); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "uses_alloc_types.hpp" + +struct ThrowsMove { + ThrowsMove(ThrowsMove&&) noexcept(false) {} +}; + +struct NoCopy { + NoCopy(NoCopy const&) = delete; +}; + +struct MoveOnly { + int value; + MoveOnly(int v) : value(v) {} + MoveOnly(MoveOnly const&) = delete; + MoveOnly(MoveOnly&&) = default; +}; + +struct MoveOnlyNT { + int value; + MoveOnlyNT(int v) : value(v) {} + MoveOnlyNT(MoveOnlyNT const&) = delete; + MoveOnlyNT(MoveOnlyNT&& other) : value(other.value) { other.value = -1; } +}; + +void test_move_ctor_sfinae() { + using ATag = std::allocator_arg_t const&; + using A = std::allocator; + { + using V = std::variant; + static_assert(std::is_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, ""); + } +} + +void test_move_ctor_basic() +{ + const auto atag = std::allocator_arg; + std::allocator a{}; + { + std::variant v(std::in_place<0>, 42); + std::variant v2(atag, a, std::move(v)); + assert(v2.index() == 0); + assert(std::get<0>(v2) == 42); + } + { + std::variant v(std::in_place<1>, 42); + std::variant v2(atag, a, std::move(v)); + assert(v2.index() == 1); + assert(std::get<1>(v2) == 42); + } + { + std::variant v(std::in_place<0>, 42); + assert(v.index() == 0); + std::variant v2(atag, a, std::move(v)); + assert(v2.index() == 0); + assert(std::get<0>(v2).value == 42); + } + { + std::variant v(std::in_place<1>, 42); + assert(v.index() == 1); + std::variant v2(atag, a, std::move(v)); + assert(v2.index() == 1); + assert(std::get<1>(v2).value == 42); + } + { + std::variant v(std::in_place<0>, 42); + assert(v.index() == 0); + std::variant v2(atag, a, std::move(v)); + assert(v2.index() == 0); + assert(std::get<0>(v).value == -1); + assert(std::get<0>(v2).value == 42); + } + { + std::variant v(std::in_place<1>, 42); + assert(v.index() == 1); + std::variant v2(atag, a, std::move(v)); + assert(v2.index() == 1); + assert(std::get<1>(v).value == -1); + assert(std::get<1>(v2).value == 42); + } +} + + +void test_move_ctor_uses_alloc() +{ + using A = std::allocator; + using A2 = std::allocator; + using UA1 = UsesAllocatorV1; + using UA2 = UsesAllocatorV2; + using UA3 = UsesAllocatorV3; + using NUA = NotUsesAllocator; + using V = std::variant; + const A a; + const A2 a2; + { + V v(std::in_place<0>); + V v2(std::allocator_arg, a, std::move(v)); + assert(v2.index() == 0); + assert(checkConstruct(std::get<0>(v2), UA_AllocArg)); + } + { + V v(std::in_place<0>); + V v2(std::allocator_arg, a2, std::move(v)); + assert(v2.index() == 0); + assert(checkConstruct(std::get<0>(v2), UA_None)); + } + { + V v(std::in_place<1>); + V v2(std::allocator_arg, a, std::move(v)); + assert(v2.index() == 1); + assert(checkConstruct(std::get<1>(v2), UA_AllocLast)); + } + { + V v(std::in_place<1>); + V v2(std::allocator_arg, a2, std::move(v)); + assert(v2.index() == 1); + assert(checkConstruct(std::get<1>(v2), UA_None)); + } + { + V v(std::in_place<2>); + V v2(std::allocator_arg, a, std::move(v)); + assert(v2.index() == 2); + assert(checkConstruct(std::get<2>(v2), UA_AllocArg)); + } + { + V v(std::in_place<2>); + V v2(std::allocator_arg, a2, std::move(v)); + assert(v2.index() == 2); + assert(checkConstruct(std::get<2>(v2), UA_None)); + } + { + V v(std::in_place<3>); + V v3(std::allocator_arg, a, std::move(v)); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } + { + V v(std::in_place<3>); + V v3(std::allocator_arg, a2, std::move(v)); + assert(v3.index() == 3); + assert(checkConstruct(std::get<3>(v3), UA_None)); + } +} + +int main() +{ + test_move_ctor_basic(); + test_move_ctor_uses_alloc(); + test_move_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/T.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/T.pass.cpp @@ -0,0 +1,109 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template constexpr variant(T&&) noexcept(see below); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +struct Dummy { + Dummy() = default; +}; + +struct ThrowsT { + ThrowsT(int) noexcept(false) {} +}; + +struct NoThrowT { + NoThrowT(int) noexcept(true) {} +}; + +void test_T_ctor_noexcept() { + { + using V = std::variant; + static_assert(std::is_nothrow_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_constructible::value, ""); + } +} + +void test_T_ctor_sfinae() { + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, "no matching constructor"); + } +} + +void test_T_ctor_basic() +{ + { + constexpr std::variant v(42); + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v) == 42, ""); + } + { + constexpr std::variant v(42l); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + using V = std::variant; + static_assert(std::is_convertible::value, "must be implicit"); + int x = 42; + V v(x); + assert(v.index() == 0); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + static_assert(std::is_convertible::value, "must be implicit"); + int x = 42; + V v(std::move(x)); + assert(v.index() == 1); + assert(&std::get<1>(v) == &x); + } +} + +int main() +{ + test_T_ctor_basic(); + test_T_ctor_noexcept(); + test_T_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/copy.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/copy.pass.cpp @@ -0,0 +1,151 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// variant(variant const&); + + +#include +#include +#include + +#include "test_macros.h" + +struct NonT { + NonT(int v) : value(v) {} + NonT(NonT const& o) : value(o.value) {} + int value; +}; +static_assert(!std::is_trivially_copy_constructible::value, ""); + + +struct NoCopy { + NoCopy(NoCopy const&) = delete; +}; + +struct MoveOnly { + MoveOnly(MoveOnly const&) = delete; + MoveOnly(MoveOnly&&) = default; +}; + + +struct MoveOnlyNT { + MoveOnlyNT(MoveOnlyNT const&) = delete; + MoveOnlyNT(MoveOnlyNT&&) {} +}; + + + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct MakeEmptyT { + static int alive; + MakeEmptyT() { ++alive; } + MakeEmptyT(MakeEmptyT const&) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + MakeEmptyT(MakeEmptyT &&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT const&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } + ~MakeEmptyT() { --alive; } +}; + +int MakeEmptyT::alive = 0; + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place); + try { + v = v2; + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +void test_copy_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_copy_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_constructible::value, ""); + } +} + +void test_copy_ctor_basic() +{ + { + std::variant v(std::in_place<0>, 42); + std::variant v2 = v; + assert(v2.index() == 0); + assert(std::get<0>(v2) == 42); + } + { + std::variant v(std::in_place<1>, 42); + std::variant v2 = v; + assert(v2.index() == 1); + assert(std::get<1>(v2) == 42); + } + { + std::variant v(std::in_place<0>, 42); + assert(v.index() == 0); + std::variant v2(v); + assert(v2.index() == 0); + assert(std::get<0>(v2).value == 42); + } + { + std::variant v(std::in_place<1>, 42); + assert(v.index() == 1); + std::variant v2(v); + assert(v2.index() == 1); + assert(std::get<1>(v2).value == 42); + } +} + +void test_copy_ctor_valueless_by_exception() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + V v1; makeEmpty(v1); + V const& cv1 = v1; + V v(cv1); + assert(v.valueless_by_exception()); +#endif +} + +int main() +{ + test_copy_ctor_basic(); + test_copy_ctor_valueless_by_exception(); + test_copy_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/default.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/default.pass.cpp @@ -0,0 +1,113 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// constexpr variant() noexcept(see below); + + +#include +#include +#include + +#include "test_macros.h" + +struct NonDefaultConstructible { + NonDefaultConstructible(int) {} +}; + +struct NotNoexcept { + NotNoexcept() noexcept(false) {} +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct DefaultCtorThrows { + DefaultCtorThrows() { throw 42; } +}; +#endif + +void test_default_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_default_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_default_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_default_constructible::value, ""); + } +} + +void test_default_ctor_noexcept() { + { + using V = std::variant; + static_assert(std::is_nothrow_default_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_default_constructible::value, ""); + } +} + +void test_default_ctor_throws() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + try { + V v; + assert(false); + } catch (int const& ex) { + assert(ex == 42); + } catch (...) { + assert(false); + } +#endif +} + +void test_default_ctor_basic() +{ + { + std::variant v; + assert(v.index() == 0); + assert(std::get<0>(v) == 0); + } + { + std::variant v; + assert(v.index() == 0); + assert(std::get<0>(v) == 0); + } + { + using V = std::variant; + constexpr V v; + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v) == 0, ""); + } + { + using V = std::variant; + constexpr V v; + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v) == 0, ""); + } +} + +int main() +{ + test_default_ctor_basic(); + test_default_ctor_sfinae(); + test_default_ctor_noexcept(); + test_default_ctor_throws(); +} Index: test/std/variant/variant.variant/variant.ctor/in_place_index_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/in_place_index_Args.pass.cpp @@ -0,0 +1,101 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// constexpr explicit variant(in_place_index_t, Args&&...); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +void test_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int*>::value, ""); + static_assert(!test_convertible, int*>(), ""); + } + { // args not convertible to type + using V = std::variant; + static_assert(!std::is_constructible, int*>::value, ""); + static_assert(!test_convertible, int*>(), ""); + } + { // index not in variant + using V = std::variant; + static_assert(!std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } +} + +void test_ctor_basic() +{ + { + constexpr std::variant v(std::in_place<0>, 42); + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v) == 42, ""); + } + { + constexpr std::variant v(std::in_place<1>, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + constexpr std::variant v(std::in_place<1>, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place<0>, x); + assert(v.index() == 0); + assert(std::get<0>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place<1>, x); + assert(v.index() == 1); + assert(std::get<1>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place<2>, x); + assert(v.index() == 2); + assert(std::get<2>(v) == x); + } +} + +int main() +{ + test_ctor_basic(); + test_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/in_place_index_init_list_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/in_place_index_init_list_Args.pass.cpp @@ -0,0 +1,93 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// constexpr explicit +// variant(in_place_index_t, initializer_list, Args&&...); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +struct InitList { + std::size_t size; + constexpr InitList(std::initializer_list il) : size(il.size()){} +}; + +struct InitListArg { + std::size_t size; + int value; + constexpr InitListArg(std::initializer_list il, int v) : size(il.size()), value(v) {} +}; + +void test_ctor_sfinae() { + using IL = std::initializer_list; + { // just init list + using V = std::variant; + static_assert(std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // too many arguments + using V = std::variant; + static_assert(!std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } + { // too few arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // init list and arguments + using V = std::variant; + static_assert(std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } + { // not constructible from arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } +} + +void test_ctor_basic() +{ + { + constexpr std::variant v(std::in_place<0>, {1, 2, 3}); + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v).size == 3, ""); + } + { + constexpr std::variant v(std::in_place<2>, {1, 2, 3}); + static_assert(v.index() == 2, ""); + static_assert(std::get<2>(v).size == 3, ""); + } + { + constexpr std::variant v(std::in_place<1>, {1, 2, 3, 4}, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v).size == 4, ""); + static_assert(std::get<1>(v).value == 42, ""); + } +} + +int main() +{ + test_ctor_basic(); + test_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/in_place_type_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/in_place_type_Args.pass.cpp @@ -0,0 +1,106 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// constexpr explicit variant(in_place_type_t, Args&&...); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +void test_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int*>::value, ""); + static_assert(!test_convertible, int*>(), ""); + } + { // duplicate type + using V = std::variant; + static_assert(!std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { // args not convertible to type + using V = std::variant; + static_assert(!std::is_constructible, int*>::value, ""); + static_assert(!test_convertible, int*>(), ""); + } + { // type not in variant + using V = std::variant; + static_assert(!std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } +} + +void test_ctor_basic() +{ + { + constexpr std::variant v(std::in_place, 42); + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v) == 42, ""); + } + { + constexpr std::variant v(std::in_place, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + constexpr std::variant v(std::in_place, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place, x); + assert(v.index() == 0); + assert(std::get<0>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place, x); + assert(v.index() == 1); + assert(std::get<1>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place, x); + assert(v.index() == 2); + assert(std::get<2>(v) == x); + } +} + +int main() +{ + test_ctor_basic(); + test_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/in_place_type_init_list_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/in_place_type_init_list_Args.pass.cpp @@ -0,0 +1,95 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// constexpr explicit +// variant(in_place_type_t, initializer_list, Args&&...); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +struct InitList { + std::size_t size; + constexpr InitList(std::initializer_list il) : size(il.size()){} +}; + +struct InitListArg { + std::size_t size; + int value; + constexpr InitListArg(std::initializer_list il, int v) : size(il.size()), value(v) {} +}; + +void test_ctor_sfinae() { + using IL = std::initializer_list; + { // just init list + using V = std::variant; + static_assert(std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // too many arguments + using V = std::variant; + static_assert(!std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } + { // too few arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // init list and arguments + using V = std::variant; + static_assert(std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } + { // not constructible from arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // duplicate types in variant + using V = std::variant; + static_assert(!std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } +} + +void test_ctor_basic() +{ + { + constexpr std::variant v(std::in_place, {1, 2, 3}); + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v).size == 3, ""); + } + { + constexpr std::variant v(std::in_place, {1, 2, 3, 4}, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v).size == 4, ""); + static_assert(std::get<1>(v).value == 42, ""); + } + +} + +int main() +{ + test_ctor_basic(); + test_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.ctor/move.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.ctor/move.pass.cpp @@ -0,0 +1,185 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// variant(variant&&) noexcept(see below); + + +#include +#include +#include +#include + +#include "test_macros.h" + +struct ThrowsMove { + ThrowsMove(ThrowsMove&&) noexcept(false) {} +}; + +struct NoCopy { + NoCopy(NoCopy const&) = delete; +}; + +struct MoveOnly { + int value; + MoveOnly(int v) : value(v) {} + MoveOnly(MoveOnly const&) = delete; + MoveOnly(MoveOnly&&) = default; +}; + +struct MoveOnlyNT { + int value; + MoveOnlyNT(int v) : value(v) {} + MoveOnlyNT(MoveOnlyNT const&) = delete; + MoveOnlyNT(MoveOnlyNT&& other) : value(other.value) { other.value = -1; } +}; + + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct MakeEmptyT { + static int alive; + MakeEmptyT() { ++alive; } + MakeEmptyT(MakeEmptyT const&) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + MakeEmptyT(MakeEmptyT &&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT const&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } + ~MakeEmptyT() { --alive; } +}; + +int MakeEmptyT::alive = 0; + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place); + try { + v = v2; + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +void test_move_noexcept() { + { + using V = std::variant; + static_assert(std::is_nothrow_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_nothrow_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_move_constructible::value, ""); + } +} + +void test_move_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_move_constructible::value, ""); + } +} + +void test_move_ctor_basic() +{ + { + std::variant v(std::in_place<0>, 42); + std::variant v2 = std::move(v); + assert(v2.index() == 0); + assert(std::get<0>(v2) == 42); + } + { + std::variant v(std::in_place<1>, 42); + std::variant v2 = std::move(v); + assert(v2.index() == 1); + assert(std::get<1>(v2) == 42); + } + { + std::variant v(std::in_place<0>, 42); + assert(v.index() == 0); + std::variant v2(std::move(v)); + assert(v2.index() == 0); + assert(std::get<0>(v2).value == 42); + } + { + std::variant v(std::in_place<1>, 42); + assert(v.index() == 1); + std::variant v2(std::move(v)); + assert(v2.index() == 1); + assert(std::get<1>(v2).value == 42); + } + { + std::variant v(std::in_place<0>, 42); + assert(v.index() == 0); + std::variant v2(std::move(v)); + assert(v2.index() == 0); + assert(std::get<0>(v).value == -1); + assert(std::get<0>(v2).value == 42); + } + { + std::variant v(std::in_place<1>, 42); + assert(v.index() == 1); + std::variant v2(std::move(v)); + assert(v2.index() == 1); + assert(std::get<1>(v).value == -1); + assert(std::get<1>(v2).value == 42); + } +} + +void test_move_ctor_valueless_by_exception() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + V v1; makeEmpty(v1); + V v(std::move(v1)); + assert(v.valueless_by_exception()); +#endif +} + +int main() +{ + test_move_ctor_basic(); + test_move_ctor_valueless_by_exception(); + test_move_noexcept(); + test_move_ctor_sfinae(); +} Index: test/std/variant/variant.variant/variant.dtor/dtor.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.dtor/dtor.pass.cpp @@ -0,0 +1,85 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// ~variant(); + + +#include +#include +#include + +#include "test_macros.h" + + +struct NonTDtor { + static int count; + NonTDtor() = default; + ~NonTDtor() { ++count; } +}; +int NonTDtor::count = 0; +static_assert(!std::is_trivially_destructible::value, ""); + + +struct NonTDtor1 { + static int count; + NonTDtor1() = default; + ~NonTDtor1() { ++count; } +}; +int NonTDtor1::count = 0; +static_assert(!std::is_trivially_destructible::value, ""); + +struct TDtor { + TDtor(TDtor const&) {} // non-trivial copy + ~TDtor() = default; +}; +static_assert(!std::is_trivially_copy_constructible::value, ""); +static_assert(std::is_trivially_destructible::value, ""); + +int main() +{ + { + using V = std::variant; + static_assert(std::is_trivially_destructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_destructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_trivially_destructible::value, ""); + { + V v(std::in_place<0>); + assert(NonTDtor::count == 0); + assert(NonTDtor1::count == 0); + } + assert(NonTDtor::count == 1); + assert(NonTDtor1::count == 0); + NonTDtor::count = 0; + { + V v(std::in_place<1>); + } + assert(NonTDtor::count == 0); + assert(NonTDtor1::count == 0); + { + V v(std::in_place<2>); + assert(NonTDtor::count == 0); + assert(NonTDtor1::count == 0); + } + assert(NonTDtor::count == 0); + assert(NonTDtor1::count == 1); + } +} Index: test/std/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp @@ -0,0 +1,97 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template void emplace(Args&&... args); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +template +constexpr auto test_emplace_exists_imp(int) -> decltype(std::declval().template emplace(std::declval()...), true) +{ return true; } + +template +constexpr auto test_emplace_exists_imp(long) -> bool { return false; } + +template +constexpr bool emplace_exists() { return test_emplace_exists_imp(0); } + +void test_emplace_sfinae() { + using V = std::variant; + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "too many args"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot default construct ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "not constructible from void*"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot construct void"); +} + +void test_basic() { + { + using V = std::variant; + V v(42); + v.emplace<0>(); + assert(std::get<0>(v) == 0); + v.emplace<0>(42); + assert(std::get<0>(v) == 42); + } + { + using V = std::variant; + const int x = 100; + int y = 42; + int z = 43; + V v(std::in_place<0>, -1); + // default emplace a value + v.emplace<1>(); + assert(std::get<1>(v) == 0); + // emplace a reference + v.emplace<2>(x); + assert(&std::get<2>(v) == &x); + // emplace an rvalue reference + v.emplace<3>(std::move(y)); + assert(&std::get<3>(v) == &y); + // re-emplace a new reference over the active member + v.emplace<3>(std::move(z)); + assert(&std::get<3>(v) == &z); + // emplace with multiple args + v.emplace<5>(3, 'a'); + assert(std::get<5>(v) == "aaa"); + } +} + + +int main() +{ + test_basic(); + test_emplace_sfinae(); +} Index: test/std/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp @@ -0,0 +1,79 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// void emplace(initializer_list il,Args&&... args); + + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +struct InitList { + std::size_t size; + constexpr InitList(std::initializer_list il) : size(il.size()){} +}; + +struct InitListArg { + std::size_t size; + int value; + constexpr InitListArg(std::initializer_list il, int v) : size(il.size()), value(v) {} +}; + +template +constexpr auto test_emplace_exists_imp(int) -> decltype(std::declval().template emplace(std::declval()...), true) +{ return true; } + +template +constexpr auto test_emplace_exists_imp(long) -> bool { return false; } + +template +constexpr bool emplace_exists() { return test_emplace_exists_imp(0); } + +void test_emplace_sfinae() { + using V = std::variant; + using IL = std::initializer_list; + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "args don't match"); + static_assert(!emplace_exists(), "too many args"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "args don't match"); + static_assert(!emplace_exists(), "too few args"); + static_assert(!emplace_exists(), "too many args"); +} + +void test_basic() { + using V = std::variant; + V v; + v.emplace<1>({1, 2, 3}); + assert(std::get<1>(v).size == 3); + v.emplace<2>({1, 2, 3, 4}, 42); + assert(std::get<2>(v).size == 4); + assert(std::get<2>(v).value == 42); + v.emplace<1>({1}); + assert(std::get<1>(v).size == 1); +} + +int main() +{ + test_basic(); + test_emplace_sfinae(); +} Index: test/std/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp @@ -0,0 +1,101 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template void emplace(Args&&... args); + + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +template +constexpr auto test_emplace_exists_imp(int) -> decltype(std::declval().template emplace(std::declval()...), true) +{ return true; } + +template +constexpr auto test_emplace_exists_imp(long) -> bool { return false; } + +template +constexpr bool emplace_exists() { return test_emplace_exists_imp(0); } + +void test_emplace_sfinae() { + using V = std::variant; + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "too many args"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot default construct ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "not constructible from void*"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "ambiguous"); + static_assert(!emplace_exists(), "cannot construct void"); +} + +void test_basic() { + { + using V = std::variant; + V v(42); + v.emplace(); + assert(std::get<0>(v) == 0); + v.emplace(42); + assert(std::get<0>(v) == 42); + } + { + using V = std::variant; + const int x = 100; + int y = 42; + int z = 43; + V v(std::in_place<0>, -1); + // default emplace a value + v.emplace(); + assert(std::get(v) == 0); + // emplace a reference + v.emplace(x); + assert(&std::get(v) == &x); + // emplace an rvalue reference + v.emplace(std::move(y)); + assert(&std::get(v) == &y); + // re-emplace a new reference over the active member + v.emplace(std::move(z)); + assert(&std::get(v) == &z); + // emplace with multiple args + v.emplace(3, 'a'); + assert(std::get(v) == "aaa"); + } +} + + +int main() +{ + test_basic(); + test_emplace_sfinae(); +} Index: test/std/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp @@ -0,0 +1,79 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// template +// void emplace(initializer_list il,Args&&... args); + + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +struct InitList { + std::size_t size; + constexpr InitList(std::initializer_list il) : size(il.size()){} +}; + +struct InitListArg { + std::size_t size; + int value; + constexpr InitListArg(std::initializer_list il, int v) : size(il.size()), value(v) {} +}; + +template +constexpr auto test_emplace_exists_imp(int) -> decltype(std::declval().template emplace(std::declval()...), true) +{ return true; } + +template +constexpr auto test_emplace_exists_imp(long) -> bool { return false; } + +template +constexpr bool emplace_exists() { return test_emplace_exists_imp(0); } + +void test_emplace_sfinae() { + using V = std::variant; + using IL = std::initializer_list; + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "args don't match"); + static_assert(!emplace_exists(), "too many args"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "args don't match"); + static_assert(!emplace_exists(), "too few args"); + static_assert(!emplace_exists(), "too many args"); +} + +void test_basic() { + using V = std::variant; + V v; + v.emplace({1, 2, 3}); + assert(std::get(v).size == 3); + v.emplace({1, 2, 3, 4}, 42); + assert(std::get(v).size == 4); + assert(std::get(v).value == 42); + v.emplace({1}); + assert(std::get(v).size == 1); +} + +int main() +{ + test_basic(); + test_emplace_sfinae(); +} Index: test/std/variant/variant.variant/variant.status/index.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.status/index.pass.cpp @@ -0,0 +1,55 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// constexpr size_t index() const noexcept; + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +int main() +{ + { + using V = std::variant; + constexpr V v; + static_assert(v.index() == 0, ""); + } + { + using V = std::variant; + constexpr V v(std::in_place<1>); + static_assert(v.index() == 1, ""); + } + { + using V = std::variant; + V v("abc"); + assert(v.index() == 1); + v = 42; + assert(v.index() == 0); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + V v; + assert(v.index() == 0); + makeEmpty(v); + assert(v.index() == std::variant_npos); + } +#endif +} Index: test/std/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp @@ -0,0 +1,48 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// constexpr bool valueless_by_exception() const noexcept; + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +int main() +{ + { + using V = std::variant; + constexpr V v; + static_assert(!v.valueless_by_exception(), ""); + } + { + using V = std::variant; + const V v("abc"); + assert(!v.valueless_by_exception()); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + V v; + assert(!v.valueless_by_exception()); + makeEmpty(v); + assert(v.valueless_by_exception()); + } +#endif +} Index: test/std/variant/variant.variant/variant.swap/swap.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.variant/variant.swap/swap.pass.cpp @@ -0,0 +1,556 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// + +// template class variant; + +// void swap(variant& rhs) noexcept(see below) + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" +#include "test_convertible.hpp" + +struct NotSwappable { +}; +void swap(NotSwappable&, NotSwappable&) = delete; + +struct NotCopyable { + NotCopyable() = default; + NotCopyable(NotCopyable const&) = delete; + NotCopyable& operator=(NotCopyable const&) = delete; +}; + +struct NotCopyableWithSwap { + NotCopyableWithSwap() = default; + NotCopyableWithSwap(NotCopyableWithSwap const&) = delete; + NotCopyableWithSwap& operator=(NotCopyableWithSwap const&) = delete; +}; +void swap(NotCopyableWithSwap&, NotCopyableWithSwap) {} + +struct NotMoveAssignable { + NotMoveAssignable() = default; + NotMoveAssignable(NotMoveAssignable&&) = default; + NotMoveAssignable& operator=(NotMoveAssignable&&) = delete; +}; + +struct NotMoveAssignableWithSwap { + NotMoveAssignableWithSwap() = default; + NotMoveAssignableWithSwap(NotMoveAssignableWithSwap&&) = default; + NotMoveAssignableWithSwap& operator=(NotMoveAssignableWithSwap&&) = delete; +}; +void swap(NotMoveAssignableWithSwap&, NotMoveAssignableWithSwap&) noexcept {} + +template +void do_throw() {} + +template <> +void do_throw() { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw 42; +#else + std::abort(); +#endif +} + +template +struct NothrowTypeImp { + static int move_called; + static int move_assign_called; + static int swap_called; + static void reset() { move_called = move_assign_called = swap_called = 0; } + NothrowTypeImp() = default; + explicit NothrowTypeImp(int v) : value(v) {} + NothrowTypeImp(NothrowTypeImp const& o) noexcept(NT_Copy) + : value(o.value) + { assert(false); } // never called by test + NothrowTypeImp(NothrowTypeImp&& o) noexcept(NT_Move) + : value(o.value) + { ++move_called; do_throw(); o.value = -1; } + NothrowTypeImp& operator=(NothrowTypeImp const&) noexcept(NT_CopyAssign) + { assert(false); return *this;} // never called by the tests + NothrowTypeImp& operator=(NothrowTypeImp&& o) noexcept(NT_MoveAssign) { + ++move_assign_called; + do_throw(); + value = o.value; o.value = -1; + return *this; + } + int value; +}; +template +int NothrowTypeImp::move_called = 0; +template +int NothrowTypeImp::move_assign_called = 0; +template +int NothrowTypeImp::swap_called = 0; + +template +void swap(NothrowTypeImp& lhs, + NothrowTypeImp& rhs) + noexcept(NT_Swap) { + lhs.swap_called++; + do_throw(); + int tmp = lhs.value; + lhs.value = rhs.value; + rhs.value = tmp; +} + +// throwing copy, nothrow move ctor/assign, no swap provided +using NothrowMoveable = NothrowTypeImp; +// throwing copy and move assign, nothrow move ctor, no swap provided +using NothrowMoveCtor = NothrowTypeImp; +// nothrow move ctor, throwing move assignment, swap provided +using NothrowMoveCtorWithThrowingSwap = NothrowTypeImp; +// throwing move ctor, nothrow move assignment, no swap provided +using ThrowingMoveCtor = NothrowTypeImp; +// throwing special members, nothrowing swap +using ThrowingTypeWithNothrowSwap = NothrowTypeImp; +using NothrowTypeWithThrowingSwap = NothrowTypeImp; +// throwing move assign with nothrow move and nothrow swap +using ThrowingMoveAssignNothrowMoveCtorWithSwap = NothrowTypeImp; +// throwing move assign with nothrow move but no swap. +using ThrowingMoveAssignNothrowMoveCtor = NothrowTypeImp; + +struct NonThrowingNonNoexceptType { + static int move_called; + static void reset() { move_called = 0; } + NonThrowingNonNoexceptType() = default; + NonThrowingNonNoexceptType(int v) : value(v) {} + NonThrowingNonNoexceptType(NonThrowingNonNoexceptType&& o) noexcept(false) + : value(o.value) { + ++move_called; + o.value = -1; + } + NonThrowingNonNoexceptType& operator=(NonThrowingNonNoexceptType&&) noexcept(false) { + assert(false); // never called by the tests. + return *this; + } + int value; +}; +int NonThrowingNonNoexceptType::move_called = 0; + +struct ThrowsOnSecondMove { + int value; + int move_count; + ThrowsOnSecondMove(int v) : value(v), move_count(0) {} + ThrowsOnSecondMove(ThrowsOnSecondMove&& o) noexcept(false) + : value(o.value), move_count(o.move_count + 1) { + if (move_count == 2) + do_throw(); + o.value = -1; + } + ThrowsOnSecondMove& operator=(ThrowsOnSecondMove&&) { + assert(false); // not called by test + return *this; + } +}; + + +void test_swap_valueless_by_exception() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + { // both empty + V v1; makeEmpty(v1); + V v2; makeEmpty(v2); + assert(MakeEmptyT::alive == 0); + { // member swap + v1.swap(v2); + assert(v1.valueless_by_exception()); + assert(v2.valueless_by_exception()); + assert(MakeEmptyT::alive == 0); + } + { // non-member swap + swap(v1, v2); + assert(v1.valueless_by_exception()); + assert(v2.valueless_by_exception()); + assert(MakeEmptyT::alive == 0); + } + } + { // only one empty + V v1(42); + V v2; makeEmpty(v2); + { // member swap + v1.swap(v2); + assert(v1.valueless_by_exception()); + assert(std::get<0>(v2) == 42); + // swap again + v2.swap(v1); + assert(v2.valueless_by_exception()); + assert(std::get<0>(v1) == 42); + } + { // non-member swap + swap(v1, v2); + assert(v1.valueless_by_exception()); + assert(std::get<0>(v2) == 42); + // swap again + swap(v1, v2); + assert(v2.valueless_by_exception()); + assert(std::get<0>(v1) == 42); + } + } +#endif +} + +void test_swap_same_alternative() +{ + { + using T = ThrowingTypeWithNothrowSwap; + using V = std::variant; + T::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<0>, 100); + v1.swap(v2); + assert(T::swap_called == 1); + assert(std::get<0>(v1).value == 100); + assert(std::get<0>(v2).value == 42); + swap(v1, v2); + assert(T::swap_called == 2); + assert(std::get<0>(v1).value == 42); + assert(std::get<0>(v2).value == 100); + } + { + using T = NothrowMoveable; + using V = std::variant; + T::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<0>, 100); + v1.swap(v2); + assert(T::swap_called == 0); + assert(T::move_called == 1); + assert(T::move_assign_called == 2); + assert(std::get<0>(v1).value == 100); + assert(std::get<0>(v2).value == 42); + T::reset(); + swap(v1, v2); + assert(T::swap_called == 0); + assert(T::move_called == 1); + assert(T::move_assign_called == 2); + assert(std::get<0>(v1).value == 42); + assert(std::get<0>(v2).value == 100); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using T = NothrowTypeWithThrowingSwap; + using V = std::variant; + T::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<0>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T::swap_called == 1); + assert(T::move_called == 0); + assert(T::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); + assert(std::get<0>(v2).value == 100); + } + { + using T = ThrowingMoveCtor; + using V = std::variant; + T::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<0>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T::move_called == 1); // call threw + assert(T::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); // throw happend before v1 was moved from + assert(std::get<0>(v2).value == 100); + } + { + using T = ThrowingMoveAssignNothrowMoveCtor; + using V = std::variant; + T::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<0>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T::move_called == 1); + assert(T::move_assign_called == 1); // call threw and didn't complete + assert(std::get<0>(v1).value == -1); // v1 was moved from + assert(std::get<0>(v2).value == 100); + } +#endif +} + + +void test_swap_different_alternatives() +{ + { + using T = NothrowMoveCtorWithThrowingSwap; + using V = std::variant; + T::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<1>, 100); + v1.swap(v2); + assert(T::swap_called == 0); + // The libc++ implementation double copies the argument, and not + // the variant swap is called on. + assert(T::move_called == 1); + assert(T::move_assign_called == 0); + assert(std::get<1>(v1) == 100); + assert(std::get<0>(v2).value == 42); + T::reset(); + swap(v1, v2); + assert(T::swap_called == 0); + assert(T::move_called == 2); + assert(T::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); + assert(std::get<1>(v2) == 100); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using T1 = ThrowingTypeWithNothrowSwap; + using T2 = NonThrowingNonNoexceptType; + using V = std::variant; + T1::reset(); + T2::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<1>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T1::swap_called == 0); + assert(T1::move_called == 1); // throws + assert(T1::move_assign_called == 0); + assert(T2::move_called == 1); + assert(std::get<0>(v1).value == 42); + assert(v2.valueless_by_exception()); + } + { + using T1 = NonThrowingNonNoexceptType; + using T2 = ThrowingTypeWithNothrowSwap; + using V = std::variant; + T1::reset(); + T2::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<1>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T2::move_called == 1); + assert(T2::swap_called == 0); + assert(T2::move_called == 1); // throws + assert(T2::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); + assert(std::get<1>(v2).value == 100); + } + { + using T1 = ThrowsOnSecondMove; + using T2 = NonThrowingNonNoexceptType; + using V = std::variant; + T2::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<1>, 100); + v1.swap(v2); + assert(T2::move_called == 2); + assert(std::get<1>(v1).value == 100); + assert(std::get<0>(v2).value == 42); + assert(std::get<0>(v2).move_count == 1); + } + { + using T1 = NonThrowingNonNoexceptType; + using T2 = ThrowsOnSecondMove; + using V = std::variant; + T1::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<1>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) {} + assert(T1::move_called == 1); + assert(v1.valueless_by_exception()); + assert(std::get<0>(v2).value == 42); + } + { + // testing libc++ extension. If either variant stores a nothrow move + // constructible type v1.swap(v2) provides the strong exception safety + // guarentee. + using T1 = ThrowingTypeWithNothrowSwap; + using T2 = NothrowMoveable; + using V = std::variant; + T1::reset(); + T2::reset(); + V v1(std::in_place<0>, 42); + V v2(std::in_place<1>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T1::swap_called == 0); + assert(T1::move_called == 1); + assert(T1::move_assign_called == 0); + assert(T2::swap_called == 0); + assert(T2::move_called == 2); + assert(T2::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); + assert(std::get<1>(v2).value == 100); + // swap again, but call v2's swap. + T1::reset(); + T2::reset(); + try { + v2.swap(v1); + assert(false); + } catch (int) { + } + assert(T1::swap_called == 0); + assert(T1::move_called == 1); + assert(T1::move_assign_called == 0); + assert(T2::swap_called == 0); + assert(T2::move_called == 2); + assert(T2::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); + assert(std::get<1>(v2).value == 100); + } +#endif +} + +template +constexpr auto has_swap_member_imp(int) -> decltype(std::declval().swap(std::declval()), true) +{ return true; } + +template +constexpr auto has_swap_member_imp(long) -> bool { return false; } + +template +constexpr bool has_swap_member() { return has_swap_member_imp(0); } + +void test_swap_sfinae() +{ + { + // This variant type does not provide either a member or non-member swap + // but is still swappable via the generic swap algorithm, since the + // variant is move constructible and move assignable. + using V = std::variant; + static_assert(!has_swap_member()); + static_assert(std::is_swappable_v, ""); + } + { + using V = std::variant; + static_assert(!has_swap_member() && !std::is_swappable_v, ""); + } + { + using V = std::variant; + static_assert(!has_swap_member() && !std::is_swappable_v, ""); + } + { + using V = std::variant; + static_assert(!has_swap_member() && !std::is_swappable_v, ""); + } +} + +void test_swap_noexcept() +{ + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(!std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(!std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(!std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + // This variant type does not provide either a member or non-member swap + // but is still swappable via the generic swap algorithm, since the + // variant is move constructible and move assignable. + using V = std::variant; + static_assert(!has_swap_member()); + static_assert(std::is_swappable_v, ""); + static_assert(std::is_nothrow_swappable_v, ""); + V v1, v2; + swap(v1, v2); + } +} + +int main() +{ + test_swap_valueless_by_exception(); + test_swap_same_alternative(); + test_swap_different_alternatives(); + test_swap_sfinae(); + test_swap_noexcept(); +} Index: test/std/variant/variant.visit/visit.pass.cpp =================================================================== --- /dev/null +++ test/std/variant/variant.visit/visit.pass.cpp @@ -0,0 +1,313 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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, c++14 + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "type_id.h" + + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct MakeEmptyT { + MakeEmptyT() = default; + MakeEmptyT(MakeEmptyT&&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } +}; +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place); + try { + v = std::move(v2); + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + + +enum CallType : unsigned { + CT_None, + CT_NonConst = 1, + CT_Const = 2, + CT_LValue = 4, + CT_RValue = 8 +}; + +inline constexpr CallType operator|(CallType LHS, CallType RHS) { + return static_cast(static_cast(LHS) | static_cast(RHS)); +} + +struct ForwardingCallObject { + + template + bool operator()(Args&&... args) & { + set_call(CT_NonConst | CT_LValue); + return true; + } + + template + bool operator()(Args&&... args) const & { + set_call(CT_Const | CT_LValue); + return true; + } + + // Don't allow the call operator to be invoked as an rvalue. + template + bool operator()(Args&&... args) && { + set_call(CT_NonConst | CT_RValue); + return true; + } + + template + bool operator()(Args&&... args) const && { + set_call(CT_Const | CT_RValue); + return true; + } + + template + static void set_call(CallType type) { + assert(last_call_type == CT_None); + assert(last_call_args == nullptr); + last_call_type = type; + last_call_args = std::addressof(makeArgumentID()); + } + + template + static bool check_call(CallType type) { + bool result = + last_call_type == type + && last_call_args + && *last_call_args == makeArgumentID(); + last_call_type = CT_None; + last_call_args = nullptr; + return result; + } + + static CallType last_call_type; + static TypeID const* last_call_args; +}; + +CallType ForwardingCallObject::last_call_type = CT_None; +TypeID const* ForwardingCallObject::last_call_args = nullptr; + + +void test_call_operator_forwarding() +{ + using Fn = ForwardingCallObject; + Fn obj{}; + Fn const& cobj = obj; + { // test call operator forwarding - single variant, single arg + using V = std::variant; + V v(42); + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + { // test call operator forwarding - single variant, multi arg + using V = std::variant; + V v(42l); + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + { // test call operator forwarding - multi variant, multi arg + using V = std::variant; + using V2 = std::variant; + V v(42l); + V2 v2("hello"); + std::visit(obj, v, v2); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v, v2); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); + } +} + +void test_argument_forwarding() +{ + using Fn = ForwardingCallObject; + Fn obj{}; + const auto Val = CT_LValue | CT_NonConst; + { // single argument - value type + using V = std::variant; + V v(42); + V const& cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); + } + { // single argument - lvalue reference + using V = std::variant; + int x = 42; + V v(x); + V const& cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); + } + { // single argument - rvalue reference + using V = std::variant; + int x = 42; + V v(std::move(x)); + V const& cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); + } + { // multi argument - multi variant + using S = std::string const&; + using V = std::variant; + std::string const str = "hello"; + long l = 43; + V v1(42); V const& cv1 = v1; + V v2(str); V const& cv2 = v2; + V v3(std::move(l)); V const& cv3 = v3; + std::visit(obj, v1, v2, v3); + assert((Fn::check_call(Val))); + std::visit(obj, cv1, cv2, std::move(v3)); + assert((Fn::check_call(Val))); + } +} + +struct ReturnFirst { + template + constexpr int operator()(int f, Args&&...) const { + return f; + } +}; + +struct ReturnArity { + template + constexpr int operator()(Args&&...) const { + return sizeof...(Args); + } +}; + +void test_constexpr() { + constexpr ReturnFirst obj{}; + constexpr ReturnArity aobj{}; + { + using V = std::variant; + constexpr V v(42); + static_assert(std::visit(obj, v) == 42, ""); + } + { + using V = std::variant; + constexpr V v(42l); + static_assert(std::visit(obj, v) == 42, ""); + } + { + using V1 = std::variant; + using V2 = std::variant; + using V3 = std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); + } + { + using V1 = std::variant; + using V2 = std::variant; + using V3 = std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); + } +} + +void test_exceptions() { +#ifndef TEST_HAS_NO_EXCEPTIONS + ReturnArity obj{}; + auto test = [&](auto&&... args) { + try { + std::visit(obj, args...); + } catch (std::bad_variant_access const&) { + return true; + } catch (...) {} + return false; + }; + { + using V = std::variant; + V v; makeEmpty(v); + assert(test(v)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; makeEmpty(v); + V2 v2("hello"); + assert(test(v, v2)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; makeEmpty(v); + V2 v2("hello"); + assert(test(v2, v)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; makeEmpty(v); + V2 v2; makeEmpty(v2); + assert(test(v, v2)); + } +#endif +} + +int main() { + test_call_operator_forwarding(); + test_argument_forwarding(); + test_constexpr(); + test_exceptions(); +} Index: test/support/variant_test_helpers.hpp =================================================================== --- /dev/null +++ test/support/variant_test_helpers.hpp @@ -0,0 +1,75 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 SUPPORT_VARIANT_TEST_HELPERS_HPP +#define SUPPORT_VARIANT_TEST_HELPERS_HPP + +#include "test_macros.h" + +#if TEST_STD_VER <= 14 +#error This file requires C++17 +#endif + + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct CopyThrows { + CopyThrows() = default; + CopyThrows(CopyThrows const&) { throw 42; } + CopyThrows& operator=(CopyThrows const&) { throw 42; } +}; + +struct MoveThrows { + static int alive; + MoveThrows() { ++alive; } + MoveThrows(MoveThrows const&) {++alive;} + MoveThrows(MoveThrows&&) { throw 42; } + MoveThrows& operator=(MoveThrows const&) { return *this; } + MoveThrows& operator=(MoveThrows&&) { throw 42; } + ~MoveThrows() { --alive; } +}; + +int MoveThrows::alive = 0; + +struct MakeEmptyT { + static int alive; + MakeEmptyT() { ++alive; } + MakeEmptyT(MakeEmptyT const&) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + MakeEmptyT(MakeEmptyT &&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT const&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } + ~MakeEmptyT() { --alive; } +}; +static_assert(std::is_swappable_v, ""); // required for test + +int MakeEmptyT::alive = 0; + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place); + try { + v = v2; + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + + +#endif // SUPPORT_VARIANT_TEST_HELPERS_HPP Index: utils/google-benchmark/AUTHORS =================================================================== --- utils/google-benchmark/AUTHORS +++ utils/google-benchmark/AUTHORS @@ -13,6 +13,7 @@ Christopher Seymour David Coeurjolly Dominic Hamon +Eric Fiselier Eugene Zhuk Evgeny Safronov Felix Homann Index: utils/google-benchmark/README.md =================================================================== --- utils/google-benchmark/README.md +++ utils/google-benchmark/README.md @@ -40,13 +40,13 @@ ```c++ static void BM_memcpy(benchmark::State& state) { - char* src = new char[state.range_x()]; - char* dst = new char[state.range_x()]; - memset(src, 'x', state.range_x()); + char* src = new char[state.range(0)]; + char* dst = new char[state.range(0)]; + memset(src, 'x', state.range(0)); while (state.KeepRunning()) - memcpy(dst, src, state.range_x()); + memcpy(dst, src, state.range(0)); state.SetBytesProcessed(int64_t(state.iterations()) * - int64_t(state.range_x())); + int64_t(state.range(0))); delete[] src; delete[] dst; } @@ -70,7 +70,7 @@ ``` Now arguments generated are [ 8, 16, 32, 64, 128, 256, 512, 1024, 2k, 4k, 8k ]. -You might have a benchmark that depends on two inputs. For example, the +You might have a benchmark that depends on two or more inputs. For example, the following code defines a family of benchmarks for measuring the speed of set insertion. @@ -78,21 +78,21 @@ static void BM_SetInsert(benchmark::State& state) { while (state.KeepRunning()) { state.PauseTiming(); - std::set data = ConstructRandomSet(state.range_x()); + std::set data = ConstructRandomSet(state.range(0)); state.ResumeTiming(); - for (int j = 0; j < state.range_y(); ++j) + for (int j = 0; j < state.range(1); ++j) data.insert(RandomNumber()); } } BENCHMARK(BM_SetInsert) - ->ArgPair(1<<10, 1) - ->ArgPair(1<<10, 8) - ->ArgPair(1<<10, 64) - ->ArgPair(1<<10, 512) - ->ArgPair(8<<10, 1) - ->ArgPair(8<<10, 8) - ->ArgPair(8<<10, 64) - ->ArgPair(8<<10, 512); + ->Args({1<<10, 1}) + ->Args({1<<10, 8}) + ->Args({1<<10, 64}) + ->Args({1<<10, 512}) + ->Args({8<<10, 1}) + ->Args({8<<10, 8}) + ->Args({8<<10, 64}) + ->Args({8<<10, 512}); ``` The preceding code is quite repetitive, and can be replaced with the following @@ -101,7 +101,7 @@ pair. ```c++ -BENCHMARK(BM_SetInsert)->RangePair(1<<10, 8<<10, 1, 512); +BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {1, 512}}); ``` For more complex patterns of inputs, passing a custom function to `Apply` allows @@ -113,7 +113,7 @@ static void CustomArguments(benchmark::internal::Benchmark* b) { for (int i = 0; i <= 10; ++i) for (int j = 32; j <= 1024*1024; j *= 8) - b->ArgPair(i, j); + b->Args({i, j}); } BENCHMARK(BM_SetInsert)->Apply(CustomArguments); ``` @@ -125,12 +125,12 @@ ```c++ static void BM_StringCompare(benchmark::State& state) { - std::string s1(state.range_x(), '-'); - std::string s2(state.range_x(), '-'); + std::string s1(state.range(0), '-'); + std::string s2(state.range(0), '-'); while (state.KeepRunning()) { benchmark::DoNotOptimize(s1.compare(s2)); } - state.SetComplexityN(state.range_x()); + state.SetComplexityN(state.range(0)); } BENCHMARK(BM_StringCompare) ->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity(benchmark::oN); @@ -162,14 +162,14 @@ Q q; typename Q::value_type v; while (state.KeepRunning()) { - for (int i = state.range_x(); i--; ) + for (int i = state.range(0); i--; ) q.push(v); - for (int e = state.range_x(); e--; ) + for (int e = state.range(0); e--; ) q.Wait(&v); } // actually messages, not bytes: state.SetBytesProcessed( - static_cast(state.iterations())*state.range_x()); + static_cast(state.iterations())*state.range(0)); } BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue)->Range(1<<0, 1<<10); ``` @@ -206,6 +206,34 @@ Note that elements of `...args` may refer to global variables. Users should avoid modifying global state inside of a benchmark. +## Using RegisterBenchmark(name, fn, args...) + +The `RegisterBenchmark(name, func, args...)` function provides an alternative +way to create and register benchmarks. +`RegisterBenchmark(name, func, args...)` creates, registers, and returns a +pointer to a new benchmark with the specified `name` that invokes +`func(st, args...)` where `st` is a `benchmark::State` object. + +Unlike the `BENCHMARK` registration macros, which can only be used at the global +scope, the `RegisterBenchmark` can be called anywhere. This allows for +benchmark tests to be registered programmatically. + +Additionally `RegisterBenchmark` allows any callable object to be registered +as a benchmark. Including capturing lambdas and function objects. This +allows the creation + +For Example: +```c++ +auto BM_test = [](benchmark::State& st, auto Inputs) { /* ... */ }; + +int main(int argc, char** argv) { + for (auto& test_input : { /* ... */ }) + benchmark::RegisterBenchmark(test_input.name(), BM_test, test_input); + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); +} +``` + ### Multithreaded benchmarks In a multithreaded test (benchmark invoked by multiple threads simultaneously), it is guaranteed that none of the threads will start until all have called @@ -256,7 +284,7 @@ ```c++ static void BM_ManualTiming(benchmark::State& state) { - int microseconds = state.range_x(); + int microseconds = state.range(0); std::chrono::duration sleep_duration { static_cast(microseconds) }; @@ -427,10 +455,10 @@ ## Output Formats The library supports multiple output formats. Use the -`--benchmark_format=` flag to set the format type. `tabular` is -the default format. +`--benchmark_format=` flag to set the format type. `console` +is the default format. -The Tabular format is intended to be a human readable format. By default +The Console format is intended to be a human readable format. By default the format generates color output. Context is output on stderr and the tabular data on stdout. Example tabular output looks like: ``` @@ -493,6 +521,12 @@ "BM_SetInsert/1024/10",106365,17238.4,8421.53,4.74973e+06,1.18743e+06, ``` +## Output Files +The library supports writing the output of the benchmark to a file specified +by `--benchmark_out=`. The format of the output can be specified +using `--benchmark_out_format={json|console|csv}`. Specifying +`--benchmark_out` does not suppress the console output. + ## Debug vs Release By default, benchmark builds as a debug library. You will see a warning in the output when this is the case. To build it as a release library instead, use: @@ -507,4 +541,22 @@ ``` ## Linking against the library -When using gcc, it is necessary to link against pthread to avoid runtime exceptions. This is due to how gcc implements std::thread. See [issue #67](https://github.com/google/benchmark/issues/67) for more details. +When using gcc, it is necessary to link against pthread to avoid runtime exceptions. +This is due to how gcc implements std::thread. +See [issue #67](https://github.com/google/benchmark/issues/67) for more details. + +## Compiler Support + +Google Benchmark uses C++11 when building the library. As such we require +a modern C++ toolchain, both compiler and standard library. + +The following minimum versions are strongly recommended build the library: + +* GCC 4.8 +* Clang 3.4 +* Visual Studio 2013 + +Anything older *may* work. + +Note: Using the library and its headers in C++03 is supported. C++11 is only +required to build the library. Index: utils/google-benchmark/include/benchmark/benchmark_api.h =================================================================== --- utils/google-benchmark/include/benchmark/benchmark_api.h +++ utils/google-benchmark/include/benchmark/benchmark_api.h @@ -38,12 +38,12 @@ // of memcpy() calls of different lengths: static void BM_memcpy(benchmark::State& state) { - char* src = new char[state.range_x()]; char* dst = new char[state.range_x()]; - memset(src, 'x', state.range_x()); + char* src = new char[state.range(0)]; char* dst = new char[state.range(0)]; + memset(src, 'x', state.range(0)); while (state.KeepRunning()) - memcpy(dst, src, state.range_x()); + memcpy(dst, src, state.range(0)); state.SetBytesProcessed(int64_t(state.iterations()) * - int64_t(state.range_x())); + int64_t(state.range(0))); delete[] src; delete[] dst; } BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10); @@ -60,27 +60,27 @@ static void BM_SetInsert(benchmark::State& state) { while (state.KeepRunning()) { state.PauseTiming(); - set data = ConstructRandomSet(state.range_x()); + set data = ConstructRandomSet(state.range(0)); state.ResumeTiming(); - for (int j = 0; j < state.range_y(); ++j) + for (int j = 0; j < state.range(1); ++j) data.insert(RandomNumber()); } } BENCHMARK(BM_SetInsert) - ->ArgPair(1<<10, 1) - ->ArgPair(1<<10, 8) - ->ArgPair(1<<10, 64) - ->ArgPair(1<<10, 512) - ->ArgPair(8<<10, 1) - ->ArgPair(8<<10, 8) - ->ArgPair(8<<10, 64) - ->ArgPair(8<<10, 512); + ->Args({1<<10, 1}) + ->Args({1<<10, 8}) + ->Args({1<<10, 64}) + ->Args({1<<10, 512}) + ->Args({8<<10, 1}) + ->Args({8<<10, 8}) + ->Args({8<<10, 64}) + ->Args({8<<10, 512}); // The preceding code is quite repetitive, and can be replaced with // the following short-hand. The following macro will pick a few // appropriate arguments in the product of the two specified ranges // and will generate a microbenchmark for each such pair. -BENCHMARK(BM_SetInsert)->RangePair(1<<10, 8<<10, 1, 512); +BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {1, 512}}); // For more complex patterns of inputs, passing a custom function // to Apply allows programmatic specification of an @@ -90,7 +90,7 @@ static void CustomArguments(benchmark::internal::Benchmark* b) { for (int i = 0; i <= 10; ++i) for (int j = 32; j <= 1024*1024; j *= 8) - b->ArgPair(i, j); + b->Args({i, j}); } BENCHMARK(BM_SetInsert)->Apply(CustomArguments); @@ -101,14 +101,14 @@ Q q; typename Q::value_type v; while (state.KeepRunning()) { - for (int i = state.range_x(); i--; ) + for (int i = state.range(0); i--; ) q.push(v); - for (int e = state.range_x(); e--; ) + for (int e = state.range(0); e--; ) q.Wait(&v); } // actually messages, not bytes: state.SetBytesProcessed( - static_cast(state.iterations())*state.range_x()); + static_cast(state.iterations())*state.range(0)); } BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue)->Range(1<<0, 1<<10); @@ -153,8 +153,15 @@ #include #include +#include + #include "macros.h" +#if defined(BENCHMARK_HAS_CXX11) +#include +#include +#endif + namespace benchmark { class BenchmarkReporter; @@ -165,11 +172,16 @@ // of each matching benchmark. Otherwise run each matching benchmark and // report the results. // -// The second overload reports the results using the specified 'reporter'. +// The second and third overload use the specified 'console_reporter' and +// 'file_reporter' respectively. 'file_reporter' will write to the file specified +// by '--benchmark_output'. If '--benchmark_output' is not given the +// 'file_reporter' is ignored. // // RETURNS: The number of matching benchmarks. size_t RunSpecifiedBenchmarks(); -size_t RunSpecifiedBenchmarks(BenchmarkReporter* reporter); +size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter); +size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter, + BenchmarkReporter* file_reporter); // If this routine is called, peak memory allocation past this point in the @@ -258,7 +270,7 @@ // benchmark to use. class State { public: - State(size_t max_iters, bool has_x, int x, bool has_y, int y, + State(size_t max_iters, const std::vector& ranges, int thread_i, int n_threads); // Returns true if the benchmark should continue through another iteration. @@ -367,7 +379,7 @@ } BENCHMARK_ALWAYS_INLINE - size_t complexity_length_n() { + int complexity_length_n() { return complexity_n_; } @@ -413,17 +425,9 @@ // Range arguments for this run. CHECKs if the argument has been set. BENCHMARK_ALWAYS_INLINE - int range_x() const { - assert(has_range_x_); - ((void)has_range_x_); // Prevent unused warning. - return range_x_; - } - - BENCHMARK_ALWAYS_INLINE - int range_y() const { - assert(has_range_y_); - ((void)has_range_y_); // Prevent unused warning. - return range_y_; + int range(std::size_t pos) const { + assert(range_.size() > pos); + return range_[pos]; } BENCHMARK_ALWAYS_INLINE @@ -434,11 +438,7 @@ bool finished_; size_t total_iterations_; - bool has_range_x_; - int range_x_; - - bool has_range_y_; - int range_y_; + std::vector range_; size_t bytes_processed_; size_t items_processed_; @@ -489,24 +489,22 @@ // REQUIRES: The function passed to the constructor must accept an arg1. Benchmark* Range(int start, int limit); - // Run this benchmark once for every value in the range [start..limit] + // Run this benchmark once for all values in the range [start..limit] with specific step // REQUIRES: The function passed to the constructor must accept an arg1. - Benchmark* DenseRange(int start, int limit); + Benchmark* DenseRange(int start, int limit, int step = 1); - // Run this benchmark once with "x,y" as the extra arguments passed + // Run this benchmark once with "args" as the extra arguments passed // to the function. - // REQUIRES: The function passed to the constructor must accept arg1,arg2. - Benchmark* ArgPair(int x, int y); + // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... + Benchmark* Args(const std::vector& args); - // Pick a set of values A from the range [lo1..hi1] and a set - // of values B from the range [lo2..hi2]. Run the benchmark for - // every pair of values in the cartesian product of A and B - // (i.e., for all combinations of the values in A and B). - // REQUIRES: The function passed to the constructor must accept arg1,arg2. - Benchmark* RangePair(int lo1, int hi1, int lo2, int hi2); + // Run this benchmark once for a number of values picked from the + // ranges [start..limit]. (starts and limits are always picked.) + // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... + Benchmark* Ranges(const std::vector >& ranges); // Pass this benchmark object to *func, which can customize - // the benchmark by calling various methods like Arg, ArgPair, + // the benchmark by calling various methods like Arg, Args, // Threads, etc. Benchmark* Apply(void (*func)(Benchmark* benchmark)); @@ -587,6 +585,20 @@ Benchmark& operator=(Benchmark const&); }; +} // namespace internal + +// Create and register a benchmark with the specified 'name' that invokes +// the specified functor 'fn'. +// +// RETURNS: A pointer to the registered benchmark. +internal::Benchmark* RegisterBenchmark(const char* name, internal::Function* fn); + +#if defined(BENCHMARK_HAS_CXX11) +template +internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn); +#endif + +namespace internal { // The class used to hold all Benchmarks created from static function. // (ie those created using the BENCHMARK(...) macros. class FunctionBenchmark : public Benchmark { @@ -600,8 +612,57 @@ Function* func_; }; +#ifdef BENCHMARK_HAS_CXX11 +template +class LambdaBenchmark : public Benchmark { +public: + virtual void Run(State& st) { lambda_(st); } + +private: + template + LambdaBenchmark(const char* name, OLambda&& lam) + : Benchmark(name), lambda_(std::forward(lam)) {} + + LambdaBenchmark(LambdaBenchmark const&) = delete; + +private: + template + friend Benchmark* ::benchmark::RegisterBenchmark(const char*, Lam&&); + + Lambda lambda_; +}; +#endif + } // end namespace internal +inline internal::Benchmark* +RegisterBenchmark(const char* name, internal::Function* fn) { + return internal::RegisterBenchmarkInternal( + ::new internal::FunctionBenchmark(name, fn)); +} + +#ifdef BENCHMARK_HAS_CXX11 +template +internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn) { + using BenchType = internal::LambdaBenchmark::type>; + return internal::RegisterBenchmarkInternal( + ::new BenchType(name, std::forward(fn))); +} +#endif + +#if defined(BENCHMARK_HAS_CXX11) && \ + (!defined(BENCHMARK_GCC_VERSION) || BENCHMARK_GCC_VERSION >= 409) +template +internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn, + Args&&... args) { + return benchmark::RegisterBenchmark(name, + [=](benchmark::State& st) { fn(st, args...); }); +} +#else +#define BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK +#endif + + // The base class for all fixture tests. class Fixture: public internal::Benchmark { public: @@ -652,11 +713,11 @@ // Old-style macros #define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) -#define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->ArgPair((a1), (a2)) +#define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->Args({(a1), (a2)}) #define BENCHMARK_WITH_UNIT(n, t) BENCHMARK(n)->Unit((t)) #define BENCHMARK_RANGE(n, lo, hi) BENCHMARK(n)->Range((lo), (hi)) #define BENCHMARK_RANGE2(n, l1, h1, l2, h2) \ - BENCHMARK(n)->RangePair((l1), (h1), (l2), (h2)) + BENCHMARK(n)->RangePair({{(l1), (h1)}, {(l2), (h2)}}) #if __cplusplus >= 201103L Index: utils/google-benchmark/include/benchmark/macros.h =================================================================== --- utils/google-benchmark/include/benchmark/macros.h +++ utils/google-benchmark/include/benchmark/macros.h @@ -14,7 +14,11 @@ #ifndef BENCHMARK_MACROS_H_ #define BENCHMARK_MACROS_H_ -#if __cplusplus < 201103L +#if __cplusplus >= 201103L +#define BENCHMARK_HAS_CXX11 +#endif + +#ifndef BENCHMARK_HAS_CXX11 # define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ TypeName& operator=(const TypeName&) @@ -53,4 +57,8 @@ # define BENCHMARK_BUILTIN_EXPECT(x, y) x #endif +#if defined(__GNUC__) && !defined(__clang__) +#define BENCHMARK_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#endif + #endif // BENCHMARK_MACROS_H_ Index: utils/google-benchmark/include/benchmark/reporter.h =================================================================== --- utils/google-benchmark/include/benchmark/reporter.h +++ utils/google-benchmark/include/benchmark/reporter.h @@ -156,14 +156,23 @@ // Simple reporter that outputs benchmark data to the console. This is the // default reporter used by RunSpecifiedBenchmarks(). class ConsoleReporter : public BenchmarkReporter { - public: +public: + enum OutputOptions { + OO_None, + OO_Color + }; + explicit ConsoleReporter(OutputOptions color_output = OO_Color) + : color_output_(color_output == OO_Color) {} + virtual bool ReportContext(const Context& context); virtual void ReportRuns(const std::vector& reports); - protected: +protected: virtual void PrintRunData(const Run& report); - size_t name_field_width_; + +private: + bool color_output_; }; class JSONReporter : public BenchmarkReporter { Index: utils/google-benchmark/src/benchmark.cc =================================================================== --- utils/google-benchmark/src/benchmark.cc +++ utils/google-benchmark/src/benchmark.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -69,6 +70,12 @@ "The format to use for console output. Valid values are " "'console', 'json', or 'csv'."); +DEFINE_string(benchmark_out_format, "json", + "The format to use for file output. Valid values are " + "'console', 'json', or 'csv'."); + +DEFINE_string(benchmark_out, "", "The file to write additonal output to"); + DEFINE_bool(color_print, true, "Enables colorized logging."); DEFINE_int32(v, 0, "The level of verbose logging to output"); @@ -306,23 +313,20 @@ // Information kept per benchmark we may want to run struct Benchmark::Instance { - std::string name; - Benchmark* benchmark; - bool has_arg1; - int arg1; - bool has_arg2; - int arg2; - TimeUnit time_unit; - int range_multiplier; - bool use_real_time; - bool use_manual_time; - BigO complexity; - BigOFunc* complexity_lambda; - bool last_benchmark_instance; - int repetitions; - double min_time; - int threads; // Number of concurrent threads to use - bool multithreaded; // Is benchmark multi-threaded? + std::string name; + Benchmark* benchmark; + std::vector arg; + TimeUnit time_unit; + int range_multiplier; + bool use_real_time; + bool use_manual_time; + BigO complexity; + BigOFunc* complexity_lambda; + bool last_benchmark_instance; + int repetitions; + double min_time; + int threads; // Number of concurrent threads to use + bool multithreaded; // Is benchmark multi-threaded? }; // Class for managing registered benchmarks. Note that each registered @@ -354,9 +358,9 @@ void Arg(int x); void Unit(TimeUnit unit); void Range(int start, int limit); - void DenseRange(int start, int limit); - void ArgPair(int start, int limit); - void RangePair(int lo1, int hi1, int lo2, int hi2); + void DenseRange(int start, int limit, int step = 1); + void Args(const std::vector& args); + void Ranges(const std::vector>& ranges); void RangeMultiplier(int multiplier); void MinTime(double n); void Repetitions(int n); @@ -371,12 +375,13 @@ static void AddRange(std::vector* dst, int lo, int hi, int mult); + int ArgsCnt() const { return args_.empty() ? -1 : static_cast(args_.front().size()); } + private: friend class BenchmarkFamilies; std::string name_; - int arg_count_; - std::vector< std::pair > args_; // Args for all benchmark runs + std::vector< std::vector > args_; // Args for all benchmark runs TimeUnit time_unit_; int range_multiplier_; double min_time_; @@ -424,10 +429,10 @@ if (!bench_family) continue; BenchmarkImp* family = bench_family->imp_; - if (family->arg_count_ == -1) { - family->arg_count_ = 0; - family->args_.emplace_back(-1, -1); + if (family->ArgsCnt() == -1) { + family->Args({}); } + for (auto const& args : family->args_) { const std::vector* thread_counts = (family->thread_counts_.empty() @@ -438,10 +443,7 @@ Benchmark::Instance instance; instance.name = family->name_; instance.benchmark = bench_family.get(); - instance.has_arg1 = family->arg_count_ >= 1; - instance.arg1 = args.first; - instance.has_arg2 = family->arg_count_ == 2; - instance.arg2 = args.second; + instance.arg = args; instance.time_unit = family->time_unit_; instance.range_multiplier = family->range_multiplier_; instance.min_time = family->min_time_; @@ -454,12 +456,10 @@ instance.multithreaded = !(family->thread_counts_.empty()); // Add arguments to instance name - if (family->arg_count_ >= 1) { - AppendHumanReadable(instance.arg1, &instance.name); - } - if (family->arg_count_ >= 2) { - AppendHumanReadable(instance.arg2, &instance.name); + for (auto const& arg : args) { + AppendHumanReadable(arg, &instance.name); } + if (!IsZero(family->min_time_)) { instance.name += StringPrintF("/min_time:%0.3f", family->min_time_); } @@ -488,7 +488,7 @@ } BenchmarkImp::BenchmarkImp(const char* name) - : name_(name), arg_count_(-1), time_unit_(kNanosecond), + : name_(name), time_unit_(kNanosecond), range_multiplier_(kRangeMultiplier), min_time_(0.0), repetitions_(0), use_real_time_(false), use_manual_time_(false), complexity_(oNone) { @@ -498,9 +498,8 @@ } void BenchmarkImp::Arg(int x) { - CHECK(arg_count_ == -1 || arg_count_ == 1); - arg_count_ = 1; - args_.emplace_back(x, -1); + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); + args_.push_back({x}); } void BenchmarkImp::Unit(TimeUnit unit) { @@ -508,42 +507,54 @@ } void BenchmarkImp::Range(int start, int limit) { - CHECK(arg_count_ == -1 || arg_count_ == 1); - arg_count_ = 1; + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); std::vector arglist; AddRange(&arglist, start, limit, range_multiplier_); for (int i : arglist) { - args_.emplace_back(i, -1); + args_.push_back({i}); } } -void BenchmarkImp::DenseRange(int start, int limit) { - CHECK(arg_count_ == -1 || arg_count_ == 1); - arg_count_ = 1; +void BenchmarkImp::DenseRange(int start, int limit, int step) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); CHECK_GE(start, 0); CHECK_LE(start, limit); - for (int arg = start; arg <= limit; arg++) { - args_.emplace_back(arg, -1); + for (int arg = start; arg <= limit; arg+= step) { + args_.push_back({arg}); } } -void BenchmarkImp::ArgPair(int x, int y) { - CHECK(arg_count_ == -1 || arg_count_ == 2); - arg_count_ = 2; - args_.emplace_back(x, y); +void BenchmarkImp::Args(const std::vector& args) +{ + args_.push_back(args); } -void BenchmarkImp::RangePair(int lo1, int hi1, int lo2, int hi2) { - CHECK(arg_count_ == -1 || arg_count_ == 2); - arg_count_ = 2; - std::vector arglist1, arglist2; - AddRange(&arglist1, lo1, hi1, range_multiplier_); - AddRange(&arglist2, lo2, hi2, range_multiplier_); +void BenchmarkImp::Ranges(const std::vector>& ranges) { + std::vector> arglists(ranges.size()); + int total = 1; + for (std::size_t i = 0; i < ranges.size(); i++) { + AddRange(&arglists[i], ranges[i].first, ranges[i].second, range_multiplier_); + total *= arglists[i].size(); + } + + std::vector ctr(total, 0); - for (int i : arglist1) { - for (int j : arglist2) { - args_.emplace_back(i, j); + for (int i = 0; i < total; i++) { + std::vector tmp; + + for (std::size_t j = 0; j < arglists.size(); j++) { + tmp.push_back(arglists[j][ctr[j]]); + } + + args_.push_back(tmp); + + for (std::size_t j = 0; j < arglists.size(); j++) { + if (ctr[j] + 1 < arglists[j].size()) { + ++ctr[j]; + break; + } + ctr[j] = 0; } } } @@ -641,6 +652,7 @@ } Benchmark* Benchmark::Arg(int x) { + CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == 1); imp_->Arg(x); return this; } @@ -651,22 +663,27 @@ } Benchmark* Benchmark::Range(int start, int limit) { + CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == 1); imp_->Range(start, limit); return this; } -Benchmark* Benchmark::DenseRange(int start, int limit) { - imp_->DenseRange(start, limit); +Benchmark* Benchmark::Ranges(const std::vector>& ranges) +{ + CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == static_cast(ranges.size())); + imp_->Ranges(ranges); return this; } -Benchmark* Benchmark::ArgPair(int x, int y) { - imp_->ArgPair(x, y); +Benchmark* Benchmark::DenseRange(int start, int limit, int step) { + CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == 1); + imp_->DenseRange(start, limit, step); return this; } -Benchmark* Benchmark::RangePair(int lo1, int hi1, int lo2, int hi2) { - imp_->RangePair(lo1, hi1, lo2, hi2); +Benchmark* Benchmark::Args(const std::vector& args) { + CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == static_cast(args.size())); + imp_->Args(args); return this; } @@ -744,7 +761,7 @@ void RunInThread(const benchmark::internal::Benchmark::Instance* b, size_t iters, int thread_id, ThreadStats* total) EXCLUDES(GetBenchmarkLock()) { - State st(iters, b->has_arg1, b->arg1, b->has_arg2, b->arg2, thread_id, b->threads); + State st(iters, b->arg, thread_id, b->threads); b->benchmark->Run(st); CHECK(st.iterations() == st.max_iterations) << "Benchmark returned before State::KeepRunning() returned false!"; @@ -758,14 +775,13 @@ timer_manager->Finalize(); } -void RunBenchmark(const benchmark::internal::Benchmark::Instance& b, - BenchmarkReporter* br, - std::vector& complexity_reports) +std::vector +RunBenchmark(const benchmark::internal::Benchmark::Instance& b, + std::vector* complexity_reports) EXCLUDES(GetBenchmarkLock()) { + std::vector reports; // return value size_t iters = 1; - std::vector reports; - std::vector pool; if (b.multithreaded) pool.resize(b.threads); @@ -872,7 +888,7 @@ report.complexity = b.complexity; report.complexity_lambda = b.complexity_lambda; if(report.complexity != oNone) - complexity_reports.push_back(report); + complexity_reports->push_back(report); } reports.push_back(report); @@ -903,27 +919,26 @@ additional_run_stats.end()); if((b.complexity != oNone) && b.last_benchmark_instance) { - additional_run_stats = ComputeBigO(complexity_reports); + additional_run_stats = ComputeBigO(*complexity_reports); reports.insert(reports.end(), additional_run_stats.begin(), additional_run_stats.end()); - complexity_reports.clear(); + complexity_reports->clear(); } - br->ReportRuns(reports); - if (b.multithreaded) { for (std::thread& thread : pool) thread.join(); } + + return reports; } } // namespace -State::State(size_t max_iters, bool has_x, int x, bool has_y, int y, +State::State(size_t max_iters, const std::vector& ranges, int thread_i, int n_threads) : started_(false), finished_(false), total_iterations_(0), - has_range_x_(has_x), range_x_(x), - has_range_y_(has_y), range_y_(y), + range_(ranges), bytes_processed_(0), items_processed_(0), complexity_n_(0), error_occurred_(false), @@ -975,8 +990,10 @@ namespace { void RunMatchingBenchmarks(const std::vector& benchmarks, - BenchmarkReporter* reporter) { - CHECK(reporter != nullptr); + BenchmarkReporter* console_reporter, + BenchmarkReporter* file_reporter) { + // Note the file_reporter can be null. + CHECK(console_reporter != nullptr); // Determine the width of the name field using a minimum width of 10. bool has_repetitions = FLAGS_benchmark_repetitions > 1; @@ -1000,23 +1017,30 @@ // Keep track of runing times of all instances of current benchmark std::vector complexity_reports; - if (reporter->ReportContext(context)) { + if (console_reporter->ReportContext(context) + && (!file_reporter || file_reporter->ReportContext(context))) { for (const auto& benchmark : benchmarks) { - RunBenchmark(benchmark, reporter, complexity_reports); + std::vector reports = + RunBenchmark(benchmark, &complexity_reports); + console_reporter->ReportRuns(reports); + if (file_reporter) file_reporter->ReportRuns(reports); } } + console_reporter->Finalize(); + if (file_reporter) file_reporter->Finalize(); } -std::unique_ptr GetDefaultReporter() { +std::unique_ptr +CreateReporter(std::string const& name, ConsoleReporter::OutputOptions allow_color) { typedef std::unique_ptr PtrType; - if (FLAGS_benchmark_format == "console") { - return PtrType(new ConsoleReporter); - } else if (FLAGS_benchmark_format == "json") { + if (name == "console") { + return PtrType(new ConsoleReporter(allow_color)); + } else if (name == "json") { return PtrType(new JSONReporter); - } else if (FLAGS_benchmark_format == "csv") { + } else if (name == "csv") { return PtrType(new CSVReporter); } else { - std::cerr << "Unexpected format: '" << FLAGS_benchmark_format << "'\n"; + std::cerr << "Unexpected format: '" << name << "'\n"; std::exit(1); } } @@ -1025,10 +1049,17 @@ } // end namespace internal size_t RunSpecifiedBenchmarks() { - return RunSpecifiedBenchmarks(nullptr); + return RunSpecifiedBenchmarks(nullptr, nullptr); +} + + +size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter) { + return RunSpecifiedBenchmarks(console_reporter, nullptr); } -size_t RunSpecifiedBenchmarks(BenchmarkReporter* reporter) { + +size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter, + BenchmarkReporter* file_reporter) { std::string spec = FLAGS_benchmark_filter; if (spec.empty() || spec == "all") spec = "."; // Regexp that matches all benchmarks @@ -1041,13 +1072,38 @@ for (auto const& benchmark : benchmarks) std::cout << benchmark.name << "\n"; } else { - std::unique_ptr default_reporter; - if (!reporter) { - default_reporter = internal::GetDefaultReporter(); - reporter = default_reporter.get(); + // Setup the reporters + std::ofstream output_file; + std::unique_ptr default_console_reporter; + std::unique_ptr default_file_reporter; + if (!console_reporter) { + auto output_opts = FLAGS_color_print ? ConsoleReporter::OO_Color + : ConsoleReporter::OO_None; + default_console_reporter = internal::CreateReporter( + FLAGS_benchmark_format, output_opts); + console_reporter = default_console_reporter.get(); } - internal::RunMatchingBenchmarks(benchmarks, reporter); - reporter->Finalize(); + std::string const& fname = FLAGS_benchmark_out; + if (fname == "" && file_reporter) { + std::cerr << "A custom file reporter was provided but " + "--benchmark_out= was not specified." << std::endl; + std::exit(1); + } + if (fname != "") { + output_file.open(fname); + if (!output_file.is_open()) { + std::cerr << "invalid file name: '" << fname << std::endl; + std::exit(1); + } + if (!file_reporter) { + default_file_reporter = internal::CreateReporter( + FLAGS_benchmark_out_format, ConsoleReporter::OO_None); + file_reporter = default_file_reporter.get(); + } + file_reporter->SetOutputStream(&output_file); + file_reporter->SetErrorStream(&output_file); + } + internal::RunMatchingBenchmarks(benchmarks, console_reporter, file_reporter); } return benchmarks.size(); } @@ -1062,6 +1118,8 @@ " [--benchmark_min_time=]\n" " [--benchmark_repetitions=]\n" " [--benchmark_format=]\n" + " [--benchmark_out=]\n" + " [--benchmark_out_format=]\n" " [--color_print={true|false}]\n" " [--v=]\n"); exit(0); @@ -1081,6 +1139,10 @@ &FLAGS_benchmark_repetitions) || ParseStringFlag(argv[i], "benchmark_format", &FLAGS_benchmark_format) || + ParseStringFlag(argv[i], "benchmark_out", + &FLAGS_benchmark_out) || + ParseStringFlag(argv[i], "benchmark_out_format", + &FLAGS_benchmark_out_format) || ParseBoolFlag(argv[i], "color_print", &FLAGS_color_print) || ParseInt32Flag(argv[i], "v", &FLAGS_v)) { @@ -1092,10 +1154,9 @@ PrintUsageAndExit(); } } - - if (FLAGS_benchmark_format != "console" && - FLAGS_benchmark_format != "json" && - FLAGS_benchmark_format != "csv") { + for (auto const* flag : {&FLAGS_benchmark_format, + &FLAGS_benchmark_out_format}) + if (*flag != "console" && *flag != "json" && *flag != "csv") { PrintUsageAndExit(); } } Index: utils/google-benchmark/src/colorprint.h =================================================================== --- utils/google-benchmark/src/colorprint.h +++ utils/google-benchmark/src/colorprint.h @@ -20,6 +20,7 @@ std::string FormatString(const char* msg, va_list args); std::string FormatString(const char* msg, ...); +void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, va_list args); void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...); } // end namespace benchmark Index: utils/google-benchmark/src/colorprint.cc =================================================================== --- utils/google-benchmark/src/colorprint.cc +++ utils/google-benchmark/src/colorprint.cc @@ -20,7 +20,6 @@ #include #include -#include "commandlineflags.h" #include "check.h" #include "internal_macros.h" @@ -28,8 +27,6 @@ #include #endif -DECLARE_bool(color_print); - namespace benchmark { namespace { #ifdef BENCHMARK_OS_WINDOWS @@ -120,14 +117,14 @@ void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); + ColorPrintf(out, color, fmt, args); + va_end(args); +} - if (!FLAGS_color_print) { - out << FormatString(fmt, args); - va_end(args); - return; - } - +void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, va_list args) { #ifdef BENCHMARK_OS_WINDOWS + ((void)out); // suppress unused warning + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. @@ -152,7 +149,6 @@ out << FormatString(fmt, args) << "\033[m"; #endif - va_end(args); } } // end namespace benchmark Index: utils/google-benchmark/src/complexity.cc =================================================================== --- utils/google-benchmark/src/complexity.cc +++ utils/google-benchmark/src/complexity.cc @@ -31,9 +31,9 @@ case oN: return [](int n) -> double { return n; }; case oNSquared: - return [](int n) -> double { return n * n; }; + return [](int n) -> double { return std::pow(n, 2); }; case oNCubed: - return [](int n) -> double { return n * n * n; }; + return [](int n) -> double { return std::pow(n, 3); }; case oLogN: return [](int n) { return std::log2(n); }; case oNLogN: Index: utils/google-benchmark/src/console_reporter.cc =================================================================== --- utils/google-benchmark/src/console_reporter.cc +++ utils/google-benchmark/src/console_reporter.cc @@ -30,8 +30,6 @@ #include "string_util.h" #include "walltime.h" -DECLARE_bool(color_print); - namespace benchmark { bool ConsoleReporter::ReportContext(const Context& context) { @@ -40,10 +38,10 @@ PrintBasicContext(&GetErrorStream(), context); #ifdef BENCHMARK_OS_WINDOWS - if (FLAGS_color_print && &std::cout != &GetOutputStream()) { + if (color_output_ && &std::cout != &GetOutputStream()) { GetErrorStream() << "Color printing is only supported for stdout on windows." " Disabling color printing\n"; - FLAGS_color_print = false; + color_output_ = false; } #endif std::string str = FormatString("%-*s %13s %13s %10s\n", @@ -59,18 +57,29 @@ PrintRunData(run); } +static void IgnoreColorPrint(std::ostream& out, LogColor, + const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + out << FormatString(fmt, args); + va_end(args); +} + void ConsoleReporter::PrintRunData(const Run& result) { + typedef void(PrinterFn)(std::ostream&, LogColor, const char*, ...); auto& Out = GetOutputStream(); - + PrinterFn* printer = color_output_ ? (PrinterFn*)ColorPrintf + : IgnoreColorPrint; auto name_color = (result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN; - ColorPrintf(Out, name_color, "%-*s ", name_field_width_, + printer(Out, name_color, "%-*s ", name_field_width_, result.benchmark_name.c_str()); if (result.error_occurred) { - ColorPrintf(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'", + printer(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'", result.error_message.c_str()); - ColorPrintf(Out, COLOR_DEFAULT, "\n"); + printer(Out, COLOR_DEFAULT, "\n"); return; } // Format bytes per second @@ -91,34 +100,34 @@ if (result.report_big_o) { std::string big_o = GetBigOString(result.complexity); - ColorPrintf(Out, COLOR_YELLOW, "%10.2f %s %10.2f %s ", real_time, + printer(Out, COLOR_YELLOW, "%10.2f %s %10.2f %s ", real_time, big_o.c_str(), cpu_time, big_o.c_str()); } else if (result.report_rms) { - ColorPrintf(Out, COLOR_YELLOW, "%10.0f %% %10.0f %% ", real_time * 100, + printer(Out, COLOR_YELLOW, "%10.0f %% %10.0f %% ", real_time * 100, cpu_time * 100); } else { const char* timeLabel = GetTimeUnitString(result.time_unit); - ColorPrintf(Out, COLOR_YELLOW, "%10.0f %s %10.0f %s ", real_time, timeLabel, + printer(Out, COLOR_YELLOW, "%10.0f %s %10.0f %s ", real_time, timeLabel, cpu_time, timeLabel); } if (!result.report_big_o && !result.report_rms) { - ColorPrintf(Out, COLOR_CYAN, "%10lld", result.iterations); + printer(Out, COLOR_CYAN, "%10lld", result.iterations); } if (!rate.empty()) { - ColorPrintf(Out, COLOR_DEFAULT, " %*s", 13, rate.c_str()); + printer(Out, COLOR_DEFAULT, " %*s", 13, rate.c_str()); } if (!items.empty()) { - ColorPrintf(Out, COLOR_DEFAULT, " %*s", 18, items.c_str()); + printer(Out, COLOR_DEFAULT, " %*s", 18, items.c_str()); } if (!result.report_label.empty()) { - ColorPrintf(Out, COLOR_DEFAULT, " %s", result.report_label.c_str()); + printer(Out, COLOR_DEFAULT, " %s", result.report_label.c_str()); } - ColorPrintf(Out, COLOR_DEFAULT, "\n"); + printer(Out, COLOR_DEFAULT, "\n"); } } // end namespace benchmark Index: utils/google-benchmark/src/cycleclock.h =================================================================== --- utils/google-benchmark/src/cycleclock.h +++ utils/google-benchmark/src/cycleclock.h @@ -113,11 +113,11 @@ uint32_t pmuseren; uint32_t pmcntenset; // Read the user mode perf monitor counter access permissions. - asm("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); + asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. - asm("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); + asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); if (pmcntenset & 0x80000000ul) { // Is it counting? - asm("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); // The counter is set up to count every 64th cycle return static_cast(pmccntr) * 64; // Should optimize to << 6 } Index: utils/google-benchmark/src/sysinfo.cc =================================================================== --- utils/google-benchmark/src/sysinfo.cc +++ utils/google-benchmark/src/sysinfo.cc @@ -239,6 +239,7 @@ } // TODO: also figure out cpuinfo_num_cpus + #elif defined BENCHMARK_OS_WINDOWS // In NT, read MHz from the registry. If we fail to do so or we're in win9x // then make a crude estimate. @@ -251,7 +252,12 @@ cpuinfo_cycles_per_second = static_cast((int64_t)data * (int64_t)(1000 * 1000)); // was mhz else cpuinfo_cycles_per_second = static_cast(EstimateCyclesPerSecond()); -// TODO: also figure out cpuinfo_num_cpus + + SYSTEM_INFO sysinfo; + // Use memset as opposed to = {} to avoid GCC missing initializer false positives. + std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO)); + GetSystemInfo(&sysinfo); + cpuinfo_num_cpus = sysinfo.dwNumberOfProcessors; // number of logical processors in the current group #elif defined BENCHMARK_OS_MACOSX // returning "mach time units" per second. the current number of elapsed Index: utils/google-benchmark/test/CMakeLists.txt =================================================================== --- utils/google-benchmark/test/CMakeLists.txt +++ utils/google-benchmark/test/CMakeLists.txt @@ -45,9 +45,15 @@ compile_benchmark_test(fixture_test) add_test(fixture_test fixture_test --benchmark_min_time=0.01) +compile_benchmark_test(register_benchmark_test) +add_test(register_benchmark_test register_benchmark_test --benchmark_min_time=0.01) + compile_benchmark_test(map_test) add_test(map_test map_test --benchmark_min_time=0.01) +compile_benchmark_test(multiple_ranges_test) +add_test(multiple_ranges_test multiple_ranges_test --benchmark_min_time=0.01) + compile_benchmark_test(reporter_output_test) add_test(reporter_output_test reporter_output_test --benchmark_min_time=0.01) Index: utils/google-benchmark/test/basic_test.cc =================================================================== --- utils/google-benchmark/test/basic_test.cc +++ utils/google-benchmark/test/basic_test.cc @@ -14,7 +14,7 @@ void BM_spin_empty(benchmark::State& state) { while (state.KeepRunning()) { - for (int x = 0; x < state.range_x(); ++x) { + for (int x = 0; x < state.range(0); ++x) { benchmark::DoNotOptimize(x); } } @@ -23,11 +23,11 @@ BASIC_BENCHMARK_TEST(BM_spin_empty)->ThreadPerCpu(); void BM_spin_pause_before(benchmark::State& state) { - for (int i = 0; i < state.range_x(); ++i) { + for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(i); } while(state.KeepRunning()) { - for (int i = 0; i < state.range_x(); ++i) { + for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(i); } } @@ -39,11 +39,11 @@ void BM_spin_pause_during(benchmark::State& state) { while(state.KeepRunning()) { state.PauseTiming(); - for (int i = 0; i < state.range_x(); ++i) { + for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(i); } state.ResumeTiming(); - for (int i = 0; i < state.range_x(); ++i) { + for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(i); } } @@ -64,11 +64,11 @@ void BM_spin_pause_after(benchmark::State& state) { while(state.KeepRunning()) { - for (int i = 0; i < state.range_x(); ++i) { + for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(i); } } - for (int i = 0; i < state.range_x(); ++i) { + for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(i); } } @@ -77,15 +77,15 @@ void BM_spin_pause_before_and_after(benchmark::State& state) { - for (int i = 0; i < state.range_x(); ++i) { + for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(i); } while(state.KeepRunning()) { - for (int i = 0; i < state.range_x(); ++i) { + for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(i); } } - for (int i = 0; i < state.range_x(); ++i) { + for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(i); } } Index: utils/google-benchmark/test/benchmark_test.cc =================================================================== --- utils/google-benchmark/test/benchmark_test.cc +++ utils/google-benchmark/test/benchmark_test.cc @@ -67,7 +67,7 @@ static void BM_CalculatePiRange(benchmark::State& state) { double pi = 0.0; while (state.KeepRunning()) - pi = CalculatePi(state.range_x()); + pi = CalculatePi(state.range(0)); std::stringstream ss; ss << pi; state.SetLabel(ss.str()); @@ -87,25 +87,25 @@ static void BM_SetInsert(benchmark::State& state) { while (state.KeepRunning()) { state.PauseTiming(); - std::set data = ConstructRandomSet(state.range_x()); + std::set data = ConstructRandomSet(state.range(0)); state.ResumeTiming(); - for (int j = 0; j < state.range_y(); ++j) + for (int j = 0; j < state.range(1); ++j) data.insert(rand()); } - state.SetItemsProcessed(state.iterations() * state.range_y()); - state.SetBytesProcessed(state.iterations() * state.range_y() * sizeof(int)); + state.SetItemsProcessed(state.iterations() * state.range(1)); + state.SetBytesProcessed(state.iterations() * state.range(1) * sizeof(int)); } -BENCHMARK(BM_SetInsert)->RangePair(1<<10,8<<10, 1,10); +BENCHMARK(BM_SetInsert)->Ranges({{1<<10,8<<10}, {1,10}}); template static void BM_Sequential(benchmark::State& state) { ValueType v = 42; while (state.KeepRunning()) { Container c; - for (int i = state.range_x(); --i; ) + for (int i = state.range(0); --i; ) c.push_back(v); } - const size_t items_processed = state.iterations() * state.range_x(); + const size_t items_processed = state.iterations() * state.range(0); state.SetItemsProcessed(items_processed); state.SetBytesProcessed(items_processed * sizeof(v)); } @@ -117,8 +117,8 @@ #endif static void BM_StringCompare(benchmark::State& state) { - std::string s1(state.range_x(), '-'); - std::string s2(state.range_x(), '-'); + std::string s1(state.range(0), '-'); + std::string s2(state.range(0), '-'); while (state.KeepRunning()) benchmark::DoNotOptimize(s1.compare(s2)); } @@ -147,14 +147,14 @@ static void BM_LongTest(benchmark::State& state) { double tracker = 0.0; while (state.KeepRunning()) { - for (int i = 0; i < state.range_x(); ++i) + for (int i = 0; i < state.range(0); ++i) benchmark::DoNotOptimize(tracker += i); } } BENCHMARK(BM_LongTest)->Range(1<<16,1<<28); static void BM_ParallelMemset(benchmark::State& state) { - int size = state.range_x() / sizeof(int); + int size = state.range(0) / sizeof(int); int thread_size = size / state.threads; int from = thread_size * state.thread_index; int to = from + thread_size; @@ -179,7 +179,7 @@ static void BM_ManualTiming(benchmark::State& state) { size_t slept_for = 0; - int microseconds = state.range_x(); + int microseconds = state.range(0); std::chrono::duration sleep_duration { static_cast(microseconds) }; Index: utils/google-benchmark/test/complexity_test.cc =================================================================== --- utils/google-benchmark/test/complexity_test.cc +++ utils/google-benchmark/test/complexity_test.cc @@ -36,18 +36,27 @@ CHECK(err_str.empty()) << "Could not construct regex \"" << regex << "\"" << " got Error: " << err_str; + std::string near = ""; std::string line; + bool first = true; while (remaining_output.eof() == false) { CHECK(remaining_output.good()); std::getline(remaining_output, line); + // Keep the first line as context. + if (first) { + near = line; + first = false; + } if (r.Match(line)) return; CHECK(match_rule != MR_Next) << "Expected line \"" << line - << "\" to match regex \"" << regex << "\""; + << "\" to match regex \"" << regex << "\"" + << "\nstarted matching at line: \"" << near << "\""; } CHECK(remaining_output.eof() == false) << "End of output reached before match for regex \"" << regex - << "\" was found"; + << "\" was found" + << "\nstarted matching at line: \"" << near << "\""; } }; @@ -112,7 +121,7 @@ return std::string(std::move(f)) + "[ ]+" + join(std::forward(args)...); } -std::string dec_re = "[0-9]+\\.[0-9]+"; +std::string dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"; #define ADD_COMPLEXITY_CASES(...) \ int CONCAT(dummy, __LINE__) = AddComplexityTest(__VA_ARGS__) @@ -138,7 +147,7 @@ }); AddCases(csv_out, { {"^\"" + big_o_test_name + "\",," + dec_re + "," + dec_re + "," + big_o + ",,,,,$"}, - {"^\"" + rms_test_name + "\",," + dec_re + "," + dec_re + ",,,,,,$"} + {"^\"" + rms_test_name + "\",," + dec_re + "," + dec_re + ",,,,,,$", MR_Next} }); return 0; } @@ -151,12 +160,15 @@ void BM_Complexity_O1(benchmark::State& state) { while (state.KeepRunning()) { + for (int i=0; i < 1024; ++i) { + benchmark::DoNotOptimize(&i); + } } - state.SetComplexityN(state.range_x()); + state.SetComplexityN(state.range(0)); } BENCHMARK(BM_Complexity_O1) -> Range(1, 1<<18) -> Complexity(benchmark::o1); -BENCHMARK(BM_Complexity_O1) -> Range(1, 1<<18) -> Complexity([](int){return 1.0; }); BENCHMARK(BM_Complexity_O1) -> Range(1, 1<<18) -> Complexity(); +BENCHMARK(BM_Complexity_O1) -> Range(1, 1<<18) -> Complexity([](int){return 1.0; }); const char* big_o_1_test_name = "BM_Complexity_O1_BigO"; const char* rms_o_1_test_name = "BM_Complexity_O1_RMS"; @@ -167,6 +179,10 @@ ADD_COMPLEXITY_CASES(&ConsoleOutputTests, &JSONOutputTests, &CSVOutputTests, big_o_1_test_name, rms_o_1_test_name, enum_auto_big_o_1); +// Add auto enum tests +ADD_COMPLEXITY_CASES(&ConsoleOutputTests, &JSONOutputTests, &CSVOutputTests, + big_o_1_test_name, rms_o_1_test_name, enum_auto_big_o_1); + // Add lambda tests ADD_COMPLEXITY_CASES(&ConsoleOutputTests, &JSONOutputTests, &CSVOutputTests, big_o_1_test_name, rms_o_1_test_name, lambda_big_o_1); @@ -185,12 +201,12 @@ } void BM_Complexity_O_N(benchmark::State& state) { - auto v = ConstructRandomVector(state.range_x()); - const int item_not_in_vector = state.range_x()*2; // Test worst case scenario (item not in vector) + auto v = ConstructRandomVector(state.range(0)); + const int item_not_in_vector = state.range(0)*2; // Test worst case scenario (item not in vector) while (state.KeepRunning()) { benchmark::DoNotOptimize(std::find(v.begin(), v.end(), item_not_in_vector)); } - state.SetComplexityN(state.range_x()); + state.SetComplexityN(state.range(0)); } BENCHMARK(BM_Complexity_O_N) -> RangeMultiplier(2) -> Range(1<<10, 1<<16) -> Complexity(benchmark::oN); BENCHMARK(BM_Complexity_O_N) -> RangeMultiplier(2) -> Range(1<<10, 1<<16) -> Complexity([](int n) -> double{return n; }); @@ -214,11 +230,11 @@ // ========================================================================= // static void BM_Complexity_O_N_log_N(benchmark::State& state) { - auto v = ConstructRandomVector(state.range_x()); + auto v = ConstructRandomVector(state.range(0)); while (state.KeepRunning()) { std::sort(v.begin(), v.end()); } - state.SetComplexityN(state.range_x()); + state.SetComplexityN(state.range(0)); } BENCHMARK(BM_Complexity_O_N_log_N) -> RangeMultiplier(2) -> Range(1<<10, 1<<16) -> Complexity(benchmark::oNLogN); BENCHMARK(BM_Complexity_O_N_log_N) -> RangeMultiplier(2) -> Range(1<<10, 1<<16) -> Complexity([](int n) {return n * std::log2(n); }); @@ -244,14 +260,8 @@ int main(int argc, char* argv[]) { - // Add --color_print=false to argv since we don't want to match color codes. - char new_arg[64]; - char* new_argv[64]; - std::copy(argv, argv + argc, new_argv); - new_argv[argc++] = std::strcpy(new_arg, "--color_print=false"); - benchmark::Initialize(&argc, new_argv); - - benchmark::ConsoleReporter CR; + benchmark::Initialize(&argc, argv); + benchmark::ConsoleReporter CR(benchmark::ConsoleReporter::OO_None); benchmark::JSONReporter JR; benchmark::CSVReporter CSVR; struct ReporterTest { Index: utils/google-benchmark/test/fixture_test.cc =================================================================== --- utils/google-benchmark/test/fixture_test.cc +++ utils/google-benchmark/test/fixture_test.cc @@ -44,7 +44,7 @@ assert(data.get() != nullptr); assert(*data == 42); } - st.SetItemsProcessed(st.range_x()); + st.SetItemsProcessed(st.range(0)); } BENCHMARK_REGISTER_F(MyFixture, Bar)->Arg(42); BENCHMARK_REGISTER_F(MyFixture, Bar)->Arg(42)->ThreadPerCpu(); Index: utils/google-benchmark/test/map_test.cc =================================================================== --- utils/google-benchmark/test/map_test.cc +++ utils/google-benchmark/test/map_test.cc @@ -17,7 +17,7 @@ // Basic version. static void BM_MapLookup(benchmark::State& state) { - const int size = state.range_x(); + const int size = state.range(0); while (state.KeepRunning()) { state.PauseTiming(); std::map m = ConstructRandomMap(size); @@ -34,7 +34,7 @@ class MapFixture : public ::benchmark::Fixture { public: void SetUp(const ::benchmark::State& st) { - m = ConstructRandomMap(st.range_x()); + m = ConstructRandomMap(st.range(0)); } void TearDown(const ::benchmark::State&) { @@ -45,7 +45,7 @@ }; BENCHMARK_DEFINE_F(MapFixture, Lookup)(benchmark::State& state) { - const int size = state.range_x(); + const int size = state.range(0); while (state.KeepRunning()) { for (int i = 0; i < size; ++i) { benchmark::DoNotOptimize(m.find(rand() % size)); Index: utils/google-benchmark/test/multiple_ranges_test.cc =================================================================== --- /dev/null +++ utils/google-benchmark/test/multiple_ranges_test.cc @@ -0,0 +1,46 @@ +#include "benchmark/benchmark.h" + +#include +#include + +class MultipleRangesFixture : public ::benchmark::Fixture { + public: + MultipleRangesFixture() + : expectedValues({ + {1, 3, 5}, {1, 3, 8}, {1, 3, 15}, {2, 3, 5}, {2, 3, 8}, {2, 3, 15}, + {1, 4, 5}, {1, 4, 8}, {1, 4, 15}, {2, 4, 5}, {2, 4, 8}, {2, 4, 15}, + {1, 7, 5}, {1, 7, 8}, {1, 7, 15}, {2, 7, 5}, {2, 7, 8}, {2, 7, 15}, + {7, 6, 3} + }) + { + } + + void SetUp(const ::benchmark::State& state) { + std::vector ranges = {state.range(0), state.range(1), state.range(2)}; + + assert(expectedValues.find(ranges) != expectedValues.end()); + + actualValues.insert(ranges); + } + + virtual ~MultipleRangesFixture() { + assert(actualValues.size() == expectedValues.size()); + } + + std::set> expectedValues; + std::set> actualValues; +}; + + +BENCHMARK_DEFINE_F(MultipleRangesFixture, Empty)(benchmark::State& state) { + while (state.KeepRunning()) { + int product = state.range(0) * state.range(1) * state.range(2); + for (int x = 0; x < product; x++) { + benchmark::DoNotOptimize(x); + } + } +} + +BENCHMARK_REGISTER_F(MultipleRangesFixture, Empty)->RangeMultiplier(2)->Ranges({{1, 2}, {3, 7}, {5, 15}})->Args({7, 6, 3}); + +BENCHMARK_MAIN() Index: utils/google-benchmark/test/options_test.cc =================================================================== --- utils/google-benchmark/test/options_test.cc +++ utils/google-benchmark/test/options_test.cc @@ -9,7 +9,7 @@ } void BM_basic_slow(benchmark::State& state) { - std::chrono::milliseconds sleep_duration(state.range_x()); + std::chrono::milliseconds sleep_duration(state.range(0)); while (state.KeepRunning()) { std::this_thread::sleep_for( std::chrono::duration_cast(sleep_duration) @@ -25,8 +25,8 @@ BENCHMARK(BM_basic)->Range(1, 8); BENCHMARK(BM_basic)->RangeMultiplier(2)->Range(1, 8); BENCHMARK(BM_basic)->DenseRange(10, 15); -BENCHMARK(BM_basic)->ArgPair(42, 42); -BENCHMARK(BM_basic)->RangePair(64, 512, 64, 512); +BENCHMARK(BM_basic)->Args({42, 42}); +BENCHMARK(BM_basic)->Ranges({{64, 512}, {64, 512}}); BENCHMARK(BM_basic)->MinTime(0.7); BENCHMARK(BM_basic)->UseRealTime(); BENCHMARK(BM_basic)->ThreadRange(2, 4); Index: utils/google-benchmark/test/register_benchmark_test.cc =================================================================== --- /dev/null +++ utils/google-benchmark/test/register_benchmark_test.cc @@ -0,0 +1,149 @@ + +#undef NDEBUG +#include "benchmark/benchmark.h" +#include "../src/check.h" // NOTE: check.h is for internal use only! +#include +#include + +namespace { + +class TestReporter : public benchmark::ConsoleReporter { +public: + virtual void ReportRuns(const std::vector& report) { + all_runs_.insert(all_runs_.end(), begin(report), end(report)); + ConsoleReporter::ReportRuns(report); + } + + std::vector all_runs_; +}; + +struct TestCase { + std::string name; + const char* label; + TestCase(const char* xname) : name(xname), label(nullptr) {} + TestCase(const char* xname, const char* xlabel) + : name(xname), label(xlabel) {} + + typedef benchmark::BenchmarkReporter::Run Run; + + void CheckRun(Run const& run) const { + CHECK(name == run.benchmark_name) << "expected " << name + << " got " << run.benchmark_name; + if (label) { + CHECK(run.report_label == label) << "expected " << label + << " got " << run.report_label; + } else { + CHECK(run.report_label == ""); + } + } +}; + +std::vector ExpectedResults; + +int AddCases(std::initializer_list const& v) { + for (auto N : v) { + ExpectedResults.push_back(N); + } + return 0; +} + +#define CONCAT(x, y) CONCAT2(x, y) +#define CONCAT2(x, y) x##y +#define ADD_CASES(...) \ +int CONCAT(dummy, __LINE__) = AddCases({__VA_ARGS__}) + +} // end namespace + +typedef benchmark::internal::Benchmark* ReturnVal; + +//----------------------------------------------------------------------------// +// Test RegisterBenchmark with no additional arguments +//----------------------------------------------------------------------------// +void BM_function(benchmark::State& state) { while (state.KeepRunning()) {} } +BENCHMARK(BM_function); +ReturnVal dummy = benchmark::RegisterBenchmark( + "BM_function_manual_registration", + BM_function); +ADD_CASES({"BM_function"}, {"BM_function_manual_registration"}); + +//----------------------------------------------------------------------------// +// Test RegisterBenchmark with additional arguments +// Note: GCC <= 4.8 do not support this form of RegisterBenchmark because they +// reject the variadic pack expansion of lambda captures. +//----------------------------------------------------------------------------// +#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK + +void BM_extra_args(benchmark::State& st, const char* label) { + while (st.KeepRunning()) {} + st.SetLabel(label); +} +int RegisterFromFunction() { + std::pair cases[] = { + {"test1", "One"}, + {"test2", "Two"}, + {"test3", "Three"} + }; + for (auto& c : cases) + benchmark::RegisterBenchmark(c.first, &BM_extra_args, c.second); + return 0; +} +int dummy2 = RegisterFromFunction(); +ADD_CASES( + {"test1", "One"}, + {"test2", "Two"}, + {"test3", "Three"} +); + +#endif // BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK + +//----------------------------------------------------------------------------// +// Test RegisterBenchmark with different callable types +//----------------------------------------------------------------------------// + +struct CustomFixture { + void operator()(benchmark::State& st) { + while (st.KeepRunning()) {} + } +}; + +void TestRegistrationAtRuntime() { +#ifdef BENCHMARK_HAS_CXX11 + { + CustomFixture fx; + benchmark::RegisterBenchmark("custom_fixture", fx); + AddCases({"custom_fixture"}); + } +#endif +#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK + { + int x = 42; + auto capturing_lam = [=](benchmark::State& st) { + while (st.KeepRunning()) {} + st.SetLabel(std::to_string(x)); + }; + benchmark::RegisterBenchmark("lambda_benchmark", capturing_lam); + AddCases({{"lambda_benchmark", "42"}}); + } +#endif +} + +int main(int argc, char* argv[]) { + TestRegistrationAtRuntime(); + + benchmark::Initialize(&argc, argv); + + TestReporter test_reporter; + benchmark::RunSpecifiedBenchmarks(&test_reporter); + + typedef benchmark::BenchmarkReporter::Run Run; + auto EB = ExpectedResults.begin(); + + for (Run const& run : test_reporter.all_runs_) { + assert(EB != ExpectedResults.end()); + EB->CheckRun(run); + ++EB; + } + assert(EB == ExpectedResults.end()); + + return 0; +} Index: utils/google-benchmark/test/reporter_output_test.cc =================================================================== --- utils/google-benchmark/test/reporter_output_test.cc +++ utils/google-benchmark/test/reporter_output_test.cc @@ -114,7 +114,9 @@ return std::string(std::move(f)) + "[ ]+" + join(std::forward(args)...); } -std::string dec_re = "[0-9]+\\.[0-9]+"; + + +std::string dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"; } // end namespace @@ -185,7 +187,7 @@ void BM_Complexity_O1(benchmark::State& state) { while (state.KeepRunning()) { } - state.SetComplexityN(state.range_x()); + state.SetComplexityN(state.range(0)); } BENCHMARK(BM_Complexity_O1)->Range(1, 1<<18)->Complexity(benchmark::o1); @@ -203,14 +205,8 @@ int main(int argc, char* argv[]) { - // Add --color_print=false to argv since we don't want to match color codes. - char new_arg[64]; - char* new_argv[64]; - std::copy(argv, argv + argc, new_argv); - new_argv[argc++] = std::strcpy(new_arg, "--color_print=false"); - benchmark::Initialize(&argc, new_argv); - - benchmark::ConsoleReporter CR; + benchmark::Initialize(&argc, argv); + benchmark::ConsoleReporter CR(benchmark::ConsoleReporter::OO_None); benchmark::JSONReporter JR; benchmark::CSVReporter CSVR; struct ReporterTest { Index: utils/google-benchmark/test/skip_with_error_test.cc =================================================================== --- utils/google-benchmark/test/skip_with_error_test.cc +++ utils/google-benchmark/test/skip_with_error_test.cc @@ -74,7 +74,7 @@ void BM_error_during_running(benchmark::State& state) { int first_iter = true; while (state.KeepRunning()) { - if (state.range_x() == 1 && state.thread_index <= (state.threads / 2)) { + if (state.range(0) == 1 && state.thread_index <= (state.threads / 2)) { assert(first_iter); first_iter = false; state.SkipWithError("error message"); @@ -116,7 +116,7 @@ void BM_error_while_paused(benchmark::State& state) { bool first_iter = true; while (state.KeepRunning()) { - if (state.range_x() == 1 && state.thread_index <= (state.threads / 2)) { + if (state.range(0) == 1 && state.thread_index <= (state.threads / 2)) { assert(first_iter); first_iter = false; state.PauseTiming(); Index: utils/google-benchmark/tools/compare_bench.py =================================================================== --- /dev/null +++ utils/google-benchmark/tools/compare_bench.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +""" +compare_bench.py - Compare two benchmarks or their results and report the + difference. +""" +import sys +import gbench +from gbench import util, report + +def main(): + # Parse the command line flags + def usage(): + print('compare_bench.py [benchmark options]...') + exit(1) + if '--help' in sys.argv or len(sys.argv) < 3: + usage() + tests = sys.argv[1:3] + bench_opts = sys.argv[3:] + bench_opts = list(bench_opts) + # Run the benchmarks and report the results + json1 = gbench.util.run_or_load_benchmark(tests[0], bench_opts) + json2 = gbench.util.run_or_load_benchmark(tests[1], bench_opts) + output_lines = gbench.report.generate_difference_report(json1, json2) + print 'Comparing %s to %s' % (tests[0], tests[1]) + for ln in output_lines: + print(ln) + + +if __name__ == '__main__': + main() Index: utils/google-benchmark/tools/gbench/Inputs/test1_run1.json =================================================================== --- /dev/null +++ utils/google-benchmark/tools/gbench/Inputs/test1_run1.json @@ -0,0 +1,46 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_SameTimes", + "iterations": 1000, + "real_time": 10, + "cpu_time": 10, + "time_unit": "ns" + }, + { + "name": "BM_2xFaster", + "iterations": 1000, + "real_time": 50, + "cpu_time": 50, + "time_unit": "ns" + }, + { + "name": "BM_2xSlower", + "iterations": 1000, + "real_time": 50, + "cpu_time": 50, + "time_unit": "ns" + }, + { + "name": "BM_10PercentFaster", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_10PercentSlower", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + } + ] +} \ No newline at end of file Index: utils/google-benchmark/tools/gbench/Inputs/test1_run2.json =================================================================== --- /dev/null +++ utils/google-benchmark/tools/gbench/Inputs/test1_run2.json @@ -0,0 +1,46 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_SameTimes", + "iterations": 1000, + "real_time": 10, + "cpu_time": 10, + "time_unit": "ns" + }, + { + "name": "BM_2xFaster", + "iterations": 1000, + "real_time": 25, + "cpu_time": 25, + "time_unit": "ns" + }, + { + "name": "BM_2xSlower", + "iterations": 20833333, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_10PercentFaster", + "iterations": 1000, + "real_time": 90, + "cpu_time": 90, + "time_unit": "ns" + }, + { + "name": "BM_10PercentSlower", + "iterations": 1000, + "real_time": 110, + "cpu_time": 110, + "time_unit": "ns" + } + ] +} \ No newline at end of file Index: utils/google-benchmark/tools/gbench/__init__.py =================================================================== --- /dev/null +++ utils/google-benchmark/tools/gbench/__init__.py @@ -0,0 +1,8 @@ +"""Google Benchmark tooling""" + +__author__ = 'Eric Fiselier' +__email__ = 'eric@efcs.ca' +__versioninfo__ = (0, 5, 0) +__version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev' + +__all__ = [] Index: utils/google-benchmark/tools/gbench/report.py =================================================================== --- /dev/null +++ utils/google-benchmark/tools/gbench/report.py @@ -0,0 +1,136 @@ +"""report.py - Utilities for reporting statistics about benchmark results +""" +import os + +class BenchmarkColor(object): + def __init__(self, name, code): + self.name = name + self.code = code + + def __repr__(self): + return '%s%r' % (self.__class__.__name__, + (self.name, self.code)) + + def __format__(self, format): + return self.code + +# Benchmark Colors Enumeration +BC_NONE = BenchmarkColor('NONE', '') +BC_MAGENTA = BenchmarkColor('MAGENTA', '\033[95m') +BC_CYAN = BenchmarkColor('CYAN', '\033[96m') +BC_OKBLUE = BenchmarkColor('OKBLUE', '\033[94m') +BC_HEADER = BenchmarkColor('HEADER', '\033[92m') +BC_WARNING = BenchmarkColor('WARNING', '\033[93m') +BC_WHITE = BenchmarkColor('WHITE', '\033[97m') +BC_FAIL = BenchmarkColor('FAIL', '\033[91m') +BC_ENDC = BenchmarkColor('ENDC', '\033[0m') +BC_BOLD = BenchmarkColor('BOLD', '\033[1m') +BC_UNDERLINE = BenchmarkColor('UNDERLINE', '\033[4m') + +def color_format(use_color, fmt_str, *args, **kwargs): + """ + Return the result of 'fmt_str.format(*args, **kwargs)' after transforming + 'args' and 'kwargs' according to the value of 'use_color'. If 'use_color' + is False then all color codes in 'args' and 'kwargs' are replaced with + the empty string. + """ + assert use_color is True or use_color is False + if not use_color: + args = [arg if not isinstance(arg, BenchmarkColor) else BC_NONE + for arg in args] + kwargs = {key: arg if not isinstance(arg, BenchmarkColor) else BC_NONE + for key, arg in kwargs.items()} + return fmt_str.format(*args, **kwargs) + + +def find_longest_name(benchmark_list): + """ + Return the length of the longest benchmark name in a given list of + benchmark JSON objects + """ + longest_name = 1 + for bc in benchmark_list: + if len(bc['name']) > longest_name: + longest_name = len(bc['name']) + return longest_name + + +def calculate_change(old_val, new_val): + """ + Return a float representing the decimal change between old_val and new_val. + """ + return float(new_val - old_val) / abs(old_val) + + +def generate_difference_report(json1, json2, use_color=True): + """ + Calculate and report the difference between each test of two benchmarks + runs specified as 'json1' and 'json2'. + """ + first_col_width = find_longest_name(json1['benchmarks']) + 5 + def find_test(name): + for b in json2['benchmarks']: + if b['name'] == name: + return b + return None + first_line = "{:<{}s} Time CPU".format( + 'Benchmark', first_col_width) + output_strs = [first_line, '-' * len(first_line)] + for bn in json1['benchmarks']: + other_bench = find_test(bn['name']) + if not other_bench: + continue + + def get_color(res): + if res > 0.05: + return BC_FAIL + elif res > -0.07: + return BC_WHITE + else: + return BC_CYAN + fmt_str = "{}{:<{}s}{endc} {}{:+.2f}{endc} {}{:+.2f}{endc}" + tres = calculate_change(bn['real_time'], other_bench['real_time']) + cpures = calculate_change(bn['cpu_time'], other_bench['cpu_time']) + output_strs += [color_format(use_color, fmt_str, + BC_HEADER, bn['name'], first_col_width, + get_color(tres), tres, get_color(cpures), cpures, + endc=BC_ENDC)] + return output_strs + +############################################################################### +# Unit tests + +import unittest + +class TestReportDifference(unittest.TestCase): + def load_results(self): + import json + testInputs = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Inputs') + testOutput1 = os.path.join(testInputs, 'test1_run1.json') + testOutput2 = os.path.join(testInputs, 'test1_run2.json') + with open(testOutput1, 'r') as f: + json1 = json.load(f) + with open(testOutput2, 'r') as f: + json2 = json.load(f) + return json1, json2 + + def test_basic(self): + expect_lines = [ + ['BM_SameTimes', '+0.00', '+0.00'], + ['BM_2xFaster', '-0.50', '-0.50'], + ['BM_2xSlower', '+1.00', '+1.00'], + ['BM_10PercentFaster', '-0.10', '-0.10'], + ['BM_10PercentSlower', '+0.10', '+0.10'] + ] + json1, json2 = self.load_results() + output_lines = generate_difference_report(json1, json2, use_color=False) + print output_lines + self.assertEqual(len(output_lines), len(expect_lines)) + for i in xrange(0, len(output_lines)): + parts = [x for x in output_lines[i].split(' ') if x] + self.assertEqual(len(parts), 3) + self.assertEqual(parts, expect_lines[i]) + + +if __name__ == '__main__': + unittest.main() Index: utils/google-benchmark/tools/gbench/util.py =================================================================== --- /dev/null +++ utils/google-benchmark/tools/gbench/util.py @@ -0,0 +1,130 @@ +"""util.py - General utilities for running, loading, and processing benchmarks +""" +import json +import os +import tempfile +import subprocess +import sys + +# Input file type enumeration +IT_Invalid = 0 +IT_JSON = 1 +IT_Executable = 2 + +_num_magic_bytes = 2 if sys.platform.startswith('win') else 4 +def is_executable_file(filename): + """ + Return 'True' if 'filename' names a valid file which is likely + an executable. A file is considered an executable if it starts with the + magic bytes for a EXE, Mach O, or ELF file. + """ + if not os.path.isfile(filename): + return False + with open(filename, 'r') as f: + magic_bytes = f.read(_num_magic_bytes) + if sys.platform == 'darwin': + return magic_bytes in [ + '\xfe\xed\xfa\xce', # MH_MAGIC + '\xce\xfa\xed\xfe', # MH_CIGAM + '\xfe\xed\xfa\xcf', # MH_MAGIC_64 + '\xcf\xfa\xed\xfe', # MH_CIGAM_64 + '\xca\xfe\xba\xbe', # FAT_MAGIC + '\xbe\xba\xfe\xca' # FAT_CIGAM + ] + elif sys.platform.startswith('win'): + return magic_bytes == 'MZ' + else: + return magic_bytes == '\x7FELF' + + +def is_json_file(filename): + """ + Returns 'True' if 'filename' names a valid JSON output file. + 'False' otherwise. + """ + try: + with open(filename, 'r') as f: + json.load(f) + return True + except: + pass + return False + + +def classify_input_file(filename): + """ + Return a tuple (type, msg) where 'type' specifies the classified type + of 'filename'. If 'type' is 'IT_Invalid' then 'msg' is a human readable + string represeting the error. + """ + ftype = IT_Invalid + err_msg = None + if not os.path.exists(filename): + err_msg = "'%s' does not exist" % filename + elif not os.path.isfile(filename): + err_msg = "'%s' does not name a file" % filename + elif is_executable_file(filename): + ftype = IT_Executable + elif is_json_file(filename): + ftype = IT_JSON + else: + err_msg = "'%s' does not name a valid benchmark executable or JSON file" + return ftype, err_msg + + +def check_input_file(filename): + """ + Classify the file named by 'filename' and return the classification. + If the file is classified as 'IT_Invalid' print an error message and exit + the program. + """ + ftype, msg = classify_input_file(filename) + if ftype == IT_Invalid: + print "Invalid input file: %s" % msg + sys.exit(1) + return ftype + + +def load_benchmark_results(fname): + """ + Read benchmark output from a file and return the JSON object. + REQUIRES: 'fname' names a file containing JSON benchmark output. + """ + with open(fname, 'r') as f: + return json.load(f) + + +def run_benchmark(exe_name, benchmark_flags): + """ + Run a benchmark specified by 'exe_name' with the specified + 'benchmark_flags'. The benchmark is run directly as a subprocess to preserve + real time console output. + RETURNS: A JSON object representing the benchmark output + """ + thandle, tname = tempfile.mkstemp() + os.close(thandle) + cmd = [exe_name] + benchmark_flags + print("RUNNING: %s" % ' '.join(cmd)) + exitCode = subprocess.call(cmd + ['--benchmark_out=%s' % tname]) + if exitCode != 0: + print('TEST FAILED...') + sys.exit(exitCode) + json_res = load_benchmark_results(tname) + os.unlink(tname) + return json_res + + +def run_or_load_benchmark(filename, benchmark_flags): + """ + Get the results for a specified benchmark. If 'filename' specifies + an executable benchmark then the results are generated by running the + benchmark. Otherwise 'filename' must name a valid JSON output file, + which is loaded and the result returned. + """ + ftype = check_input_file(filename) + if ftype == IT_JSON: + return load_benchmark_results(filename) + elif ftype == IT_Executable: + return run_benchmark(filename, benchmark_flags) + else: + assert False # This branch is unreachable \ No newline at end of file Index: www/index.html =================================================================== --- www/index.html +++ www/index.html @@ -140,11 +140,6 @@ "C++1z" (probably to be C++17) can be found here.

Implementation of the post-c++14 Technical Specifications is in progress. A list of features and the current status of these features can be found here.

-

- Ports to other platforms are underway. Here are recent test - results for Windows - and Linux. -

Build Bots

Index: www/results.Linux.html =================================================================== --- www/results.Linux.html +++ /dev/null @@ -1,513 +0,0 @@ - - - - results.Linux - - -
-All failures in the libc++ test suite will be documented here.
-Note: glibc >= 2.16 is required for full C11 compatibility.
-
-Test Suite Run Information:
-Date: 8/18/2014
-Compiler: Clang Tip-of-Tree (r215809)
-ABI: libc++abi
-C Library: eglibc 2.19
-Platform: x86_64-linux-gnu
-Kernel: 3.13.0-32-generic
-Distribution: Ubuntu 14.04
-Run By: Eric Fiselier (eric at efcs dot ca)
-
-
-Testing Time: 1187.82s
-********************
-Failing Tests (33):
-    libc++ :: localization/locale.categories/category.collate/locale.collate.byname/compare.pass.cpp
-        - GLIBC's locales collate strings differently. Needs investigation.
-    libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/tolower_1.pass.cpp
-        - Needs Investigation.
-    libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/tolower_many.pass.cpp
-        - Idem.
-    libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/toupper_1.pass.cpp
-        - Idem.
-    libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/toupper_many.pass.cpp
-        - Idem.
-    libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/widen_1.pass.cpp
-        - Idem
-    libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/widen_many.pass.cpp
-        - Idem
-    libc++ :: localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_ru_RU.pass.cpp
-        - Differences in GLIBC locales. Needs investigation.
-    libc++ :: localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_zh_CN.pass.cpp
-        - Differences in GLIBC locales. Puts '-' before 'CNY' as opposed to after.
-    libc++ :: localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_ru_RU.pass.cpp
-        - Differences in GLIBC locales. Needs investigation.
-    libc++ :: localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_zh_CN.pass.cpp
-        - Differences in GLIBC locales. Puts '-' before 'CNY' as opposed to after.
-    libc++ :: localization/locale.categories/category.monetary/locale.moneypunct.byname/decimal_point.pass.cpp
-        - Expects ',' for ru_RU but gets '.'.
-    libc++ :: localization/locale.categories/category.monetary/locale.moneypunct.byname/thousands_sep.pass.cpp
-        - Expects ',' for ru_RU but gets '.'.
-    libc++ :: localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp
-        - GLIBC puts "+nan" where "nan" is expected.
-    libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_date.pass.cpp
-        - GLIBC has different locale data for fr_FR, ru_RU and zh_CN.
-          The is also a possible bug in zh_CN tests. Needs investigation.
-    libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_date_wide.pass.cpp
-        - Idem.
-    libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_one.pass.cpp
-        - Some test cases are non-portible with GLIBC (include time zone).
-          Other failures related to GLIBC locale data. Needs investigation.
-    libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_one_wide.pass.cpp
-        - Idem.
-    libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_weekday.pass.cpp
-        - GLIBC starts weekdays with lowercase letters. Test case expectes upper case.
-    libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_weekday_wide.pass.cpp
-        - Idem.
-    libc++ :: localization/locale.categories/category.time/locale.time.put.byname/put1.pass.cpp
-        - GLIBC abbreviated days end with '.'. Test case expects no '.'.
-    libc++ :: localization/locale.categories/category.time/locale.time.put/locale.time.put.members/put2.pass.cpp
-        - Needs investigation.
-    libc++ :: localization/locale.categories/facet.numpunct/locale.numpunct.byname/grouping.pass.cpp
-        - Fails due to differences in GLIBC locales
-    libc++ :: localization/locale.categories/facet.numpunct/locale.numpunct.byname/thousands_sep.pass.cpp
-        - Fails due to differences in GLIBC locales
-    libc++ :: re/re.alg/re.alg.match/basic.pass.cpp
-        - Needs investigation.
-    libc++ :: re/re.alg/re.alg.match/ecma.pass.cpp
-        - Idem.
-    libc++ :: re/re.alg/re.alg.match/extended.pass.cpp
-        - Idem.
-    libc++ :: re/re.alg/re.alg.search/awk.pass.cpp
-        - Idem.
-    libc++ :: re/re.alg/re.alg.search/basic.pass.cpp
-        - Idem.
-    libc++ :: re/re.alg/re.alg.search/ecma.pass.cpp
-        - Idem.
-    libc++ :: re/re.alg/re.alg.search/extended.pass.cpp
-        - Idem.
-    libc++ :: re/re.traits/lookup_collatename.pass.cpp
-        - Idem.
-    libc++ :: re/re.traits/translate_nocase.pass.cpp
-        - Idem.
-
-********************
-Expected Failing Tests (5):
-    libc++ :: depr/depr.c.headers/math_h.pass.cpp
-        - Fails a static assert that the return type of
-          isnan(double) and isinf(double) is a bool. see PR18382.
-    libc++ :: numerics/c.math/cmath_isinf.pass.cpp
-        - Idem.
-    libc++ :: numerics/c.math/cmath_isnan.pass.cpp
-        - Idem.
-    libc++ :: strings/c.strings/cuchar.pass.cpp
-        - <cuchar> is not implemented.
-    libc++ :: strings/c.strings/version_cuchar.pass.cpp
-        - Idem.
-
-  Expected Passes    : 4716
-  Expected Failures  : 5
-  Unexpected Failures: 33
-
-********************************************************************************
-
--- Testing: 4754 tests, 2 threads --
-FAIL: libc++ :: localization/locale.categories/category.collate/locale.collate.byname/compare.pass.cpp (2073 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.collate/locale.collate.byname/compare.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmp4DtKocexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.collate/locale.collate.byname/compare.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmp4DtKocexe'
-Exit Code: -6
-Standard Error:
---
-tmp4DtKocexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.collate/locale.collate.byname/compare.pass.cpp:38: int main(): Assertion `f.compare(s2.data(), s2.data() + s2.size(), s3.data(), s3.data() + s3.size()) == 1' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/tolower_1.pass.cpp (2152 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/tolower_1.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpAfkClkexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/tolower_1.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpAfkClkexe'
-Exit Code: -6
-Standard Error:
---
-tmpAfkClkexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/tolower_1.pass.cpp:38: int main(): Assertion `f.tolower('\xDA') == '\xFA'' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/tolower_many.pass.cpp (2153 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/tolower_many.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpGjakKeexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/tolower_many.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpGjakKeexe'
-Exit Code: -6
-Standard Error:
---
-tmpGjakKeexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/tolower_many.pass.cpp:35: int main(): Assertion `in[0] == '\xFA'' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/toupper_1.pass.cpp (2154 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/toupper_1.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmp0gK3Y6exe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/toupper_1.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmp0gK3Y6exe'
-Exit Code: -6
-Standard Error:
---
-tmp0gK3Y6exe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/toupper_1.pass.cpp:39: int main(): Assertion `f.toupper('\xFA') == '\xDA'' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/toupper_many.pass.cpp (2155 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/toupper_many.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpCoF624exe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/toupper_many.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpCoF624exe'
-Exit Code: -6
-Standard Error:
---
-tmpCoF624exe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/toupper_many.pass.cpp:35: int main(): Assertion `in[0] == '\xDA'' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/widen_1.pass.cpp (2157 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/widen_1.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpjOo8fnexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/widen_1.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpjOo8fnexe'
-Exit Code: -6
-Standard Error:
---
-tmpjOo8fnexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/widen_1.pass.cpp:53: int main(): Assertion `f.widen(char(-5)) == wchar_t(251)' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/widen_many.pass.cpp (2158 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.ctype/locale.ctype.byname/widen_many.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpDWZ5aNexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/widen_many.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpDWZ5aNexe'
-Exit Code: -6
-Standard Error:
---
-tmpDWZ5aNexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.ctype/locale.ctype.byname/widen_many.pass.cpp:60: int main(): Assertion `v[6] == wchar_t(133)' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_ru_RU.pass.cpp (2184 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_ru_RU.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpfA5HOrexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_ru_RU.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpfA5HOrexe'
-Exit Code: -6
-Standard Error:
---
-tmpfA5HOrexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_ru_RU.pass.cpp:71: int main(): Assertion `iter.base() == v.data() + v.size()' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_zh_CN.pass.cpp (2185 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_zh_CN.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpTI59qtexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_zh_CN.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpTI59qtexe'
-Exit Code: -6
-Standard Error:
---
-tmpTI59qtexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_zh_CN.pass.cpp:314: int main(): Assertion `iter.base() == v.data() + v.size()' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_ru_RU.pass.cpp (2192 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_ru_RU.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmp1psSk2exe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_ru_RU.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmp1psSk2exe'
-Exit Code: -6
-Standard Error:
---
-tmp1psSk2exe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_ru_RU.pass.cpp:70: int main(): Assertion `ex == "0,00 "' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_zh_CN.pass.cpp (2193 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_zh_CN.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpKwjbrPexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_zh_CN.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpKwjbrPexe'
-Exit Code: -6
-Standard Error:
---
-tmpKwjbrPexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_zh_CN.pass.cpp:218: int main(): Assertion `ex == "CNY -0.01"' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.monetary/locale.moneypunct.byname/decimal_point.pass.cpp (2198 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.monetary/locale.moneypunct.byname/decimal_point.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmp4UnNQ2exe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.moneypunct.byname/decimal_point.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmp4UnNQ2exe'
-Exit Code: -6
-Standard Error:
---
-tmp4UnNQ2exe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.moneypunct.byname/decimal_point.pass.cpp:114: int main(): Assertion `f.decimal_point() == ','' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.monetary/locale.moneypunct.byname/thousands_sep.pass.cpp (2205 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.monetary/locale.moneypunct.byname/thousands_sep.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmp6MGZAmexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.moneypunct.byname/thousands_sep.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmp6MGZAmexe'
-Exit Code: -6
-Standard Error:
---
-tmp6MGZAmexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.monetary/locale.moneypunct.byname/thousands_sep.pass.cpp:114: int main(): Assertion `f.thousands_sep() == ' '' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp (2229 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmp7AME77exe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmp7AME77exe'
-Exit Code: -6
-Standard Error:
---
-tmp7AME77exe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp:10886: void test5(): Assertion `ex == "nan"' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_date_wide.pass.cpp (2249 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_date_wide.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpooRjFgexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_date_wide.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpooRjFgexe'
-Exit Code: -6
-Standard Error:
---
-tmpooRjFgexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_date_wide.pass.cpp:64: int main(): Assertion `i.base() == in+sizeof(in)/sizeof(in[0])-1' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_date.pass.cpp (2250 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_date.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpcm_vb9exe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_date.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpcm_vb9exe'
-Exit Code: -6
-Standard Error:
---
-tmpcm_vb9exe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_date.pass.cpp:64: int main(): Assertion `i.base() == in+sizeof(in)/sizeof(in[0])-1' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_one.pass.cpp (2253 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_one.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpLKJQXHexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_one.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpLKJQXHexe'
-Exit Code: -6
-Standard Error:
---
-tmpLKJQXHexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_one.pass.cpp:51: int main(): Assertion `i.base() == in+sizeof(in)/sizeof(in[0])-1' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_one_wide.pass.cpp (2254 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_one_wide.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpiDgYiqexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_one_wide.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpiDgYiqexe'
-Exit Code: -6
-Standard Error:
---
-tmpiDgYiqexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_one_wide.pass.cpp:51: int main(): Assertion `i.base() == in+sizeof(in)/sizeof(in[0])-1' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_weekday.pass.cpp (2257 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_weekday.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpAUaH78exe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_weekday.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpAUaH78exe'
-Exit Code: -6
-Standard Error:
---
-tmpAUaH78exe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_weekday.pass.cpp:74: int main(): Assertion `i.base() == in+sizeof(in)/sizeof(in[0])-1' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_weekday_wide.pass.cpp (2258 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.time/locale.time.get.byname/get_weekday_wide.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmp7iGNTDexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_weekday_wide.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmp7iGNTDexe'
-Exit Code: -6
-Standard Error:
---
-tmp7iGNTDexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.get.byname/get_weekday_wide.pass.cpp:72: int main(): Assertion `i.base() == in+sizeof(in)/sizeof(in[0])-1' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.time/locale.time.put.byname/put1.pass.cpp (2277 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.time/locale.time.put.byname/put1.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpnT0vVFexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.put.byname/put1.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpnT0vVFexe'
-Exit Code: -6
-Standard Error:
---
-tmpnT0vVFexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.put.byname/put1.pass.cpp:73: int main(): Assertion `(ex == "Today is Samedi which is abbreviated Sam.")|| (ex == "Today is samedi which is abbreviated sam." )' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/category.time/locale.time.put/locale.time.put.members/put2.pass.cpp (2281 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/category.time/locale.time.put/locale.time.put.members/put2.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmp47THCHexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.put/locale.time.put.members/put2.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmp47THCHexe'
-Exit Code: -6
-Standard Error:
---
-tmp47THCHexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/category.time/locale.time.put/locale.time.put.members/put2.pass.cpp:185: int main(): Assertion `ex == "May"' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/facet.numpunct/locale.numpunct.byname/grouping.pass.cpp (2285 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/facet.numpunct/locale.numpunct.byname/grouping.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpn6fLHJexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/facet.numpunct/locale.numpunct.byname/grouping.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpn6fLHJexe'
-Exit Code: -6
-Standard Error:
---
-tmpn6fLHJexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/facet.numpunct/locale.numpunct.byname/grouping.pass.cpp:57: int main(): Assertion `np.grouping() == "\x7F"' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: localization/locale.categories/facet.numpunct/locale.numpunct.byname/thousands_sep.pass.cpp (2286 of 4754)
-******************** TEST 'libc++ :: localization/locale.categories/facet.numpunct/locale.numpunct.byname/thousands_sep.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpkna8llexe' '/home/eric/workspace/staging-libcxx/test/localization/locale.categories/facet.numpunct/locale.numpunct.byname/thousands_sep.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpkna8llexe'
-Exit Code: -6
-Standard Error:
---
-tmpkna8llexe: /home/eric/workspace/staging-libcxx/test/localization/locale.categories/facet.numpunct/locale.numpunct.byname/thousands_sep.pass.cpp:57: int main(): Assertion `np.thousands_sep() == ','' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: re/re.alg/re.alg.match/basic.pass.cpp (3203 of 4754)
-******************** TEST 'libc++ :: re/re.alg/re.alg.match/basic.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmp0wkTrlexe' '/home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.match/basic.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmp0wkTrlexe'
-Exit Code: -6
-Standard Error:
---
-tmp0wkTrlexe: /home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.match/basic.pass.cpp:624: int main(): Assertion `std::regex_match(s, m, std::regex("[a[=M=]z]", std::regex_constants::basic))' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: re/re.alg/re.alg.match/ecma.pass.cpp (3204 of 4754)
-******************** TEST 'libc++ :: re/re.alg/re.alg.match/ecma.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpghcl7yexe' '/home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.match/ecma.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpghcl7yexe'
-Exit Code: -6
-Standard Error:
---
-tmpghcl7yexe: /home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.match/ecma.pass.cpp:585: int main(): Assertion `std::regex_match(s, m, std::regex("[a[=M=]z]"))' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: re/re.alg/re.alg.match/extended.pass.cpp (3208 of 4754)
-******************** TEST 'libc++ :: re/re.alg/re.alg.match/extended.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpGVUdIMexe' '/home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.match/extended.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpGVUdIMexe'
-Exit Code: -6
-Standard Error:
---
-tmpGVUdIMexe: /home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.match/extended.pass.cpp:622: int main(): Assertion `std::regex_match(s, m, std::regex("[a[=M=]z]", std::regex_constants::extended))' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: re/re.alg/re.alg.search/awk.pass.cpp (3218 of 4754)
-******************** TEST 'libc++ :: re/re.alg/re.alg.search/awk.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpgFuw4cexe' '/home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.search/awk.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpgFuw4cexe'
-Exit Code: -6
-Standard Error:
---
-tmpgFuw4cexe: /home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.search/awk.pass.cpp:694: int main(): Assertion `std::regex_search(s, m, std::regex("[a[=M=]z]", std::regex_constants::awk))' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: re/re.alg/re.alg.search/basic.pass.cpp (3219 of 4754)
-******************** TEST 'libc++ :: re/re.alg/re.alg.search/basic.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpXeQuwGexe' '/home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.search/basic.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpXeQuwGexe'
-Exit Code: -6
-Standard Error:
---
-tmpXeQuwGexe: /home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.search/basic.pass.cpp:696: int main(): Assertion `std::regex_search(s, m, std::regex("[a[=M=]z]", std::regex_constants::basic))' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: re/re.alg/re.alg.search/ecma.pass.cpp (3220 of 4754)
-******************** TEST 'libc++ :: re/re.alg/re.alg.search/ecma.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpvGAAImexe' '/home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.search/ecma.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpvGAAImexe'
-Exit Code: -6
-Standard Error:
---
-tmpvGAAImexe: /home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.search/ecma.pass.cpp:675: int main(): Assertion `std::regex_search(s, m, std::regex("[a[=M=]z]"))' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: re/re.alg/re.alg.search/extended.pass.cpp (3224 of 4754)
-******************** TEST 'libc++ :: re/re.alg/re.alg.search/extended.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpGvouurexe' '/home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.search/extended.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpGvouurexe'
-Exit Code: -6
-Standard Error:
---
-tmpGvouurexe: /home/eric/workspace/staging-libcxx/test/re/re.alg/re.alg.search/extended.pass.cpp:694: int main(): Assertion `std::regex_search(s, m, std::regex("[a[=M=]z]", std::regex_constants::extended))' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: re/re.traits/lookup_collatename.pass.cpp (3349 of 4754)
-******************** TEST 'libc++ :: re/re.traits/lookup_collatename.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpItXmtJexe' '/home/eric/workspace/staging-libcxx/test/re/re.traits/lookup_collatename.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpItXmtJexe'
-Exit Code: -6
-Standard Error:
---
-tmpItXmtJexe: /home/eric/workspace/staging-libcxx/test/re/re.traits/lookup_collatename.pass.cpp:31: void test(const char_type *, const std::basic_string &) [char_type = char]: Assertion `t.lookup_collatename(F(A), F(A + t.length(A))) == expected' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-FAIL: libc++ :: re/re.traits/translate_nocase.pass.cpp (3354 of 4754)
-******************** TEST 'libc++ :: re/re.traits/translate_nocase.pass.cpp' FAILED ********************
-Compiled With: '/opt/llvm-tot/bin/clang++' '-o' '/tmp/tmpGsRNu3exe' '/home/eric/workspace/staging-libcxx/test/re/re.traits/translate_nocase.pass.cpp' '-nostdinc++' '-std=c++11' '-D__STDC_FORMAT_MACROS' '-D__STDC_LIMIT_MACROS' '-D__STDC_CONSTANT_MACROS' '-I/home/eric/workspace/staging-libcxx/test/../include' '-I/home/eric/workspace/staging-libcxx/test/../test/support' '-nodefaultlibs' '-L/home/eric/workspace/build-libcxx-staging/lib' '-lc++' '-lc++abi' '-lgcc_eh' '-lc' '-lm' '-lpthread' '-lrt' '-lgcc_s' '-Wl,-R' '/home/eric/workspace/build-libcxx-staging/lib'
-Command: '/tmp/tmpGsRNu3exe'
-Exit Code: -6
-Standard Error:
---
-tmpGsRNu3exe: /home/eric/workspace/staging-libcxx/test/re/re.traits/translate_nocase.pass.cpp:44: int main(): Assertion `t.translate_nocase('\xDA') == '\xFA'' failed.
---
-
-Compiled test failed unexpectedly!
-********************
-
- - Index: www/results.Windows.html =================================================================== --- www/results.Windows.html +++ /dev/null @@ -1,487 +0,0 @@ - - - - results.Windows - - -
-All failures in the libc++ test suite will be documented here.
-
-Last run was with Clang (pre-3.1) and GCC 4.6.3 (with dw2 exception handling) and
- mingw-w64 v2.0.3 on i686-w64-mingw32.
-
-The following line was added to ./lib/buildit to make a static libc++ library because a DLL requires "declspec(dllexport)" or a .def file:
-ar rcs libc++.a *.o
-I also deleted libc++.dll and libc++.dll.a to make sure libc++ was linked statically to prevent unrelated issues from contaminating the test results.
-The commands to build and test were (-nodefaultlibs does not work, lots of MinGW related stuff gets left out resulting in linker failures):
-TRIPLE=i686-w64-mingw32 ./buildit
-TRIPLE=i686-w64-mingw32 HEADER_INCLUDE="-I/home/Ruben/libcxx/include" LIBS="-L/home/ruben/libcxx/lib -lc++ -lpthread -lsupc++ -lmsvcr100 -Wl,--allow-multiple-definition" ./testit > test.log 2>&1
-
-Note: Some locale tests may "Need investigating", but I think most problems are
-      caused by wrong/unportable locale naming in the tests.
-Note: Some tests failed to link because "test.exe" was still running when ld.exe
-      tried to link the next test. I left these failures out of the list; they
-      account for about 10-30 failures, and are counted in the total scores below.
-      I reran some of these failures manually and they passed.
-Note: Some tests fail at runtime but pass when run manually. Usage of std::cout
-      segfaults so further investigation is difficult. These also contribute to
-      the failures total, but are left out of the failure list, as the cause is
-      probably not located in that part of libc++, not locatable due to the lack
-      of usable debug info generated by Clang at this time.
-
-TOTAL RESULTS:
-Section failures / total sections: 104 / 1064 = 9.8% failures
-Test failures / total number of tests: 292 / 4326 = 6.7% failures
-
-depr/
- depr.c.headers/
-  inttypes_h.pass.cpp: missing macros for C++.
-  uchar_h.pass.cpp: bug in mingw-w64 headers for C++11 builtin char types.
-  wchar_h.pass.cpp: Windows does not have swprintf, should use _snwprintf.
-                    Suggest #define swprintf as _snwprintf for _WIN32.
-exception.unexpected/
-   set.unexpected/
-    get_unexpected.pass.cpp: Segmentation fault - needs investigation.
-    set_unexpected.pass.cpp: idem.
-diagnostics/
- syserr/
-  syserr.errcat/
-   syserr.errcat.objects/
-    system_category.pass.cpp: Needs investigation.
-input.output/
- file.streams/
-  c.files/
-   cinttypes.pass.cpp: missing macros for C++.
-  fstreams/
-   filebuf.assign/
-    member_swap.pass.cpp: Segmentation fault - needs investigation.
-    move_assign.pass.cpp: idem.
-    nonmember_swap.pass.cpp: idem.
-   filebuf.cons/
-    move.pass.cpp: idem.
-   filebuf.members/
-    open_pointers.pass.cpp: idem.
-   filebuf.virtuals/
-    overflow.pass.cpp: idem.
-    pbackfail.pass.cpp: idem.
-    seekoff.pass.cpp: idem.
-    underflow.pass.cpp: idem.
-   fstream.assign/
-    member_swap.pass.cpp: idem.
-    move_assign.pass.cpp: idem.
-    nonmember_swap.pass.cpp: idem.
-   fstream.cons/
-    move.pass.cpp: idem.
-    pointer.pass.cpp: idem.
-    string.pass.cpp: idem.
-   fstream.members/
-    open_pointer.pass.cpp: idem.
-    open_string.pass.cpp: idem.
-   ifstream.assign/
-    member_swap.pass.cpp: idem.
-    move_assign.pass.cpp: idem.
-    nonmember_swap.pass.cpp: idem.
-   ifstream.cons/
-    move.pass.cpp: idem.
-    pointer.pass.cpp: idem.
-    string.pass.cpp: idem.
-   ifstream.members/
-    open_pointer.pass.cpp: idem.
-    open_string.pass.cpp: idem.
-	  rdbuf.pass.cpp: idem.
-   ofstream.assign/
-    member_swap.pass.cpp: idem.
-    move_assign.pass.cpp: idem.
-    nonmember_swap.pass.cpp: idem.
-   ofstream.cons/
-    move.pass.cpp: idem.
-    pointer.pass.cpp: idem.
-    string.pass.cpp: idem.
-   ofstream.members/
-    open_pointer.pass.cpp: idem.
-    open_string.pass.cpp: idem.
-	  rdbuf.pass.cpp: idem.
- iostream.format/
-  ext.manip
-   get_money.pass.cpp: Windows locale names don't follow UNIX convention.
-   get_time.pass.cpp: idem.
-   put_money.pass.cpp: idem.
-   put_time.pass.cpp: idem.
-  output.streams/
-   ostream.formatted/
-    ostream.inserters.arithmetic/
-     long_double.pass.cpp: Segfault - needs investigation.
-     pointer.pass.cpp: idem.
-   ostream_sentry/
-    destruct.pass.cpp: idem.
- iostream.objects/
-  narrow.stream.objects/
-   cerr.pass.cpp: idem.
-   cin.pass.cpp: idem.
-  wide.stream.objects/
-   wcerr.pass.cpp: idem.
-   wcin.pass.cpp: idem.
- iostreams.base/
-  ios/
-   basic.ios.members/
-    copyfmt.pass.cpp: Windows locale names don't follow UNIX convention.
-    imbue.pass.cpp: idem.
-    move.pass.cpp: idem.
-    swap.pass.cpp: Windows locale names don't follow UNIX convention.
-  ios.base/
-   ios.base.callback/
-    register_callback.pass.cpp: Windows locale names don't follow UNIX convention.
-   ios.base.locales/
-    imbue.pass.cpp: Windows locale names don't follow UNIX convention.
- stream.buffers/
-  streambuf/
-   streambuf.cons/
-    copy.pass.cpp: Windows locale names don't follow UNIX convention.
-    default.pass.cpp: idem.
-   streambuf.members/
-    streambuf.buffer/
-     locales.pass.cpp: Windows locale names don't follow UNIX convention.
-   streambuf.protected/
-    streambuf.assign/
-	   assign.pass.cpp: Windows locale names don't follow UNIX convention.
-     swap.pass.cpp: idem.
-language.support/
- support.exception/
-  except.nested/
-   assign.pass.cpp: Needs investigation.
-   ctor_copy.pass.cpp: idem.
-   ctor_default.pass.cpp: idem.
-   rethrow_if_nested.pass.cpp: idem.
-   rethrow_nested.pass.cpp: idem.
-   throw_with_nested.pass.cpp: idem.
-  propagation/
-   current_exception.pass.cpp: Needs investigation.
-   exception_ptr.pass.cpp: idem.
-   make_exception_ptr.pass.cpp: idem.
-   rethrow_exception.pass.cpp: idem.
-  uncaught/
-   uncaught_exception.pass.cpp: Needs investigation.
- support.limits/
-  limits/
-   numeric.limits.members/
-    digits.pass.cpp: Needs investigation (wrong assumptions?).
-    digits10.pass.cpp: idem.
- support.runtime/
-  support.start.term/
-   quick_exit.pass.cpp: Not declared in libc++ headers. Is it from the ABI lib?
- support.types/
-  max_align_t.pass.cpp: needs investigation (wrong assumptions?).
-localization/
- locale.categories/
-  category.collate/
-   locale.collate.byname/
-    compare.pass.cpp: Windows locale names don't follow UNIX convention.
-    hash.pass.cpp: idem.
-    transform.pass.cpp: getenv should be replaced by putenv for portability.
-                        Windows locale names don't follow UNIX convention.
-    types.pass.cpp: Windows locale names don't follow UNIX convention.
- locale.categories/
-  category.ctype/
-   locale.codecvt/
-    locale.codecvt.members/
-     wchar_t_in.pass.cpp: Most likely wchar_t is assumed 4 bytes.
-     wchar_t_length.pass.cpp: idem.
-     wchar_t_out.pass.cpp: idem.
-     wchar_t_unshift.pass.cpp: idem.
-   locale.codecvt.byname/
-    ctor_wchar_t.pass.cpp: Windows locale names don't follow UNIX convention.
-   locale.ctype.byname/
-    is_1.pass.cpp: Windows locale names don't follow UNIX convention.
-    is_many.pass.cpp: idem.
-    narrow_1.pass.cpp: idem.
-    narrow_many.pass.cpp: idem.
-    scan_is.pass.cpp: idem.
-    scan_not.pass.cpp: idem.
-    tolower_1.pass.cpp: idem.
-    tolower_many.pass.cpp: idem.
-    toupper_1.pass.cpp: idem.
-    toupper_many.pass.cpp: idem.
-    types.pass.cpp: idem.
-    widen_1.pass.cpp: idem.
-    widen_many.pass.cpp: idem.
-  category.monetary/
-   locale.money.get/
-    locale.money.get.members/
-     get_long_double_en_US.pass.cpp: Windows locale names don't follow UNIX convention.
-     get_long_double_fr_FR.pass.cpp: idem.
-     get_long_double_ru_RU.pass.cpp: idem.
-     get_long_double_zh_CN.pass.cpp: idem.
-     get_string_en_US.pass.cpp: idem.
-   locale.money.put/
-    locale.money.put.members/
-	 put_long_double_en_US.pass.cpp: Windows locale names don't follow UNIX convention.
-     put_long_double_fr_FR.pass.cpp: idem.
-     put_long_double_ru_RU.pass.cpp: idem.
-     put_long_double_zh_CN.pass.cpp: idem.
-     put_string_en_US.pass.cpp: idem.
-   locale.moneypunct.byname/
-     curr_symbol.pass.cpp: Failed constructing from C locale. Needs investigation.
-     decimal_point.pass.cpp: idem.
-     frac_digits.pass.cpp: idem.
-     grouping.pass.cpp: idem.
-     neg_format.pass.cpp: idem.
-     negative_sign.pass.cpp: idem.
-     pos_format.pass.cpp: idem.
-     positive_sign.pass.cpp: idem.
-     thousands_sep.pass.cpp: idem.
-  category.numeric/
-   locale.nm.put/
-    facet.num.put.members/
-     put_double.pass.cpp: idem. (different floating point format?)
-     put_long_double.pass.cpp: idem.
-     put_pointer.pass.cpp: idem.
-   locale.num.get/
-    facet.num.get.members/
-     get_double.pass.cpp: Needs investigating.
-     get_float.pass.cpp: idem.
-     get_long_double.pass.cpp: idem.
-     get_pointer.pass.cpp: idem.
-  category.time/
-   locale.time.get/
-    locale.time.get.byname/
-     date_order.pass.cpp: Windows locale names don't follow UNIX convention.
-     date_order_wide.pass.cpp: idem.
-     get_date.pass.cpp: idem.
-     get_date_wide.pass.cpp: idem.
-     get_monthname.pass.cpp: idem.
-     get_monthname_wide.pass.cpp: idem.
-     get_one.pass.cpp: idem.
-     get_one_wide.pass.cpp: idem.
-     get_time.pass.cpp: idem.
-     get_time_wide.pass.cpp: idem.
-     get_weekday.pass.cpp: idem.
-     get_weekday_wide.pass.cpp: idem.
-     get_year.pass.cpp: idem.
-     get_year_wide.pass.cpp: idem.
-   locale.time.put/
-    locale.time.put.members/
-     put1.pass.cpp: Needs investigating.
-     put2.pass.cpp: idem.
-    locale.time.put.byname/
-     put1.pass.cpp: Windows locale names don't follow UNIX convention.
-   facet.numpunct/
-    locale.numpunct/
-     locale.numpunct.byname/
-      decimal_point.pass.cpp: Failed constructing from C locale. Needs investigation.
-      grouping.pass.cpp: idem.
-      thousands_sep.pass.cpp: idem.
- locale.stdcvt/
-  codecvt_utf16_in.pass.cpp: 0x40003 does not fit in a 2-byte wchar_t.
-  codecvt_utf16_out.pass.cpp: idem.
-  codecvt_utf8_in.pass.cpp: idem.
-  codecvt_utf8_out.pass.cpp: idem.
-  codecvt_utf8_utf16_in.pass: idem.
-  codecvt_utf8_utf16_out.pass.cpp: idem.
- locales/
-  locale/
-   locale.cons/
-    assign.pass.cpp: Windows locale names don't follow UNIX convention.
-    char_pointer.pass.cpp: idem.
-    copy.pass.cpp: idem.
-    default.pass.cpp: idem.
-    locale_char_pointer_cat.pass.cpp: idem.
-    locale_facetptr.pass.cpp: idem.
-    locale_locale_cat.pass.cpp: idem.
-    locale_string_cat.pass.cpp: idem.
-    string.pass.cpp: idem.
-   locale.members/
-    name.pass.cpp: Windows locale names don't follow UNIX convention.
-   locale.operators/
-    eq.pass.cpp: Windows locale names don't follow UNIX convention.
-   locale/locale.statics/
-    classic.pass.cpp: Failed constructing from C locale. Needs investigation.
-    global.pass.cpp: Windows locale names don't follow UNIX convention.
-   locale.convenience/
-    conversions/
-     conversions.buffer/
-      overflow.pass.cpp: Needs investigation.
-      pbackfail.pass.cpp: idem.
-      seekoff.pass.cpp: idem.
-      test.pass.cpp: idem.
-      underflow.pass.cpp: idem.
-     conversions.string/
-      converted.pass.cpp: out of range hex sequence due to 2-byte wchar_t.
-      from_bytes.pass.cpp: idem (This test passed while it probably shouldn't!).
-      to_bytes.pass.cpp: idem.
-numerics/
- complex.number/
-  complex.value.ops/
-   abs.pass.cpp: Failed assertion.
-   arg.pass.cpp: idem.
- rand/
-  rand.device/
-   ctor.pass.cpp: No such thing as /dev/urandom on Windows. Need alternative.
-   entropy.pass.cpp: idem.
-   eval.pass.cpp: idem.
-  rand.dis/
-   rand.dist.bern/
-    rand.dist.bern.bernoulli/
-     io.pass.cpp: Needs investigation. (different output double format?)
-    rand.dist.bern.bin/
-     io.pass.cpp: Needs investigation. (different output double format?)
-    rand.dist.bern.geo/
-     io.pass.cpp: Needs investigation. (different output double format?)
-    rand.dist.bern.negbin/
-     io.pass.cpp: Needs investigation. (different output double format?)
-   rand.dist.norm/
-	  rand.dist.norm.cauchy/
-     io.pass.cpp: Needs investigation. (different output double format?)
-	  rand.dist.norm.chisq/
-     io.pass.cpp: Needs investigation. (different output double format?)
-	  rand.dist.norm.norm.f/
-     io.pass.cpp: Needs investigation. (different output double format?)
-	  rand.dist.norm.lognormal/
-     io.pass.cpp: Needs investigation. (different output double format?)
-	  rand.dist.norm.normal/
-     io.pass.cpp: Needs investigation. (different output double format?)
-	  rand.dist.norm.t/
-     io.pass.cpp: Needs investigation. (different output double format?)
-   rand.dist.pois/
-    rand.dist.pois.exp/
-     io.pass.cpp: Needs investigation. (different output double format?)
-    rand.dist.pois.extreme/
-     io.pass.cpp: Needs investigation. (different output double format?)
-    rand.dist.pois.gamma/
-     io.pass.cpp: Needs investigation. (different output double format?)
-    rand.dist.pois.poisson/
-     io.pass.cpp: Needs investigation. (different output double format?)
-    rand.dist.pois.weibull/
-     io.pass.cpp: Needs investigation. (different output double format?)
-   rand.dist.samp/
-    rand.dist.samp.discrete/
-     io.pass.cpp: Needs investigation. (different output double format?)
-    rand.dist.samp.pconst/
-     io.pass.cpp: Needs investigation. (different output double format?)
-    rand.dist.samp.plinear/
-     io.pass.cpp: Needs investigation. (different output double format?)
-   rand.dist.uni/
-    rand.dist.uni.real/
-     io.pass.cpp: Needs investigation. (different output double format?)
-re/
- re.alg/
-  re.alg.match/
-   awk.pass.cpp: Needs investigation.
-   basic.pass.cpp: idem.
-   ecma.pass.cpp: idem.
-   extended.pass.cpp: idem.
-  re.alg.search/
-   awk.pass.cpp: Needs investigation.
-   basic.pass.cpp: idem.
-   ecma.pass.cpp: idem.
-   extended.pass.cpp: idem.
- re.regex/
-  re.regex.locale/
-   imbue.pass.cpp: Windows locale names don't follow UNIX convention.
- re.traits/
-  default.pass.cpp: Windows locale names don't follow UNIX convention.
-  getloc.pass.cpp: idem.
-  imbue.pass.cpp: idem.
-  isctype.pass.cpp: Needs investigation.
-  lookup_classname.pass.cpp: idem.
-  lookup_collatename.pass.cpp: Windows locale names don't follow UNIX convention.
-  transform.pass.cpp: idem.
-  transform_primary.pass.cpp: idem
-  translate_nocase.pass.cpp: Needs investigation.
-strings/
- c.strings/
-  cuchar.pass.cpp: see previous note about uchar.h.
-  cwchar.pass.cpp: I suggest including the win32 support header which defines
-                   (v)swprintf to the Windows equivalent.
-  version_cuchar.pass.cpp: see previous note about uchar.h.
- string.conversions/
-  stod.pass.cpp: "no conversion". Needs investigation.
-  stof.pass.cpp: idem.
-  to_string.pass.cpp: Needs investigation.
-  to_wstring.pass.cpp: idem.
-thread/
- futures/
-  futures.async/
-   async.pass.cpp: Needs investigation.
-  futures.promise/
-   alloc_ctor.pass.cpp: Needs investigation.
-   default.pass.cpp: idem.
-   dtor.pass.cpp: idem.
-   get_future.pass.cpp: idem.
-   move_assign.pass.cpp: idem.
-   move_ctor.pass.cpp: idem.
-   set_exception.pass.cpp: idem.
-   set_exception_at_thread_exit.pass.cpp: idem.
-   set_lvalue.pass.cpp: idem.
-   set_lvalue_at_thread_exit.pass.cpp: idem.
-   set_rvalue.pass.cpp: idem.
-   set_rvalue_at_thread_exit.pass.cpp: idem.
-   set_value_at_thread_exit_const.pass.cpp: idem.
-   set_value_at_thread_exit_void.pass.cpp: idem.
-   set_value_const.pass.cpp: idem.
-   set_value_void.pass.cpp: idem.
-   swap.pass.cpp: idem.
-  futures.shared_future/
-   copy_assign.pass.cpp: Needs investigation.
-   copy_ctor.pass.cpp: idem.
-   ctor_future.pass.cpp: idem.
-   dtor.pass.cpp: idem.
-   get.pass.cpp: idem.
-   move_assign.pass.cpp: idem.
-   move_ctor.pass.cpp: idem.
-   wait.pass.cpp: idem.
-   wait_for.pass.cpp: idem.
-   wait_until.pass.cpp: idem.
-  futures.tas/
-   futures.task.members/
-    assign_move.pass.cpp: Needs investigation.
-    ctor_func.pass.cpp: idem.
-    ctor_func_alloc.pass.cpp: idem.
-    ctor_move.pass.cpp: idem.
-    dtor.pass.cpp: idem.
-    get_future.pass.cpp: idem.
-    make_ready_at_thread_exit.pass.cpp: idem.
-    operator.pass.cpp: idem.
-    reset.pass.cpp: idem.
-    swap.pass.cpp: idem.
-   futures.task.nonmembers/
-    swap.pass.cpp: Needs investigation.
-   futures.unique_future/
-    dtor.pass.cpp: Needs investigation.
-    get.pass.cpp: idem.
-    move_assign.pass.cpp: idem.
-    move_ctor.pass.cpp: idem.
-    share.pass.cpp: idem.
-    wait.pass.cpp: idem.
-    wait_for.pass.cpp: idem.
-    wait_until.pass.cpp: idem.
- thread.condition/
-  thread.condition.condvar/
-   wait_for.pass.cpp: Needs investigation.
-  thread.condition.condvarany/
-   wait_for.pass.cpp: Needs investigation.
- thread.mutex/
-  thread.lock/
-   thread.lock.unique/
-    thread.lock.unique.cons/
-     mutex_try_to_lock.pass.cpp: Needs investigation.
- thread.threads/
-  thread.thread.class/
-   thread.thread.constr/
-    move.pass.cpp: Needs investigation.
-   thread.thread.id/
-    join.pass.cpp: Needs investigation.
-   thread.thread.static/
-    hardware_concurrency.pass.cpp: Needs investigation.
-utilities/
- meta/
-  meta.trans/
-   meta.trans.other/
-    aligned_storage.pass.cpp: Probably due to sizeof(long) != 8.
-   meta.trans.sign/
-    make_signed.pass.cpp: Probably due to sizeof(wchar_t) != 4.
-    make_unsigned.pass.cpp: idem.
-   meta.unary.prop.query/
-    alignment_of.pass.cpp: Probably a Clang problem on Windows.
-
- -