[libcxx] r227359 - Fix PR22366. When move-constructing an associative container and explicitly passing an allocator that compares different, we were not calling the destructor of the elements in the moved-from container.

Marshall Clow mclow.lists at gmail.com
Wed Jan 28 11:54:25 PST 2015


Author: marshall
Date: Wed Jan 28 13:54:25 2015
New Revision: 227359

URL: http://llvm.org/viewvc/llvm-project?rev=227359&view=rev
Log:
Fix PR22366. When move-constructing an associative container and explicitly passing an allocator that compares different, we were not calling the destructor of the elements in the moved-from container.

Added:
    libcxx/trunk/test/support/Counter.h
Modified:
    libcxx/trunk/include/__tree
    libcxx/trunk/test/std/containers/associative/map/map.cons/move_alloc.pass.cpp
    libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/move_alloc.pass.cpp
    libcxx/trunk/test/std/containers/associative/multiset/multiset.cons/move_alloc.pass.cpp
    libcxx/trunk/test/std/containers/associative/set/set.cons/move_alloc.pass.cpp

Modified: libcxx/trunk/include/__tree
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__tree?rev=227359&r1=227358&r2=227359&view=diff
==============================================================================
--- libcxx/trunk/include/__tree (original)
+++ libcxx/trunk/include/__tree Wed Jan 28 13:54:25 2015
@@ -522,9 +522,9 @@ public:
     bool __value_constructed;
 
     _LIBCPP_INLINE_VISIBILITY
-    explicit __tree_node_destructor(allocator_type& __na) _NOEXCEPT
+    explicit __tree_node_destructor(allocator_type& __na, bool __val = false) _NOEXCEPT
         : __na_(__na),
-          __value_constructed(false)
+          __value_constructed(__val)
         {}
 
     _LIBCPP_INLINE_VISIBILITY
@@ -2291,7 +2291,7 @@ __tree<_Tp, _Compare, _Allocator>::remov
     --size();
     __tree_remove(__end_node()->__left_,
                   static_cast<__node_base_pointer>(__np));
-    return __node_holder(__np, _Dp(__node_alloc()));
+    return __node_holder(__np, _Dp(__node_alloc(), true));
 }
 
 template <class _Tp, class _Compare, class _Allocator>

Modified: libcxx/trunk/test/std/containers/associative/map/map.cons/move_alloc.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/associative/map/map.cons/move_alloc.pass.cpp?rev=227359&r1=227358&r2=227359&view=diff
==============================================================================
--- libcxx/trunk/test/std/containers/associative/map/map.cons/move_alloc.pass.cpp (original)
+++ libcxx/trunk/test/std/containers/associative/map/map.cons/move_alloc.pass.cpp Wed Jan 28 13:54:25 2015
@@ -20,6 +20,7 @@
 #include "../../../test_compare.h"
 #include "test_allocator.h"
 #include "min_allocator.h"
+#include "Counter.h"
 
 int main()
 {
@@ -141,6 +142,53 @@ int main()
         assert(m3.key_comp() == C(5));
         assert(m1.empty());
     }
