This patch ensures that SFINAE is used to delete assignment operators in pair and tuple based on issue 2729.
Differential Review: https://reviews.llvm.org/D62454
"`2699 <https://wg21.link/LWG2699>`__","Missing restriction in [numeric.requirements]","Issaquah","|Complete|",""
"`2712 <https://wg21.link/LWG2712>`__","copy_file(from, to, ...) has a number of unspecified error conditions","Issaquah","|Complete|",""
"`2722 <https://wg21.link/LWG2722>`__","equivalent incorrectly specifies throws clause","Issaquah","|Complete|",""
-"`2729 <https://wg21.link/LWG2729>`__","Missing SFINAE on std::pair::operator=","Issaquah","",""
+"`2729 <https://wg21.link/LWG2729>`__","Missing SFINAE on std::pair::operator=","Issaquah","|Complete|",""
"`2732 <https://wg21.link/LWG2732>`__","Questionable specification of path::operator/= and path::append","Issaquah","|Complete|",""
"`2733 <https://wg21.link/LWG2733>`__","[fund.ts.v2] gcd / lcm and bool","Issaquah","|Complete|",""
"`2735 <https://wg21.link/LWG2735>`__","std::abs(short), std::abs(signed char) and others should return int instead of double in order to be compatible with C++98 and C","Issaquah","|Complete|",""
#include <tuple>
#include <utility>
+#include <memory>
#include <cassert>
#include "test_macros.h"
assert(std::get<0>(t1) == 2);
assert(std::get<1>(t1) == short('a'));
}
+ {
+ // test that the implicitly generated copy assignment operator
+ // is properly deleted
+ using T = std::tuple<int, int>;
+ using P = std::tuple<std::unique_ptr<int>, std::unique_ptr<int>>;
+ static_assert(!std::is_assignable<T, const P &>::value, "");
+ }
return 0;
}
explicit D(int i = 0) : B(i) {}
};
+struct NonAssignable {
+ NonAssignable& operator=(NonAssignable const&) = delete;
+ NonAssignable& operator=(NonAssignable&&) = delete;
+};
+
int main(int, char**)
{
{
assert(std::get<0>(t) == 43);
assert(&std::get<0>(t) == &x);
}
+ {
+ using T = std::tuple<int, NonAssignable>;
+ using U = std::tuple<NonAssignable, int>;
+ static_assert(!std::is_assignable<T, U const&>::value, "");
+ static_assert(!std::is_assignable<U, T const&>::value, "");
+ }
return 0;
}
}
};
+struct NonAssignable {
+ NonAssignable& operator=(NonAssignable const&) = delete;
+ NonAssignable& operator=(NonAssignable&&) = delete;
+};
+
int main(int, char**)
{
{
assert(std::get<0>(t) == 43);
assert(&std::get<0>(t) == &x);
}
+ {
+ using T = std::tuple<int, NonAssignable>;
+ using U = std::tuple<NonAssignable, int>;
+ static_assert(!std::is_assignable<T, U&&>::value, "");
+ static_assert(!std::is_assignable<U, T&&>::value, "");
+ }
return 0;
}
MoveAssignable& operator=(MoveAssignable&&) = default;
};
+struct CopyAssignableInt {
+ CopyAssignableInt& operator=(int&) { return *this; }
+};
+
int main(int, char**)
{
{
static_assert(!std::is_copy_assignable<T>::value, "");
}
{
- using T = std::tuple<int, NonAssignable>;
- static_assert(!std::is_copy_assignable<T>::value, "");
+ using T = std::tuple<int, NonAssignable>;
+ static_assert(!std::is_copy_assignable<T>::value, "");
}
{
using T = std::tuple<int, CopyAssignable>;
using T = std::tuple<int, MoveAssignable>;
static_assert(!std::is_copy_assignable<T>::value, "");
}
+ {
+ using T = std::tuple<int, int, int>;
+ using P = std::pair<int, int>;
+ static_assert(!std::is_assignable<T, P>::value, "");
+ }
+ { // test const requirement
+ using T = std::tuple<CopyAssignableInt, CopyAssignableInt>;
+ using P = std::pair<int, int>;
+ static_assert(!std::is_assignable<T&, P const>::value, "");
+ }
+ {
+ using T = std::tuple<int, MoveAssignable>;
+ using P = std::pair<int, MoveAssignable>;
+ static_assert(!std::is_assignable<T&, P&>::value, "");
+ }
return 0;
}
}
{
- using T = std::tuple<int, NonAssignable>;
- static_assert(!std::is_move_assignable<T>::value, "");
+ using T = std::tuple<int, NonAssignable>;
+ static_assert(!std::is_move_assignable<T>::value, "");
}
{
using T = std::tuple<int, MoveAssignable>;
explicit D(int i) : B(i) {}
};
+struct NonMoveAssignable {
+ NonMoveAssignable& operator=(NonMoveAssignable const&) = default;
+ NonMoveAssignable& operator=(NonMoveAssignable&&) = delete;
+};
+
int main(int, char**)
{
{
assert(std::get<0>(t1) == 2);
assert(std::get<1>(t1)->id_ == 3);
}
+ {
+ using T = std::tuple<int, NonMoveAssignable>;
+ using P = std::pair<int, NonMoveAssignable>;
+ static_assert(!std::is_assignable<T&, P&&>::value, "");
+ }
+ {
+ using T = std::tuple<int, int, int>;
+ using P = std::pair<int, int>;
+ static_assert(!std::is_assignable<T&, P&&>::value, "");
+ }
return 0;
}
#include "archetypes.h"
#endif
+struct CopyAssignableInt {
+ CopyAssignableInt& operator=(int&) { return *this; }
+};
+
+struct Unrelated {};
+
TEST_CONSTEXPR_CXX20 bool test() {
{
typedef std::pair<int, short> P1;
assert(p.second.value == -42);
}
#endif
+
+ { // test const requirement
+ using T = std::pair<CopyAssignableInt, CopyAssignableInt>;
+ using P = std::pair<int, int>;
+ static_assert(!std::is_assignable<T&, P const>::value, "");
+ }
+ {
+ using T = std::pair<int, Unrelated>;
+ using P = std::pair<Unrelated, int>;
+ static_assert(!std::is_assignable<T&, P&>::value, "");
+ static_assert(!std::is_assignable<P&, T&>::value, "");
+ }
return true;
}
static_assert(!std::is_copy_assignable<P>::value, "");
}
{
+ using P = std::pair<int, std::unique_ptr<int> >;
+ static_assert(!std::is_copy_assignable<P>::value, "");
+ }
+ {
using P = std::pair<int, Incomplete&>;
static_assert(!std::is_copy_assignable<P>::value, "");
P p(42, inc_obj);
}
};
+struct NotAssignable {
+ NotAssignable& operator=(NotAssignable const&) = delete;
+ NotAssignable& operator=(NotAssignable&&) = delete;
+};
+
TEST_CONSTEXPR_CXX20 bool test() {
{
typedef std::pair<ConstexprTestTypes::MoveOnly, int> P;
assert(p2.first.moved == 0);
assert(p2.first.copied == 0);
}
+ {
+ using T = std::pair<int, NotAssignable>;
+ using P = std::pair<int, NotAssignable>;
+ static_assert(!std::is_assignable<T, P&&>::value, "");
+ }
return true;
}
}
};
+struct CopyAssignableInt {
+ CopyAssignableInt& operator=(int&) { return *this; }
+};
+
TEST_CONSTEXPR_CXX20 bool test() {
{
typedef std::pair<Derived, short> P1;
assert(t.second.moved == 0);
assert(t.second.copied == 0);
}
+ { // test const requirement
+ using T = std::pair<CopyAssignableInt, CopyAssignableInt>;
+ using P = std::pair<int, int>;
+ static_assert(!std::is_assignable<T, P&&>::value, "");
+ static_assert(!std::is_assignable<P, T&&>::value, "");
+ }
return true;
}