changeset 114:5880c12dba83 trunk

[svn r118] Fixed dynamic casts. Fixed a few interface bugs.
author lindquist
date Sun, 25 Nov 2007 00:19:13 +0100
parents 27b9f749d9fe
children 5ba6d286c941
files dmd/mtype.c gen/classes.cpp gen/classes.h gen/toir.cpp gen/tollvm.cpp gen/tollvm.h llvmdc.kdevelop.filelist test/classes9.d test/interface5.d test/interface6.d test/interface7.d
diffstat 11 files changed, 243 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/mtype.c	Sat Nov 24 06:33:00 2007 +0100
+++ b/dmd/mtype.c	Sun Nov 25 00:19:13 2007 +0100
@@ -4518,14 +4518,36 @@
          */
 #if IN_LLVM
 
-        e = e->castTo(sc, t->pointerTo()->pointerTo());
+        Type* ct;
+        if (sym->isInterfaceDeclaration()) {
+            ct = t->pointerTo()->pointerTo()->pointerTo();
+        }
+        else {
+            ct = t->pointerTo()->pointerTo();
+        }
+
+        e = e->castTo(sc, ct);
         e = new PtrExp(e->loc, e);
-        e->type = t->pointerTo();
+        e->type = ct->next;
         e = new PtrExp(e->loc, e);
-        e->type = t;
+        e->type = ct->next->next;
+
         if (sym->isInterfaceDeclaration())
         {
-            assert(0 && "No interfaces yet!");
+            if (sym->isCOMinterface())
+            {   /* COM interface vtbl[]s are different in that the
+             * first entry is always pointer to QueryInterface().
+             * We can't get a .classinfo for it.
+             */
+            error(e->loc, "no .classinfo for COM interface objects");
+            }
+            /* For an interface, the first entry in the vtbl[]
+             * is actually a pointer to an instance of struct Interface.
+             * The first member of Interface is the .classinfo,
+             * so add an extra pointer indirection.
+             */
+            e = new PtrExp(e->loc, e);
+            e->type = ct->next->next->next;
         }
 
 #else
--- a/gen/classes.cpp	Sat Nov 24 06:33:00 2007 +0100
+++ b/gen/classes.cpp	Sun Nov 25 00:19:13 2007 +0100
@@ -60,7 +60,7 @@
             BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i];
             ClassDeclaration *id = b->base;
             DtoResolveClass(id);
-            // Fill in vtbl[]
+            // Fill in vtbl[]
             b->fillVtbl(cd, &b->vtbl, 1);
         }
     }
@@ -128,11 +128,11 @@
     else
         *ts->llvmType = structtype;
 
