From 2b2aae19269f7d03c253c46525def26c9473b432 Mon Sep 17 00:00:00 2001 From: Albert24GG Date: Wed, 25 Jun 2025 17:54:55 +0300 Subject: [PATCH 1/7] Fix inlined cast lowering --- compiler/src/dmd/inline.d | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/src/dmd/inline.d b/compiler/src/dmd/inline.d index 47b94926eb24..c6b773e9656e 100644 --- a/compiler/src/dmd/inline.d +++ b/compiler/src/dmd/inline.d @@ -1289,6 +1289,14 @@ public: override void visit(UnaExp e) { + if (auto ce = e.isCastExp()) + { + if (ce.lowering !is null) + { + inlineScan(ce.lowering); + return; + } + } inlineScan(e.e1); } From 4580a51b340537966575a99233b6d3a4cc8e2e66 Mon Sep 17 00:00:00 2001 From: Albert24GG Date: Mon, 23 Jun 2025 13:51:01 +0300 Subject: [PATCH 2/7] Templatize `_d_interface_cast` --- compiler/src/dmd/backend/drtlsym.d | 1 - compiler/src/dmd/backend/rtlsym.d | 1 - compiler/src/dmd/e2ir.d | 10 +---- compiler/src/dmd/expressionsem.d | 52 +++++++++++----------- druntime/src/core/internal/cast_.d | 70 +++++++++++++++++++++++++++++- druntime/src/rt/cast_.d | 25 ----------- 6 files changed, 97 insertions(+), 62 deletions(-) diff --git a/compiler/src/dmd/backend/drtlsym.d b/compiler/src/dmd/backend/drtlsym.d index c89d25ece34e..2aec454f1e43 100644 --- a/compiler/src/dmd/backend/drtlsym.d +++ b/compiler/src/dmd/backend/drtlsym.d @@ -109,7 +109,6 @@ Symbol* getRtlsym(RTLSYM i) @trusted case RTLSYM.CALLFINALIZER: symbolz(ps,FL.func,FREGSAVED,"_d_callfinalizer", 0, t); break; case RTLSYM.CALLINTERFACEFINALIZER: symbolz(ps,FL.func,FREGSAVED,"_d_callinterfacefinalizer", 0, t); break; case RTLSYM.ALLOCMEMORY: symbolz(ps,FL.func,FREGSAVED,"_d_allocmemory", 0, t); break; - case RTLSYM.INTERFACE_CAST: symbolz(ps,FL.func,FREGSAVED,"_d_interface_cast", 0, t); break; case RTLSYM.ARRAYCATT: symbolz(ps,FL.func,FREGSAVED,"_d_arraycatT", 0, t); break; case RTLSYM.ARRAYAPPENDCD: symbolz(ps,FL.func,FREGSAVED,"_d_arrayappendcd", 0, t); break; case RTLSYM.ARRAYAPPENDWD: symbolz(ps,FL.func,FREGSAVED,"_d_arrayappendwd", 0, t); break; diff --git a/compiler/src/dmd/backend/rtlsym.d b/compiler/src/dmd/backend/rtlsym.d index 584ac2de0d34..79b2569efc41 100644 --- a/compiler/src/dmd/backend/rtlsym.d +++ b/compiler/src/dmd/backend/rtlsym.d @@ -54,7 +54,6 @@ enum RTLSYM CALLFINALIZER, CALLINTERFACEFINALIZER, ALLOCMEMORY, - INTERFACE_CAST, ARRAYCATT, ARRAYAPPENDCD, ARRAYAPPENDWD, diff --git a/compiler/src/dmd/e2ir.d b/compiler/src/dmd/e2ir.d index 8f15c1a7972d..c0850af326f5 100644 --- a/compiler/src/dmd/e2ir.d +++ b/compiler/src/dmd/e2ir.d @@ -4781,15 +4781,7 @@ elem* toElemCast(CastExp ce, elem* e, bool isLvalue, ref IRState irs) } else { - if (cdfrom.isInterfaceDeclaration()) - { - elem* ep = el_param(el_ptr(toExtSymbol(cdto)), e); - e = el_bin(OPcall, TYnptr, el_var(getRtlsym(RTLSYM.INTERFACE_CAST)), ep); - } - else - { - assert(ce.lowering, "This case should have been rewritten to `_d_cast` in the semantic phase"); - } + assert(ce.lowering, "This case should have been rewritten to `_d_cast` in the semantic phase"); } return Lret(ce, e); } diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index c8fadf852d4f..f78104255f42 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -6948,7 +6948,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (tf.next.isBaseOf(t, &offset) && offset) { exp.type = tf.next; - result = Expression.combine(argprefix, exp.castTo(sc, t)); + auto casted_exp = exp.castTo(sc, t); + if (casted_exp.isCastExp()) + { + casted_exp.type = null; + casted_exp = casted_exp.expressionSemantic(sc); + } + result = Expression.combine(argprefix, casted_exp); return; } } @@ -9389,35 +9395,31 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!(cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME) && cdfrom.classKind != ClassKind.cpp) { - if (!cdfrom.isInterfaceDeclaration()) - { + Identifier hook = Id._d_cast; + if (!verifyHookExist(cex.loc, *sc, hook, "d_cast", Id.object)) + goto LskipCastLowering; - Identifier hook = Id._d_cast; - if (!verifyHookExist(cex.loc, *sc, hook, "d_cast", Id.object)) - goto LskipCastLowering; + // Lower to .object._d_cast!(To)(exp.e1) + Expression lowering = new IdentifierExp(cex.loc, Id.empty); + lowering = new DotIdExp(cex.loc, lowering, Id.object); - // Lower to .object._d_cast!(To)(exp.e1) - Expression lowering = new IdentifierExp(cex.loc, Id.empty); - lowering = new DotIdExp(cex.loc, lowering, Id.object); - - auto tiargs = new Objects(); - // Unqualify the type being casted to, avoiding multiple instantiations - auto unqual_tob = tob.unqualify(MODFlags.wild | MODFlags.const_ | - MODFlags.immutable_ | MODFlags.shared_); - tiargs.push(unqual_tob); - lowering = new DotTemplateInstanceExp(cex.loc, lowering, hook, tiargs); + auto tiargs = new Objects(); + // Unqualify the type being casted to, avoiding multiple instantiations + auto unqual_tob = tob.unqualify(MODFlags.wild | MODFlags.const_ | + MODFlags.immutable_ | MODFlags.shared_); + tiargs.push(unqual_tob); + lowering = new DotTemplateInstanceExp(cex.loc, lowering, hook, tiargs); - auto arguments = new Expressions(); - // Unqualify the type being casted from to avoid multiple instantiations - auto unqual_t1b = t1b.unqualify(MODFlags.wild | MODFlags.const_ | - MODFlags.immutable_ | MODFlags.shared_); - cex.e1.type = unqual_t1b; - arguments.push(cex.e1); + auto arguments = new Expressions(); + // Unqualify the type being casted from to avoid multiple instantiations + auto unqual_t1b = t1b.unqualify(MODFlags.wild | MODFlags.const_ | + MODFlags.immutable_ | MODFlags.shared_); + cex.e1.type = unqual_t1b; + arguments.push(cex.e1); - lowering = new CallExp(cex.loc, lowering, arguments); + lowering = new CallExp(cex.loc, lowering, arguments); - cex.lowering = lowering.expressionSemantic(sc); - } + cex.lowering = lowering.expressionSemantic(sc); } } diff --git a/druntime/src/core/internal/cast_.d b/druntime/src/core/internal/cast_.d index da928344e531..c4de76ea6266 100644 --- a/druntime/src/core/internal/cast_.d +++ b/druntime/src/core/internal/cast_.d @@ -101,6 +101,27 @@ private void* _d_class_cast(To)(const return scope Object o) return _d_class_cast_impl(o, typeid(To)); } +/************************************* + * Attempts to cast interface Object o to class type `To`. + * Returns o if successful, null if not. + */ +private void* _d_interface_cast(To)(void* p) @trusted +{ + if (!p) + return null; + + Interface* pi = **cast(Interface***) p; + + Object o2 = cast(Object)(p - pi.offset); + void* res = null; + size_t offset = 0; + if (o2 && _d_isbaseof2!To(typeid(o2), offset)) + { + res = cast(void*) o2 + offset; + } + return res; +} + /** * Hook that detects the type of cast performed and calls the appropriate function. * Params: @@ -149,7 +170,21 @@ void* _d_cast(To, From)(From o) @trusted return null; } - return null; + static if (is(From == interface)) + { + static if (is(From == To)) + { + return cast(void*)o; + } + else + { + return _d_interface_cast!To(cast(void*)o); + } + } + else + { + return null; + } } private bool _d_isbaseof2(To)(scope ClassInfo oc, scope ref size_t offset) @@ -241,3 +276,36 @@ private bool _d_isbaseof2(To)(scope ClassInfo oc, scope ref size_t offset) assert(_d_cast!D(a) is null); // A(a) to D assert(_d_class_cast!D(a) is null); } + +@safe pure unittest +{ + interface I1 {} + interface I2 {} + interface I3 {} + class A {} + class B : A, I1, I2 {} + class C : B, I3 {} + + I1 bi = new B(); + assert(_d_cast!I2(bi) !is null); // I1(b) to I2 + assert(_d_interface_cast!I2(cast(void*)bi) !is null); + + assert(_d_cast!A(bi) !is null); // I1(b) to A + assert(_d_interface_cast!A(cast(void*)bi) !is null); + + assert(_d_cast!B(bi) !is null); // I1(b) to B + assert(_d_interface_cast!B(cast(void*)bi) !is null); + + assert(_d_cast!I3(bi) is null); // I1(b) to I3 + assert(_d_interface_cast!I3(cast(void*)bi) is null); + + assert(_d_cast!C(bi) is null); // I1(b) to C + assert(_d_interface_cast!C(cast(void*)bi) is null); + + assert(_d_cast!I1(bi) !is null); // I1(b) to I1 + assert(_d_interface_cast!I1(cast(void*)bi) !is null); + + I3 ci = new C(); + assert(_d_cast!I1(ci) !is null); // I3(c) to I1 + assert(_d_interface_cast!I1(cast(void*)ci) !is null); +} diff --git a/druntime/src/rt/cast_.d b/druntime/src/rt/cast_.d index dc2b78c7f846..19e9f7dae652 100644 --- a/druntime/src/rt/cast_.d +++ b/druntime/src/rt/cast_.d @@ -50,31 +50,6 @@ Object _d_toObject(return scope void* p) return o; } -/************************************* - * Attempts to cast interface Object o to class c. - * Returns o if successful, null if not. - */ -void* _d_interface_cast(void* p, ClassInfo c) -{ - debug(cast_) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, cast(int) c.name.length, c.name.ptr); - if (!p) - return null; - - Interface* pi = **cast(Interface***) p; - - debug(cast_) printf("\tpi.offset = %zd\n", pi.offset); - Object o2 = cast(Object)(p - pi.offset); - void* res = null; - size_t offset = 0; - if (o2 && _d_isbaseof2(typeid(o2), c, offset)) - { - debug(cast_) printf("\toffset = %zd\n", offset); - res = cast(void*) o2 + offset; - } - debug(cast_) printf("\tresult = %p\n", res); - return res; -} - int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe { if (areClassInfosEqual(oc, c)) From 33c257ca69b5acf475bbfe9a4da1137fac0777e8 Mon Sep 17 00:00:00 2001 From: Albert24GG Date: Tue, 24 Jun 2025 14:33:26 +0300 Subject: [PATCH 3/7] Move `CastExp` lowering logic in a separate function --- compiler/src/dmd/expressionsem.d | 109 ++++++++++++++++--------------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index f78104255f42..4be6b97ee7ad 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -3807,6 +3807,58 @@ Package resolveIsPackage(Dsymbol sym) return pkg; } +/** + * Performs the lowering of a CastExp to a call to `.object._d_cast`, + * populating the `lowering` field of the CastExp. + * This is only done for casts between classes/interfaces. + * + * Params: + * cex = the CastExp to lower + * sc = the current scope + */ +private void lowerCastExp(CastExp cex, Scope* sc) +{ + Type t1b = cex.e1.type.toBasetype(); + Type tob = cex.to.toBasetype(); + + if (t1b.ty == Tclass && tob.ty == Tclass) + { + ClassDeclaration cdfrom = t1b.isClassHandle(); + ClassDeclaration cdto = tob.isClassHandle(); + + int offset; + if (!(cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME) + && cdfrom.classKind != ClassKind.cpp) + { + Identifier hook = Id._d_cast; + if (!verifyHookExist(cex.loc, *sc, hook, "d_cast", Id.object)) + return; + + // Lower to .object._d_cast!(To)(exp.e1) + Expression lowering = new IdentifierExp(cex.loc, Id.empty); + lowering = new DotIdExp(cex.loc, lowering, Id.object); + + auto tiargs = new Objects(); + // Unqualify the type being casted to, avoiding multiple instantiations + auto unqual_tob = tob.unqualify(MODFlags.wild | MODFlags.const_ | + MODFlags.immutable_ | MODFlags.shared_); + tiargs.push(unqual_tob); + lowering = new DotTemplateInstanceExp(cex.loc, lowering, hook, tiargs); + + auto arguments = new Expressions(); + // Unqualify the type being casted from to avoid multiple instantiations + auto unqual_t1b = t1b.unqualify(MODFlags.wild | MODFlags.const_ | + MODFlags.immutable_ | MODFlags.shared_); + Expression e1c = cex.e1.copy(); + e1c.type = unqual_t1b; + arguments.push(e1c); + + lowering = new CallExp(cex.loc, lowering, arguments); + + cex.lowering = lowering.expressionSemantic(sc); + } + } +} private extern (C++) final class ExpressionSemanticVisitor : Visitor { @@ -6949,10 +7001,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { exp.type = tf.next; auto casted_exp = exp.castTo(sc, t); - if (casted_exp.isCastExp()) + if (auto cex = casted_exp.isCastExp()) { - casted_exp.type = null; - casted_exp = casted_exp.expressionSemantic(sc); + lowerCastExp(cex, sc); } result = Expression.combine(argprefix, casted_exp); return; @@ -9372,59 +9423,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - // If the cast is from an alias this, we need to unalias it - if (t1b.ty == Tstruct) + if (auto cex = ex.isCastExp()) { - if (auto t1b_unalias = t1b.aliasthisOf()) - { - t1b = t1b_unalias; - } - } - - if (t1b.ty == Tclass && tob.ty == Tclass) - { - CastExp cex = ex.isCastExp(); - - if (cex is null) - goto LskipCastLowering; - - ClassDeclaration cdfrom = t1b.isClassHandle(); - ClassDeclaration cdto = tob.isClassHandle(); - - int offset; - if (!(cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME) - && cdfrom.classKind != ClassKind.cpp) - { - Identifier hook = Id._d_cast; - if (!verifyHookExist(cex.loc, *sc, hook, "d_cast", Id.object)) - goto LskipCastLowering; - - // Lower to .object._d_cast!(To)(exp.e1) - Expression lowering = new IdentifierExp(cex.loc, Id.empty); - lowering = new DotIdExp(cex.loc, lowering, Id.object); - - auto tiargs = new Objects(); - // Unqualify the type being casted to, avoiding multiple instantiations - auto unqual_tob = tob.unqualify(MODFlags.wild | MODFlags.const_ | - MODFlags.immutable_ | MODFlags.shared_); - tiargs.push(unqual_tob); - lowering = new DotTemplateInstanceExp(cex.loc, lowering, hook, tiargs); - - auto arguments = new Expressions(); - // Unqualify the type being casted from to avoid multiple instantiations - auto unqual_t1b = t1b.unqualify(MODFlags.wild | MODFlags.const_ | - MODFlags.immutable_ | MODFlags.shared_); - cex.e1.type = unqual_t1b; - arguments.push(cex.e1); - - lowering = new CallExp(cex.loc, lowering, arguments); - - cex.lowering = lowering.expressionSemantic(sc); - } + lowerCastExp(cex, sc); } - LskipCastLowering: - result = ex; } From 9ec2c0e83a3d0bd7df5034045d8cadddd690b2ba Mon Sep 17 00:00:00 2001 From: Albert24GG Date: Sun, 29 Jun 2025 22:44:35 +0300 Subject: [PATCH 4/7] Remove redundant branch --- compiler/src/dmd/inline.d | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compiler/src/dmd/inline.d b/compiler/src/dmd/inline.d index c6b773e9656e..47b94926eb24 100644 --- a/compiler/src/dmd/inline.d +++ b/compiler/src/dmd/inline.d @@ -1289,14 +1289,6 @@ public: override void visit(UnaExp e) { - if (auto ce = e.isCastExp()) - { - if (ce.lowering !is null) - { - inlineScan(ce.lowering); - return; - } - } inlineScan(e.e1); } From 2ece573abda086a8061f5883b2d88ca46a709fa7 Mon Sep 17 00:00:00 2001 From: Albert24GG Date: Mon, 30 Jun 2025 14:39:01 +0300 Subject: [PATCH 5/7] Remove `rt/cast_.d` --- druntime/mak/SRCS | 1 - druntime/src/object.d | 53 +++++++++++++++++++++++++- druntime/src/rt/cast_.d | 84 ----------------------------------------- 3 files changed, 51 insertions(+), 87 deletions(-) delete mode 100644 druntime/src/rt/cast_.d diff --git a/druntime/mak/SRCS b/druntime/mak/SRCS index 065c6d720799..b9d3bdc738cc 100644 --- a/druntime/mak/SRCS +++ b/druntime/mak/SRCS @@ -565,7 +565,6 @@ SRCS=\ src\rt\adi.d \ src\rt\alloca.d \ src\rt\arraycat.d \ - src\rt\cast_.d \ src\rt\cmath2.d \ src\rt\config.d \ src\rt\cover.d \ diff --git a/druntime/src/object.d b/druntime/src/object.d index fb3fe86b56b5..b4dc2f720495 100644 --- a/druntime/src/object.d +++ b/druntime/src/object.d @@ -1572,8 +1572,57 @@ class TypeInfo_Delegate : TypeInfo } private extern (C) Object _d_newclass(const TypeInfo_Class ci); -private extern (C) int _d_isbaseof(scope TypeInfo_Class child, - scope const TypeInfo_Class parent) @nogc nothrow pure @safe; // rt.cast_ + +extern(C) int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @nogc nothrow pure @safe +{ + import core.internal.cast_ : areClassInfosEqual; + + if (areClassInfosEqual(oc, c)) + return true; + + do + { + if (oc.base && areClassInfosEqual(oc.base, c)) + return true; + + // Bugzilla 2013: Use depth-first search to calculate offset + // from the derived (oc) to the base (c). + foreach (iface; oc.interfaces) + { + if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof(iface.classinfo, c)) + return true; + } + + oc = oc.base; + } while (oc); + + return false; +} + +/****************************************** + * Given a pointer: + * If it is an Object, return that Object. + * If it is an interface, return the Object implementing the interface. + * If it is null, return null. + * Else, undefined crash + */ +extern(C) Object _d_toObject(return scope void* p) @nogc nothrow pure @trusted +{ + if (!p) + return null; + + Object o = cast(Object) p; + Interface* pi = **cast(Interface***) p; + + /* Interface.offset lines up with ClassInfo.name.ptr, + * so we rely on pointers never being less than 64K, + * and Objects never being greater. + */ + if (pi.offset < 0x10000) + return cast(Object)(p - pi.offset); + + return o; +} /** * Runtime type information about a class. diff --git a/druntime/src/rt/cast_.d b/druntime/src/rt/cast_.d deleted file mode 100644 index 19e9f7dae652..000000000000 --- a/druntime/src/rt/cast_.d +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Implementation of array assignment support routines. - * - * Copyright: Copyright Digital Mars 2004 - 2010. - * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). - * Authors: Walter Bright, Sean Kelly - * Source: $(DRUNTIMESRC rt/_cast_.d) - */ - -/* Copyright Digital Mars 2004 - 2010. - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE or copy at - * http://www.boost.org/LICENSE_1_0.txt) - */ -module rt.cast_; - -debug(cast_) import core.stdc.stdio : printf; -import core.internal.cast_ : areClassInfosEqual; - -extern (C): -@nogc: -nothrow: -pure: - -/****************************************** - * Given a pointer: - * If it is an Object, return that Object. - * If it is an interface, return the Object implementing the interface. - * If it is null, return null. - * Else, undefined crash - */ -Object _d_toObject(return scope void* p) -{ - if (!p) - return null; - - Object o = cast(Object) p; - ClassInfo oc = typeid(o); - Interface* pi = **cast(Interface***) p; - - /* Interface.offset lines up with ClassInfo.name.ptr, - * so we rely on pointers never being less than 64K, - * and Objects never being greater. - */ - if (pi.offset < 0x10000) - { - debug(cast_) printf("\tpi.offset = %zd\n", pi.offset); - return cast(Object)(p - pi.offset); - } - return o; -} - -int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe -{ - if (areClassInfosEqual(oc, c)) - return true; - - do - { - if (oc.base && areClassInfosEqual(oc.base, c)) - return true; - - // Bugzilla 2013: Use depth-first search to calculate offset - // from the derived (oc) to the base (c). - foreach (iface; oc.interfaces) - { - if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof2(iface.classinfo, c, offset)) - { - offset += iface.offset; - return true; - } - } - - oc = oc.base; - } while (oc); - - return false; -} - -int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @safe -{ - size_t offset = 0; - return _d_isbaseof2(oc, c, offset); -} From a6a25a83d13738bbed4a502b86cb177d905d9b1c Mon Sep 17 00:00:00 2001 From: Albert24GG Date: Fri, 4 Jul 2025 11:47:30 +0300 Subject: [PATCH 6/7] Remove `rt_cast_` entry from `mak/DOCS` --- druntime/mak/DOCS | 1 - 1 file changed, 1 deletion(-) diff --git a/druntime/mak/DOCS b/druntime/mak/DOCS index 574a18b19c82..d61d53323b12 100644 --- a/druntime/mak/DOCS +++ b/druntime/mak/DOCS @@ -542,7 +542,6 @@ DOCS=\ $(DOCDIR)\rt_adi.html \ $(DOCDIR)\rt_alloca.html \ $(DOCDIR)\rt_arraycat.html \ - $(DOCDIR)\rt_cast_.html \ $(DOCDIR)\rt_config.html \ $(DOCDIR)\rt_deh.html \ $(DOCDIR)\rt_deh_win32.html \ From 675692d0538457f2bc1c1a21d05be8f6965bee44 Mon Sep 17 00:00:00 2001 From: Albert24GG Date: Fri, 4 Jul 2025 14:33:56 +0300 Subject: [PATCH 7/7] refactor: Rewrite if conditions to reduce code indentation --- compiler/src/dmd/expressionsem.d | 62 ++++++++++++++++---------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 4be6b97ee7ad..6f9ac8674622 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -3821,43 +3821,43 @@ private void lowerCastExp(CastExp cex, Scope* sc) Type t1b = cex.e1.type.toBasetype(); Type tob = cex.to.toBasetype(); - if (t1b.ty == Tclass && tob.ty == Tclass) - { - ClassDeclaration cdfrom = t1b.isClassHandle(); - ClassDeclaration cdto = tob.isClassHandle(); + if (t1b.ty != Tclass || tob.ty != Tclass) + return; - int offset; - if (!(cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME) - && cdfrom.classKind != ClassKind.cpp) - { - Identifier hook = Id._d_cast; - if (!verifyHookExist(cex.loc, *sc, hook, "d_cast", Id.object)) - return; + ClassDeclaration cdfrom = t1b.isClassHandle(); + ClassDeclaration cdto = tob.isClassHandle(); - // Lower to .object._d_cast!(To)(exp.e1) - Expression lowering = new IdentifierExp(cex.loc, Id.empty); - lowering = new DotIdExp(cex.loc, lowering, Id.object); + int offset; + if ((cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME) + || cdfrom.classKind == ClassKind.cpp) + return; - auto tiargs = new Objects(); - // Unqualify the type being casted to, avoiding multiple instantiations - auto unqual_tob = tob.unqualify(MODFlags.wild | MODFlags.const_ | - MODFlags.immutable_ | MODFlags.shared_); - tiargs.push(unqual_tob); - lowering = new DotTemplateInstanceExp(cex.loc, lowering, hook, tiargs); + Identifier hook = Id._d_cast; + if (!verifyHookExist(cex.loc, *sc, hook, "d_cast", Id.object)) + return; - auto arguments = new Expressions(); - // Unqualify the type being casted from to avoid multiple instantiations - auto unqual_t1b = t1b.unqualify(MODFlags.wild | MODFlags.const_ | - MODFlags.immutable_ | MODFlags.shared_); - Expression e1c = cex.e1.copy(); - e1c.type = unqual_t1b; - arguments.push(e1c); + // Lower to .object._d_cast!(To)(exp.e1) + Expression lowering = new IdentifierExp(cex.loc, Id.empty); + lowering = new DotIdExp(cex.loc, lowering, Id.object); - lowering = new CallExp(cex.loc, lowering, arguments); + auto tiargs = new Objects(); + // Unqualify the type being casted to, avoiding multiple instantiations + auto unqual_tob = tob.unqualify(MODFlags.wild | MODFlags.const_ | + MODFlags.immutable_ | MODFlags.shared_); + tiargs.push(unqual_tob); + lowering = new DotTemplateInstanceExp(cex.loc, lowering, hook, tiargs); - cex.lowering = lowering.expressionSemantic(sc); - } - } + auto arguments = new Expressions(); + // Unqualify the type being casted from to avoid multiple instantiations + auto unqual_t1b = t1b.unqualify(MODFlags.wild | MODFlags.const_ | + MODFlags.immutable_ | MODFlags.shared_); + Expression e1c = cex.e1.copy(); + e1c.type = unqual_t1b; + arguments.push(e1c); + + lowering = new CallExp(cex.loc, lowering, arguments); + + cex.lowering = lowering.expressionSemantic(sc); } private extern (C++) final class ExpressionSemanticVisitor : Visitor