Skip to content

Commit

Permalink
Fix issue 19891 - Confusing error messages for auto ref parameters wi…
Browse files Browse the repository at this point in the history
…th default values
  • Loading branch information
SSoulaimane committed Jun 2, 2019
1 parent 41e2c0a commit b8869f6
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 10 deletions.
9 changes: 5 additions & 4 deletions src/dmd/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
for (size_t i = 0; i < tf.parameterList.parameters.dim; i++)
(*tf.parameterList.parameters)[i].defaultArg = null;
tf.next = null;
tf.incomplete = true;

// Resolve parameter types and 'auto ref's.
tf.fargs = fargs;
Expand Down Expand Up @@ -2169,6 +2170,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
// Shouldn't run semantic on default arguments and return type.
for (size_t i = 0; i < tf.parameterList.parameters.dim; i++)
(*tf.parameterList.parameters)[i].defaultArg = null;
tf.incomplete = true;

if (fd.isCtorDeclaration())
{
// For constructors, emitting return type is necessary for
Expand Down Expand Up @@ -6212,11 +6215,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol
Parameter fparam = fparameters[j];
if (fparam.storageClass & STC.autoref) // if "auto ref"
{
if (!fargs)
Expression farg = fargs && j < fargs.dim ? (*fargs)[j] : fparam.defaultArg;
if (!farg)
goto Lnotequals;
if (fargs.dim <= j)
break;
Expression farg = (*fargs)[j];
if (farg.isLvalue())
{
if (!(fparam.storageClass & STC.ref_))
Expand Down
1 change: 1 addition & 0 deletions src/dmd/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -4154,6 +4154,7 @@ extern (C++) final class TypeFunction : TypeNext
ubyte iswild; // bit0: inout on params, bit1: inout on qualifier
Expressions* fargs; // function arguments
int inuse;
bool incomplete; // return type or default arguments removed

extern (D) this(ParameterList pl, Type treturn, LINK linkage, StorageClass stc = 0)
{
Expand Down
1 change: 1 addition & 0 deletions src/dmd/mtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ class TypeFunction : public TypeNext
Expressions *fargs; // function arguments

int inuse;
bool incomplete;

static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0);
const char *kind();
Expand Down
22 changes: 16 additions & 6 deletions src/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1349,8 +1349,9 @@ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc)
if (fparam.defaultArg)
{
Expression e = fparam.defaultArg;
auto isRefOrOut = fparam.storageClass & (STC.ref_ | STC.out_);
if (isRefOrOut)
const isRefOrOut = fparam.storageClass & (STC.ref_ | STC.out_);
const isAuto = fparam.storageClass & STC.auto_;
if (isRefOrOut && !isAuto)
{
e = e.expressionSemantic(argsc);
e = resolveProperties(argsc, e);
Expand All @@ -1372,7 +1373,8 @@ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc)
e = new AddrExp(e.loc, e);
e = e.expressionSemantic(argsc);
}
if (isRefOrOut && !MODimplicitConv(e.type.mod, fparam.type.mod))
if (isRefOrOut && (!isAuto || e.isLvalue())
&& !MODimplicitConv(e.type.mod, fparam.type.mod))
{
const(char)* errTxt = fparam.storageClass & STC.ref_ ? "ref" : "out";
.error(e.loc, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
Expand All @@ -1381,7 +1383,7 @@ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc)
e = e.implicitCastTo(argsc, fparam.type);

// default arg must be an lvalue
if (fparam.storageClass & (STC.out_ | STC.ref_))
if (isRefOrOut && !isAuto)
e = e.toLvalue(argsc, e);

fparam.defaultArg = e;
Expand Down Expand Up @@ -1460,9 +1462,9 @@ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc)
*/
if (fparam.storageClass & STC.auto_)
{
if (mtype.fargs && i < mtype.fargs.dim && (fparam.storageClass & STC.ref_))
Expression farg = mtype.fargs && i < mtype.fargs.dim ? (*mtype.fargs)[i] : fparam.defaultArg;
if (farg && (fparam.storageClass & STC.ref_))
{
Expression farg = (*mtype.fargs)[i];
if (farg.isLvalue())
{
// ref parameter
Expand All @@ -1472,6 +1474,14 @@ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc)
fparam.storageClass &= ~STC.auto_; // https://issues.dlang.org/show_bug.cgi?id=14656
fparam.storageClass |= STC.autoref;
}
else if (mtype.incomplete && (fparam.storageClass & STC.ref_))
{
// the default argument may have been temporarily removed,
// see usage of `TypeFunction.incomplete`.
// https://issues.dlang.org/show_bug.cgi?id=19891
fparam.storageClass &= ~STC.auto_;
fparam.storageClass |= STC.autoref;
}
else
{
.error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
Expand Down
13 changes: 13 additions & 0 deletions test/runnable/test19891.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
int g;

void fun(R)(auto ref int a, auto ref R r = g)
{
++r;
}

void main()
{
fun(10, 2);
fun(10);
assert(g == 1);
}

0 comments on commit b8869f6

Please sign in to comment.