Index: .gitignore =================================================================== --- .gitignore +++ .gitignore @@ -56,3 +56,4 @@ # MSVC libraries test harness env.lst keep.lst +.vscode/ Index: include/any =================================================================== --- include/any +++ include/any @@ -545,10 +545,12 @@ void any::swap(any & __rhs) _NOEXCEPT { if (__h && __rhs.__h) { - any __tmp; - __rhs.__call(_Action::_Move, &__tmp); - this->__call(_Action::_Move, &__rhs); - __tmp.__call(_Action::_Move, this); + if (this != &__rhs) { + any __tmp; + __rhs.__call(_Action::_Move, &__tmp); + this->__call(_Action::_Move, &__rhs); + __tmp.__call(_Action::_Move, this); + } } else if (__h) { this->__call(_Action::_Move, &__rhs); Index: test/libcxx/utilities/any/any.class/any.assign/value.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/utilities/any/any.class/any.assign/value.pass.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 +// any& operator=(ValueType &&); + +// Test value copy and move assignment. + +#include +#include +#include + +int main() { +// Test that any& operator=(ValueType&&) is *never* selected for: +// * std::in_place type. + { + using Tag = std::in_place_type_t; + using RawTag = std::remove_reference_t; + static_assert(!std::is_assignable::value, ""); + } + { + struct Dummy { Dummy() = delete; }; + using T = std::in_place_type_t; + static_assert(!std::is_assignable::value, ""); + } +} Index: test/libcxx/utilities/any/any.class/any.cons/value.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/utilities/any/any.class/any.cons/value.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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 any(Value &&) + +#include +#include + +#include "any_helpers.h" +#include "test_macros.h" + +int main() { + // test construction from INSANE copy-but-not-movable types. + 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(); +} Index: test/libcxx/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// 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 const any_cast(any const&); +// +// template +// ValueType any_cast(any &); +// +// template +// ValueType any_cast(any &&); + +#include +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::any; +using std::any_cast; + +// Test that I can retrieve INSANE copy-but-not-movable type from an any +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(); +} + +int main() { + test_cast_to_value_deleted_move(); +} Index: test/std/utilities/any/any.class/any.assign/move.pass.cpp =================================================================== --- test/std/utilities/any/any.class/any.assign/move.pass.cpp +++ test/std/utilities/any/any.class/any.assign/move.pass.cpp @@ -40,10 +40,11 @@ a = std::move(a2); assert(LHS::count == 1); - assert(RHS::count == 2); + assert(RHS::count == 2 + a2.has_value()); assertContains(a, 2); - assertEmpty(a2); + if (a2.has_value()) + assertContains(a2, 0); } assert(LHS::count == 0); assert(RHS::count == 0); @@ -54,16 +55,17 @@ 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()); assertContains(a, 1); - assertEmpty(a2); + if (a2.has_value()) + assertContains(a2, 0); } assert(LHS::count == 0); { Index: test/std/utilities/any/any.class/any.assign/value.pass.cpp =================================================================== --- test/std/utilities/any/any.class/any.assign/value.pass.cpp +++ 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,11 @@ assert(RHS::moved >= 1); assert(RHS::copied == 0); assert(LHS::count == 0); - assert(RHS::count == 1); + assert(RHS::count == 1 + 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 +116,7 @@ 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) @@ -164,31 +166,15 @@ #endif } - -// Test that any& operator=(ValueType&&) is *never* selected for: -// * std::in_place type. -// * Non-copyable types void test_sfinae_constraints() { - { - using Tag = std::in_place_type_t; - using RawTag = std::remove_reference_t; - static_assert(!std::is_assignable::value, ""); - } - { - struct Dummy { Dummy() = delete; }; - using T = std::in_place_type_t; - static_assert(!std::is_assignable::value, ""); - } - { - // Test that the ValueType&& constructor SFINAE's away when the - // argument is non-copyable - struct NoCopy { - NoCopy() = default; - NoCopy(NoCopy const&) = delete; - NoCopy(NoCopy&&) = default; - }; - static_assert(!std::is_assignable::value, ""); - } + // Test that the ValueType&& assignment SFINAE's away when the + // argument is non-copyable + struct NoCopy { + NoCopy() = default; + NoCopy(NoCopy const&) = delete; + NoCopy(NoCopy&&) = default; + }; + static_assert(!std::is_assignable::value, ""); } int main() { @@ -202,4 +188,4 @@ test_assign_throws(); test_assign_throws(); test_sfinae_constraints(); -} \ No newline at end of file +} Index: test/std/utilities/any/any.class/any.cons/copy.pass.cpp =================================================================== --- test/std/utilities/any/any.class/any.cons/copy.pass.cpp +++ test/std/utilities/any/any.class/any.cons/copy.pass.cpp @@ -71,7 +71,7 @@ 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); Index: test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp =================================================================== --- test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp +++ test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp @@ -149,4 +149,4 @@ test_in_place_type_tracked(); test_ctor_sfinae(); test_constructor_explicit(); -} \ No newline at end of file +} Index: test/std/utilities/any/any.class/any.cons/move.pass.cpp =================================================================== --- test/std/utilities/any/any.class/any.cons/move.pass.cpp +++ test/std/utilities/any/any.class/any.cons/move.pass.cpp @@ -77,11 +77,12 @@ 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 one move operations can be performed. assert(Type::copied == 0); // no copies can be performed. - assert(Type::count == 1); - assertEmpty(a); // Moves are always destructive. + assert(Type::count == 1 + a.has_value()); // Moves may be destructive. assertContains(a2, 42); + if (a.has_value()) + assertContains(a, 0); } assert(Type::count == 0); } Index: test/std/utilities/any/any.class/any.cons/value.pass.cpp =================================================================== --- test/std/utilities/any/any.class/any.cons/value.pass.cpp +++ test/std/utilities/any/any.class/any.cons/value.pass.cpp @@ -107,32 +107,6 @@ } } -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() { @@ -179,6 +153,5 @@ 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 +} Index: test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp =================================================================== --- test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp +++ test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp @@ -129,7 +129,7 @@ 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, ""); @@ -252,4 +252,4 @@ test_emplace_throws(); test_emplace_throws(); #endif -} \ No newline at end of file +} Index: test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp =================================================================== --- test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp +++ test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp @@ -89,6 +89,28 @@ ); } +void test_self_swap() +{ + { + // empty + any a; + a.swap(a); + assertEmpty(a); + } + { + // small + any a{small{42}}; + a.swap(a); + assertContains(a, 42); + } + { + // large + any a{large{42}}; + a.swap(a); + assertContains(a, 42); + } +} + int main() { test_noexcept(); @@ -98,4 +120,5 @@ test_swap(); test_swap(); test_swap(); + test_self_swap(); } Index: test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp =================================================================== --- test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp +++ test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp @@ -68,21 +68,29 @@ static_assert(std::is_same(ca)), int const&&>::value, ""); } -template -void checkThrows(any& a) +template +void checkThrowsRvalue(any&, std::true_type) +{} + +template +void checkThrowsRvalue(any& a, std::false_type) { -#if !defined(TEST_HAS_NO_EXCEPTIONS) try { - any_cast(a); + any_cast(static_cast(a)); assert(false); } catch (bad_any_cast const &) { // do nothing } catch (...) { assert(false); } +} +template +void checkThrows(any& a) +{ +#if !defined(TEST_HAS_NO_EXCEPTIONS) try { - any_cast(static_cast(a)); + any_cast(a); assert(false); } catch (bad_any_cast const &) { // do nothing @@ -91,13 +99,15 @@ } try { - any_cast(static_cast(a)); + any_cast(static_cast(a)); assert(false); } catch (bad_any_cast const &) { // do nothing } catch (...) { assert(false); } + + checkThrowsRvalue(a, std::is_lvalue_reference{}); #endif } @@ -142,23 +152,7 @@ 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)); - assert(v.value == 42); - - Type const &cv = any_cast(std::move(ca)); - assert(&cv == &v); - } - // Check getting a type by reference from a const rvalue any. + // Check getting a type by rvalue reference from a non-const rvalue any. { Type&& v = any_cast(std::move(a)); assert(v.value == 42); @@ -168,7 +162,7 @@ assert(&cv == &v); assert(any_cast(a).value == 42); } - // Check getting a type by reference from a const rvalue any. + // Check getting a type by rvalue reference from a const rvalue any. { Type const&& v = any_cast(std::move(a)); assert(v.value == 42); @@ -195,7 +189,6 @@ Type::reset(); { any a((Type(42))); - any const& ca = a; assert(Type::count == 1); assert(Type::copied == 0); assert(Type::moved == 1); @@ -236,7 +229,7 @@ } assert(Type::count == 1); Type::reset(); - // Check getting Type by value from a non-const lvalue any. + // Check getting Type by value from a const lvalue any. // This should cause the const copy constructor to be called. { Type t = any_cast(static_cast(a)); @@ -251,7 +244,7 @@ assert(Type::count == 1); Type::reset(); // Check getting Type by value from a non-const rvalue any. - // This should cause the non-const copy constructor to be called. + // This should cause the move constructor to be called. { Type t = any_cast(static_cast(a)); @@ -303,69 +296,6 @@ 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() { @@ -391,6 +321,5 @@ test_cast_to_reference(); test_cast_to_value(); test_cast_to_value(); - test_cast_to_value_deleted_move(); test_non_copyable_ref(); } Index: test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp =================================================================== --- test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp +++ test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp @@ -42,4 +42,4 @@ 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 +} Index: test/std/utilities/any/any.nonmembers/make_any.pass.cpp =================================================================== --- test/std/utilities/any/any.nonmembers/make_any.pass.cpp +++ test/std/utilities/any/any.nonmembers/make_any.pass.cpp @@ -99,7 +99,7 @@ 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, ""); @@ -135,6 +135,5 @@ #ifndef TEST_HAS_NO_EXCEPTIONS test_make_any_throws(); test_make_any_throws(); - #endif -} \ No newline at end of file +}