From eb1deec50d6f6ea108d5c43f732e4eaefc440d4c Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Tue, 24 Mar 2009 14:33:57 +0100 Subject: [PATCH] Fix #239. --- gen/toir.cpp | 33 +++++++++++++++++++++++---------- tests/mini/classes13_bug239.d | 28 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 tests/mini/classes13_bug239.d diff --git a/gen/toir.cpp b/gen/toir.cpp index ce55d27b..0e955bc8 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1104,14 +1104,32 @@ DValue* DotVarExp::toElem(IRState* p) 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 @@ DValue* DotVarExp::toElem(IRState* p) 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 --git a/tests/mini/classes13_bug239.d b/tests/mini/classes13_bug239.d new file mode 100644 index 00000000..0db5c2e7 --- /dev/null +++ b/tests/mini/classes13_bug239.d @@ -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); +}