From c0891db6300eec0f6a088f4d021c81c4457a6dfa Mon Sep 17 00:00:00 2001 From: k-hara Date: Sat, 29 Nov 2014 12:03:31 +0900 Subject: [PATCH] fix Issue 13783 - Function overload with rvalue `inout` parameter not 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. --- src/mtype.c | 43 +++++++++++++++++++--------------------- test/runnable/overload.d | 15 ++++++++++++++ 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/mtype.c b/src/mtype.c index e38426a80892..80c32f770f06 100644 --- a/src/mtype.c +++ b/src/mtype.c @@ -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 @@ -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) diff --git a/test/runnable/overload.d b/test/runnable/overload.d index db4243b593cf..4a71b2128177 100644 --- a/test/runnable/overload.d +++ b/test/runnable/overload.d @@ -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() @@ -1086,6 +1100,7 @@ int main() test11785(); test11915(); test11916(); + test13783(); printf("Success\n"); return 0;