diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 0ccd016b9c2d..526faaaeccbe 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -4993,10 +4993,23 @@ private void lowerCastExp(CastExp cex, Scope* sc) ClassDeclaration cdto = tob.isClassHandle(); int offset; - if ((cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME) - || cdfrom.classKind == ClassKind.cpp || cdto.classKind == ClassKind.cpp) + if (cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME) + return; // codegen has to deal with pointer adjustment + + if (cdfrom.classKind != ClassKind.d || + (cdto.classKind != ClassKind.d && + !(cdto.classKind == ClassKind.cpp && cdto.isInterfaceDeclaration()))) + { + if (cdfrom.classKind == cdto.classKind) + return; // for non-D classes, generate a reinterpreting cast + + // conversion other than D -> C++ interface result in null + Expression lowerNull = new NullExp(cex.loc, cex.to); + cex.lowering = lowerNull .expressionSemantic(sc); return; + } + // cast D -> D / C++ interface calls _d_cast Identifier hook = Id._d_cast; if (!verifyHookExist(cex.loc, *sc, hook, "d_cast", Id.object)) return; diff --git a/compiler/test/runnable/casting.d b/compiler/test/runnable/casting.d index 1eb262c5c682..25f7a63e03fd 100644 --- a/compiler/test/runnable/casting.d +++ b/compiler/test/runnable/casting.d @@ -210,6 +210,42 @@ void test14218() } } +/***************************************************/ +// https://github.com/dlang/dmd/issues/23262 + +extern(C++) interface iface23262 +{ + int funCpp(); +} + +extern(C++) class cpp23262 +{ + int funCpp() { return 1; } +} + +class class23262 : Object, iface23262 +{ + extern(C++) int funCpp() { return 42; } +} + +void test23262() +{ + Object obj = new class23262; + auto cpp = cast(iface23262) obj; // ok for C++ interface + assert(cpp); + assert(cpp.funCpp() == 42); + + auto cpp2 = cast(cpp23262) obj; + assert(cpp2 is null); // impossible for C++ class + + auto d = cast(class23262) cpp; + assert(d is null); // no way back + + auto cppobj = new cpp23262; + auto d2 = cast(class23262) cppobj; + assert(d2 is null); // classes of different linkage never mix +} + /***************************************************/ int main() @@ -223,6 +259,7 @@ int main() test10842(); test11722(); test14218(); + test23262(); printf("Success\n"); return 0;