160 changes: 90 additions & 70 deletions src/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ void ClassDeclaration::semantic(Scope *sc)
* we need to set baseClass field for class covariance check.
*/
baseClass = tc->sym;
b->base = baseClass;
b->sym = baseClass;

if (tc->sym->scope && tc->sym->baseok < BASEOKdone)
tc->sym->semantic(NULL); // Try to resolve forward reference
Expand Down Expand Up @@ -452,9 +452,9 @@ void ClassDeclaration::semantic(Scope *sc)
for (size_t j = (baseClass ? 1 : 0); j < i; j++)
{
BaseClass *b2 = (*baseclasses)[j];
if (b2->base == tc->sym)
if (b2->sym == tc->sym)
{
error("inherits from duplicate interface %s", b2->base->toChars());
error("inherits from duplicate interface %s", b2->sym->toChars());
baseclasses->remove(i);
continue;
}
Expand All @@ -471,7 +471,7 @@ void ClassDeclaration::semantic(Scope *sc)
}
}

b->base = tc->sym;
b->sym = tc->sym;

if (tc->sym->scope && tc->sym->baseok < BASEOKdone)
tc->sym->semantic(NULL); // Try to resolve forward reference
Expand Down Expand Up @@ -514,7 +514,7 @@ void ClassDeclaration::semantic(Scope *sc)

baseClass = tc->sym;
assert(!baseClass->isInterfaceDeclaration());
b->base = baseClass;
b->sym = baseClass;
}
if (baseClass)
{
Expand All @@ -540,11 +540,11 @@ void ClassDeclaration::semantic(Scope *sc)
BaseClass *b = interfaces[i];
// If this is an interface, and it derives from a COM interface,
// then this is a COM interface too.
if (b->base->isCOMinterface())
if (b->sym->isCOMinterface())
com = true;
if (cpp && !b->base->isCPPinterface())
if (cpp && !b->sym->isCPPinterface())
{
::error(loc, "C++ class '%s' cannot implement D interface '%s'", toPrettyChars(), b->base->toPrettyChars());
::error(loc, "C++ class '%s' cannot implement D interface '%s'", toPrettyChars(), b->sym->toPrettyChars());
}
}

