From cdaeccd7d460697b2db9785f55e03eaabdb8b9de Mon Sep 17 00:00:00 2001 From: Rainer Date: Sun, 14 Jun 2026 10:01:53 +0200 Subject: [PATCH 1/2] fix #23262 - [REG v2.113.0-beta.1] ICE when trying to cast a class instance to a C++ interface no need to exclude C++ classes/interfaces from runtime cast target --- compiler/src/dmd/expressionsem.d | 2 +- compiler/test/runnable/casting.d | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 0ccd016b9c2d..7474b607b52e 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -4994,7 +4994,7 @@ private void lowerCastExp(CastExp cex, Scope* sc) int offset; if ((cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME) - || cdfrom.classKind == ClassKind.cpp || cdto.classKind == ClassKind.cpp) + || cdfrom.classKind == ClassKind.cpp) return; Identifier hook = Id._d_cast; diff --git a/compiler/test/runnable/casting.d b/compiler/test/runnable/casting.d index 1eb262c5c682..9934fe50fa38 100644 --- a/compiler/test/runnable/casting.d +++ b/compiler/test/runnable/casting.d @@ -210,6 +210,27 @@ void test14218() } } +/***************************************************/ +// https://github.com/dlang/dmd/issues/23262 + +extern(C++) interface iface23262 +{ + int funCpp(); +} + +class class23262 : Object, iface23262 +{ + extern(C++) int funCpp() { return 42; } +} + +void test23262() +{ + Object obj = new class23262; + auto cpp = cast(iface23262) obj; + assert(cpp); + assert(cpp.funCpp() == 42); +} + /***************************************************/ int main() @@ -223,6 +244,7 @@ int main() test10842(); test11722(); test14218(); + test23262(); printf("Success\n"); return 0; From 193a6edbdee27354b057f9349805a5c954eede30 Mon Sep 17 00:00:00 2001 From: Rainer Date: Thu, 18 Jun 2026 21:58:46 +0200 Subject: [PATCH 2/2] generate null lowering for mismatching linkage types --- compiler/src/dmd/expressionsem.d | 17 +++++++++++++++-- compiler/test/runnable/casting.d | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 7474b607b52e..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) + 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 9934fe50fa38..25f7a63e03fd 100644 --- a/compiler/test/runnable/casting.d +++ b/compiler/test/runnable/casting.d @@ -218,6 +218,11 @@ extern(C++) interface iface23262 int funCpp(); } +extern(C++) class cpp23262 +{ + int funCpp() { return 1; } +} + class class23262 : Object, iface23262 { extern(C++) int funCpp() { return 42; } @@ -226,9 +231,19 @@ class class23262 : Object, iface23262 void test23262() { Object obj = new class23262; - auto cpp = cast(iface23262) obj; + 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 } /***************************************************/