-    if (cd->parent->isModule()) {
-        gIR->module->addTypeName(cd->mangle(), ts->llvmType->get());
+    if (cd->isNested()) {
+        assert(0 && "nested classes not implemented");
     }
     else {
-        assert(0 && "class parent is not a module");
+        gIR->module->addTypeName(cd->mangle(), ts->llvmType->get());
     }
 
     // build interface info type
@@ -592,11 +592,51 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
-DValue* DtoCastObjectToInterface(DValue* val, Type* _to)
+DValue* DtoCastClass(DValue* val, Type* _to)
+{
+    Type* to = DtoDType(_to);
+    if (to->ty == Tpointer) {
+        const llvm::Type* tolltype = DtoType(_to);
+        llvm::Value* rval = DtoBitCast(val->getRVal(), tolltype);
+        return new DImValue(_to, rval);
+    }
+
+    assert(to->ty == Tclass);
+    TypeClass* tc = (TypeClass*)to;
+
+    Type* from = DtoDType(val->getType());
+    TypeClass* fc = (TypeClass*)from;
+
+    if (tc->sym->isInterfaceDeclaration()) {
+        assert(!fc->sym->isInterfaceDeclaration());
+        return DtoDynamicCastObject(val, _to);
+    }
+    else {
+        int poffset;
+        if (fc->sym->isInterfaceDeclaration()) {
+            return DtoCastInterfaceToObject(val, _to);
+        }
+        else if (tc->sym->isBaseOf(fc->sym,NULL)) {
+            const llvm::Type* tolltype = DtoType(_to);
+            llvm::Value* rval = DtoBitCast(val->getRVal(), tolltype);
+            return new DImValue(_to, rval);
+        }
+        else {
+            return DtoDynamicCastObject(val, _to);
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoDynamicCastObject(DValue* val, Type* _to)
 {
     // call:
     // Object _d_dynamic_cast(Object o, ClassInfo c)
 
+    DtoForceDeclareDsymbol(ClassDeclaration::object);
+    DtoForceDeclareDsymbol(ClassDeclaration::classinfo);
+
     llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast");
     const llvm::FunctionType* funcTy = func->getFunctionType();
 
@@ -606,22 +646,31 @@
     llvm::Value* tmp = val->getRVal();
     tmp = DtoBitCast(tmp, funcTy->getParamType(0));
     args.push_back(tmp);
+    assert(funcTy->getParamType(0) == tmp->getType());
 
     // ClassInfo c
     TypeClass* to = (TypeClass*)DtoDType(_to);
     DtoForceDeclareDsymbol(to->sym);
     assert(to->sym->llvmClass);
-    args.push_back(to->sym->llvmClass);
+    tmp = to->sym->llvmClass;
+    // unfortunately this is needed as the implementation of object differs somehow from the declaration
+    // this could happen in user code as well :/
+    tmp = DtoBitCast(tmp, funcTy->getParamType(1));
+    args.push_back(tmp);
+    assert(funcTy->getParamType(1) == tmp->getType());
 
     // call it
     llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "tmp");
+
+    // cast return value
     ret = DtoBitCast(ret, DtoType(_to));
+
     return new DImValue(_to, ret);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
-DValue* DtoCastInterfaceToObject(DValue* val)
+DValue* DtoCastInterfaceToObject(DValue* val, Type* to)
 {
     // call:
     // Object _d_toObject(void* p)
@@ -635,7 +684,14 @@
 
     // call it
     llvm::Value* ret = gIR->ir->CreateCall(func, tmp, "tmp");
-    return new DImValue(ClassDeclaration::object->type, ret);
+
+    // cast return value
+    if (to != NULL)
+        ret = DtoBitCast(ret, DtoType(to));
+    else
+        to = ClassDeclaration::object->type;
+
+    return new DImValue(to, ret);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
--- a/gen/classes.h	Sat Nov 24 06:33:00 2007 +0100
+++ b/gen/classes.h	Sun Nov 25 00:19:13 2007 +0100
@@ -27,7 +27,8 @@
 void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance);
 void DtoInitClass(TypeClass* tc, llvm::Value* dst);
 
-DValue* DtoCastObjectToInterface(DValue* val, Type* to);
-DValue* DtoCastInterfaceToObject(DValue* val);
+DValue* DtoCastClass(DValue* val, Type* to);
+DValue* DtoDynamicCastObject(DValue* val, Type* to);
+DValue* DtoCastInterfaceToObject(DValue* val, Type* to);
 
 #endif
--- a/gen/toir.cpp	Sat Nov 24 06:33:00 2007 +0100
+++ b/gen/toir.cpp	Sun Nov 25 00:19:13 2007 +0100
@@ -1289,7 +1289,7 @@
         if (e1type->ty == Tclass) {
             TypeClass* tc = (TypeClass*)e1type;
             if (tc->sym->isInterfaceDeclaration()) {
-                vthis2 = DtoCastInterfaceToObject(l)->getRVal();
+                vthis2 = DtoCastInterfaceToObject(l, NULL)->getRVal();
             }
         }
         llvm::Value* vthis = l->getRVal();
--- a/gen/tollvm.cpp	Sat Nov 24 06:33:00 2007 +0100
+++ b/gen/tollvm.cpp	Sun Nov 25 00:19:13 2007 +0100
@@ -1138,39 +1138,6 @@
     assert(0);
 }
 
-DValue* DtoCastClass(DValue* val, Type* _to)
-{
-    Type* to = DtoDType(_to);
-    if (to->ty == Tpointer) {
-        const llvm::Type* tolltype = DtoType(_to);
-        llvm::Value* rval = DtoBitCast(val->getRVal(), tolltype);
-        return new DImValue(_to, rval);
-    }
-
-    assert(to->ty == Tclass);
-    TypeClass* tc = (TypeClass*)to;
-
-    Type* from = DtoDType(val->getType());
-    TypeClass* fc = (TypeClass*)from;
-
-    if (tc->sym->isInterfaceDeclaration()) {
-        assert(!fc->sym->isInterfaceDeclaration());
-        return DtoCastObjectToInterface(val, _to);
-    }
-    else {
-        if (fc->sym->isInterfaceDeclaration()) {
-            assert(0);
-            return DtoCastInterfaceToObject(val);
-        }
-        else {
-            const llvm::Type* tolltype = DtoType(_to);
-            assert(to->ty == Tclass);
-            llvm::Value* rval = DtoBitCast(val->getRVal(), tolltype);
-            return new DImValue(_to, rval);
-        }
-    }
-}
-
 DValue* DtoCast(DValue* val, Type* to)
 {
     Type* fromtype = DtoDType(val->getType());
--- a/gen/tollvm.h	Sat Nov 24 06:33:00 2007 +0100
+++ b/gen/tollvm.h	Sun Nov 25 00:19:13 2007 +0100
@@ -101,7 +101,6 @@
 DValue* DtoCastPtr(DValue* val, Type* to);
 DValue* DtoCastFloat(DValue* val, Type* to);
 DValue* DtoCastComplex(DValue* val, Type* to);
-DValue* DtoCastClass(DValue* val, Type* to);
 DValue* DtoCast(DValue* val, Type* to);
 
 // binary operations
--- a/llvmdc.kdevelop.filelist	Sat Nov 24 06:33:00 2007 +0100
+++ b/llvmdc.kdevelop.filelist	Sun Nov 25 00:19:13 2007 +0100
@@ -328,6 +328,7 @@
 test/bug9.d
 test/c.d
 test/classes.d
+test/classes10.d
 test/classes2.d
 test/classes3.d
 test/classes4.d
@@ -335,6 +336,7 @@
 test/classes6.d
 test/classes7.d
 test/classes8.d
+test/classes9.d
 test/classinfo1.d
 test/classinfo2.d
 test/classinfo3.d
@@ -382,6 +384,9 @@
 test/interface2.d
 test/interface3.d
 test/interface4.d
+test/interface5.d
+test/interface6.d
+test/interface7.d
 test/intrinsics.d
 test/mainargs1.d
 test/memory1.d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/classes9.d	Sun Nov 25 00:19:13 2007 +0100
@@ -0,0 +1,47 @@
+module classes9;
+
+class C
+{
+}
+
+class D : C
+{
+}
+
+class E
+{
+}
+
+class F : E
+{
+}
+
+void main()
+{
+    {
+        D d = new D;
+        {
+            C c = d;
+            assert(c !is null);
+            D d2 = cast(D)c;
+            assert(d2 !is null);
+            E e = cast(E)d;
+            assert(e is null);
+            F f = cast(F)d;
+            assert(f is null);
+        }
+    }
+    {
+        F f = new F;
+        {
+            E e = f;
+            assert(e !is null);
+            F f2 = cast(F)e;
+            assert(f2 !is null);
+            C c = cast(C)f;
+            assert(c is null);
+            D d2 = cast(D)f;
+            assert(d2 is null);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/interface5.d	Sun Nov 25 00:19:13 2007 +0100
@@ -0,0 +1,32 @@
+module interface5;
+
+interface I
+{
+    void func();
+}
+
+class C : I
+{
+    int i;
+    void func()
+    {
+        printf("C\n");
+        i++;
+    }
+}
+
+void main()
+{
+    C c = new C;
+    c.func();
+    {
+        I i = c;
+        c.func();
+
+        C c2 = cast(C)i;
+        c2.func();
+
+        c.func();
+        assert(c.i == 4);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/interface6.d	Sun Nov 25 00:19:13 2007 +0100
@@ -0,0 +1,44 @@
+module interface6;
+
+interface I
+{
+    void Ifunc();
+}
+
+interface J
+{
+    void Jfunc();
+}
+
+class C : I,J
+{
+    int i;
+    int j;
+    void Ifunc()
+    {
+        i++;
+    }
+    void Jfunc()
+    {
+        j++;
+    }
+}
+
+void main()
+{
+    C c = new C;
+    c.Ifunc();
+    c.Jfunc();
+    I i = c;
+    i.Ifunc();
+    J j = c;
+    j.Jfunc();
+    C c2 = cast(C)i;
+    c2.Ifunc();
+    c2.Jfunc();
+    C c3 = cast(C)j;
+    c3.Ifunc();
+    c3.Jfunc();
+    assert(c.i == 4);
+    assert(c.j == 4);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/interface7.d	Sun Nov 25 00:19:13 2007 +0100
@@ -0,0 +1,21 @@
+module interface7;
+
+interface I
+{
+}
+
+class C : I
+{
+}
+
+void main()
+{
+    I i = new C;
+    ClassInfo ci = i.classinfo;
+    char[] name = ci.name;
+    printf("ci.name = %.*s\n", name.length, name.ptr);
+    ClassInfo cI = I.classinfo;
+    name = cI.name;
+    printf("cI.name = %.*s\n", name.length, name.ptr);
+    assert(ci is cI);
+}