CaseyCarter created this revision.
CaseyCarter added reviewers: EricWF, mclow.lists.
CaseyCarter added a subscriber: cfe-commits.

Changes to non-portable behavior in <any> tests. Inline detailed description of 
each change is forthcoming. Changes are almost entirely in test code, with one 
behavioral change to <any> itself to fix self-swap behavior.


https://reviews.llvm.org/D25249

Files:
  .gitignore
  include/any
  test/libcxx/utilities/any/any.class/any.assign/value.pass.cpp
  test/libcxx/utilities/any/any.class/any.cons/value.pass.cpp
  test/libcxx/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp
  test/std/utilities/any/any.class/any.assign/move.pass.cpp
  test/std/utilities/any/any.class/any.assign/value.pass.cpp
  test/std/utilities/any/any.class/any.cons/copy.pass.cpp
  test/std/utilities/any/any.class/any.cons/in_place_type.pass.cpp
  test/std/utilities/any/any.class/any.cons/move.pass.cpp
  test/std/utilities/any/any.class/any.cons/value.pass.cpp
  test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp
  test/std/utilities/any/any.class/any.modifiers/swap.pass.cpp
  test/std/utilities/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp
  test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp
  test/std/utilities/any/any.nonmembers/make_any.pass.cpp

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>, int) { throw 42; }
-  int data[10];
+  int data[sizeof(std::any)];
 };
 static_assert(!IsSmallObject<LargeThrows>::value, "");
 
@@ -135,6 +135,5 @@
 #ifndef TEST_HAS_NO_EXCEPTIONS
     test_make_any_throws<SmallThrows>();
     test_make_any_throws<LargeThrows>();
-
 #endif
-}
\ No newline at end of file
+}
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<no_copy>(static_cast<any &&>(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/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<decltype(any_cast<int const&&>(ca)), int const&&>::value, "");
 }
 
-template <class Type, class ConstT = Type>
-void checkThrows(any& a)
+template <class Type>
+void checkThrowsRvalue(any&, std::true_type)
+{}
+
+template <class Type>
+void checkThrowsRvalue(any& a, std::false_type)
 {
-#if !defined(TEST_HAS_NO_EXCEPTIONS)
     try {
-        any_cast<Type>(a);
+        any_cast<Type>(static_cast<any&&>(a));
         assert(false);
     } catch (bad_any_cast const &) {
             // do nothing
     } catch (...) {
         assert(false);
     }
+}
 
+template <class Type, class ConstT = Type>
+void checkThrows(any& a)
+{
+#if !defined(TEST_HAS_NO_EXCEPTIONS)
     try {
-        any_cast<ConstT>(static_cast<any const&>(a));
+        any_cast<Type>(a);
         assert(false);
     } catch (bad_any_cast const &) {
             // do nothing
@@ -91,13 +99,15 @@
     }
 
     try {
-        any_cast<Type>(static_cast<any&&>(a));
+        any_cast<ConstT>(static_cast<any const&>(a));
         assert(false);
     } catch (bad_any_cast const &) {
             // do nothing
     } catch (...) {
         assert(false);
     }
+
+    checkThrowsRvalue<Type>(a, std::is_lvalue_reference<Type>{});
 #endif
 }
 
@@ -142,23 +152,7 @@
             Type const &cv = any_cast<Type const&>(ca);
             assert(&cv == &v);
         }
