Selaa lähdekoodia

any/meta_any: safe but unspecified state after self move - close #1206

Related Work Items: #1
Michele Caini 1 vuosi sitten
vanhempi
commit
32fbc8a51f
4 muutettua tiedostoa jossa 51 lisäystä ja 17 poistoa
  1. 4 2
      src/entt/core/any.hpp
  2. 5 3
      src/entt/meta/meta.hpp
  3. 24 6
      test/entt/core/any.cpp
  4. 18 6
      test/entt/meta/meta_any.cpp

+ 4 - 2
src/entt/core/any.hpp

@@ -249,12 +249,14 @@ public:
 
     /**
      * @brief Move assignment operator.
+     *
+     * @warning
+     * Self-moving puts objects in a safe but unspecified state.
+     *
      * @param other The instance to move from.
      * @return This any object.
      */
     basic_any &operator=(basic_any &&other) noexcept {
-        ENTT_ASSERT(this != &other, "Self move assignment");
-
         reset();
 
         if(other.mode == any_policy::embedded) {

+ 5 - 3
src/entt/meta/meta.hpp

@@ -357,13 +357,15 @@ public:
 
     /**
      * @brief Move assignment operator.
+     *
+     * @warning
+     * Self-moving puts objects in a safe but unspecified state.
+     *
      * @param other The instance to move from.
      * @return This meta any object.
      */
     meta_any &operator=(meta_any &&other) noexcept {
-        ENTT_ASSERT(this != &other, "Self move assignment");
-
-        release();
+        reset();
         storage = std::move(other.storage);
         ctx = other.ctx;
         node = std::exchange(other.node, internal::meta_type_node{});

+ 24 - 6
test/entt/core/any.cpp

@@ -282,11 +282,17 @@ TEST(Any, SBOMoveAssignment) {
     ASSERT_EQ(entt::any_cast<int>(other), 2);
 }
 
-ENTT_DEBUG_TEST(AnyDeathTest, SBOSelfMoveAssignment) {
+TEST(AnyDeathTest, SBOSelfMoveAssignment) {
     entt::any any{2};
 
     // avoid warnings due to self-assignment
-    ASSERT_DEATH(any = std::move(*&any), "");
+    any = std::move(*&any);
+
+    ASSERT_FALSE(any);
+    ASSERT_FALSE(any.owner());
+    ASSERT_EQ(any.policy(), entt::any_policy::empty);
+    ASSERT_EQ(any.type(), entt::type_id<void>());
+    ASSERT_EQ(any.data(), nullptr);
 }
 
 TEST(Any, SBODirectAssignment) {
@@ -600,12 +606,18 @@ TEST(Any, NoSBOMoveAssignment) {
     ASSERT_EQ(entt::any_cast<fat>(other), instance);
 }
 
-ENTT_DEBUG_TEST(AnyDeathTest, NoSBOSelfMoveAssignment) {
+TEST(AnyDeathTest, NoSBOSelfMoveAssignment) {
     const fat instance{.1, .2, .3, .4};
     entt::any any{instance};
 
     // avoid warnings due to self-assignment
-    ASSERT_DEATH(any = std::move(*&any), "");
+    any = std::move(*&any);
+
+    ASSERT_FALSE(any);
+    ASSERT_FALSE(any.owner());
+    ASSERT_EQ(any.policy(), entt::any_policy::empty);
+    ASSERT_EQ(any.type(), entt::type_id<void>());
+    ASSERT_EQ(any.data(), nullptr);
 }
 
 TEST(Any, NoSBODirectAssignment) {
@@ -808,11 +820,17 @@ TEST(Any, VoidMoveAssignment) {
     ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
 }
 
-ENTT_DEBUG_TEST(AnyDeathTest, VoidSelfMoveAssignment) {
+TEST(AnyDeathTest, VoidSelfMoveAssignment) {
     entt::any any{std::in_place_type<void>};
 
     // avoid warnings due to self-assignment
-    ASSERT_DEATH(any = std::move(*&any), "");
+    any = std::move(*&any);
+
+    ASSERT_FALSE(any);
+    ASSERT_FALSE(any.owner());
+    ASSERT_EQ(any.policy(), entt::any_policy::empty);
+    ASSERT_EQ(any.type(), entt::type_id<void>());
+    ASSERT_EQ(any.data(), nullptr);
 }
 
 TEST(Any, SBOMoveValidButUnspecifiedState) {

+ 18 - 6
test/entt/meta/meta_any.cpp

@@ -356,11 +356,15 @@ TEST_F(MetaAny, SBOMoveAssignment) {
     ASSERT_NE(other, entt::meta_any{0});
 }
 
-ENTT_DEBUG_TEST_F(MetaAnyDeathTest, SBOSelfMoveAssignment) {
+TEST_F(MetaAnyDeathTest, SBOSelfMoveAssignment) {
     entt::meta_any any{3};
 
     // avoid warnings due to self-assignment
-    ASSERT_DEATH(any = std::move(*&any), "");
+    any = std::move(*&any);
+
+    ASSERT_FALSE(any);
+    ASSERT_FALSE(any.type());
+    ASSERT_EQ(any.base().data(), nullptr);
 }
 
 TEST_F(MetaAny, SBODirectAssignment) {
@@ -685,12 +689,16 @@ TEST_F(MetaAny, NoSBOMoveAssignment) {
     ASSERT_NE(other, fat{});
 }
 
-ENTT_DEBUG_TEST_F(MetaAnyDeathTest, NoSBOSelfMoveAssignment) {
+TEST_F(MetaAnyDeathTest, NoSBOSelfMoveAssignment) {
     const fat instance{.1, .2, .3, .4};
     entt::meta_any any{instance};
 
     // avoid warnings due to self-assignment
-    ASSERT_DEATH(any = std::move(*&any), "");
+    any = std::move(*&any);
+
+    ASSERT_FALSE(any);
+    ASSERT_FALSE(any.type());
+    ASSERT_EQ(any.base().data(), nullptr);
 }
 
 TEST_F(MetaAny, NoSBODirectAssignment) {
@@ -908,11 +916,15 @@ TEST_F(MetaAny, VoidMoveAssignment) {
     ASSERT_EQ(other, entt::meta_any{std::in_place_type<void>});
 }
 
-ENTT_DEBUG_TEST_F(MetaAnyDeathTest, VoidSelfMoveAssignment) {
+TEST_F(MetaAnyDeathTest, VoidSelfMoveAssignment) {
     entt::meta_any any{std::in_place_type<void>};
 
     // avoid warnings due to self-assignment
-    ASSERT_DEATH(any = std::move(*&any), "");
+    any = std::move(*&any);
+
+    ASSERT_FALSE(any);
+    ASSERT_FALSE(any.type());
+    ASSERT_EQ(any.base().data(), nullptr);
 }
 
 TEST_F(MetaAny, SBOMoveInvalidate) {