[svn r118] Fixed dynamic casts.

Fixed a few interface bugs.
This commit is contained in:
Tomas Lindquist Olsen 2007-11-25 00:19:13 +01:00
parent b43f5729b0
commit 541a677a54
11 changed files with 243 additions and 49 deletions

View file

@ -4518,14 +4518,36 @@ L1:
*/ */
#if IN_LLVM #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 = new PtrExp(e->loc, e);
e->type = t->pointerTo(); e->type = ct->next;
e = new PtrExp(e->loc, e); e = new PtrExp(e->loc, e);
e->type = t; e->type = ct->next->next;
if (sym->isInterfaceDeclaration()) 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 #else

View file

@ -60,7 +60,7 @@ void DtoResolveClass(ClassDeclaration* cd)
BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i]; BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i];
ClassDeclaration *id = b->base; ClassDeclaration *id = b->base;
DtoResolveClass(id); DtoResolveClass(id);
// Fill in vtbl[] // Fill in vtbl[]
b->fillVtbl(cd, &b->vtbl, 1); b->fillVtbl(cd, &b->vtbl, 1);
} }
} }
@ -128,11 +128,11 @@ void DtoResolveClass(ClassDeclaration* cd)
else else
*ts->llvmType = structtype; *ts->llvmType = structtype;
if (cd->parent->isModule()) { if (cd->isNested()) {
gIR->module->addTypeName(cd->mangle(), ts->llvmType->get()); assert(0 && "nested classes not implemented");
} }
else { else {
assert(0 && "class parent is not a module"); gIR->module->addTypeName(cd->mangle(), ts->llvmType->get());
} }
// build interface info type // build interface info type
@ -592,11 +592,51 @@ void DtoInitClass(TypeClass* tc, llvm::Value* dst)
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
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: // call:
// Object _d_dynamic_cast(Object o, ClassInfo c) // 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"); llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast");
const llvm::FunctionType* funcTy = func->getFunctionType(); const llvm::FunctionType* funcTy = func->getFunctionType();
@ -606,22 +646,31 @@ DValue* DtoCastObjectToInterface(DValue* val, Type* _to)
llvm::Value* tmp = val->getRVal(); llvm::Value* tmp = val->getRVal();
tmp = DtoBitCast(tmp, funcTy->getParamType(0)); tmp = DtoBitCast(tmp, funcTy->getParamType(0));
args.push_back(tmp); args.push_back(tmp);
assert(funcTy->getParamType(0) == tmp->getType());
// ClassInfo c // ClassInfo c
TypeClass* to = (TypeClass*)DtoDType(_to); TypeClass* to = (TypeClass*)DtoDType(_to);
DtoForceDeclareDsymbol(to->sym); DtoForceDeclareDsymbol(to->sym);
assert(to->sym->llvmClass); 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 // call it
llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "tmp"); llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "tmp");
// cast return value
ret = DtoBitCast(ret, DtoType(_to)); ret = DtoBitCast(ret, DtoType(_to));
return new DImValue(_to, ret); return new DImValue(_to, ret);
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoCastInterfaceToObject(DValue* val) DValue* DtoCastInterfaceToObject(DValue* val, Type* to)
{ {
// call: // call:
// Object _d_toObject(void* p) // Object _d_toObject(void* p)
@ -635,7 +684,14 @@ DValue* DtoCastInterfaceToObject(DValue* val)
// call it // call it
llvm::Value* ret = gIR->ir->CreateCall(func, tmp, "tmp"); 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);
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////

View file

@ -27,7 +27,8 @@ void DtoDefineClassInfo(ClassDeclaration* cd);
void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance); void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance);
void DtoInitClass(TypeClass* tc, llvm::Value* dst); void DtoInitClass(TypeClass* tc, llvm::Value* dst);
DValue* DtoCastObjectToInterface(DValue* val, Type* to); DValue* DtoCastClass(DValue* val, Type* to);
DValue* DtoCastInterfaceToObject(DValue* val); DValue* DtoDynamicCastObject(DValue* val, Type* to);
DValue* DtoCastInterfaceToObject(DValue* val, Type* to);
#endif #endif

View file

@ -1289,7 +1289,7 @@ DValue* DotVarExp::toElem(IRState* p)
if (e1type->ty == Tclass) { if (e1type->ty == Tclass) {
TypeClass* tc = (TypeClass*)e1type; TypeClass* tc = (TypeClass*)e1type;
if (tc->sym->isInterfaceDeclaration()) { if (tc->sym->isInterfaceDeclaration()) {
vthis2 = DtoCastInterfaceToObject(l)->getRVal(); vthis2 = DtoCastInterfaceToObject(l, NULL)->getRVal();
} }
} }
llvm::Value* vthis = l->getRVal(); llvm::Value* vthis = l->getRVal();

View file

@ -1138,39 +1138,6 @@ DValue* DtoCastComplex(DValue* val, Type* _to)
assert(0); 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) DValue* DtoCast(DValue* val, Type* to)
{ {
Type* fromtype = DtoDType(val->getType()); Type* fromtype = DtoDType(val->getType());

View file

@ -101,7 +101,6 @@ DValue* DtoCastInt(DValue* val, Type* to);
DValue* DtoCastPtr(DValue* val, Type* to); DValue* DtoCastPtr(DValue* val, Type* to);
DValue* DtoCastFloat(DValue* val, Type* to); DValue* DtoCastFloat(DValue* val, Type* to);
DValue* DtoCastComplex(DValue* val, Type* to); DValue* DtoCastComplex(DValue* val, Type* to);
DValue* DtoCastClass(DValue* val, Type* to);
DValue* DtoCast(DValue* val, Type* to); DValue* DtoCast(DValue* val, Type* to);
// binary operations // binary operations

View file

@ -328,6 +328,7 @@ test/bug8.d
test/bug9.d test/bug9.d
test/c.d test/c.d
test/classes.d test/classes.d
test/classes10.d
test/classes2.d test/classes2.d
test/classes3.d test/classes3.d
test/classes4.d test/classes4.d
@ -335,6 +336,7 @@ test/classes5.d
test/classes6.d test/classes6.d
test/classes7.d test/classes7.d
test/classes8.d test/classes8.d
test/classes9.d
test/classinfo1.d test/classinfo1.d
test/classinfo2.d test/classinfo2.d
test/classinfo3.d test/classinfo3.d
@ -382,6 +384,9 @@ test/interface1.d
test/interface2.d test/interface2.d
test/interface3.d test/interface3.d
test/interface4.d test/interface4.d
test/interface5.d
test/interface6.d
test/interface7.d
test/intrinsics.d test/intrinsics.d
test/mainargs1.d test/mainargs1.d
test/memory1.d test/memory1.d

47
test/classes9.d Normal file
View file

@ -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);
}
}
}

32
test/interface5.d Normal file
View file

@ -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);
}
}

44
test/interface6.d Normal file
View file

@ -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);
}

21
test/interface7.d Normal file
View file

@ -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);
}