[libcxx-commits] [libcxx] [libc++] Assert preconditions of operator= of containers (PR #129625)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Mar 10 21:35:00 PDT 2025
https://github.com/halbi2 updated https://github.com/llvm/llvm-project/pull/129625
>From 546663cdaf75e38fc57080fb8242a3161e30075e Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Mon, 3 Mar 2025 19:49:12 -0500
Subject: [PATCH 1/2] [libc++] Assert preconditions of operator= of containers
Container requirements require that value_type is Cpp17CopyAssignable
or Cpp17MoveAssignable when a container is copy assigned or move assigned.
Assert that requirement.
Fixes #59683
---
libcxx/include/__vector/vector.h | 5 +++
libcxx/include/deque | 4 +++
libcxx/include/list | 5 +++
libcxx/include/map | 15 ++++++++
libcxx/include/set | 9 +++++
libcxx/include/unordered_map | 15 ++++++++
libcxx/include/unordered_set | 9 +++++
.../copy_assign.not_assignable.verify.cpp | 31 ++++++++++++++++
.../copy_assign.not_assignable.verify.cpp | 31 ++++++++++++++++
.../copy_assign.not_assignable.verify.cpp | 31 ++++++++++++++++
.../copy_assign.not_assignable.verify.cpp | 31 ++++++++++++++++
.../copy_assign.not_assignable.verify.cpp | 30 ++++++++++++++++
.../copy_assign.not_assignable.verify.cpp | 30 ++++++++++++++++
.../copy_assign.not_assignable.verify.cpp | 30 ++++++++++++++++
.../copy_assign.not_assignable.verify.cpp | 36 +++++++++++++++++++
.../copy_assign.not_assignable.verify.cpp | 36 +++++++++++++++++++
.../copy_assign.not_assignable.verify.cpp | 36 +++++++++++++++++++
.../copy_assign.not_assignable.verify.cpp | 36 +++++++++++++++++++
18 files changed, 420 insertions(+)
create mode 100644 libcxx/test/std/containers/associative/map/map.cons/copy_assign.not_assignable.verify.cpp
create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.cons/copy_assign.not_assignable.verify.cpp
create mode 100644 libcxx/test/std/containers/associative/multiset/multiset.cons/copy_assign.not_assignable.verify.cpp
create mode 100644 libcxx/test/std/containers/associative/set/set.cons/copy_assign.not_assignable.verify.cpp
create mode 100644 libcxx/test/std/containers/sequences/deque/deque.cons/copy_assign.not_assignable.verify.cpp
create mode 100644 libcxx/test/std/containers/sequences/list/list.cons/copy_assign.not_assignable.verify.cpp
create mode 100644 libcxx/test/std/containers/sequences/vector/vector.cons/copy_assign.not_assignable.verify.cpp
create mode 100644 libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/copy_assign.not_assignable.verify.cpp
create mode 100644 libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/copy_assign.not_assignable.verify.cpp
create mode 100644 libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/copy_assign.not_assignable.verify.cpp
create mode 100644 libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/copy_assign.not_assignable.verify.cpp
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index ef796a8ed0a9e..e6ea3b9c8d67f 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -50,6 +50,7 @@
#include <__type_traits/conditional.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_allocator.h>
+#include <__type_traits/is_assignable.h>
#include <__type_traits/is_constant_evaluated.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_nothrow_assignable.h>
@@ -294,6 +295,9 @@ class _LIBCPP_TEMPLATE_VIS vector {
vector(vector&& __x, const __type_identity_t<allocator_type>& __a);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector& operator=(vector&& __x)
_NOEXCEPT_(__noexcept_move_assign_container<_Allocator, __alloc_traits>::value) {
+ static_assert(
+ __alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<value_type>::value,
+ "T must be Cpp17MoveAssignable");
__move_assign(__x, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>());
return *this;
}
@@ -1011,6 +1015,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__move_assign(vector
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocator>&
vector<_Tp, _Allocator>::operator=(const vector& __x) {
+ static_assert(is_copy_assignable<value_type>::value, "T must be Cpp17CopyAssignable");
if (this != std::addressof(__x)) {
__copy_assign_alloc(__x);
assign(__x.__begin_, __x.__end_);
diff --git a/libcxx/include/deque b/libcxx/include/deque
index 95200b4801d7f..e631fe38cd4ee 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -227,6 +227,7 @@ template <class T, class Allocator, class Predicate>
# include <__type_traits/disjunction.h>
# include <__type_traits/enable_if.h>
# include <__type_traits/is_allocator.h>
+# include <__type_traits/is_assignable.h>
# include <__type_traits/is_convertible.h>
# include <__type_traits/is_nothrow_assignable.h>
# include <__type_traits/is_nothrow_constructible.h>
@@ -1328,6 +1329,7 @@ deque<_Tp, _Allocator>::deque(const deque& __c, const __type_identity_t<allocato
template <class _Tp, class _Allocator>
deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(const deque& __c) {
+ static_assert(is_copy_assignable<value_type>::value, "T must be Cpp17CopyAssignable");
if (this != std::addressof(__c)) {
__copy_assign_alloc(__c);
assign(__c.begin(), __c.end());
@@ -1383,6 +1385,8 @@ inline deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(deque&& __c) no
(__alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value) ||
allocator_traits<allocator_type>::is_always_equal::value) {
+ static_assert(__alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<value_type>::value,
+ "T must be Cpp17MoveAssignable");
__move_assign(__c, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>());
return *this;
}
diff --git a/libcxx/include/list b/libcxx/include/list
index 1285174f1c384..a71bbce784c81 100644
--- a/libcxx/include/list
+++ b/libcxx/include/list
@@ -232,6 +232,7 @@ template <class T, class Allocator, class Predicate>
# include <__type_traits/container_traits.h>
# include <__type_traits/enable_if.h>
# include <__type_traits/is_allocator.h>
+# include <__type_traits/is_assignable.h>
# include <__type_traits/is_nothrow_assignable.h>
# include <__type_traits/is_nothrow_constructible.h>
# include <__type_traits/is_pointer.h>
@@ -1071,6 +1072,9 @@ inline list<_Tp, _Alloc>& list<_Tp, _Alloc>::operator=(list&& __c) noexcept(
(__node_alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<__node_allocator>::value) ||
allocator_traits<allocator_type>::is_always_equal::value) {
+ static_assert(
+ __node_alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<value_type>::value,
+ "T must be Cpp17MoveAssignable");
__move_assign(__c, integral_constant<bool, __node_alloc_traits::propagate_on_container_move_assignment::value>());
return *this;
}
@@ -1096,6 +1100,7 @@ void list<_Tp, _Alloc>::__move_assign(list& __c,
template <class _Tp, class _Alloc>
inline list<_Tp, _Alloc>& list<_Tp, _Alloc>::operator=(const list& __c) {
+ static_assert(is_copy_assignable<value_type>::value, "T must be Cpp17CopyAssignable");
if (this != std::addressof(__c)) {
__base::__copy_assign_alloc(__c);
assign(__c.begin(), __c.end());
diff --git a/libcxx/include/map b/libcxx/include/map
index 37a8ec91b8f1f..2c20a2d5df97f 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -600,6 +600,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20
# include <__tree>
# include <__type_traits/container_traits.h>
# include <__type_traits/is_allocator.h>
+# include <__type_traits/is_assignable.h>
# include <__type_traits/remove_const.h>
# include <__type_traits/type_identity.h>
# include <__utility/forward.h>
@@ -1084,6 +1085,8 @@ public:
_LIBCPP_HIDE_FROM_ABI map(const map& __m) : __tree_(__m.__tree_) { insert(__m.begin(), __m.end()); }
_LIBCPP_HIDE_FROM_ABI map& operator=(const map& __m) {
+ static_assert(is_copy_assignable<key_type>::value, "T must be Cpp17CopyAssignable");
+ static_assert(is_copy_assignable<mapped_type>::value, "T must be Cpp17CopyAssignable");
# ifndef _LIBCPP_CXX03_LANG
__tree_ = __m.__tree_;
# else
@@ -1105,6 +1108,11 @@ public:
_LIBCPP_HIDE_FROM_ABI map(map&& __m, const allocator_type& __a);
_LIBCPP_HIDE_FROM_ABI map& operator=(map&& __m) noexcept(is_nothrow_move_assignable<__base>::value) {
+ static_assert(__alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<key_type>::value,
+ "T must be Cpp17MoveAssignable");
+ static_assert(
+ __alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<mapped_type>::value,
+ "T must be Cpp17MoveAssignable");
__tree_ = std::move(__m.__tree_);
return *this;
}
@@ -1771,6 +1779,8 @@ public:
}
_LIBCPP_HIDE_FROM_ABI multimap& operator=(const multimap& __m) {
+ static_assert(is_copy_assignable<key_type>::value, "T must be Cpp17CopyAssignable");
+ static_assert(is_copy_assignable<mapped_type>::value, "T must be Cpp17CopyAssignable");
# ifndef _LIBCPP_CXX03_LANG
__tree_ = __m.__tree_;
# else
@@ -1792,6 +1802,11 @@ public:
_LIBCPP_HIDE_FROM_ABI multimap(multimap&& __m, const allocator_type& __a);
_LIBCPP_HIDE_FROM_ABI multimap& operator=(multimap&& __m) noexcept(is_nothrow_move_assignable<__base>::value) {
+ static_assert(__alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<key_type>::value,
+ "T must be Cpp17MoveAssignable");
+ static_assert(
+ __alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<mapped_type>::value,
+ "T must be Cpp17MoveAssignable");
__tree_ = std::move(__m.__tree_);
return *this;
}
diff --git a/libcxx/include/set b/libcxx/include/set
index bd7bfef1f3e29..74affdde6db13 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -537,6 +537,7 @@ erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred); // C++20
# include <__type_traits/container_traits.h>
# include <__type_traits/enable_if.h>
# include <__type_traits/is_allocator.h>
+# include <__type_traits/is_assignable.h>
# include <__type_traits/is_nothrow_assignable.h>
# include <__type_traits/is_nothrow_constructible.h>
# include <__type_traits/is_same.h>
@@ -665,6 +666,7 @@ public:
_LIBCPP_HIDE_FROM_ABI set(const set& __s) : __tree_(__s.__tree_) { insert(__s.begin(), __s.end()); }
_LIBCPP_HIDE_FROM_ABI set& operator=(const set& __s) {
+ static_assert(is_copy_assignable<value_type>::value, "T must be Cpp17CopyAssignable");
__tree_ = __s.__tree_;
return *this;
}
@@ -704,6 +706,9 @@ public:
}
_LIBCPP_HIDE_FROM_ABI set& operator=(set&& __s) noexcept(is_nothrow_move_assignable<__base>::value) {
+ static_assert(
+ __alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<value_type>::value,
+ "T must be Cpp17MoveAssignable");
__tree_ = std::move(__s.__tree_);
return *this;
}
@@ -1130,6 +1135,7 @@ public:
}
_LIBCPP_HIDE_FROM_ABI multiset& operator=(const multiset& __s) {
+ static_assert(is_copy_assignable<value_type>::value, "T must be Cpp17CopyAssignable");
__tree_ = __s.__tree_;
return *this;
}
@@ -1169,6 +1175,9 @@ public:
}
_LIBCPP_HIDE_FROM_ABI multiset& operator=(multiset&& __s) _NOEXCEPT_(is_nothrow_move_assignable<__base>::value) {
+ static_assert(
+ __alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<value_type>::value,
+ "T must be Cpp17MoveAssignable");
__tree_ = std::move(__s.__tree_);
return *this;
}
diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index be36b65cb85b4..9253e04c495ca 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -612,6 +612,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
# include <__type_traits/enable_if.h>
# include <__type_traits/invoke.h>
# include <__type_traits/is_allocator.h>
+# include <__type_traits/is_assignable.h>
# include <__type_traits/is_integral.h>
# include <__type_traits/remove_const.h>
# include <__type_traits/type_identity.h>
@@ -1192,6 +1193,8 @@ public:
}
_LIBCPP_HIDE_FROM_ABI unordered_map& operator=(const unordered_map& __u) {
+ static_assert(is_copy_assignable<key_type>::value, "T must be Cpp17CopyAssignable");
+ static_assert(is_copy_assignable<mapped_type>::value, "T must be Cpp17CopyAssignable");
# ifndef _LIBCPP_CXX03_LANG
__table_ = __u.__table_;
# else
@@ -1715,6 +1718,12 @@ template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
inline unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>&
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(unordered_map&& __u)
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) {
+ static_assert(allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
+ is_move_assignable<key_type>::value,
+ "T must be Cpp17MoveAssignable");
+ static_assert(allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
+ is_move_assignable<mapped_type>::value,
+ "T must be Cpp17MoveAssignable");
__table_ = std::move(__u.__table_);
return *this;
}
@@ -2001,6 +2010,8 @@ public:
}
_LIBCPP_HIDE_FROM_ABI unordered_multimap& operator=(const unordered_multimap& __u) {
+ static_assert(is_copy_assignable<key_type>::value, "T must be Cpp17CopyAssignable");
+ static_assert(is_copy_assignable<mapped_type>::value, "T must be Cpp17CopyAssignable");
# ifndef _LIBCPP_CXX03_LANG
__table_ = __u.__table_;
# else
@@ -2472,6 +2483,10 @@ template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
inline unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>&
unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(unordered_multimap&& __u)
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) {
+ static_assert(__alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<key_type>::value,
+ "T must be Cpp17MoveAssignable");
+ static_assert(__alloc_traits::propagate_on_container_move_assignment::value || is_move_assignable<mapped_type>::value,
+ "T must be Cpp17MoveAssignable");
__table_ = std::move(__u.__table_);
return *this;
}
diff --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set
index 87d98435329f3..d5ae37d575a3e 100644
--- a/libcxx/include/unordered_set
+++ b/libcxx/include/unordered_set
@@ -557,6 +557,7 @@ template <class Value, class Hash, class Pred, class Alloc>
# include <__type_traits/enable_if.h>
# include <__type_traits/invoke.h>
# include <__type_traits/is_allocator.h>
+# include <__type_traits/is_assignable.h>
# include <__type_traits/is_integral.h>
# include <__type_traits/is_nothrow_assignable.h>
# include <__type_traits/is_nothrow_constructible.h>
@@ -734,6 +735,7 @@ public:
}
_LIBCPP_HIDE_FROM_ABI unordered_set& operator=(const unordered_set& __u) {
+ static_assert(is_copy_assignable<value_type>::value, "T must be Cpp17CopyAssignable");
__table_ = __u.__table_;
return *this;
}
@@ -1129,6 +1131,9 @@ template <class _Value, class _Hash, class _Pred, class _Alloc>
inline unordered_set<_Value, _Hash, _Pred, _Alloc>&
unordered_set<_Value, _Hash, _Pred, _Alloc>::operator=(unordered_set&& __u)
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) {
+ static_assert(allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
+ is_move_assignable<value_type>::value,
+ "T must be Cpp17MoveAssignable");
__table_ = std::move(__u.__table_);
return *this;
}
@@ -1338,6 +1343,7 @@ public:
}
_LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(const unordered_multiset& __u) {
+ static_assert(is_copy_assignable<value_type>::value, "T must be Cpp17CopyAssignable");
__table_ = __u.__table_;
return *this;
}
@@ -1745,6 +1751,9 @@ template <class _Value, class _Hash, class _Pred, class _Alloc>
inline unordered_multiset<_Value, _Hash, _Pred, _Alloc>&
unordered_multiset<_Value, _Hash, _Pred, _Alloc>::operator=(unordered_multiset&& __u)
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) {
+ static_assert(allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
+ is_move_assignable<value_type>::value,
+ "T must be Cpp17MoveAssignable");
__table_ = std::move(__u.__table_);
return *this;
}
diff --git a/libcxx/test/std/containers/associative/map/map.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/associative/map/map.cons/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..4be858626ea03
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.cons/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::map containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <map>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+ bool operator<(const AttributeType&) const;
+};
+
+void f() {
+ std::map<int, AttributeType> v;
+ std::map<int, AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error@* {{no viable overloaded '='}}
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/associative/multimap/multimap.cons/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..c19f1818a6ce6
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.cons/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::multimap containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <map>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+ bool operator<(const AttributeType&) const;
+};
+
+void f() {
+ std::multimap<int, AttributeType> v;
+ std::multimap<int, AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error@* {{no viable overloaded '='}}
+}
diff --git a/libcxx/test/std/containers/associative/multiset/multiset.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/associative/multiset/multiset.cons/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..00aa361cea900
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/multiset.cons/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::multiset containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <set>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+ bool operator<(const AttributeType&) const;
+};
+
+void f() {
+ std::multiset<AttributeType> v;
+ std::multiset<AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error@* {{overload resolution selected deleted operator '='}}
+}
diff --git a/libcxx/test/std/containers/associative/set/set.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/associative/set/set.cons/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..082a6717af321
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/set.cons/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::set containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <set>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+ bool operator<(const AttributeType&) const;
+};
+
+void f() {
+ std::set<AttributeType> v;
+ std::set<AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error@* {{overload resolution selected deleted operator '='}}
+}
diff --git a/libcxx/test/std/containers/sequences/deque/deque.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..7e81162ef9e45
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::deque containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <deque>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+};
+
+void f() {
+ std::deque<AttributeType> v;
+ std::deque<AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error@* {{overload resolution selected deleted operator '='}}
+}
diff --git a/libcxx/test/std/containers/sequences/list/list.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/sequences/list/list.cons/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..30c7020ee012d
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/list/list.cons/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::list containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <list>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+};
+
+void f() {
+ std::list<AttributeType> v;
+ std::list<AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error@* {{overload resolution selected deleted operator '='}}
+}
diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..3027fd90382c0
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector/vector.cons/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::vector containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <vector>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+};
+
+void f() {
+ std::vector<AttributeType> v;
+ std::vector<AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error-re@* {{{{no matching function for call to object of type 'const __copy_n'|overload resolution selected deleted operator '='}}}}
+}
diff --git a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..3d2a1ec394787
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::unordered_map containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <unordered_map>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+ bool operator==(const AttributeType&) const;
+};
+
+template <>
+struct std::hash<AttributeType> {
+ size_t operator()(const AttributeType&) const;
+};
+
+void f() {
+ std::unordered_map<int, AttributeType> v;
+ std::unordered_map<int, AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error@* {{no viable overloaded '='}}
+}
diff --git a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..acd70a9e6ba84
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::unordered_multimap containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <unordered_map>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+ bool operator==(const AttributeType&) const;
+};
+
+template <>
+struct std::hash<AttributeType> {
+ size_t operator()(const AttributeType&) const;
+};
+
+void f() {
+ std::unordered_multimap<int, AttributeType> v;
+ std::unordered_multimap<int, AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error@* {{no viable overloaded '='}}
+}
diff --git a/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..0f820fa5d660b
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::unordered_multiset containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <unordered_set>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+ bool operator==(const AttributeType&) const;
+};
+
+template <>
+struct std::hash<AttributeType> {
+ size_t operator()(const AttributeType&) const;
+};
+
+void f() {
+ std::unordered_multiset<AttributeType> v;
+ std::unordered_multiset<AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error@* {{overload resolution selected deleted operator '='}}
+}
diff --git a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/copy_assign.not_assignable.verify.cpp
new file mode 100644
index 0000000000000..503235265dcbc
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/copy_assign.not_assignable.verify.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that a std::unordered_set containing move-only types can't be copy-assigned.
+
+// UNSUPPORTED: c++03
+
+#include <unordered_set>
+
+struct AttributeType {
+ AttributeType();
+ AttributeType(const AttributeType&);
+ AttributeType(AttributeType&&);
+ AttributeType& operator=(const AttributeType&) = delete;
+ AttributeType& operator=(AttributeType&&);
+ ~AttributeType();
+ bool operator==(const AttributeType&) const;
+};
+
+template <>
+struct std::hash<AttributeType> {
+ size_t operator()(const AttributeType&) const;
+};
+
+void f() {
+ std::unordered_set<AttributeType> v;
+ std::unordered_set<AttributeType> copy;
+ copy = v;
+ // expected-error@* {{T must be Cpp17CopyAssignable}}
+ // expected-error@* {{overload resolution selected deleted operator '='}}
+}
>From 137c437d1a57dcca9a17d18c57910acf9bb36ac6 Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Tue, 11 Mar 2025 00:33:48 -0400
Subject: [PATCH 2/2] reverse order of comment lines
---
.../map/map.cons/copy_assign.not_assignable.verify.cpp | 4 ++--
.../multimap.cons/copy_assign.not_assignable.verify.cpp | 4 ++--
.../multiset.cons/copy_assign.not_assignable.verify.cpp | 4 ++--
.../set/set.cons/copy_assign.not_assignable.verify.cpp | 4 ++--
.../deque/deque.cons/copy_assign.not_assignable.verify.cpp | 4 ++--
.../list/list.cons/copy_assign.not_assignable.verify.cpp | 4 ++--
.../vector/vector.cons/copy_assign.not_assignable.verify.cpp | 4 ++--
.../unord.map.cnstr/copy_assign.not_assignable.verify.cpp | 4 ++--
.../copy_assign.not_assignable.verify.cpp | 4 ++--
.../copy_assign.not_assignable.verify.cpp | 4 ++--
.../unord.set.cnstr/copy_assign.not_assignable.verify.cpp | 4 ++--
11 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/libcxx/test/std/containers/associative/map/map.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/associative/map/map.cons/copy_assign.not_assignable.verify.cpp
index 4be858626ea03..5ac88a1070926 100644
--- a/libcxx/test/std/containers/associative/map/map.cons/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/associative/map/map.cons/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::map containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::map containing move-only types can't be copy-assigned.
+
#include <map>
struct AttributeType {
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/associative/multimap/multimap.cons/copy_assign.not_assignable.verify.cpp
index c19f1818a6ce6..e3db9c4f6782a 100644
--- a/libcxx/test/std/containers/associative/multimap/multimap.cons/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/associative/multimap/multimap.cons/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::multimap containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::multimap containing move-only types can't be copy-assigned.
+
#include <map>
struct AttributeType {
diff --git a/libcxx/test/std/containers/associative/multiset/multiset.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/associative/multiset/multiset.cons/copy_assign.not_assignable.verify.cpp
index 00aa361cea900..b3feb32c4b6a3 100644
--- a/libcxx/test/std/containers/associative/multiset/multiset.cons/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/associative/multiset/multiset.cons/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::multiset containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::multiset containing move-only types can't be copy-assigned.
+
#include <set>
struct AttributeType {
diff --git a/libcxx/test/std/containers/associative/set/set.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/associative/set/set.cons/copy_assign.not_assignable.verify.cpp
index 082a6717af321..e1b9e6f4a81c8 100644
--- a/libcxx/test/std/containers/associative/set/set.cons/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/associative/set/set.cons/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::set containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::set containing move-only types can't be copy-assigned.
+
#include <set>
struct AttributeType {
diff --git a/libcxx/test/std/containers/sequences/deque/deque.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/copy_assign.not_assignable.verify.cpp
index 7e81162ef9e45..4c16893b69ce6 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::deque containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::deque containing move-only types can't be copy-assigned.
+
#include <deque>
struct AttributeType {
diff --git a/libcxx/test/std/containers/sequences/list/list.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/sequences/list/list.cons/copy_assign.not_assignable.verify.cpp
index 30c7020ee012d..139f108c6ed2c 100644
--- a/libcxx/test/std/containers/sequences/list/list.cons/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/sequences/list/list.cons/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::list containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::list containing move-only types can't be copy-assigned.
+
#include <list>
struct AttributeType {
diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/copy_assign.not_assignable.verify.cpp
index 3027fd90382c0..705e87a5413af 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.cons/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.cons/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::vector containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::vector containing move-only types can't be copy-assigned.
+
#include <vector>
struct AttributeType {
diff --git a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/copy_assign.not_assignable.verify.cpp
index 3d2a1ec394787..aed05bf5ab922 100644
--- a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::unordered_map containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::unordered_map containing move-only types can't be copy-assigned.
+
#include <unordered_map>
struct AttributeType {
diff --git a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/copy_assign.not_assignable.verify.cpp
index acd70a9e6ba84..96341dadd529e 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::unordered_multimap containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::unordered_multimap containing move-only types can't be copy-assigned.
+
#include <unordered_map>
struct AttributeType {
diff --git a/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/copy_assign.not_assignable.verify.cpp
index 0f820fa5d660b..6d783da5d00ce 100644
--- a/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::unordered_multiset containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::unordered_multiset containing move-only types can't be copy-assigned.
+
#include <unordered_set>
struct AttributeType {
diff --git a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/copy_assign.not_assignable.verify.cpp b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/copy_assign.not_assignable.verify.cpp
index 503235265dcbc..66c9485361d62 100644
--- a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/copy_assign.not_assignable.verify.cpp
+++ b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/copy_assign.not_assignable.verify.cpp
@@ -6,10 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// Make sure that a std::unordered_set containing move-only types can't be copy-assigned.
-
// UNSUPPORTED: c++03
+// Make sure that a std::unordered_set containing move-only types can't be copy-assigned.
+
#include <unordered_set>
struct AttributeType {
More information about the libcxx-commits
mailing list