diff --git a/src/dclass.d b/src/dclass.d index 0dfafae16280..c8bef77b5224 100644 --- a/src/dclass.d +++ b/src/dclass.d @@ -1156,6 +1156,9 @@ public: structsize = Target.ptrsize * 2; // allow room for __vptr and __monitor } + // Add vptr's for any interfaces implemented by this class + structsize += setBaseInterfaceOffsets(structsize); + uint offset = structsize; for (size_t i = 0; i < members.dim; i++) { @@ -1165,8 +1168,6 @@ public: if (sizeok == SIZEOKfwd) return; - // Add vptr's for any interfaces implemented by this class - structsize += setBaseInterfaceOffsets(structsize); sizeok = SIZEOKdone; // Calculate fields[i].overlapped diff --git a/src/e2ir.c b/src/e2ir.c index 7bf46fdeb5d5..294d84c0e0de 100644 --- a/src/e2ir.c +++ b/src/e2ir.c @@ -3970,28 +3970,6 @@ elem *toElem(Expression *e, IRState *irs) ClassDeclaration *cdfrom = tfrom->isClassHandle(); ClassDeclaration *cdto = t->isClassHandle(); - if (cdfrom->cpp) - { - if (cdto->cpp) - { - /* Casting from a C++ interface to a C++ interface - * is always a 'paint' operation - */ - goto Lret; // no-op - } - - /* Casting from a C++ interface to a class - * always results in null because there is no runtime - * information available to do it. - * - * Casting from a C++ interface to a non-C++ interface - * always results in null because there's no way one - * can be derived from the other. - */ - e = el_bin(OPcomma, TYnptr, e, el_long(TYnptr, 0)); - goto Lret; - } - int offset; if (cdto->isBaseOf(cdfrom, &offset) && offset != OFFSET_RUNTIME) { @@ -4024,6 +4002,27 @@ elem *toElem(Expression *e, IRState *irs) // Casting from derived class to base class is a no-op } } + else if (cdfrom->cpp) + { + if (cdto->cpp) + { + /* Casting from a C++ interface to a C++ interface + * is always a 'paint' operation + */ + goto Lret; // no-op + } + + /* Casting from a C++ interface to a class + * always results in null because there is no runtime + * information available to do it. + * + * Casting from a C++ interface to a non-C++ interface + * always results in null because there's no way one + * can be derived from the other. + */ + e = el_bin(OPcomma, TYnptr, e, el_long(TYnptr, 0)); + goto Lret; + } else { /* The offset from cdfrom => cdto can only be determined at runtime. diff --git a/src/todt.c b/src/todt.c index deaa34940b5b..57037a472702 100644 --- a/src/todt.c +++ b/src/todt.c @@ -640,6 +640,12 @@ dt_t **cpp_type_info_ptr_toDt(ClassDeclaration *cd, dt_t **pdt) * Put out initializers of ad->fields[]. * Although this is consistent with the elements[] version, we * have to use this optimized version to reduce memory footprint. + * Params: + * ad = aggregate with members + * pdt = tail of initializer list + * concreteType = structs: null, classes: top level class + * Returns: + * updated tail of dt_t list */ dt_t **membersToDt(AggregateDeclaration *ad, dt_t **pdt, ClassDeclaration *concreteType) @@ -647,6 +653,12 @@ dt_t **membersToDt(AggregateDeclaration *ad, dt_t **pdt, //printf("membersToDt(ad = '%s')\n", ad->toChars()); ClassDeclaration *cd = ad->isClassDeclaration(); + /* Order: + * { base class } or { __vptr, __monitor) + * interfaces + * fields + */ + unsigned offset; if (cd) { @@ -666,6 +678,30 @@ dt_t **membersToDt(AggregateDeclaration *ad, dt_t **pdt, else offset = 0; + if (cd) + { + // Interface vptr initializations + toSymbol(cd); // define csym + + for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) + { + BaseClass *b = (*cd->vtblInterfaces)[i]; + for (ClassDeclaration *cd2 = concreteType; 1; cd2 = cd2->baseClass) + { + assert(cd2); + unsigned csymoffset = baseVtblOffset(cd2, b); + if (csymoffset != ~0) + { + if (offset < b->offset) + pdt = dtnzeros(pdt, b->offset - offset); + pdt = dtxoff(pdt, toSymbol(cd2), csymoffset); + break; + } + } + offset = b->offset + Target::ptrsize; + } + } + for (size_t i = 0; i < ad->fields.dim; i++) { if (ad->fields[i]->_init && ad->fields[i]->_init->isVoidInitializer()) @@ -730,30 +766,6 @@ dt_t **membersToDt(AggregateDeclaration *ad, dt_t **pdt, offset = vd->offset + vd->type->size(); } - if (cd) - { - // Interface vptr initializations - toSymbol(cd); // define csym - - for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) - { - BaseClass *b = (*cd->vtblInterfaces)[i]; - for (ClassDeclaration *cd2 = concreteType; 1; cd2 = cd2->baseClass) - { - assert(cd2); - unsigned csymoffset = baseVtblOffset(cd2, b); - if (csymoffset != ~0) - { - if (offset < b->offset) - pdt = dtnzeros(pdt, b->offset - offset); - pdt = dtxoff(pdt, toSymbol(cd2), csymoffset); - break; - } - } - offset = b->offset + Target::ptrsize; - } - } - if (offset < ad->structsize) pdt = dtnzeros(pdt, ad->structsize - offset); @@ -792,6 +804,30 @@ dt_t **membersToDt(AggregateDeclaration *ad, dt_t **pdt, else offset = 0; + if (cd) + { + // Interface vptr initializations + toSymbol(cd); // define csym + + for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) + { + BaseClass *b = (*cd->vtblInterfaces)[i]; + for (ClassDeclaration *cd2 = concreteType; 1; cd2 = cd2->baseClass) + { + assert(cd2); + unsigned csymoffset = baseVtblOffset(cd2, b); + if (csymoffset != ~0) + { + if (offset < b->offset) + pdt = dtnzeros(pdt, b->offset - offset); + pdt = dtxoff(pdt, toSymbol(cd2), csymoffset); + break; + } + } + offset = b->offset + Target::ptrsize; + } + } + assert(firstFieldIndex <= elements->dim && firstFieldIndex + ad->fields.dim <= elements->dim); for (size_t i = 0; i < ad->fields.dim; i++) @@ -835,30 +871,6 @@ dt_t **membersToDt(AggregateDeclaration *ad, dt_t **pdt, offset = vd->offset + vd->type->size(); } - if (cd) - { - // Interface vptr initializations - toSymbol(cd); // define csym - - for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) - { - BaseClass *b = (*cd->vtblInterfaces)[i]; - for (ClassDeclaration *cd2 = concreteType; 1; cd2 = cd2->baseClass) - { - assert(cd2); - unsigned csymoffset = baseVtblOffset(cd2, b); - if (csymoffset != ~0) - { - if (offset < b->offset) - pdt = dtnzeros(pdt, b->offset - offset); - pdt = dtxoff(pdt, toSymbol(cd2), csymoffset); - break; - } - } - offset = b->offset + Target::ptrsize; - } - } - if (offset < ad->structsize) pdt = dtnzeros(pdt, ad->structsize - offset); diff --git a/test/runnable/cppa.d b/test/runnable/cppa.d index 8466ba25d68a..a3727c9aee79 100644 --- a/test/runnable/cppa.d +++ b/test/runnable/cppa.d @@ -982,6 +982,61 @@ void testeh3() } } +/****************************************/ +// 15579 + +extern (C++) +{ + class Base + { + //~this() {} + void based() { } + ubyte x = 4; + } + + interface Interface + { + int MethodCPP(); + int MethodD(); + } + + class Derived : Base, Interface + { + short y = 5; + int MethodCPP(); + int MethodD() { return 3; } + } + + Derived cppfoo(Derived); + Interface cppfooi(Interface); +} + +void test15579() +{ + Derived d = new Derived(); + assert(d.x == 4); + assert(d.y == 5); + assert(d.MethodD() == 3); + assert(d.MethodCPP() == 30); + + d = cppfoo(d); + assert(d.x == 7); + assert(d.y == 8); + version (Win64) + { + // needs more work + } + else + { + assert(d.MethodD() == 3); + assert(d.MethodCPP() == 30); + } + printf("d = %p, i = %p\n", d, cast(Interface)d); + Interface i = cppfooi(d); + assert(i.MethodD() == 3); + assert(i.MethodCPP() == 30); +} + /****************************************/ void main() @@ -1018,6 +1073,7 @@ void main() testeh(); testeh2(); testeh3(); + test15579(); printf("Success\n"); } diff --git a/test/runnable/extra-files/cppb.cpp b/test/runnable/extra-files/cppb.cpp index 9e6c2b8aa73e..e4da150a59bd 100644 --- a/test/runnable/extra-files/cppb.cpp +++ b/test/runnable/extra-files/cppb.cpp @@ -578,4 +578,66 @@ void throwle() #endif /******************************************/ +// 15579 + +class Base +{ +public: + //virtual ~Base() {} + virtual void base(); + unsigned char x; +}; + +class Interface +{ +public: + virtual int MethodCPP() = 0; + virtual int MethodD() = 0; +}; + +class Derived : public Base, public Interface +{ +public: + Derived(); + short y; + int MethodCPP(); +#if _WIN32 || _WIN64 + int MethodD(); +#else + int MethodD() { return 3; } // need def or vtbl[] is not generated +#endif +}; + +void Base::base() { } +int Derived::MethodCPP() { return 30; } +Derived::Derived() { } + + +Derived *cppfoo(Derived *d) +{ + assert(d->x == 4); + assert(d->y == 5); + assert(d->MethodD() == 3); + assert(d->MethodCPP() == 30); + + d = new Derived(); + d->x = 7; + d->y = 8; + assert(d->MethodD() == 3); + assert(d->MethodCPP() == 30); + return d; +} + +Interface *cppfooi(Interface *i) +{ + printf("i = %p\n", i); + assert(i->MethodD() == 3); + assert(i->MethodCPP() == 30); + + Derived *d = new Derived(); + printf("d = %p, i = %p\n", d, (Interface *)d); + return d; +} + +/******************************************/