changeset 1136:9d308feaec27

Fix #239.
author Christian Kamm <kamm incasoftware de>
date Tue, 24 Mar 2009 14:33:57 +0100
parents 76e72fdef04d
children 45d73f0a9b43
files gen/toir.cpp tests/mini/classes13_bug239.d
diffstat 2 files changed, 51 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- 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 {
--- /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);
+}