From ebfc50ee89c8e47151bf6abe999fb7def08c908b Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Sat, 8 Feb 2014 04:03:14 +0000 Subject: [PATCH] Fix for PR18735 - self-assignment for map/multimap gives incorrect results in C++03 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@201021 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/map | 20 +++++++------ include/unordered_map | 28 +++++++++++-------- .../map/map.cons/copy_assign.pass.cpp | 15 ++++++++++ .../multimap.cons/copy_assign.pass.cpp | 20 +++++++++++++ .../multiset.cons/copy_assign.pass.cpp | 20 +++++++++++++ .../set/set.cons/copy_assign.pass.cpp | 15 ++++++++++ .../unord.map.cnstr/assign_copy.pass.cpp | 18 ++++++++++++ .../unord.multimap.cnstr/assign_copy.pass.cpp | 18 ++++++++++++ .../unord.multiset.cnstr/assign_copy.pass.cpp | 19 +++++++++++++ .../unord.set.cnstr/assign_copy.pass.cpp | 18 ++++++++++++ 10 files changed, 171 insertions(+), 20 deletions(-) diff --git a/include/map b/include/map index 009e8e21..9779b70e 100644 --- a/include/map +++ b/include/map @@ -884,10 +884,12 @@ public: #if __cplusplus >= 201103L __tree_ = __m.__tree_; #else - __tree_.clear(); - __tree_.value_comp() = __m.__tree_.value_comp(); - __tree_.__copy_assign_alloc(__m.__tree_); - insert(__m.begin(), __m.end()); + if (this != &__m) { + __tree_.clear(); + __tree_.value_comp() = __m.__tree_.value_comp(); + __tree_.__copy_assign_alloc(__m.__tree_); + insert(__m.begin(), __m.end()); + } #endif return *this; } @@ -1616,10 +1618,12 @@ public: #if __cplusplus >= 201103L __tree_ = __m.__tree_; #else - __tree_.clear(); - __tree_.value_comp() = __m.__tree_.value_comp(); - __tree_.__copy_assign_alloc(__m.__tree_); - insert(__m.begin(), __m.end()); + if (this != &__m) { + __tree_.clear(); + __tree_.value_comp() = __m.__tree_.value_comp(); + __tree_.__copy_assign_alloc(__m.__tree_); + insert(__m.begin(), __m.end()); + } #endif return *this; } diff --git a/include/unordered_map b/include/unordered_map index 78fee481..4e2298bf 100644 --- a/include/unordered_map +++ b/include/unordered_map @@ -831,12 +831,14 @@ public: #if __cplusplus >= 201103L __table_ = __u.__table_; #else - __table_.clear(); - __table_.hash_function() = __u.__table_.hash_function(); - __table_.key_eq() = __u.__table_.key_eq(); - __table_.max_load_factor() = __u.__table_.max_load_factor(); - __table_.__copy_assign_alloc(__u.__table_); - insert(__u.begin(), __u.end()); + if (this != &__u) { + __table_.clear(); + __table_.hash_function() = __u.__table_.hash_function(); + __table_.key_eq() = __u.__table_.key_eq(); + __table_.max_load_factor() = __u.__table_.max_load_factor(); + __table_.__copy_assign_alloc(__u.__table_); + insert(__u.begin(), __u.end()); + } #endif return *this; } @@ -1567,12 +1569,14 @@ public: #if __cplusplus >= 201103L __table_ = __u.__table_; #else - __table_.clear(); - __table_.hash_function() = __u.__table_.hash_function(); - __table_.key_eq() = __u.__table_.key_eq(); - __table_.max_load_factor() = __u.__table_.max_load_factor(); - __table_.__copy_assign_alloc(__u.__table_); - insert(__u.begin(), __u.end()); + if (this != &__u) { + __table_.clear(); + __table_.hash_function() = __u.__table_.hash_function(); + __table_.key_eq() = __u.__table_.key_eq(); + __table_.max_load_factor() = __u.__table_.max_load_factor(); + __table_.__copy_assign_alloc(__u.__table_); + insert(__u.begin(), __u.end()); + } #endif return *this; } diff --git a/test/containers/associative/map/map.cons/copy_assign.pass.cpp b/test/containers/associative/map/map.cons/copy_assign.pass.cpp index ac05e291..a1bcb30f 100644 --- a/test/containers/associative/map/map.cons/copy_assign.pass.cpp +++ b/test/containers/associative/map/map.cons/copy_assign.pass.cpp @@ -57,6 +57,21 @@ int main() assert(*next(mo.begin()) == V(2, 1)); assert(*next(mo.begin(), 2) == V(3, 1)); } + { + typedef std::pair V; + const V ar[] = + { + V(1, 1), + V(2, 1), + V(3, 1), + }; + std::map m(ar, ar+sizeof(ar)/sizeof(ar[0])); + std::map *p = &m; + m = *p; + + assert(m.size() == 3); + assert(std::equal(m.begin(), m.end(), ar)); + } { typedef std::pair V; V ar[] = diff --git a/test/containers/associative/multimap/multimap.cons/copy_assign.pass.cpp b/test/containers/associative/multimap/multimap.cons/copy_assign.pass.cpp index f00f0fed..2bdc4d6a 100644 --- a/test/containers/associative/multimap/multimap.cons/copy_assign.pass.cpp +++ b/test/containers/associative/multimap/multimap.cons/copy_assign.pass.cpp @@ -48,6 +48,26 @@ int main() assert(mo.get_allocator() == A(2)); assert(mo.key_comp() == C(5)); } + { + typedef std::pair V; + const V ar[] = + { + V(1, 1), + V(1, 1.5), + V(1, 2), + V(2, 1), + V(2, 1.5), + V(2, 2), + V(3, 1), + V(3, 1.5), + V(3, 2), + }; + std::multimap m(ar, ar+sizeof(ar)/sizeof(ar[0])); + std::multimap *p = &m; + m = *p; + assert(m.size() == sizeof(ar)/sizeof(ar[0])); + assert(std::equal(m.begin(), m.end(), ar)); + } { typedef std::pair V; V ar[] = diff --git a/test/containers/associative/multiset/multiset.cons/copy_assign.pass.cpp b/test/containers/associative/multiset/multiset.cons/copy_assign.pass.cpp index 19bdd713..cca63632 100644 --- a/test/containers/associative/multiset/multiset.cons/copy_assign.pass.cpp +++ b/test/containers/associative/multiset/multiset.cons/copy_assign.pass.cpp @@ -68,6 +68,26 @@ int main() assert(*next(mo.begin(), 7) == 3); assert(*next(mo.begin(), 8) == 3); } + { + typedef int V; + const V ar[] = + { + 1, + 1, + 1, + 2, + 2, + 2, + 3, + 3, + 3 + }; + std::multiset m(ar, ar+sizeof(ar)/sizeof(ar[0])); + std::multiset *p = &m; + m = *p; + assert(m.size() == 9); + assert(std::equal(m.begin(), m.end(), ar)); + } { typedef int V; V ar[] = diff --git a/test/containers/associative/set/set.cons/copy_assign.pass.cpp b/test/containers/associative/set/set.cons/copy_assign.pass.cpp index ae83eb3c..7f0f0447 100644 --- a/test/containers/associative/set/set.cons/copy_assign.pass.cpp +++ b/test/containers/associative/set/set.cons/copy_assign.pass.cpp @@ -56,6 +56,21 @@ int main() assert(*next(mo.begin()) == 2); assert(*next(mo.begin(), 2) == 3); } + { + typedef int V; + const V ar[] = + { + 1, + 2, + 3 + }; + std::set m(ar, ar+sizeof(ar)/sizeof(ar[0])); + std::set *p = &m; + m = *p; + + assert(m.size() == 3); + assert(std::equal(m.begin(), m.end(), ar)); + } { typedef int V; V ar[] = diff --git a/test/containers/unord/unord.map/unord.map.cnstr/assign_copy.pass.cpp b/test/containers/unord/unord.map/unord.map.cnstr/assign_copy.pass.cpp index 928377b3..622ce506 100644 --- a/test/containers/unord/unord.map/unord.map.cnstr/assign_copy.pass.cpp +++ b/test/containers/unord/unord.map/unord.map.cnstr/assign_copy.pass.cpp @@ -72,6 +72,24 @@ int main() assert(fabs(c.load_factor() - (float)c.size()/c.bucket_count()) < FLT_EPSILON); assert(c.max_load_factor() == 1); } + { + typedef std::unordered_map C; + typedef std::pair P; + const P a[] = + { + P(1, "one"), + P(2, "two"), + P(3, "three"), + P(4, "four"), + P(1, "four"), + P(2, "four"), + }; + C c(a, a + sizeof(a)/sizeof(a[0])); + C *p = &c; + c = *p; + assert(c.size() == 4); + assert(std::is_permutation(c.begin(), c.end(), a)); + } { typedef other_allocator > A; typedef std::unordered_map C; + typedef std::pair P; + const P a[] = + { + P(1, "one"), + P(2, "two"), + P(3, "three"), + P(4, "four"), + P(1, "four"), + P(2, "four"), + }; + C c(a, a+sizeof(a)/sizeof(a[0])); + C *p = &c; + c = *p; + assert(c.size() == 6); + assert(std::is_permutation(c.begin(), c.end(), a)); + } { typedef other_allocator > A; typedef std::unordered_multimap C; + typedef int P; + P a[] = + { + P(1), + P(2), + P(3), + P(4), + P(1), + P(2) + }; + C c(a, a + sizeof(a)/sizeof(a[0])); + C *p = &c; + c = *p; + + assert(c.size() == 6); + assert(std::is_permutation(c.begin(), c.end(), a)); + } { typedef other_allocator A; typedef std::unordered_multiset C; + typedef int P; + P a[] = + { + P(1), + P(2), + P(3), + P(4), + P(1), + P(2) + }; + C c(a, a + sizeof(a)/sizeof(a[0])); + C *p = &c; + c = *p; + assert(c.size() == 4); + assert(std::is_permutation(c.begin(), c.end(), a)); + } { typedef other_allocator A; typedef std::unordered_set