Expand Down Expand Up @@ -849,7 +849,7 @@ bool ClassDeclaration::isBaseOf2(ClassDeclaration *cd)
for (size_t i = 0; i < cd->baseclasses->dim; i++)
{
BaseClass *b = (*cd->baseclasses)[i];
if (b->base == this || isBaseOf2(b->base))
if (b->sym == this || isBaseOf2(b->sym))
return true;
}
return false;
Expand Down Expand Up @@ -925,13 +925,13 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags)
{
BaseClass *b = (*baseclasses)[i];

if (b->base)
if (b->sym)
{
if (!b->base->symtab)
error("base %s is forward referenced", b->base->ident->toChars());
if (!b->sym->symtab)
error("base %s is forward referenced", b->sym->ident->toChars());
else
{
s = b->base->search(loc, ident, flags);
s = b->sym->search(loc, ident, flags);
if (s == this) // happens if s is nested in this and derives from this
s = NULL;
else if (s)
Expand Down Expand Up @@ -995,30 +995,8 @@ void ClassDeclaration::finalizeSize(Scope *sc)
if (sizeok == SIZEOKfwd)
return;

// Allocate instance of each new interface
offset = structsize;
assert(vtblInterfaces); // Bugzilla 12984
for (size_t i = 0; i < vtblInterfaces->dim; i++)
{
BaseClass *b = (*vtblInterfaces)[i];
unsigned thissize = Target::ptrsize;

alignmember(STRUCTALIGN_DEFAULT, thissize, &offset);
assert(b->offset == 0);
b->offset = offset;

// Take care of single inheritance offsets
while (b->baseInterfaces_dim)
{
b = &b->baseInterfaces[0];
b->offset = offset;
}

offset += thissize;
if (alignsize < thissize)
alignsize = thissize;
}
structsize = offset;
// Add vptr's for any interfaces implemented by this class
structsize += setBaseInterfaceOffsets(structsize);
sizeok = SIZEOKdone;

// Look for the constructor
Expand Down Expand Up @@ -1194,6 +1172,39 @@ void ClassDeclaration::interfaceSemantic(Scope *sc)
}
}

unsigned ClassDeclaration::setBaseInterfaceOffsets(unsigned baseOffset)
{
assert(vtblInterfaces); // Bugzilla 12984

// set the offset of base interfaces from this (most derived) class/interface.
unsigned offset = baseOffset;

//if (vtblInterfaces->dim) printf("\n%s->finalizeSize()\n", toChars());
for (size_t i = 0; i < vtblInterfaces->dim; i++)
{
BaseClass *b = (*vtblInterfaces)[i];
unsigned thissize = Target::ptrsize;

alignmember(STRUCTALIGN_DEFAULT, thissize, &offset);
b->offset = offset;
//printf("\tvtblInterfaces[%d] b->sym = %s, offset = %d\n", i, b->sym->toChars(), b->offset);

// Take care of single inheritance offsets
while (b->baseInterfaces_dim)
{
b = &b->baseInterfaces[0];
b->offset = offset;
//printf("\tvtblInterfaces[%d] + sym = %s, offset = %d\n", i, b->sym->toChars(), b->offset);
}

offset += thissize;
if (alignsize < thissize)
alignsize = thissize;
}

return offset - baseOffset;
}

/****************************************
*/

Expand Down Expand Up @@ -1407,9 +1418,9 @@ void InterfaceDeclaration::semantic(Scope *sc)
for (size_t j = 0; j < i; j++)
{
BaseClass *b2 = (*baseclasses)[j];
if (b2->base == tc->sym)
if (b2->sym == tc->sym)
{
error("inherits from duplicate interface %s", b2->base->toChars());
error("inherits from duplicate interface %s", b2->sym->toChars());
baseclasses->remove(i);
continue;
}
Expand All @@ -1433,7 +1444,7 @@ void InterfaceDeclaration::semantic(Scope *sc)
}
}

b->base = tc->sym;
b->sym = tc->sym;

if (tc->sym->scope && tc->sym->baseok < BASEOKdone)
tc->sym->semantic(NULL); // Try to resolve forward reference
Expand Down Expand Up @@ -1464,9 +1475,9 @@ void InterfaceDeclaration::semantic(Scope *sc)
BaseClass *b = interfaces[i];
// If this is an interface, and it derives from a COM interface,
// then this is a COM interface too.
if (b->base->isCOMinterface())
if (b->sym->isCOMinterface())
com = true;
if (b->base->isCPPinterface())
if (b->sym->isCPPinterface())
cpp = true;
}

Expand Down Expand Up @@ -1522,19 +1533,19 @@ void InterfaceDeclaration::semantic(Scope *sc)
}

// Copy vtbl[] from base class
if (b->base->vtblOffset())
if (b->sym->vtblOffset())
{
size_t d = b->base->vtbl.dim;
size_t d = b->sym->vtbl.dim;
if (d > 1)
{
vtbl.reserve(d - 1);
for (size_t j = 1; j < d; j++)
vtbl.push(b->base->vtbl[j]);
vtbl.push(b->sym->vtbl[j]);
}
}
else
{
vtbl.append(&b->base->vtbl);
vtbl.append(&b->sym->vtbl);
}

Lcontinue:
Expand Down Expand Up @@ -1613,6 +1624,9 @@ void InterfaceDeclaration::finalizeSize(Scope *sc)
{
structsize = Target::ptrsize * 2;
sizeok = SIZEOKdone;

// set the offset of base interfaces
setBaseInterfaceOffsets(0);
}

