# HG changeset patch # User lindquist # Date 1195946353 -3600 # Node ID 5880c12dba835458cf52fb55271667d5ec55cae3 # Parent 27b9f749d9fe4a55012f4027141875423321d4d9 [svn r118] Fixed dynamic casts. Fixed a few interface bugs. diff -r 27b9f749d9fe -r 5880c12dba83 dmd/mtype.c --- 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 diff -r 27b9f749d9fe -r 5880c12dba83 gen/classes.cpp --- 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); } ////////////////////////////////////////////////////////////////////////////////////////// diff -r 27b9f749d9fe -r 5880c12dba83 gen/classes.h --- 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 diff -r 27b9f749d9fe -r 5880c12dba83 gen/toir.cpp --- 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(); diff -r 27b9f749d9fe -r 5880c12dba83 gen/tollvm.cpp --- 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()); diff -r 27b9f749d9fe -r 5880c12dba83 gen/tollvm.h --- 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 diff -r 27b9f749d9fe -r 5880c12dba83 llvmdc.kdevelop.filelist --- 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 diff -r 27b9f749d9fe -r 5880c12dba83 test/classes9.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); + } + } +} diff -r 27b9f749d9fe -r 5880c12dba83 test/interface5.d --- /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); + } +} diff -r 27b9f749d9fe -r 5880c12dba83 test/interface6.d --- /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); +} diff -r 27b9f749d9fe -r 5880c12dba83 test/interface7.d --- /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); +}