diff --git a/compiler/src/dmd/typesem.d b/compiler/src/dmd/typesem.d index 8b677521c59f..f5e4f2f6349f 100644 --- a/compiler/src/dmd/typesem.d +++ b/compiler/src/dmd/typesem.d @@ -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 { diff --git a/compiler/test/runnable/test21478a.d b/compiler/test/runnable/test21478a.d new file mode 100644 index 000000000000..1906e4e7d979 --- /dev/null +++ b/compiler/test/runnable/test21478a.d @@ -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. +} diff --git a/compiler/test/runnable/test21478b.d b/compiler/test/runnable/test21478b.d new file mode 100644 index 000000000000..05b2e1f494bd --- /dev/null +++ b/compiler/test/runnable/test21478b.d @@ -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); +}