Skip to content

Commit 82c4701

Browse files
committed
[libc++][nfc] SFINAE on pair/tuple assignment operators: LWG 2729.
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
1 parent 7e54d73 commit 82c4701

File tree

11 files changed

+111
-5
lines changed

11 files changed

+111
-5
lines changed

libcxx/docs/Cxx1zStatusIssuesStatus.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@
232232
"`2699 <https://wg21.link/LWG2699>`__","Missing restriction in [numeric.requirements]","Issaquah","|Complete|",""
233233
"`2712 <https://wg21.link/LWG2712>`__","copy_file(from, to, ...) has a number of unspecified error conditions","Issaquah","|Complete|",""
234234
"`2722 <https://wg21.link/LWG2722>`__","equivalent incorrectly specifies throws clause","Issaquah","|Complete|",""
235-
"`2729 <https://wg21.link/LWG2729>`__","Missing SFINAE on std::pair::operator=","Issaquah","",""
235+
"`2729 <https://wg21.link/LWG2729>`__","Missing SFINAE on std::pair::operator=","Issaquah","|Complete|",""
236236
"`2732 <https://wg21.link/LWG2732>`__","Questionable specification of path::operator/= and path::append","Issaquah","|Complete|",""
237237
"`2733 <https://wg21.link/LWG2733>`__","[fund.ts.v2] gcd / lcm and bool","Issaquah","|Complete|",""
238238
"`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|",""

libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_pair.pass.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <tuple>
1919
#include <utility>
20+
#include <memory>
2021
#include <cassert>
2122

2223
#include "test_macros.h"
@@ -32,6 +33,13 @@ int main(int, char**)
3233
assert(std::get<0>(t1) == 2);
3334
assert(std::get<1>(t1) == short('a'));
3435
}
36+
{
37+
// test that the implicitly generated copy assignment operator
38+
// is properly deleted
39+
using T = std::tuple<int, int>;
40+
using P = std::tuple<std::unique_ptr<int>, std::unique_ptr<int>>;
41+
static_assert(!std::is_assignable<T, const P &>::value, "");
42+
}
3543

3644
return 0;
3745
}

libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_copy.pass.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ struct D
3434
explicit D(int i = 0) : B(i) {}
3535
};
3636

37+
struct NonAssignable {
38+
NonAssignable& operator=(NonAssignable const&) = delete;
39+
NonAssignable& operator=(NonAssignable&&) = delete;
40+
};
41+
3742
int main(int, char**)
3843
{
3944
{
@@ -87,6 +92,12 @@ int main(int, char**)
8792
assert(std::get<0>(t) == 43);
8893
assert(&std::get<0>(t) == &x);
8994
}
95+
{
96+
using T = std::tuple<int, NonAssignable>;
97+
using U = std::tuple<NonAssignable, int>;
98+
static_assert(!std::is_assignable<T, U const&>::value, "");
99+
static_assert(!std::is_assignable<U, T const&>::value, "");
100+
}
90101

91102
return 0;
92103
}

libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_move.pass.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ struct E {
4545
}
4646
};
4747

48+
struct NonAssignable {
49+
NonAssignable& operator=(NonAssignable const&) = delete;
50+
NonAssignable& operator=(NonAssignable&&) = delete;
51+
};
52+
4853
int main(int, char**)
4954
{
5055
{
@@ -108,6 +113,12 @@ int main(int, char**)
108113
assert(std::get<0>(t) == 43);
109114
assert(&std::get<0>(t) == &x);
110115
}
116+
{
117+
using T = std::tuple<int, NonAssignable>;
118+
using U = std::tuple<NonAssignable, int>;
119+
static_assert(!std::is_assignable<T, U&&>::value, "");
120+
static_assert(!std::is_assignable<U, T&&>::value, "");
121+
}
111122

112123
return 0;
113124
}

libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/copy.pass.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ struct MoveAssignable {
3535
MoveAssignable& operator=(MoveAssignable&&) = default;
3636
};
3737

38+
struct CopyAssignableInt {
39+
CopyAssignableInt& operator=(int&) { return *this; }
40+
};
41+
3842
int main(int, char**)
3943
{
4044
{
@@ -89,8 +93,8 @@ int main(int, char**)
8993
static_assert(!std::is_copy_assignable<T>::value, "");
9094
}
9195
{
92-
using T = std::tuple<int, NonAssignable>;
93-
static_assert(!std::is_copy_assignable<T>::value, "");
96+
using T = std::tuple<int, NonAssignable>;
97+
static_assert(!std::is_copy_assignable<T>::value, "");
9498
}
9599
{
96100
using T = std::tuple<int, CopyAssignable>;
@@ -100,6 +104,21 @@ int main(int, char**)
100104
using T = std::tuple<int, MoveAssignable>;
101105
static_assert(!std::is_copy_assignable<T>::value, "");
102106
}
107+
{
108+
using T = std::tuple<int, int, int>;
109+
using P = std::pair<int, int>;
110+
static_assert(!std::is_assignable<T, P>::value, "");
111+
}
112+
{ // test const requirement
113+
using T = std::tuple<CopyAssignableInt, CopyAssignableInt>;
114+
using P = std::pair<int, int>;
115+
static_assert(!std::is_assignable<T&, P const>::value, "");
116+
}
117+
{
118+
using T = std::tuple<int, MoveAssignable>;
119+
using P = std::pair<int, MoveAssignable>;
120+
static_assert(!std::is_assignable<T&, P&>::value, "");
121+
}
103122

104123
return 0;
105124
}

libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/move.pass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ int main(int, char**)
105105

106106
}
107107
{
108-
using T = std::tuple<int, NonAssignable>;
109-
static_assert(!std::is_move_assignable<T>::value, "");
108+
using T = std::tuple<int, NonAssignable>;
109+
static_assert(!std::is_move_assignable<T>::value, "");
110110
}
111111
{
112112
using T = std::tuple<int, MoveAssignable>;

libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/move_pair.pass.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ struct D
3737
explicit D(int i) : B(i) {}
3838
};
3939

40+
struct NonMoveAssignable {
41+
NonMoveAssignable& operator=(NonMoveAssignable const&) = default;
42+
NonMoveAssignable& operator=(NonMoveAssignable&&) = delete;
43+
};
44+
4045
int main(int, char**)
4146
{
4247
{
@@ -48,6 +53,16 @@ int main(int, char**)
4853
assert(std::get<0>(t1) == 2);
4954
assert(std::get<1>(t1)->id_ == 3);
5055
}
56+
{
57+
using T = std::tuple<int, NonMoveAssignable>;
58+
using P = std::pair<int, NonMoveAssignable>;
59+
static_assert(!std::is_assignable<T&, P&&>::value, "");
60+
}
61+
{
62+
using T = std::tuple<int, int, int>;
63+
using P = std::pair<int, int>;
64+
static_assert(!std::is_assignable<T&, P&&>::value, "");
65+
}
5166

5267
return 0;
5368
}

libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_pair_U_V.pass.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
#include "archetypes.h"
2121
#endif
2222

23+
struct CopyAssignableInt {
24+
CopyAssignableInt& operator=(int&) { return *this; }
25+
};
26+
27+
struct Unrelated {};
28+
2329
TEST_CONSTEXPR_CXX20 bool test() {
2430
{
2531
typedef std::pair<int, short> P1;
@@ -58,6 +64,18 @@ TEST_CONSTEXPR_CXX20 bool test() {
5864
assert(p.second.value == -42);
5965
}
6066
#endif
67+
68+
{ // test const requirement
69+
using T = std::pair<CopyAssignableInt, CopyAssignableInt>;
70+
using P = std::pair<int, int>;
71+
static_assert(!std::is_assignable<T&, P const>::value, "");
72+
}
73+
{
74+
using T = std::pair<int, Unrelated>;
75+
using P = std::pair<Unrelated, int>;
76+
static_assert(!std::is_assignable<T&, P&>::value, "");
77+
static_assert(!std::is_assignable<P&, T&>::value, "");
78+
}
6179
return true;
6280
}
6381

libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ TEST_CONSTEXPR_CXX20 bool test() {
7777
using P = std::pair<int, ConstexprTestTypes::MoveAssignOnly>;
7878
static_assert(!std::is_copy_assignable<P>::value, "");
7979
}
80+
{
81+
using P = std::pair<int, std::unique_ptr<int> >;
82+
static_assert(!std::is_copy_assignable<P>::value, "");
83+
}
8084
{
8185
using P = std::pair<int, Incomplete&>;
8286
static_assert(!std::is_copy_assignable<P>::value, "");

libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ struct CountAssign {
3535
}
3636
};
3737

38+
struct NotAssignable {
39+
NotAssignable& operator=(NotAssignable const&) = delete;
40+
NotAssignable& operator=(NotAssignable&&) = delete;
41+
};
42+
3843
TEST_CONSTEXPR_CXX20 bool test() {
3944
{
4045
typedef std::pair<ConstexprTestTypes::MoveOnly, int> P;
@@ -83,6 +88,11 @@ TEST_CONSTEXPR_CXX20 bool test() {
8388
assert(p2.first.moved == 0);
8489
assert(p2.first.copied == 0);
8590
}
91+
{
92+
using T = std::pair<int, NotAssignable>;
93+
using P = std::pair<int, NotAssignable>;
94+
static_assert(!std::is_assignable<T, P&&>::value, "");
95+
}
8696
return true;
8797
}
8898

libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair_U_V.pass.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ struct CountAssign {
4040
}
4141
};
4242

43+
struct CopyAssignableInt {
44+
CopyAssignableInt& operator=(int&) { return *this; }
45+
};
46+
4347
TEST_CONSTEXPR_CXX20 bool test() {
4448
{
4549
typedef std::pair<Derived, short> P1;
@@ -61,6 +65,12 @@ TEST_CONSTEXPR_CXX20 bool test() {
6165
assert(t.second.moved == 0);
6266
assert(t.second.copied == 0);
6367
}
68+
{ // test const requirement
69+
using T = std::pair<CopyAssignableInt, CopyAssignableInt>;
70+
using P = std::pair<int, int>;
71+
static_assert(!std::is_assignable<T, P&&>::value, "");
72+
static_assert(!std::is_assignable<P, T&&>::value, "");
73+
}
6474
return true;
6575
}
6676

0 commit comments

Comments
 (0)