Skip to content

Commit

Permalink
fix Issue 2013 - interface to interface dynamic cast is incorrect in …
Browse files Browse the repository at this point in the history
…some cases

For the runtime cast behavior, also requires fixing a druntime internal function `_d_isbaseof2()` in `druntime/src/rt/cast_.d`.
  • Loading branch information
9rnsr committed Jul 19, 2015
1 parent 5cefffd commit 2c28cec
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 27 deletions.
1 change: 1 addition & 0 deletions src/aggregate.h
Expand Up @@ -284,6 +284,7 @@ class ClassDeclaration : public AggregateDeclaration
bool isFuncHidden(FuncDeclaration *fd);
FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
void interfaceSemantic(Scope *sc);
unsigned setBaseInterfaceOffsets(unsigned baseOffset);
bool isCOMclass();
virtual bool isCOMinterface();
bool isCPPclass();
Expand Down
62 changes: 38 additions & 24 deletions src/class.c
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 @@ -1613,6 +1624,9 @@ void InterfaceDeclaration::finalizeSize(Scope *sc)
{
structsize = Target::ptrsize * 2;
sizeok = SIZEOKdone;

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

/*******************************************
Expand Down
6 changes: 3 additions & 3 deletions test/runnable/interface2.d
Expand Up @@ -923,7 +923,7 @@ void test27()
}

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

void test1747()
{
Expand Down Expand Up @@ -961,11 +961,11 @@ void test1747()
assert(pia == pc + n);

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

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

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

0 comments on commit 2c28cec

Please sign in to comment.