+    {
+        typedef Counter<int> T;
+        typedef std::pair<int, T> V;
+        typedef std::pair<const int, T> VC;
+        typedef test_allocator<VC> A;
+        typedef std::less<int> C;
+        typedef std::map<const int, T, C, A> M;
+        typedef V* I;
+        Counter_base::gConstructed = 0;
+        {
+            V a1[] =
+            {
+                V(1, 1),
+                V(1, 2),
+                V(1, 3),
+                V(2, 1),
+                V(2, 2),
+                V(2, 3),
+                V(3, 1),
+                V(3, 2),
+                V(3, 3)
+            };
+            const size_t num = sizeof(a1)/sizeof(a1[0]);
+            assert(Counter_base::gConstructed == num);
+
+            M m1(I(a1), I(a1+num), C(), A());
+            assert(Counter_base::gConstructed == num+3);
+        
+            M m2(m1);
+            assert(m2 == m1);
+            assert(Counter_base::gConstructed == num+6);
+
+            M m3(std::move(m1), A());
+            assert(m3 == m2);
+            assert(m1.empty());
+            assert(Counter_base::gConstructed == num+6);
+
+            {
+            M m4(std::move(m2), A(5));
+            assert(Counter_base::gConstructed == num+6);
+            assert(m4 == m3);
+            assert(m2.empty());
+            }
+            assert(Counter_base::gConstructed == num+3);
+        }
+        assert(Counter_base::gConstructed == 0);            
+    }
 #if __cplusplus >= 201103L
     {
         typedef std::pair<MoveOnly, MoveOnly> V;

Modified: libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/move_alloc.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/move_alloc.pass.cpp?rev=227359&r1=227358&r2=227359&view=diff
==============================================================================
--- libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/move_alloc.pass.cpp (original)
+++ libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/move_alloc.pass.cpp Wed Jan 28 13:54:25 2015
@@ -20,6 +20,7 @@
 #include "../../../test_compare.h"
 #include "test_allocator.h"
 #include "min_allocator.h"
+#include "Counter.h"
 
 int main()
 {
@@ -141,6 +142,53 @@ int main()
         assert(m3.key_comp() == C(5));
         assert(m1.empty());
     }
+    {
+        typedef Counter<int> T;
+        typedef std::pair<int, T> V;
+        typedef std::pair<const int, T> VC;
+        typedef test_allocator<VC> A;
+        typedef std::less<int> C;
+        typedef std::multimap<const int, T, C, A> M;
+        typedef V* I;
+        Counter_base::gConstructed = 0;
+        {
+            V a1[] =
+            {
+                V(1, 1),
+                V(1, 2),
+                V(1, 3),
+                V(2, 1),
+                V(2, 2),
+                V(2, 3),
+                V(3, 1),
+                V(3, 2),
+                V(3, 3)
+            };
+            const size_t num = sizeof(a1)/sizeof(a1[0]);
+            assert(Counter_base::gConstructed == num);
+
+            M m1(I(a1), I(a1+num), C(), A());
+            assert(Counter_base::gConstructed == 2*num);
+        
+            M m2(m1);
+            assert(m2 == m1);
+            assert(Counter_base::gConstructed == 3*num);
+
+            M m3(std::move(m1), A());
+            assert(m3 == m2);
+            assert(m1.empty());
+            assert(Counter_base::gConstructed == 3*num);
+
+            {
+            M m4(std::move(m2), A(5));
+            assert(Counter_base::gConstructed == 3*num);
+            assert(m4 == m3);
+            assert(m2.empty());
+            }
+            assert(Counter_base::gConstructed == 2*num);
+        }
+        assert(Counter_base::gConstructed == 0);            
+    }
 #if __cplusplus >= 201103L
     {
         typedef std::pair<MoveOnly, MoveOnly> V;

Modified: libcxx/trunk/test/std/containers/associative/multiset/multiset.cons/move_alloc.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/associative/multiset/multiset.cons/move_alloc.pass.cpp?rev=227359&r1=227358&r2=227359&view=diff
==============================================================================
--- libcxx/trunk/test/std/containers/associative/multiset/multiset.cons/move_alloc.pass.cpp (original)
+++ libcxx/trunk/test/std/containers/associative/multiset/multiset.cons/move_alloc.pass.cpp Wed Jan 28 13:54:25 2015
@@ -19,6 +19,7 @@
 #include "../../../MoveOnly.h"
 #include "../../../test_compare.h"
 #include "test_allocator.h"
+#include "Counter.h"
 
 int main()
 {
@@ -137,5 +138,50 @@ int main()
         assert(m3.key_comp() == C(5));
         assert(m1.empty());
     }
+    {
+        typedef Counter<int> V;
+        typedef std::less<V> C;
+        typedef test_allocator<V> A;
+        typedef std::multiset<V, C, A> M;
+        typedef V* I;
+        Counter_base::gConstructed = 0;
+        {
+            V a1[] =
+            {
+            V(1),
+            V(1),
+            V(1),
+            V(2),
+            V(2),
+            V(2),
+            V(3),
+            V(3),
+            V(3)
+            };
+            const size_t num = sizeof(a1)/sizeof(a1[0]);
+            assert(Counter_base::gConstructed == num);
+
+            M m1(I(a1), I(a1+num), C(), A());
+            assert(Counter_base::gConstructed == 2*num);
+        
+            M m2(m1);
+            assert(m2 == m1);
+            assert(Counter_base::gConstructed == 3*num);
+
+            M m3(std::move(m1), A());
+            assert(m3 == m2);
+            assert(m1.empty());
+            assert(Counter_base::gConstructed == 3*num);
+
+            {
+            M m4(std::move(m2), A(5));
+            assert(Counter_base::gConstructed == 3*num);
+            assert(m4 == m3);
+            assert(m2.empty());
+            }
+            assert(Counter_base::gConstructed == 2*num);
+        }
+        assert(Counter_base::gConstructed == 0);            
+    }
 #endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
 }

Modified: libcxx/trunk/test/std/containers/associative/set/set.cons/move_alloc.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/associative/set/set.cons/move_alloc.pass.cpp?rev=227359&r1=227358&r2=227359&view=diff
==============================================================================
--- libcxx/trunk/test/std/containers/associative/set/set.cons/move_alloc.pass.cpp (original)
+++ libcxx/trunk/test/std/containers/associative/set/set.cons/move_alloc.pass.cpp Wed Jan 28 13:54:25 2015
@@ -19,6 +19,7 @@
 #include "../../../MoveOnly.h"
 #include "../../../test_compare.h"
 #include "test_allocator.h"
+#include "Counter.h"
 
 int main()
 {
@@ -137,5 +138,51 @@ int main()
         assert(m3.key_comp() == C(5));
         assert(m1.empty());
     }
+    {
+        typedef Counter<int> V;
+        typedef std::less<V> C;
+        typedef test_allocator<V> A;
+        typedef std::set<V, C, A> M;
+        typedef V* I;
+        Counter_base::gConstructed = 0;
+        {
+            V a1[] =
+            {
+            V(1),
+            V(1),
+            V(1),
+            V(2),
+            V(2),
+            V(2),
+            V(3),
+            V(3),
+            V(3)
+            };
+            const size_t num = sizeof(a1)/sizeof(a1[0]);
+            assert(Counter_base::gConstructed == num);
+
+            M m1(I(a1), I(a1+num), C(), A());
+            assert(Counter_base::gConstructed == 3+num);
+        
+            M m2(m1);
+            assert(m2 == m1);
+            assert(Counter_base::gConstructed == 6+num);
+
+            M m3(std::move(m1), A());
+            assert(m3 == m2);
+            assert(m1.empty());
+            assert(Counter_base::gConstructed == 6+num);
+
+            {
+            M m4(std::move(m2), A(5));
+            assert(Counter_base::gConstructed == 6+num);
+            assert(m4 == m3);
+            assert(m2.empty());
+            }
+            assert(Counter_base::gConstructed == 3+num);
+        }
+        assert(Counter_base::gConstructed == 0);            
+    }
+
 #endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
 }

