Skip to content

Commit

Permalink
Fix bugzilla #24465: Make Tuple work with copy constructors
Browse files Browse the repository at this point in the history
If there's a constructor that looks like a copy constructor except that
it takes an rvalue instead of taking the argument by ref, then that type
can't have a copy constructor, and one of Tuple's constructors was
causing that problem. So, this fixes it so that it doesn't.
  • Loading branch information
jmdavis authored and dlang-bot committed Apr 1, 2024
1 parent 9f735fd commit 7858069
Showing 1 changed file with 46 additions and 1 deletion.
47 changes: 46 additions & 1 deletion std/typecons.d
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,14 @@ private template isBuildableFrom(U)
enum isBuildableFrom(T) = isBuildable!(T, U);
}

private enum hasCopyCtor(T) = __traits(hasCopyConstructor, T);

// T is expected to be an instantiation of Tuple.
private template noMemberHasCopyCtor(T)
{
import std.meta : anySatisfy;
enum noMemberHasCopyCtor = !anySatisfy!(hasCopyCtor, T.Types);
}

/**
_Tuple of values, for example $(D Tuple!(int, string)) is a record that
Expand Down Expand Up @@ -745,7 +753,8 @@ if (distinctFieldNames!(Specs))
* compatible with the target `Tuple`'s type.
*/
this(U)(U another)
if (areBuildCompatibleTuples!(typeof(this), U))
if (areBuildCompatibleTuples!(typeof(this), U) &&
(noMemberHasCopyCtor!(typeof(this)) || !is(Unqual!U == Unqual!(typeof(this)))))
{
field[] = another.field[];
}
Expand Down Expand Up @@ -1655,6 +1664,42 @@ if (distinctFieldNames!(Specs))
Tuple!(MyStruct) t;
}

// https://issues.dlang.org/show_bug.cgi?id=24465
@safe unittest
{
{
static struct S
{
this(ref return scope inout(S) rhs) scope @trusted inout pure nothrow {}
}

static void foo(Tuple!S)
{
}

Tuple!S t;
foo(t);

auto t2 = Tuple!S(t);
}

{
static struct S {}
Tuple!S t;
auto t2 = Tuple!S(t);

// This can't be done if Tuple has a copy constructor, because it's not
// allowed to have an rvalue constructor at that point, and the
// compiler doesn't to something intelligent like transform it into a
// move instead. However, it has been legal with Tuple for a while
// (maybe even since it was first added) when the type doesn't have a
// copy constructor, so this is testing to make sure that the fix to
// make copy constructors work doesn't mess up the rvalue constructor
// when none of the Tuple's members have copy constructors.
auto t3 = Tuple!S(Tuple!S.init);
}
}

/**
Creates a copy of a $(LREF Tuple) with its fields in _reverse order.
Expand Down

0 comments on commit 7858069

Please sign in to comment.