/*******************************************
Expand All @@ -1634,22 +1648,31 @@ bool InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
{
BaseClass *b = cd->interfaces[j];

//printf("\tbase %s\n", b->base->toChars());
if (this == b->base)
//printf("\tX base %s\n", b->sym->toChars());
if (this == b->sym)
{
//printf("\tfound at offset %d\n", b->offset);
if (poffset)
{
*poffset = b->offset;
if (j && cd->isInterfaceDeclaration())
*poffset = OFFSET_RUNTIME;

/* TODO: Even though it's an interface to base interface upcast,
* I think we can avoid runtime offset determination ultimately.
* (I doubt that it was just a workaround for the bug in the
* inferface to Object downcast)
*/
}
return true;
}
if (isBaseOf(b, poffset))
{
if (j && poffset && cd->isInterfaceDeclaration())
*poffset = OFFSET_RUNTIME;
if (poffset)
{
if (j && cd->isInterfaceDeclaration())
*poffset = OFFSET_RUNTIME;
}
return true;
}
}
Expand All @@ -1662,28 +1685,25 @@ bool InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
return false;
}


bool InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset)
{
//printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars());
//printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->sym->toChars());
for (size_t j = 0; j < bc->baseInterfaces_dim; j++)
{
BaseClass *b = &bc->baseInterfaces[j];

if (this == b->base)
//printf("\tY base %s\n", b->sym->toChars());
if (this == b->sym)
{
//printf("\tfound at offset %d\n", b->offset);
if (poffset)
{
*poffset = b->offset;
if (j && bc->base->isInterfaceDeclaration())
*poffset = OFFSET_RUNTIME;
}
return true;
}
if (isBaseOf(b, poffset))
{
if (j && poffset && bc->base->isInterfaceDeclaration())
*poffset = OFFSET_RUNTIME;
return true;
}
}
Expand Down Expand Up @@ -1737,11 +1757,11 @@ BaseClass::BaseClass(Type *type, Prot protection)
//printf("BaseClass(this = %p, '%s')\n", this, type->toChars());
this->type = type;
this->protection = protection;
base = NULL;
offset = 0;
this->sym = NULL;
this->offset = 0;

baseInterfaces_dim = 0;
baseInterfaces = NULL;
this->baseInterfaces_dim = 0;
this->baseInterfaces = NULL;
}

/****************************************
Expand All @@ -1759,14 +1779,14 @@ bool BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newin
{
bool result = false;

//printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars());
//printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", sym->toChars(), cd->toChars());
if (vtbl)
vtbl->setDim(base->vtbl.dim);
vtbl->setDim(sym->vtbl.dim);

// first entry is ClassInfo reference
for (size_t j = base->vtblOffset(); j < base->vtbl.dim; j++)
for (size_t j = sym->vtblOffset(); j < sym->vtbl.dim; j++)
{
FuncDeclaration *ifd = base->vtbl[j]->isFuncDeclaration();
FuncDeclaration *ifd = sym->vtbl[j]->isFuncDeclaration();
FuncDeclaration *fd;
TypeFunction *tf;

Expand All @@ -1787,7 +1807,7 @@ bool BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newin
// Check that it is current
if (newinstance &&
fd->toParent() != cd &&
ifd->toParent() == base)
ifd->toParent() == sym)
cd->error("interface function '%s' is not implemented", ifd->toFullSignature());

if (fd->toParent() == cd)
Expand All @@ -1811,18 +1831,18 @@ bool BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newin

void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces)
{
//printf("+copyBaseInterfaces(), %s\n", base->toChars());
//printf("+copyBaseInterfaces(), %s\n", sym->toChars());
// if (baseInterfaces_dim)
// return;

baseInterfaces_dim = base->interfaces_dim;
baseInterfaces_dim = sym->interfaces_dim;
baseInterfaces = (BaseClass *)mem.xcalloc(baseInterfaces_dim, sizeof(BaseClass));

//printf("%s.copyBaseInterfaces()\n", base->toChars());
//printf("%s.copyBaseInterfaces()\n", sym->toChars());
for (size_t i = 0; i < baseInterfaces_dim; i++)
{
BaseClass *b = &baseInterfaces[i];
BaseClass *b2 = base->interfaces[i];
BaseClass *b2 = sym->interfaces[i];

assert(b2->vtbl.dim == 0); // should not be filled yet
memcpy(b, b2, sizeof(BaseClass));
Expand Down
6 changes: 3 additions & 3 deletions src/doc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1205,7 +1205,7 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc)

if (bc->protection.kind == PROTprivate)
continue;
if (bc->base && bc->base->ident == Id::Object)
if (bc->sym && bc->sym->ident == Id::Object)
continue;

if (any)
Expand All @@ -1216,9 +1216,9 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc)
any = 1;
}
emitProtection(buf, bc->protection);
if (bc->base)
if (bc->sym)
{
buf->printf("$(DDOC_PSUPER_SYMBOL %s)", bc->base->toPrettyChars());
buf->printf("$(DDOC_PSUPER_SYMBOL %s)", bc->sym->toPrettyChars());
}
else
{
Expand Down
43 changes: 27 additions & 16 deletions src/e2ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -3958,15 +3958,12 @@ elem *toElem(Expression *e, IRState *irs)
goto Lret;
}

// Casting from base class to derived class requires a runtime check
// Casting between class/interface may require a runtime check
if (fty == Tclass && tty == Tclass)
{
// Casting from derived class to base class is a no-op
int offset;
int rtl = RTLSYM_DYNAMIC_CAST;

ClassDeclaration *cdfrom = tfrom->isClassHandle();
ClassDeclaration *cdto = t->isClassHandle();

if (cdfrom->cpp)
{
if (cdto->cpp)
Expand All @@ -3988,13 +3985,14 @@ elem *toElem(Expression *e, IRState *irs)
e = el_bin(OPcomma, TYnptr, e, el_long(TYnptr, 0));
goto Lret;
}
if (cdfrom->isInterfaceDeclaration())
{
rtl = RTLSYM_INTERFACE_CAST;
}

int offset;
if (cdto->isBaseOf(cdfrom, &offset) && offset != OFFSET_RUNTIME)
{
/* The offset from cdfrom=>cdto is known at compile time.
/* The offset from cdfrom => cdto is known at compile time.
* Cases:
* - class => base class (upcast)
* - class => base interface (upcast)
*/

