mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-05 09:31:03 +03:00
[svn r118] Fixed dynamic casts.
Fixed a few interface bugs.
This commit is contained in:
parent
b43f5729b0
commit
541a677a54
11 changed files with 243 additions and 49 deletions
30
dmd/mtype.c
30
dmd/mtype.c
|
@ -4518,14 +4518,36 @@ L1:
|
|||
*/
|
||||
#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
|
||||
|
|
|
@ -128,11 +128,11 @@ void DtoResolveClass(ClassDeclaration* cd)
|
|||
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 @@ 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:
|
||||
// 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 @@ DValue* DtoCastObjectToInterface(DValue* val, Type* _to)
|
|||
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 @@ DValue* DtoCastInterfaceToObject(DValue* val)
|
|||
|
||||
// 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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -27,7 +27,8 @@ void DtoDefineClassInfo(ClassDeclaration* cd);
|
|||
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
|
||||
|
|
|
@ -1289,7 +1289,7 @@ DValue* DotVarExp::toElem(IRState* p)
|
|||
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();
|
||||
|
|
|
@ -1138,39 +1138,6 @@ DValue* DtoCastComplex(DValue* val, Type* _to)
|
|||
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());
|
||||
|
|
|
@ -101,7 +101,6 @@ DValue* DtoCastInt(DValue* val, Type* to);
|
|||
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
|
||||
|
|
|
@ -328,6 +328,7 @@ test/bug8.d
|
|||
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/classes5.d
|
|||
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/interface1.d
|
|||
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
|
||||
|
|
47
test/classes9.d
Normal file
47
test/classes9.d
Normal 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
32
test/interface5.d
Normal 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
44
test/interface6.d
Normal 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
21
test/interface7.d
Normal 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue