From b18fd9654f67876d366dc7d5577a5c91287d8353 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Fri, 7 Oct 2016 21:27:45 +0000 Subject: [PATCH] Fix various issues in std::any and the related tests. * Fix self-swap. Patch from Casey Carter. * Remove workarounds and tests for types with deleted move constructors. This was originally added as part of a LWG proposed resolution that has since changed. * Re-apply most recent PR for LWG 2769. * Re-apply most recent PR for LWG 2754. Specifically fix the SFINAE checks to use the decayed type. * Fix tests to allow moved-from std::any's to have a non-empty state. This is the behavior of MSVC's std::any. * Various whitespace and test fixes. llvm-svn: 283606 --- libcxx/include/any | 108 ++++++++--------- libcxx/include/type_traits | 5 + .../any/any.class/any.assign/move.pass.cpp | 16 ++- .../any/any.class/any.assign/value.pass.cpp | 14 ++- .../any/any.class/any.cons/copy.pass.cpp | 2 +- .../any.class/any.cons/in_place_type.pass.cpp | 46 +++++++- .../any/any.class/any.cons/move.pass.cpp | 6 +- .../any/any.class/any.cons/value.pass.cpp | 30 +---- .../any.class/any.modifiers/emplace.pass.cpp | 11 +- .../any/any.class/any.modifiers/swap.pass.cpp | 32 +++++ .../any.cast/any_cast_reference.pass.cpp | 110 +++--------------- .../any.cast/const_correctness.fail.cpp | 12 +- .../any.cast/not_copy_constructible.fail.cpp | 25 +++- .../rvalue_any_cast_request_lvalue.fail.cpp | 36 ++++++ .../any/any.nonmembers/make_any.pass.cpp | 4 +- libcxx/test/support/any_helpers.h | 61 ---------- libcxx/test/support/test_macros.h | 2 + 17 files changed, 244 insertions(+), 276 deletions(-) create mode 100644 libcxx/test/std/utilities/any/any.nonmembers/any.cast/rvalue_any_cast_request_lvalue.fail.cpp diff --git a/libcxx/include/any b/libcxx/include/any index 6f742cbdf73b..69fdbddd621d 100644 --- a/libcxx/include/any +++ b/libcxx/include/any @@ -197,30 +197,33 @@ public: template < class _ValueType + , class _Tp = decay_t<_ValueType> , class = enable_if_t< - !is_same, any>::value && + !is_same<_Tp, any>::value && !__is_inplace_type<_ValueType>::value && - is_copy_constructible<_ValueType>::value> + is_copy_constructible<_Tp>::value> > _LIBCPP_INLINE_VISIBILITY any(_ValueType && __value); - template , class = enable_if_t< is_constructible<_Tp, _Args...>::value && is_copy_constructible<_Tp>::value > > _LIBCPP_INLINE_VISIBILITY - explicit any(in_place_type_t<_Tp>, _Args&&... __args); + explicit any(in_place_type_t<_ValueType>, _Args&&... __args); - template , class = enable_if_t< is_constructible<_Tp, initializer_list<_Up>&, _Args...>::value && is_copy_constructible<_Tp>::value> > _LIBCPP_INLINE_VISIBILITY - explicit any(in_place_type_t<_Tp>, initializer_list<_Up>, _Args&&... __args); + explicit any(in_place_type_t<_ValueType>, initializer_list<_Up>, _Args&&... __args); _LIBCPP_INLINE_VISIBILITY ~any() { this->reset(); } @@ -242,15 +245,17 @@ public: // ValueType constructor? template < class _ValueType + , class _Tp = decay_t<_ValueType> , class = enable_if_t< - !is_same, any>::value - && is_copy_constructible<_ValueType>::value + !is_same<_Tp, any>::value + && is_copy_constructible<_Tp>::value && !__is_inplace_type<_ValueType>::value> > _LIBCPP_INLINE_VISIBILITY any & operator=(_ValueType && __rhs); - template , class = enable_if_t< is_constructible<_Tp, _Args...>::value && is_copy_constructible<_Tp>::value> @@ -258,7 +263,8 @@ public: _LIBCPP_INLINE_VISIBILITY void emplace(_Args&&... args); - template , class = enable_if_t< is_constructible<_Tp, initializer_list<_Up>&, _Args...>::value && is_copy_constructible<_Tp>::value> @@ -490,60 +496,49 @@ namespace __any_imp } // namespace __any_imp -template +template any::any(_ValueType && __v) : __h(nullptr) { - typedef typename decay<_ValueType>::type _Tp; - static_assert(is_copy_constructible<_Tp>::value, - "_ValueType must be CopyConstructible."); - using _ForwardTp = conditional_t< - is_move_constructible<_Tp>::value, _ValueType, _ValueType&>; - typedef __any_imp::_Handler<_Tp> _HandlerType; - _HandlerType::__create(*this, _VSTD::forward<_ForwardTp>(__v)); + __any_imp::_Handler<_Tp>::__create(*this, _VSTD::forward<_ValueType>(__v)); } -template -any::any(in_place_type_t<_Tp>, _Args&&... __args) { - using _Hp = __any_imp::_Handler<_Tp>; - _Hp::__create(*this, _VSTD::forward<_Args>(__args)...); +template +any::any(in_place_type_t<_ValueType>, _Args&&... __args) { + __any_imp::_Handler<_Tp>::__create(*this, _VSTD::forward<_Args>(__args)...); }; -template -any::any(in_place_type_t<_Tp>, initializer_list<_Up> __il, _Args&&... __args) { - using _Hp = __any_imp::_Handler<_Tp>; - _Hp::__create(*this, __il, _VSTD::forward<_Args>(__args)...); +template +any::any(in_place_type_t<_ValueType>, initializer_list<_Up> __il, _Args&&... __args) { + __any_imp::_Handler<_Tp>::__create(*this, __il, _VSTD::forward<_Args>(__args)...); } -template +template inline _LIBCPP_INLINE_VISIBILITY any & any::operator=(_ValueType && __v) { - typedef typename decay<_ValueType>::type _Tp; - static_assert(is_copy_constructible<_Tp>::value, - "_ValueType must be CopyConstructible."); any(_VSTD::forward<_ValueType>(__v)).swap(*this); return *this; } -template +template inline _LIBCPP_INLINE_VISIBILITY void any::emplace(_Args&&... __args) { - using _Hp = __any_imp::_Handler<_Tp>; reset(); - _Hp::__create(*this, _VSTD::forward<_Args>(__args)...); + __any_imp::_Handler<_Tp>::__create(*this, _VSTD::forward<_Args>(__args)...); } -template +template inline _LIBCPP_INLINE_VISIBILITY void any::emplace(initializer_list<_Up> __il, _Args&&... __args) { - using _Hp = __any_imp::_Handler<_Tp>; reset(); - _Hp::__create(*this, __il, _VSTD::forward<_Args>(__args)...); + __any_imp::_Handler<_Tp>::__create(*this, __il, _VSTD::forward<_Args>(__args)...); } inline _LIBCPP_INLINE_VISIBILITY void any::swap(any & __rhs) _NOEXCEPT { + if (this == &__rhs) + return; if (__h && __rhs.__h) { any __tmp; __rhs.__call(_Action::_Move, &__tmp); @@ -582,50 +577,39 @@ template inline _LIBCPP_INLINE_VISIBILITY _ValueType any_cast(any const & __v) { - static_assert( - is_reference<_ValueType>::value - || is_copy_constructible<_ValueType>::value, - "_ValueType is required to be a reference or a CopyConstructible type."); - using _Tp = add_const_t>; - _Tp * __tmp = _VSTD::any_cast<_Tp>(&__v); + using _RawValueType = __uncvref_t<_ValueType>; + static_assert(is_constructible<_ValueType, _RawValueType const &>::value, + "ValueType is required to be a reference or a CopyConstructible type"); + auto __tmp = _VSTD::any_cast>(&__v); if (__tmp == nullptr) __throw_bad_any_cast(); - return *__tmp; + return static_cast<_ValueType>(*__tmp); } template inline _LIBCPP_INLINE_VISIBILITY _ValueType any_cast(any & __v) { - static_assert( - is_reference<_ValueType>::value - || is_copy_constructible<_ValueType>::value, - "_ValueType is required to be a reference or a CopyConstructible type."); - typedef typename remove_reference<_ValueType>::type _Tp; - _Tp * __tmp = _VSTD::any_cast<_Tp>(&__v); + using _RawValueType = __uncvref_t<_ValueType>; + static_assert(is_constructible<_ValueType, _RawValueType &>::value, + "ValueType is required to be a reference or a CopyConstructible type"); + auto __tmp = _VSTD::any_cast<_RawValueType>(&__v); if (__tmp == nullptr) __throw_bad_any_cast(); - return *__tmp; + return static_cast<_ValueType>(*__tmp); } template inline _LIBCPP_INLINE_VISIBILITY _ValueType any_cast(any && __v) { - static_assert( - is_reference<_ValueType>::value - || is_copy_constructible<_ValueType>::value, - "_ValueType is required to be a reference or a CopyConstructible type."); - typedef typename remove_reference<_ValueType>::type _Tp; - using _ForwardTp = conditional_t< - is_reference<_ValueType>::value, - _ValueType, - conditional_t::value, _Tp, _Tp&> - >; - _Tp * __tmp = _VSTD::any_cast<_Tp>(&__v); + using _RawValueType = __uncvref_t<_ValueType>; + static_assert(is_constructible<_ValueType, _RawValueType>::value, + "ValueType is required to be an rvalue reference or a CopyConstructible type"); + auto __tmp = _VSTD::any_cast<_RawValueType>(&__v); if (__tmp == nullptr) __throw_bad_any_cast(); - return _VSTD::forward<_ForwardTp>(*__tmp); + return static_cast<_ValueType>(_VSTD::move(*__tmp)); } template diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits index 26165713a248..519d91f4bd84 100644 --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -1122,6 +1122,11 @@ struct __unconstref { typedef typename remove_const::type>::type type; }; +#ifndef _LIBCPP_CXX03_LANG +template +using __uncvref_t = typename __uncvref<_Tp>::type; +#endif + // __is_same_uncvref template diff --git a/libcxx/test/std/utilities/any/any.class/any.assign/move.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.assign/move.pass.cpp index bac3edb7cdb0..2063e4f1e9f1 100644 --- a/libcxx/test/std/utilities/any/any.class/any.assign/move.pass.cpp +++ b/libcxx/test/std/utilities/any/any.class/any.assign/move.pass.cpp @@ -40,10 +40,13 @@ void test_move_assign() { a = std::move(a2); assert(LHS::count == 1); - assert(RHS::count == 2); + assert(RHS::count == 2 + a2.has_value()); + LIBCPP_ASSERT(RHS::count == 2); // libc++ leaves the object empty assertContains(a, 2); - assertEmpty(a2); + if (a2.has_value()) + assertContains(a2, 0); + LIBCPP_ASSERT(!a2.has_value()); } assert(LHS::count == 0); assert(RHS::count == 0); @@ -54,16 +57,19 @@ void test_move_assign_empty() { assert(LHS::count == 0); { any a; - any a2((LHS(1))); + any a2((LHS(1))); assert(LHS::count == 1); a = std::move(a2); - assert(LHS::count == 1); + assert(LHS::count == 1 + a2.has_value()); + LIBCPP_ASSERT(LHS::count == 1); assertContains(a, 1); - assertEmpty(a2); + if (a2.has_value()) + assertContains(a2, 0); + LIBCPP_ASSERT(!a2.has_value()); } assert(LHS::count == 0); { diff --git a/libcxx/test/std/utilities/any/any.class/any.assign/value.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.assign/value.pass.cpp index d844fcfaa7c3..cb8dd4ca964a 100644 --- a/libcxx/test/std/utilities/any/any.class/any.assign/value.pass.cpp +++ b/libcxx/test/std/utilities/any/any.class/any.assign/value.pass.cpp @@ -11,7 +11,8 @@ // -// any& operator=(any const &); +// template +// any& operator=(ValueType&&); // Test value copy and move assignment. @@ -65,10 +66,12 @@ void test_assign_value() { assert(RHS::moved >= 1); assert(RHS::copied == 0); assert(LHS::count == 0); - assert(RHS::count == 1); + assert(RHS::count == 1 + rhs.has_value()); + LIBCPP_ASSERT(!rhs.has_value()); assertContains(lhs, 2); - assertEmpty(rhs); + if (rhs.has_value()) + assertContains(rhs, 0); } assert(LHS::count == 0); assert(RHS::count == 0); @@ -114,7 +117,7 @@ void test_assign_value_empty() { template void test_assign_throws() { #if !defined(TEST_HAS_NO_EXCEPTIONS) - auto try_throw= + auto try_throw = [](any& lhs, auto&& rhs) { try { Move ? lhs = std::move(rhs) @@ -188,6 +191,7 @@ void test_sfinae_constraints() { NoCopy(NoCopy&&) = default; }; static_assert(!std::is_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); } } @@ -202,4 +206,4 @@ int main() { test_assign_throws(); test_assign_throws(); test_sfinae_constraints(); -} \ No newline at end of file +} diff --git a/libcxx/test/std/utilities/any/any.class/any.cons/copy.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.cons/copy.pass.cpp index 03870caa531b..021c9e452841 100644 --- a/libcxx/test/std/utilities/any/any.class/any.cons/copy.pass.cpp +++ b/libcxx/test/std/utilities/any/any.class/any.cons/copy.pass.cpp @@ -71,7 +71,7 @@ void test_copy() assert(Type::copied == 1); assert(Type::count == 2); assertContains(a, 42); - assertContains(a, 42); + assertContains(a2, 42); // Modify a and check that a2 is unchanged modifyValue(a, -1); diff --git a/libcxx/test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp index 949c105f9886..98b8c8701624 100644 --- a/libcxx/test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp +++ b/libcxx/test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp @@ -49,6 +49,16 @@ void test_in_place_type() { } assert(Type::count == 0); Type::reset(); + { // Test that the in_place argument is properly decayed + any a(std::in_place); + + assert(Type::count == 1); + assert(Type::copied == 0); + assert(Type::moved == 0); + assertContains(a, 0); + } + assert(Type::count == 0); + Type::reset(); { any a(std::in_place, 101); @@ -90,11 +100,38 @@ void test_in_place_type_tracked() { } { int x = 42; - any a(std::in_place, {-1, 42, -1}, x); + any a(std::in_place, {-1, 42, -1}, x); assertArgsMatch, int&>(a); } } +void test_func() {} + +void test_in_place_type_decayed() { + { + using Type = decltype(test_func); + using DecayT = void(*)(); + any a(std::in_place, test_func); + assert(containsType(a)); + assert(any_cast(a) == test_func); + } + { + int my_arr[5]; + using Type = int(&)[5]; + using DecayT = int*; + any a(std::in_place, my_arr); + assert(containsType(a)); + assert(any_cast(a) == my_arr); + } + { + using Type = int[5]; + using DecayT = int*; + any a(std::in_place); + assert(containsType(a)); + assert(any_cast(a) == nullptr); + } +} + void test_ctor_sfinae() { { // Test that the init-list ctor SFINAE's away properly when @@ -115,10 +152,14 @@ void test_ctor_sfinae() { NoCopy(std::initializer_list, int) {} }; using Tag = std::in_place_type_t; + using RefTag = std::in_place_type_t; using IL = std::initializer_list; static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); } } @@ -147,6 +188,7 @@ int main() { test_in_place_type(); test_in_place_type_tracked(); test_in_place_type_tracked(); + test_in_place_type_decayed(); test_ctor_sfinae(); test_constructor_explicit(); -} \ No newline at end of file +} diff --git a/libcxx/test/std/utilities/any/any.class/any.cons/move.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.cons/move.pass.cpp index 9a83e66ab8a6..ebd49ccdcbd6 100644 --- a/libcxx/test/std/utilities/any/any.class/any.cons/move.pass.cpp +++ b/libcxx/test/std/utilities/any/any.class/any.cons/move.pass.cpp @@ -77,11 +77,13 @@ void test_move() { any a2(std::move(a)); - assert(Type::moved >= 1); // zero or more move operations can be performed. + assert(Type::moved == 1 || Type::moved == 2); // zero or more move operations can be performed. assert(Type::copied == 0); // no copies can be performed. - assert(Type::count == 1); + assert(Type::count == 1 + a.has_value()); assertEmpty(a); // Moves are always destructive. assertContains(a2, 42); + if (a.has_value()) + assertContains(a, 0); } assert(Type::count == 0); } diff --git a/libcxx/test/std/utilities/any/any.class/any.cons/value.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.cons/value.pass.cpp index ba5419b12454..e39f139dadc4 100644 --- a/libcxx/test/std/utilities/any/any.class/any.cons/value.pass.cpp +++ b/libcxx/test/std/utilities/any/any.class/any.cons/value.pass.cpp @@ -30,7 +30,6 @@ using std::any; using std::any_cast; - template void test_copy_value_throws() { @@ -107,33 +106,6 @@ void test_copy_move_value() { } } -void test_non_moveable_type() -{ - using Type = deleted_move; - { - deleted_move mv(42); - std::any a(mv); - assert(Type::count == 2); - assert(Type::copied == 1); - assert(Type::moved == 0); - assertContains(a, 42); - } - assert(Type::count == 0); - Type::reset(); - { - deleted_move mv(42); - std::any a(std::move(mv)); - assert(Type::count == 2); - assert(Type::copied == 1); - assert(Type::moved == 0); - assertContains(a, 42); - } - assert(Type::count == 0); - Type::reset(); -} - - - // Test that any(ValueType&&) is *never* selected for a std::in_place type. void test_sfinae_constraints() { using Tag = std::in_place_type_t; @@ -169,6 +141,7 @@ void test_sfinae_constraints() { NoCopy(int) {} }; static_assert(!std::is_constructible::value, ""); + static_assert(!std::is_constructible::value, ""); static_assert(!std::is_convertible::value, ""); } } @@ -179,6 +152,5 @@ int main() { test_copy_value_throws(); test_copy_value_throws(); test_move_value_throws(); - test_non_moveable_type(); test_sfinae_constraints(); } \ No newline at end of file diff --git a/libcxx/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp index fa8b093d3048..2afb41e02bab 100644 --- a/libcxx/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp +++ b/libcxx/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp @@ -129,7 +129,7 @@ static_assert(IsSmallObject::value, ""); struct LargeThrows { LargeThrows(int) { throw 42; } LargeThrows(std::initializer_list, int) { throw 42; } - int data[10]; + int data[sizeof(std::any)]; }; static_assert(!IsSmallObject::value, ""); @@ -236,6 +236,13 @@ void test_emplace_sfinae_constraints() { static_assert(!has_emplace(), ""); static_assert(!has_emplace(), ""); static_assert(!has_emplace_init_list(), ""); + static_assert(!has_emplace(), ""); + static_assert(!has_emplace(), ""); + static_assert(!has_emplace_init_list(), ""); + static_assert(!has_emplace(), ""); + static_assert(!has_emplace(), ""); + static_assert(!has_emplace_init_list(), ""); + } } @@ -252,4 +259,4 @@ int main() { test_emplace_throws(); test_emplace_throws(); #endif -} \ No newline at end of file +} diff --git a/libcxx/test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp b/libcxx/test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp index 013982478eeb..1fef43fc5850 100644 --- a/libcxx/test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp +++ b/libcxx/test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp @@ -89,6 +89,37 @@ void test_noexcept() ); } +void test_self_swap() { + { + // empty + any a; + a.swap(a); + assertEmpty(a); + } + { // small + using T = small; + any a{T{42}}; + T::reset(); + a.swap(a); + assertContains(a, 42); + assert(T::count == 1); + assert(T::copied == 0); + assert(T::moved == 0); + } + assert(small::count == 0); + { // large + using T = large; + any a{T{42}}; + T::reset(); + a.swap(a); + assertContains(a, 42); + assert(T::copied == 0); + assert(T::moved == 0); + assert(T::count == 1); + } + assert(large::count == 0); +} + int main() { test_noexcept(); @@ -98,4 +129,5 @@ int main() test_swap(); test_swap(); test_swap(); + test_self_swap(); } diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp index 852e776ce2d2..0b49ceefc324 100644 --- a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp +++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp @@ -91,7 +91,12 @@ void checkThrows(any& a) } try { - any_cast(static_cast(a)); + using RefType = typename std::conditional< + std::is_lvalue_reference::value, + typename std::remove_reference::type&&, + Type + >::type; + any_cast(static_cast(a)); assert(false); } catch (bad_any_cast const &) { // do nothing @@ -142,14 +147,6 @@ void test_cast_to_reference() { Type const &cv = any_cast(ca); assert(&cv == &v); } - // Check getting a type by reference from a non-const rvalue - { - Type& v = any_cast(std::move(a)); - assert(v.value == 42); - - Type const &cv = any_cast(std::move(a)); - assert(&cv == &v); - } // Check getting a type by reference from a const rvalue any. { Type const& v = any_cast(std::move(ca)); @@ -229,8 +226,8 @@ void test_cast_to_value() { assert(Type::count == 2); assert(Type::copied == 1); - assert(Type::const_copied == 1); - assert(Type::non_const_copied == 0); + assert(Type::const_copied == 0); + assert(Type::non_const_copied == 1); assert(Type::moved == 0); assert(t.value == 42); } @@ -272,12 +269,13 @@ void test_cast_to_value() { Type t = any_cast(static_cast(a)); assert(Type::count == 2); - assert(Type::copied == 1); - assert(Type::const_copied == 1); + assert(Type::copied == 0); + assert(Type::const_copied == 0); assert(Type::non_const_copied == 0); - assert(Type::moved == 0); + assert(Type::moved == 1); assert(t.value == 42); - assert(any_cast(a).value == 42); + assert(any_cast(a).value == 0); + any_cast(a).value = 42; // reset the value } assert(Type::count == 1); Type::reset(); @@ -303,86 +301,6 @@ void test_cast_to_value() { assert(Type::count == 0); } -void test_cast_to_value_deleted_move() -{ - using Type = deleted_move; - { - std::any a(deleted_move(42)); - assert(Type::count == 1); - assert(Type::copied == 1); - assert(Type::moved == 0); - - Type const& t = any_cast(a); - assert(Type::count == 2); - assert(Type::copied == 2); - assert(Type::moved == 0); - assertContains(a, 42); - } - assert(Type::count == 0); - Type::reset(); - { - std::any a(deleted_move(42)); - std::any const& ca = a; - assert(Type::count == 1); - assert(Type::copied == 1); - assert(Type::moved == 0); - - Type const& t = any_cast(ca); - assert(Type::count == 2); - assert(Type::copied == 2); - assert(Type::moved == 0); - assertContains(a, 42); - } - assert(Type::count == 0); - Type::reset(); - { - std::any a(deleted_move(42)); - assert(Type::count == 1); - assert(Type::copied == 1); - assert(Type::moved == 0); - - Type&& t = any_cast(std::move(a)); - assert(Type::count == 2); - assert(Type::copied == 2); - assert(Type::moved == 0); - assertContains(a, 42); - } - assert(Type::count == 0); - Type::reset(); - { - std::any a(deleted_move(42)); - std::any const& ca = a; - assert(Type::count == 1); - assert(Type::copied == 1); - assert(Type::moved == 0); - - Type&& t = any_cast(std::move(ca)); - assert(Type::count == 2); - assert(Type::copied == 2); - assert(Type::moved == 0); - assertContains(a, 42); - } - assert(Type::count == 0); - Type::reset(); -} - -// Even though you can't get a non-copyable class into std::any -// the standard requires that these overloads compile and function. -void test_non_copyable_ref() { - struct no_copy - { - no_copy() {} - no_copy(no_copy &&) {} - private: - no_copy(no_copy const &); - }; - - any a; - checkThrows(a); - checkThrows(a); - assertEmpty(a); -} - int main() { test_cast_is_not_noexcept(); test_cast_return_type(); @@ -391,6 +309,4 @@ int main() { test_cast_to_reference(); test_cast_to_value(); test_cast_to_value(); - test_cast_to_value_deleted_move(); - test_non_copyable_ref(); } diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp index a141b05ef7cd..59294e780851 100644 --- a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp +++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp @@ -28,11 +28,19 @@ int main() any a; - // expected-error@any:* 2 {{binding value of type '_Tp' (aka 'const TestType') to reference to type 'TestType' drops 'const' qualifier}} + // expected-error@any:* {{binding value of type 'const TestType' to reference to type 'TestType' drops 'const' qualifier}} + // expected-error@any:* {{static_assert failed "ValueType is required to be a reference or a CopyConstructible type"}} any_cast(static_cast(a)); // expected-note {{requested here}} + + // expected-error@any:* {{cannot cast from lvalue of type 'const TestType' to rvalue reference type 'TestType &&'; types are not compatible}} + // expected-error@any:* {{static_assert failed "ValueType is required to be a reference or a CopyConstructible type"}} any_cast(static_cast(a)); // expected-note {{requested here}} - // expected-error@any:* 2 {{binding value of type '_Tp' (aka 'const TestType2') to reference to type 'TestType2' drops 'const' qualifier}} + // expected-error@any:* {{binding value of type 'const TestType2' to reference to type 'TestType2' drops 'const' qualifier}} + // expected-error@any:* {{static_assert failed "ValueType is required to be a reference or a CopyConstructible type"}} any_cast(static_cast(a)); // expected-note {{requested here}} + + // expected-error@any:* {{cannot cast from lvalue of type 'const TestType2' to rvalue reference type 'TestType2 &&'; types are not compatible}} + // expected-error@any:* {{static_assert failed "ValueType is required to be a reference or a CopyConstructible type"}} any_cast(static_cast(a)); // expected-note {{requested here}} } diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp index 415da8396db9..13e1a556086d 100644 --- a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp +++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp @@ -31,15 +31,28 @@ struct no_copy { no_copy() {} no_copy(no_copy &&) {} -private: - no_copy(no_copy const &); + no_copy(no_copy const &) = delete; +}; + +struct no_move { + no_move() {} + no_move(no_move&&) = delete; + no_move(no_move const&) {} }; int main() { any a; + // expected-error@any:* {{static_assert failed "ValueType is required to be a reference or a CopyConstructible type"}} + // expected-error@any:* {{static_cast from 'no_copy' to 'no_copy' uses deleted function}} any_cast(static_cast(a)); // expected-note {{requested here}} + + // expected-error@any:* {{static_assert failed "ValueType is required to be a reference or a CopyConstructible type"}} + // expected-error@any:* {{static_cast from 'const no_copy' to 'no_copy' uses deleted function}} any_cast(static_cast(a)); // expected-note {{requested here}} - any_cast(static_cast(a)); // expected-note {{requested here}} - // expected-error@any:* 3 {{static_assert failed "_ValueType is required to be a reference or a CopyConstructible type."}} - // expected-error@any:* 2 {{calling a private constructor of class 'no_copy'}} -} \ No newline at end of file + + any_cast(static_cast(a)); // OK + + // expected-error@any:* {{static_assert failed "ValueType is required to be an rvalue reference or a CopyConstructible type"}} + // expected-error@any:* {{static_cast from 'typename remove_reference::type' (aka 'no_move') to 'no_move' uses deleted function}} + any_cast(static_cast(a)); +} diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/rvalue_any_cast_request_lvalue.fail.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/rvalue_any_cast_request_lvalue.fail.cpp new file mode 100644 index 000000000000..76df14c33aa0 --- /dev/null +++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/rvalue_any_cast_request_lvalue.fail.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// ValueType any_cast(any &&); + +// Try and use the rvalue any_cast to cast to an lvalue reference + +#include + +struct TestType {}; + +int main() +{ + using std::any; + using std::any_cast; + + any a; + // expected-error@any:* {{static_assert failed "ValueType is required to be an rvalue reference or a CopyConstructible type"}} + // expected-error@any:* {{non-const lvalue reference to type 'TestType' cannot bind to a temporary}} + any_cast(std::move(a)); // expected-note {{requested here}} + + // expected-error@any:* {{static_assert failed "ValueType is required to be an rvalue reference or a CopyConstructible type"}} + // expected-error@any:* {{non-const lvalue reference to type 'int' cannot bind to a temporary}} + any_cast(42); +} diff --git a/libcxx/test/std/utilities/any/any.nonmembers/make_any.pass.cpp b/libcxx/test/std/utilities/any/any.nonmembers/make_any.pass.cpp index 143b60dd8648..59c06be6aad3 100644 --- a/libcxx/test/std/utilities/any/any.nonmembers/make_any.pass.cpp +++ b/libcxx/test/std/utilities/any/any.nonmembers/make_any.pass.cpp @@ -99,7 +99,7 @@ static_assert(IsSmallObject::value, ""); struct LargeThrows { LargeThrows(int) { throw 42; } LargeThrows(std::initializer_list, int) { throw 42; } - int data[10]; + int data[sizeof(std::any)]; }; static_assert(!IsSmallObject::value, ""); @@ -137,4 +137,4 @@ int main() { test_make_any_throws(); #endif -} \ No newline at end of file +} diff --git a/libcxx/test/support/any_helpers.h b/libcxx/test/support/any_helpers.h index a0ff8dbc1f9a..ae332d5e0a5f 100644 --- a/libcxx/test/support/any_helpers.h +++ b/libcxx/test/support/any_helpers.h @@ -246,67 +246,6 @@ typedef large_type<> large; typedef large_type<1> large1; typedef large_type<2> large2; - -struct deleted_move -{ - static int count; - static int copied; - static int moved; - static int const_copied; - static int non_const_copied; - - static void reset() { - deleted_move::copied = 0; - deleted_move::moved = 0; - deleted_move::const_copied = 0; - deleted_move::non_const_copied = 0; - } - - int value; - - explicit deleted_move(int val = 0) : value(val) { - ++count; - } - explicit deleted_move(int, int val, int) : value(val) { - ++count; - } - deleted_move(std::initializer_list il) : value(*il.begin()) { - ++count; - } - - deleted_move(deleted_move const & other) noexcept { - value = other.value; - ++count; - ++copied; - ++const_copied; - } - - deleted_move(deleted_move& other) noexcept { - value = other.value; - ++count; - ++copied; - ++non_const_copied; - } - - deleted_move(deleted_move && other) = delete; - - ~deleted_move() { - value = -1; - --count; - } - -private: - deleted_move& operator=(deleted_move const&) = delete; - deleted_move& operator=(deleted_move&&) = delete; -}; - -int deleted_move::count = 0; -int deleted_move::copied = 0; -int deleted_move::moved = 0; -int deleted_move::const_copied = 0; -int deleted_move::non_const_copied = 0; - - // The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy' // and 'throws_on_move'. struct my_any_exception {}; diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h index c751388e5f26..e89127a0ff10 100644 --- a/libcxx/test/support/test_macros.h +++ b/libcxx/test/support/test_macros.h @@ -124,9 +124,11 @@ #if defined(_LIBCPP_VERSION) #define LIBCPP_ASSERT(...) assert(__VA_ARGS__) #define LIBCPP_STATIC_ASSERT(...) static_assert(__VA_ARGS__) +#define LIBCPP_ONLY(...) __VA_ARGS__ #else #define LIBCPP_ASSERT(...) ((void)0) #define LIBCPP_STATIC_ASSERT(...) ((void)0) +#define LIBCPP_ONLY(...) ((void)0) #endif #define ASSERT_NOEXCEPT(...) \