# HG changeset patch # User Christian Kamm # Date 1237901637 -3600 # Node ID 9d308feaec27eefce40442e78f4ddb69e3419e77 # Parent 76e72fdef04d8fa0d34bf81bff7dee87e3b92fb7 Fix #239. diff -r 76e72fdef04d -r 9d308feaec27 gen/toir.cpp --- a/gen/toir.cpp Mon Mar 23 14:47:51 2009 +0100 +++ b/gen/toir.cpp Tue Mar 24 14:33:57 2009 +0100 @@ -1104,14 +1104,32 @@ LLValue* vthis = l->getRVal(); if (!vthis2) vthis2 = vthis; - // super call - if (e1->op == TOKsuper) { + // + // decide whether this function needs to be looked up in the vtable + // + bool vtbllookup = fdecl->isAbstract() || (!fdecl->isFinal() && fdecl->isVirtual()); + + // even virtual functions are looked up directly if super or DotTypeExp + // are used, thus we need to walk through the this expression and check + Expression* e = e1; + while (e && vtbllookup) { + if (e->op == TOKsuper || e->op == TOKdottype) + vtbllookup = false; + else if (e->op == TOKcast) + e = ((CastExp*)e)->e1; + else + break; + } + + // + // look up function + // + if (!vtbllookup) { DtoForceDeclareDsymbol(fdecl); funcval = fdecl->ir.irFunc->func; assert(funcval); } - // normal virtual call - else if (fdecl->isAbstract() || (!fdecl->isFinal() && fdecl->isVirtual())) { + else { assert(fdecl->vtblIndex > 0); assert(e1type->ty == Tclass); @@ -1131,12 +1149,7 @@ if (Logger::enabled()) Logger::cout() << "funcval casted: " << *funcval << '\n'; } - // static call - else { - DtoForceDeclareDsymbol(fdecl); - funcval = fdecl->ir.irFunc->func; - assert(funcval); - } + return new DFuncValue(fdecl, funcval, vthis2); } else { diff -r 76e72fdef04d -r 9d308feaec27 tests/mini/classes13_bug239.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/mini/classes13_bug239.d Tue Mar 24 14:33:57 2009 +0100 @@ -0,0 +1,28 @@ +extern(C) int printf(char*, ...); + +class A { + bool Afoo = false; + void foo() { Afoo = true; } +} + +class B : A {} + +class C : B { + bool Cfoo = false; + void foo() { Cfoo = true; } +} + +void main() +{ + scope c1 = new C(); + c1.foo(); + assert(c1.Cfoo && !c1.Afoo); + + scope c2 = new C(); + c2.B.foo(); + assert(!c2.Cfoo && c2.Afoo); + + scope c3 = new C(); + c3.A.foo(); + assert(!c3.Cfoo && c3.Afoo); +}