Added: libcxx/trunk/test/support/Counter.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/Counter.h?rev=227359&view=auto
==============================================================================
--- libcxx/trunk/test/support/Counter.h (added)
+++ libcxx/trunk/test/support/Counter.h Wed Jan 28 13:54:25 2015
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef COUNTER_H
+#define COUNTER_H
+
+#include <functional> // for std::hash
+
+struct Counter_base { static int gConstructed; };
+    
+template <typename T>
+class Counter : public Counter_base
+{
+public:
+    Counter() : data_()                             { ++gConstructed; }
+    Counter(const T &data) : data_(data)            { ++gConstructed; }
+    Counter(const Counter& rhs) : data_(rhs.data_)  { ++gConstructed; }
+    Counter& operator=(const Counter& rhs)          { ++gConstructed; data_ = rhs.data_; return *this; }
+#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    Counter(Counter&& rhs) : data_(std::move(rhs.data_))  { ++gConstructed; }
+    Counter& operator=(Counter&& rhs) { ++gConstructed; data_ = std::move(rhs.data_); return *this; }
+#endif
+    ~Counter() { --gConstructed; }
+    
+    const T& get() const {return data_;}
+
+    bool operator==(const Counter& x) const {return data_ == x.data_;}
+    bool operator< (const Counter& x) const {return data_ <  x.data_;}
+
+private:
+    T data_;
+};
+
+int Counter_base::gConstructed = 0;
+
+namespace std {
+
+template <class T>
+struct hash<Counter<T> >
+    : public std::unary_function<Counter<T>, std::size_t>
+{
+    std::size_t operator()(const Counter<T>& x) const {return std::hash<T>(x.get());}
+};
+}
+
+#endif





More information about the cfe-commits mailing list