Skip to content

fix #21478: Ref parameter overload not called when struct implements copy constructor #21493

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions compiler/src/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1070,11 +1070,10 @@ private extern(D) MATCH argumentMatchParameter (FuncDeclaration fd, TypeFunction
}

// check if the copy constructor may be called to copy the argument
if (arg.isLvalue() && !isRef && argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
if (arg.isLvalue() && !isRef && argStruct && argStruct == prmStruct && argStruct.hasCopyCtor &&
!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
{
if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
return MATCH.nomatch;
m = MATCH.exact;
return MATCH.nomatch;
}
else
{
Expand Down
23 changes: 23 additions & 0 deletions compiler/test/runnable/test21478a.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// https://github.com/dlang/dmd/issues/21478

// Test struct that implements "rule of five"

struct S21478
{
// 1. destructor
~this() { }
// 2. copy constructor
this(ref return scope S21478) { assert(0); }
// 3. copy assign
void opAssign(const ref S21478) { }
// 4. move constructor
this(return scope S21478) { assert(0); }
// 5. move assign
void opAssign(const S21478) { assert(0); }
}

void main()
{
S21478 sa, sb;
sb = sa; // Should call 3, not 2 + 5.
}
36 changes: 36 additions & 0 deletions compiler/test/runnable/test21478b.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// https://github.com/dlang/dmd/issues/21478

// Test struct that implements copy constructor follows rvalue expression spec:
// If both ref and non-ref parameter overloads are present,
// an rvalue is preferably matched to the non-ref parameters,
// and an lvalue is preferably matched to the ref parameter.
// An RvalueExpression will preferably match with the non-ref parameter.

struct S21478
{
this(ref return scope S21478) { assert(0); }
}

struct P21478
{
int plain_old_data;
}

int overload(const S21478) { return 1; }
int overload(const ref S21478) { return 2; }

int overload(const P21478) { return 1; }
int overload(const ref P21478) { return 2; }

void main()
{
S21478 s;
assert(overload(s) == 2);
assert(overload(S21478()) == 1);
assert(overload(__rvalue(s)) == 1);

P21478 p;
assert(overload(p) == 2);
assert(overload(P21478()) == 1);
assert(overload(__rvalue(p)) == 1);
}
Loading