-        // Check getting a type by reference from a non-const rvalue
-        {
-            Type& v = any_cast<Type&>(std::move(a));
-            assert(v.value == 42);
-
-            Type const &cv = any_cast<Type const&>(std::move(a));
-            assert(&cv == &v);
-        }
-        // Check getting a type by reference from a const rvalue any.
-        {
-            Type const& v = any_cast<Type const&>(std::move(ca));
-            assert(v.value == 42);
-
-            Type const &cv = any_cast<Type const&>(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<Type&&>(std::move(a));
             assert(v.value == 42);
@@ -168,7 +162,7 @@
             assert(&cv == &v);
             assert(any_cast<Type&>(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<Type const&&>(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<Type>(static_cast<any const&>(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<Type>(static_cast<any &&>(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<Type>(a);
-        assert(Type::count == 2);
-        assert(Type::copied == 2);
-        assert(Type::moved == 0);
-        assertContains<Type>(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<Type>(ca);
-        assert(Type::count == 2);
-        assert(Type::copied == 2);
-        assert(Type::moved == 0);
-        assertContains<Type>(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<Type>(std::move(a));
-        assert(Type::count == 2);
-        assert(Type::copied == 2);
-        assert(Type::moved == 0);
-        assertContains<Type>(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<Type>(std::move(ca));
-        assert(Type::count == 2);
-        assert(Type::copied == 2);
-        assert(Type::moved == 0);
-        assertContains<Type>(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<large>();
     test_cast_to_value<small>();
     test_cast_to_value<large>();
-    test_cast_to_value_deleted_move();
     test_non_copyable_ref();
 }
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
@@ -85,8 +85,30 @@
     any a2;
     static_assert(
         noexcept(a1.swap(a2))
-      , "any::swap(any&) must be noexcept"
-      );
+    , "any::swap(any&) must be noexcept"
+    );
+}
+
+void test_self_swap()
+{
+    {
+        // empty
+        any a;
+        a.swap(a);
+        assertEmpty(a);
+    }
+    {
+        // small
+        any a{small{42}};
+        a.swap(a);
+        assertContains<small>(a, 42);
+    }
+    {
+        // large
+        any a{large{42}};
+        a.swap(a);
+        assertContains<large>(a, 42);
+    }
 }
 
 int main()
@@ -98,4 +120,5 @@
     test_swap<large1, large2>();
     test_swap<small, large>();
     test_swap<large, small>();
+    test_self_swap();
 }
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>, int) { throw 42; }
-  int data[10];
+  int data[sizeof(std::any)];
 };
 static_assert(!IsSmallObject<LargeThrows>::value, "");
 
@@ -228,10 +228,10 @@
         // Test that the emplace SFINAE's away when the
         // argument is non-copyable
         struct NoCopy {
-          NoCopy() = default;
-          NoCopy(NoCopy const&) = delete;
-          NoCopy(int) {}
-          NoCopy(std::initializer_list<int>, int, int) {}
+        NoCopy() = default;
+        NoCopy(NoCopy const&) = delete;
+        NoCopy(int) {}
+        NoCopy(std::initializer_list<int>, int, int) {}
         };
         static_assert(!has_emplace<NoCopy>(), "");
         static_assert(!has_emplace<NoCopy, int>(), "");
@@ -252,4 +252,4 @@
     test_emplace_throws<SmallThrows>();
     test_emplace_throws<LargeThrows>();
 #endif
-}
\ No newline at end of file
+}
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<Type>(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<Type>(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() {
@@ -164,9 +138,9 @@
         // Test that the ValueType&& constructor SFINAE's away when the
         // argument is non-copyable
         struct NoCopy {
-          NoCopy() = default;
-          NoCopy(NoCopy const&) = delete;
-          NoCopy(int) {}
+        NoCopy() = default;
+        NoCopy(NoCopy const&) = delete;
+        NoCopy(int) {}
         };
         static_assert(!std::is_constructible<std::any, NoCopy>::value, "");
         static_assert(!std::is_convertible<NoCopy, std::any>::value, "");
@@ -179,6 +153,5 @@
     test_copy_value_throws<small_throws_on_copy>();
     test_copy_value_throws<large_throws_on_copy>();
     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.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<Type>(a2, 42);
+        if (a.has_value())
+            assertContains<Type>(a, 0);
     }
     assert(Type::count == 0);
 }
@@ -92,8 +93,8 @@
     {
         static_assert(
             std::is_nothrow_move_constructible<any>::value
-          , "any must be nothrow move constructible"
-          );
+        , "any must be nothrow move constructible"
+        );
     }
     test_move<small>();
     test_move<large>();
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<large_tracked_t>();
     test_ctor_sfinae();
     test_constructor_explicit();
-}
\ 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<Type>(a, 42);
-        assertContains<Type>(a, 42);
+        assertContains<Type>(a2, 42);
 
         // Modify a and check that a2 is unchanged
         modifyValue<Type>(a, -1);
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>
 
-// any& operator=(any const &);
+// template<class ValueType>
+// 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<RHS>(lhs, 2);
-        assertEmpty<RHS>(rhs);
+        if (rhs.has_value())
+            assertContains<RHS>(rhs, 0);
     }
     assert(LHS::count == 0);
     assert(RHS::count == 0);
@@ -114,11 +116,11 @@
 template <class Tp, bool Move = false>
 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)
-                 : lhs = rhs;
+                : lhs = rhs;
             assert(false);
         } catch (my_any_exception const &) {
             // do nothing
@@ -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<int>;
-        using RawTag = std::remove_reference_t<Tag>;
-        static_assert(!std::is_assignable<std::any, RawTag&&>::value, "");
-    }
-    {
-        struct Dummy { Dummy() = delete; };
-        using T = std::in_place_type_t<Dummy>;
-        static_assert(!std::is_assignable<std::any, T>::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<std::any, NoCopy>::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<std::any, NoCopy>::value, "");
 }
 
 int main() {
@@ -202,4 +188,4 @@
     test_assign_throws<large_throws_on_copy>();
     test_assign_throws<throws_on_move, /* Move = */ true>();
     test_sfinae_constraints();
-}
\ No newline at end of file
+}
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<RHS>(a, 2);
-        assertEmpty<RHS>(a2);
+        if (a2.has_value())
+            assertContains<RHS>(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<LHS>(a, 1);
-        assertEmpty<LHS>(a2);
+        if (a2.has_value())
+            assertContains<LHS>(a2, 0);
     }
     assert(LHS::count == 0);
     {
@@ -87,8 +89,8 @@
     any a2;
     static_assert(
         noexcept(a1 = std::move(a2))
-      , "any & operator=(any &&) must be noexcept"
-      );
+    , "any & operator=(any &&) must be noexcept"
+    );
 }
 
 int main() {
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
+
+// <any>
+
+// template <class ValueType>
+// ValueType const any_cast(any const&);
+//
+// template <class ValueType>
+// ValueType any_cast(any &);
+//
+// template <class ValueType>
+// ValueType any_cast(any &&);
+
+#include <any>
+#include <type_traits>
+#include <cassert>
+
+#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<Type>(a);
+        assert(Type::count == 2);
+        assert(Type::copied == 2);
+        assert(Type::moved == 0);
+        assertContains<Type>(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<Type>(ca);
+        assert(Type::count == 2);
+        assert(Type::copied == 2);
+        assert(Type::moved == 0);
+        assertContains<Type>(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<Type>(std::move(a));
+        assert(Type::count == 2);
+        assert(Type::copied == 2);
+        assert(Type::moved == 0);
+        assertContains<Type>(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<Type>(std::move(ca));
+        assert(Type::count == 2);
+        assert(Type::copied == 2);
+        assert(Type::moved == 0);
+        assertContains<Type>(a, 42);
+    }
+    assert(Type::count == 0);
+    Type::reset();
+}
+
+int main() {
+    test_cast_to_value_deleted_move();
+}
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
+
+// <any>
+
+// template <class Value> any(Value &&)
+
+#include <any>
+#include <cassert>
+
+#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<Type>(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<Type>(a, 42);
+    }
+    assert(Type::count == 0);
+    Type::reset();
+}
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
+
+// <any>
+
+// template<class ValueType>
+// any& operator=(ValueType &&);
+
+// Test value copy and move assignment.
+
+#include <any>
+#include <type_traits>
+#include <utility>
+
+int main() {
+// Test that any& operator=(ValueType&&) is *never* selected for:
+// * std::in_place type.
+    {
+        using Tag = std::in_place_type_t<int>;
+        using RawTag = std::remove_reference_t<Tag>;
+        static_assert(!std::is_assignable<std::any, RawTag&&>::value, "");
+    }
+    {
+        struct Dummy { Dummy() = delete; };
+        using T = std::in_place_type_t<Dummy>;
+        static_assert(!std::is_assignable<std::any, T>::value, "");
+    }
+}
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: .gitignore
===================================================================
--- .gitignore
+++ .gitignore
@@ -56,3 +56,4 @@
 # MSVC libraries test harness
 env.lst
 keep.lst
+.vscode/
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to