Skip to content

Commit 5f39350

Browse files
ntrel0xEAB
andauthored
Fix #10538 - Cannot swap a std.typecons.Tuple (#8864)
* Fix #10538 - Cannot swap a std.typecons.Tuple Co-authored-by: Elias Batek <0xEAB@users.noreply.github.com> * De-optimize `opAssign` of `std.typecons.Tuple` --------- Co-authored-by: Elias Batek <0xEAB@users.noreply.github.com> Co-authored-by: Elias Batek <desisma@heidel.beer>
1 parent 336bed6 commit 5f39350

File tree

2 files changed

+45
-11
lines changed

2 files changed

+45
-11
lines changed

std/algorithm/mutation.d

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2885,6 +2885,17 @@ if (isBlitAssignable!T && !is(typeof(lhs.proxySwap(rhs))))
28852885
{
28862886
if (&lhs != &rhs)
28872887
{
2888+
static if (__traits(compiles, lhs.tupleof = rhs.tupleof))
2889+
{
2890+
if (__ctfe)
2891+
{
2892+
// can't reinterpret cast
2893+
foreach (i, ref e; lhs.tupleof)
2894+
swap(e, rhs.tupleof[i]);
2895+
return;
2896+
}
2897+
}
2898+
28882899
// For structs with non-trivial assignment, move memory directly
28892900
ubyte[T.sizeof] t = void;
28902901
auto a = (cast(ubyte*) &lhs)[0 .. T.sizeof];
@@ -3128,6 +3139,18 @@ if (isBlitAssignable!T && !is(typeof(lhs.proxySwap(rhs))))
31283139
swap(a3, a4);
31293140
}
31303141

3142+
// https://issues.dlang.org/show_bug.cgi?id=21429
3143+
@safe unittest
3144+
{
3145+
enum e = (){
3146+
Tuple!int a = 5, b = 6;
3147+
swap(a, b);
3148+
assert(a[0] == 6);
3149+
assert(b[0] == 5);
3150+
return 0;
3151+
}();
3152+
}
3153+
31313154
/**
31323155
Swaps two elements in-place of a range `r`,
31333156
specified by their indices `i1` and `i2`.

std/typecons.d

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -980,24 +980,35 @@ if (distinctFieldNames!(Specs))
980980
{
981981
import std.algorithm.mutation : swap;
982982

983-
static if (is(R == Tuple!Types) && !__traits(isRef, rhs) && isTuple!R)
983+
/*
984+
This optimization caused compilation failures with no error message available:
985+
986+
> Error: unknown, please file report on issues.dlang.org
987+
> std/sumtype.d(1262): Error: template instance `std.sumtype.SumType!(Flag, Tuple!(This*))` error instantiating
988+
*/
989+
version (none)
984990
{
985-
if (__ctfe)
991+
static if (is(R == Tuple!Types) && !__traits(isRef, rhs) && isTuple!R)
986992
{
987-
// Cannot use swap at compile time
988-
field[] = rhs.field[];
993+
if (__ctfe)
994+
{
995+
// Cannot use swap at compile time
996+
field[] = rhs.field[];
997+
}
998+
else
999+
{
1000+
// Use swap-and-destroy to optimize rvalue assignment
1001+
swap!(Tuple!Types)(this, rhs);
1002+
}
9891003
}
9901004
else
9911005
{
992-
// Use swap-and-destroy to optimize rvalue assignment
993-
swap!(Tuple!Types)(this, rhs);
1006+
// Do not swap; opAssign should be called on the fields.
1007+
field[] = rhs.field[];
9941008
}
9951009
}
996-
else
997-
{
998-
// Do not swap; opAssign should be called on the fields.
999-
field[] = rhs.field[];
1000-
}
1010+
1011+
field[] = rhs.field[];
10011012
return this;
10021013
}
10031014

0 commit comments

Comments
 (0)