Index: test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp =================================================================== --- test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp @@ -385,6 +385,27 @@ #endif } +template +constexpr bool triviality_test = + std::is_trivially_copy_assignable>::value == + std::conjunction< + std::is_trivially_destructible..., + std::is_trivially_copy_constructible..., + std::is_trivially_copy_assignable...>::value; + +void test_triviality_extension() { +#if defined(_MSVC_STL_VER) + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); +#endif +} int main() { test_copy_assignment_empty_empty(); @@ -394,4 +415,5 @@ test_copy_assignment_different_index(); test_copy_assignment_sfinae(); test_copy_assignment_not_noexcept(); + test_triviality_extension(); } Index: test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp =================================================================== --- test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp @@ -308,6 +308,56 @@ #endif } +template +constexpr bool triviality_test = + // move assignent of variant is trivial when + std::is_trivially_move_assignable>::value == + std::conjunction< + // All Ts are trivially destructible and + std::is_trivially_destructible..., + // either + std::disjunction< + // All Ts are trivially move (constructible and assignable) so that + // variant's move assignment operator is non-deleted and trivial, or + std::conjunction< + std::is_trivially_move_constructible..., + std::is_trivially_move_assignable...>, + // At least one of the Ts is not move (constructible or assignable) so + // that variant's move assignment operator is *implicitly* deleted but + // all of the Ts are trivially *copy* (constructible and deletable) so + // that move assignment actually invokes the trivial copy assignment + // operator. + std::conjunction< + std::disjunction< + std::negation>..., + std::negation>...>, + std::is_trivially_copy_constructible..., + std::is_trivially_copy_assignable...>>>::value; + +void test_triviality_extension() { +#if defined(_MSVC_STL_VER) + struct TrivialCopyNontrivialMove { + TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default; + TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {} + TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default; + TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept { + return *this; + } + }; + + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); +#endif +} + int main() { test_move_assignment_empty_empty(); test_move_assignment_non_empty_empty(); @@ -316,4 +366,5 @@ test_move_assignment_different_index(); test_move_assignment_sfinae(); test_move_assignment_noexcept(); + test_triviality_extension(); } Index: test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp =================================================================== --- test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp @@ -21,6 +21,7 @@ #include #include "test_macros.h" +#include "test_workarounds.h" struct NonT { NonT(int v) : value(v) {} @@ -137,23 +138,48 @@ auto v2 = v; return v2.index() == v.index() && v2.index() == Idx && - std::get(v2) == std::get(v); + std::get(v2) == std::get(v); } void test_constexpr_copy_ctor_extension() { -#ifdef _LIBCPP_VERSION +#if defined(_LIBCPP_VER) || defined(_MSVC_STL_VER) using V = std::variant; - static_assert(std::is_trivially_copyable::value, ""); +#ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE + static_assert(std::is_trivially_destructible::value, ""); static_assert(std::is_trivially_copy_constructible::value, ""); + static_assert(std::is_trivially_move_constructible::value, ""); + static_assert(!std::is_copy_assignable::value, ""); + static_assert(!std::is_move_assignable::value, ""); +#else + static_assert(std::is_trivially_copyable::value, ""); +#endif static_assert(test_constexpr_copy_ctor_extension_imp<0>(V(42l)), ""); static_assert(test_constexpr_copy_ctor_extension_imp<1>(V(nullptr)), ""); static_assert(test_constexpr_copy_ctor_extension_imp<2>(V(101)), ""); #endif } +template +constexpr bool triviality_test = + std::is_trivially_copy_constructible>::value == + std::conjunction...>::value; + +void test_triviality_extension() { +#if defined(_MSVC_STL_VER) + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); +#endif +} + int main() { test_copy_ctor_basic(); test_copy_ctor_valueless_by_exception(); test_copy_ctor_sfinae(); test_constexpr_copy_ctor_extension(); + test_triviality_extension(); } Index: test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp =================================================================== --- test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp @@ -22,6 +22,7 @@ #include #include "test_macros.h" +#include "test_workarounds.h" struct ThrowsMove { ThrowsMove(ThrowsMove &&) noexcept(false) {} @@ -178,9 +179,17 @@ } void test_constexpr_move_ctor_extension() { -#ifdef _LIBCPP_VERSION +#if defined(_LIBCPP_VER) || defined(_MSVC_STL_VER) using V = std::variant; +#ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE + static_assert(std::is_trivially_destructible::value, ""); + static_assert(std::is_trivially_copy_constructible::value, ""); + static_assert(std::is_trivially_move_constructible::value, ""); + static_assert(!std::is_copy_assignable::value, ""); + static_assert(!std::is_move_assignable::value, ""); +#else static_assert(std::is_trivially_copyable::value, ""); +#endif static_assert(std::is_trivially_move_constructible::value, ""); static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), ""); static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), ""); @@ -188,10 +197,30 @@ #endif } +template +constexpr bool triviality_test = + std::is_trivially_move_constructible>::value == + std::conjunction...>::value; + +void test_triviality_extension() { +#if defined(_MSVC_STL_VER) + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); + static_assert(triviality_test, ""); +#endif +} + int main() { test_move_ctor_basic(); test_move_ctor_valueless_by_exception(); test_move_noexcept(); test_move_ctor_sfinae(); test_constexpr_move_ctor_extension(); + test_triviality_extension(); } Index: test/support/msvc_stdlib_force_include.hpp =================================================================== --- test/support/msvc_stdlib_force_include.hpp +++ test/support/msvc_stdlib_force_include.hpp @@ -26,6 +26,11 @@ #error This header may not be used when targeting libc++ #endif +// Indicates that we are using the MSVC standard library. +#ifndef _MSVC_STL_VER +#define _MSVC_STL_VER 42 +#endif + struct AssertionDialogAvoider { AssertionDialogAvoider() { _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); Index: test/support/test.workarounds/c1xx_broken_is_trivially_copyable.pass.cpp =================================================================== --- /dev/null +++ test/support/test.workarounds/c1xx_broken_is_trivially_copyable.pass.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// Verify TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE. + +#include + +#include "test_workarounds.h" + +struct S { + S(S const&) = default; + S(S&&) = default; + S& operator=(S const&) = delete; + S& operator=(S&&) = delete; +}; + +int main() { +#if defined(TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE) + static_assert(!std::is_trivially_copyable::value, ""); +#else + static_assert(std::is_trivially_copyable::value, ""); +#endif +} Index: test/support/test_workarounds.h =================================================================== --- test/support/test_workarounds.h +++ test/support/test_workarounds.h @@ -15,6 +15,7 @@ #if defined(TEST_COMPILER_C1XX) # define TEST_WORKAROUND_C1XX_BROKEN_NULLPTR_CONVERSION_OPERATOR +# define TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE #endif #endif // SUPPORT_TEST_WORKAROUNDS_H