//printf("offset = %d\n", offset);
Expand All @@ -4015,13 +4013,26 @@ elem *toElem(Expression *e, IRState *irs)
e = el_bin(OPcond, TYnptr, e, ex);
}
}
goto Lret; // no-op
else
{
// Casting from derived class to base class is a no-op
}
}
else
{
/* The offset from cdfrom => cdto can only be determined at runtime.
* Cases:
* - class => derived class (downcast)
* - interface => derived class (downcast)
* - class => foreign interface (cross cast)
* - interface => base or foreign interface (cross cast)
*/
int rtl = cdfrom->isInterfaceDeclaration()
? RTLSYM_INTERFACE_CAST
: RTLSYM_DYNAMIC_CAST;
elem *ep = el_param(el_ptr(toSymbol(cdto)), e);
e = el_bin(OPcall, TYnptr, el_var(rtlsym[rtl]), ep);
}

/* The offset from cdfrom=>cdto can only be determined at runtime.
*/
elem *ep = el_param(el_ptr(toSymbol(cdto)), e);
e = el_bin(OPcall, TYnptr, el_var(rtlsym[rtl]), ep);
goto Lret;
}

Expand Down
12 changes: 6 additions & 6 deletions src/func.c
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,7 @@ void FuncDeclaration::semantic(Scope *sc)
for (size_t i = 0; i < cd->interfaces_dim; i++)
{
BaseClass *b = cd->interfaces[i];
vi = findVtblIndex((Dsymbols *)&b->base->vtbl, (int)b->base->vtbl.dim);
vi = findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.dim);
switch (vi)
{
case -1:
Expand All @@ -934,7 +934,7 @@ void FuncDeclaration::semantic(Scope *sc)

default:
{
FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl[vi];
FuncDeclaration *fdv = (FuncDeclaration *)b->sym->vtbl[vi];
Type *ti = NULL;

/* Remember which functions this overrides
Expand Down Expand Up @@ -995,7 +995,7 @@ void FuncDeclaration::semantic(Scope *sc)
Dsymbol *s = NULL;
for (size_t i = 0; i < cd->baseclasses->dim; i++)
{
s = (*cd->baseclasses)[i]->base->search_correct(ident);
s = (*cd->baseclasses)[i]->sym->search_correct(ident);
if (s) break;
}

Expand All @@ -1013,17 +1013,17 @@ void FuncDeclaration::semantic(Scope *sc)
for (size_t i = 0; i < cd->interfaces_dim; i++)
{
BaseClass *b = cd->interfaces[i];
if (b->base)
if (b->sym)
{
Dsymbol *s = search_function(b->base, ident);
Dsymbol *s = search_function(b->sym, ident);
if (s)
{
FuncDeclaration *f2 = s->isFuncDeclaration();
if (f2)
{
f2 = f2->overloadExactMatch(type);
if (f2 && f2->isFinalFunc() && f2->prot().kind != PROTprivate)
error("cannot override final function %s.%s", b->base->toChars(), f2->toPrettyChars());
error("cannot override final function %s.%s", b->sym->toChars(), f2->toPrettyChars());
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ class ToJsonVisitor : public Visitor
for (size_t i = 0; i < cd->interfaces_dim; i++)
{
BaseClass *b = cd->interfaces[i];
item(b->base->toPrettyChars(true));
item(b->sym->toPrettyChars(true));
}
arrayEnd();
}
Expand Down
4 changes: 2 additions & 2 deletions src/template.c
Original file line number Diff line number Diff line change
Expand Up @@ -4122,7 +4122,7 @@ MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *par
Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes,
Objects *best, int &numBaseClassMatches)
{
TemplateInstance *parti = b->base ? b->base->parent->isTemplateInstance() : NULL;
TemplateInstance *parti = b->sym ? b->sym->parent->isTemplateInstance() : NULL;
if (parti)
{
// Make a temporary copy of dedtypes so we don't destroy it
Expand Down Expand Up @@ -4235,7 +4235,7 @@ MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *par
deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes,
best, numBaseClassMatches);
}
s = (*s->baseclasses)[0]->base;
s = (*s->baseclasses)[0]->sym;
}

if (numBaseClassMatches == 0)
Expand Down
2 changes: 1 addition & 1 deletion src/tocvdebug.c
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ void toDebug(ClassDeclaration *cd)
for (size_t i = 0; i < cd->baseclasses->dim; i++)
{
BaseClass *bc = (*cd->baseclasses)[i];
idx_t typidx = cv4_typidx(Type_toCtype(bc->base->type)->Tnext);
idx_t typidx = cv4_typidx(Type_toCtype(bc->sym->type)->Tnext);
unsigned attribute = PROTtoATTR(bc->protection);

unsigned elementlen;
Expand Down
14 changes: 7 additions & 7 deletions src/toobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ void toObjFile(Dsymbol *ds, bool multiobj)
for (size_t i = 0; i < cd->vtblInterfaces->dim; i++)
{
BaseClass *b = (*cd->vtblInterfaces)[i];
ClassDeclaration *id = b->base;
ClassDeclaration *id = b->sym;

/* The layout is:
* struct Interface
Expand Down Expand Up @@ -496,7 +496,7 @@ void toObjFile(Dsymbol *ds, bool multiobj)
for (size_t i = 0; i < cd->vtblInterfaces->dim; i++)
{
BaseClass *b = (*cd->vtblInterfaces)[i];
ClassDeclaration *id = b->base;
ClassDeclaration *id = b->sym;

//printf(" interface[%d] is '%s'\n", i, id->toChars());
size_t j = 0;
Expand Down Expand Up @@ -543,8 +543,8 @@ void toObjFile(Dsymbol *ds, bool multiobj)
FuncDeclarations bvtbl;
if (bs->fillVtbl(cd, &bvtbl, 0))
{
//printf("\toverriding vtbl[] for %s\n", bs->base->toChars());
ClassDeclaration *id = bs->base;
//printf("\toverriding vtbl[] for %s\n", bs->sym->toChars());
ClassDeclaration *id = bs->sym;

size_t j = 0;
if (id->vtblOffset())
Expand Down Expand Up @@ -793,7 +793,7 @@ void toObjFile(Dsymbol *ds, bool multiobj)
for (size_t i = 0; i < id->vtblInterfaces->dim; i++)
{
BaseClass *b = (*id->vtblInterfaces)[i];
ClassDeclaration *base = b->base;
ClassDeclaration *base = b->sym;

// ClassInfo
dtxoff(&dt, toSymbol(base), 0, TYnptr);
Expand Down Expand Up @@ -1191,7 +1191,7 @@ unsigned baseVtblOffset(ClassDeclaration *cd, BaseClass *bc)

if (b == bc)
return csymoffset;
csymoffset += b->base->vtbl.dim * Target::ptrsize;
csymoffset += b->sym->vtbl.dim * Target::ptrsize;
}

// Put out the overriding interface vtbl[]s.
Expand All @@ -1211,7 +1211,7 @@ unsigned baseVtblOffset(ClassDeclaration *cd, BaseClass *bc)
//printf("\tcsymoffset = x%x\n", csymoffset);
return csymoffset;
}
csymoffset += bs->base->vtbl.dim * Target::ptrsize;
csymoffset += bs->sym->vtbl.dim * Target::ptrsize;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/traits.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
{
for (size_t i = 0; i < cd->baseclasses->dim; i++)
{
ClassDeclaration *cb = (*cd->baseclasses)[i]->base;
ClassDeclaration *cb = (*cd->baseclasses)[i]->sym;
assert(cb);
ScopeDsymbol::foreach(NULL, cb->members, &PushIdentsDg::dg, idents);
if (cb->baseclasses->dim)
Expand Down
65 changes: 60 additions & 5 deletions test/runnable/interface2.d
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ void test4()
{
Z z = new Z();
if (cast(K) z)
{ printf("not ok\n");
{
printf("not ok\n");
assert(0);
}
}
Expand Down Expand Up @@ -231,7 +232,8 @@ class C9 : IC9
}

void f9(IA9 i1, IB9 i2)
{ int i;
{
int i;

printf("f9\n");
i = i1.i1();
Expand Down Expand Up @@ -682,12 +684,12 @@ interface Iface2

class C1_20 : Iface1
{
C2_20 func1(){ return null; }
C2_20 func1(){ return null; }
}

class C2_20 : Iface2
{
C1_20 func2(){ return null; }
C1_20 func2(){ return null; }
}

void test20()
Expand Down Expand Up @@ -911,14 +913,66 @@ class C27 : I27
}

void test27()
{ C27 c = new C27();
{
C27 c = new C27();
c.x = 8;
I27 i = c;
assert(i.foo() == 3);
assert(I27.foo() == 3);
assert(i.bar() == 87);
}

/*******************************************************/
// 1747 & 2013

void test1747()
{
interface IA { int mA(); }
interface IB : IA { int mB(); }
interface IC : IB { }
interface ID : IA, IC { int mD(); }

// offset: 0 +n +n + ptrsize
// (IA)
// IB
// IA, IC
static class C : ID
{
int mA() { return 1; }
int mB() { return 2; }
int mD() { return 3; }
}

C c = new C; void* pc = *cast(void**)&c;
ID id = c; void* pid = *cast(void**)&id;
IC ic = c; void* pic = *cast(void**)&ic;
IB ib = c; void* pib = *cast(void**)&ib;
IA ia = c; void* pia = *cast(void**)&ia;

//printf(" c = %p\n", pc);
//printf("id = %p\n", pid);
//printf("ic = %p\n", pic);
//printf("ib = %p\n", pib);
//printf("ia = %p\n", pia);

size_t n = pid - pc;
assert(pic == pc + n + (void*).sizeof);
assert(pib == pc + n + (void*).sizeof); // OK <- NG
assert(pia == pc + n);

assert(id.mA() == 1);
assert(id.mB() == 2); // OK <- NG (bugzilla 2013 case)
assert(id.mD() == 3);

assert(ic.mA() == 1);
assert(ic.mB() == 2); // OK <- NG (bugzilla 2013 case)

assert(ib.mA() == 1);
assert(ib.mB() == 2); // OK <- NG

assert(ia.mA() == 1);
}

/*******************************************************/

private interface IFoo
Expand Down Expand Up @@ -1097,6 +1151,7 @@ int main()
test25();
test26();
test27();
test1747();
test2553();
test11034();
testTypeid();
Expand Down