Skip to content

Commit

Permalink
fix Issue 13783 - Function overload with rvalue inout parameter not…
Browse files Browse the repository at this point in the history
… selected when `enum` parameter implicitly converted to its base type

The root issue is a flaw in the overload resolution mechanism.
For the function `auto f(ref T);`, an lvalue of `enum E : T` should not match.
  • Loading branch information
9rnsr committed Dec 2, 2014
1 parent a2cf7bd commit c0891db
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 23 deletions.
43 changes: 20 additions & 23 deletions src/mtype.c
Expand Up @@ -5831,30 +5831,30 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
// Non-lvalues do not match ref or out parameters
if (p->storageClass & STCref)
{
Type *targb = targ->toBasetype();
Type *tprmb = tprm->toBasetype();
//printf("%s\n", targb->toChars());
//printf("%s\n", tprmb->toChars());
// Bugzilla 13783: Don't use toBasetype() to handle enum types.
Type *ta = targ;
Type *tp = tprm;
//printf("fparam[%d] ta = %s, tp = %s\n", u, ta->toChars(), tp->toChars());

if (m && !arg->isLvalue())
{
if (arg->op == TOKstring && tprmb->ty == Tsarray)
if (arg->op == TOKstring && tp->ty == Tsarray)
{
if (targb->ty != Tsarray)
if (ta->ty != Tsarray)
{
Type *tn = tprmb->nextOf()->castMod(targb->nextOf()->mod);
Type *tn = tp->nextOf()->castMod(ta->nextOf()->mod);
dinteger_t dim = ((StringExp *)arg)->len;
targb = tn->sarrayOf(dim);
ta = tn->sarrayOf(dim);
}
}
else if (arg->op == TOKslice && tprmb->ty == Tsarray)
else if (arg->op == TOKslice && tp->ty == Tsarray)
{
// Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
if (targb->ty != Tsarray)
if (ta->ty != Tsarray)
{
Type *tn = targb->nextOf();
dinteger_t dim = ((TypeSArray *)tprmb)->dim->toUInteger();
targb = tn->sarrayOf(dim);
Type *tn = ta->nextOf();
dinteger_t dim = ((TypeSArray *)tp)->dim->toUInteger();
ta = tn->sarrayOf(dim);
}
}
else
Expand All @@ -5865,21 +5865,18 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
*/
while (1)
{
Type *tat = targb->aliasthisOf();
Type *tat = ta->toBasetype()->aliasthisOf();
if (!tat || !tat->implicitConvTo(tprm))
break;
targb = tat;
ta = tat;
}

/* Don't allow static arrays to be passed to mutable references
* to static arrays if the argument cannot be modified.
/* A ref variable should work like a head-const reference.
* e.g. disallows:
* ref T <- an lvalue of const(T) argument
* ref T[dim] <- an lvalue of const(T[dim]) argument
*/
if (targb->nextOf() && tprmb->ty == Tsarray &&
!MODimplicitConv(targb->nextOf()->mod, tprmb->nextOf()->mod))
goto Nomatch;

// ref variable behaves like head-const reference
if (!targb->constConv(tprmb))
if (!ta->constConv(tp))
goto Nomatch;
}
else if (p->storageClass & STCout)
Expand Down
15 changes: 15 additions & 0 deletions test/runnable/overload.d
Expand Up @@ -1053,6 +1053,20 @@ void test11916()
assert(g11916(m) == 2);
}

/***************************************************/
// 13783

enum E13783 { a = 5 }

inout(int) f( inout(int) t) { return t * 2; }
ref inout(int) f(ref inout(int) t) { return t; }

void test13783()
{
const E13783 e = E13783.a;
assert(f(e) == 10);
}

/***************************************************/

int main()
Expand Down Expand Up @@ -1086,6 +1100,7 @@ int main()
test11785();
test11915();
test11916();
test13783();

printf("Success\n");
return 0;
Expand Down

0 comments on commit c0891db

Please sign in to comment.