From 793efaf523640eb41f03851a8ea17d25ca2a64f6 Mon Sep 17 00:00:00 2001 From: Nicholas Wilson Date: Thu, 3 Oct 2024 18:37:26 +0800 Subject: [PATCH] Move `callScopeDtor` to `dsymbolsem.d`, make private reduce nesting --- compiler/src/dmd/declaration.d | 112 --------------------------------- compiler/src/dmd/dsymbolsem.d | 111 ++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 112 deletions(-) diff --git a/compiler/src/dmd/declaration.d b/compiler/src/dmd/declaration.d index e132c99808af..9ae92ad53dd7 100644 --- a/compiler/src/dmd/declaration.d +++ b/compiler/src/dmd/declaration.d @@ -1172,118 +1172,6 @@ extern (C++) class VarDeclaration : Declaration return edtor && !(storage_class & STC.nodtor); } - /****************************************** - * If a variable has a scope destructor call, return call for it. - * Otherwise, return NULL. - */ - extern (D) final Expression callScopeDtor(Scope* sc) - { - //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); - - // Destruction of STC.field's is handled by buildDtor() - if (storage_class & (STC.nodtor | STC.ref_ | STC.out_ | STC.field)) - { - return null; - } - - if (iscatchvar) - return null; // destructor is built by `void semantic(Catch c, Scope* sc)`, not here - - Expression e = null; - // Destructors for structs and arrays of structs - Type tv = type.baseElemOf(); - if (tv.ty == Tstruct) - { - StructDeclaration sd = (cast(TypeStruct)tv).sym; - if (!sd.dtor || sd.errors) - return null; - - const sz = type.size(); - assert(sz != SIZE_INVALID); - if (!sz) - return null; - - if (type.toBasetype().ty == Tstruct) - { - // v.__xdtor() - e = new VarExp(loc, this); - - /* This is a hack so we can call destructors on const/immutable objects. - * Need to add things like "const ~this()" and "immutable ~this()" to - * fix properly. - */ - e.type = e.type.mutableOf(); - - // Enable calling destructors on shared objects. - // The destructor is always a single, non-overloaded function, - // and must serve both shared and non-shared objects. - e.type = e.type.unSharedOf; - - e = new DotVarExp(loc, e, sd.dtor, false); - e = new CallExp(loc, e); - } - else - { - // __ArrayDtor(v[0 .. n]) - e = new VarExp(loc, this); - - const sdsz = sd.type.size(); - assert(sdsz != SIZE_INVALID && sdsz != 0); - const n = sz / sdsz; - SliceExp se = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t), - new IntegerExp(loc, n, Type.tsize_t)); - - // Prevent redundant bounds check - se.upperIsInBounds = true; - se.lowerIsLessThanUpper = true; - - // This is a hack so we can call destructors on const/immutable objects. - se.type = sd.type.arrayOf(); - - e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se); - } - return e; - } - // Destructors for classes - if (storage_class & (STC.auto_ | STC.scope_) && !(storage_class & STC.parameter)) - { - for (ClassDeclaration cd = type.isClassHandle(); cd; cd = cd.baseClass) - { - /* We can do better if there's a way with onstack - * classes to determine if there's no way the monitor - * could be set. - */ - //if (cd.isInterfaceDeclaration()) - // error("interface `%s` cannot be scope", cd.toChars()); - - if (onstack) // if any destructors - { - // delete'ing C++ classes crashes (and delete is deprecated anyway) - if (cd.classKind == ClassKind.cpp) - { - // Don't call non-existant dtor - if (!cd.dtor) - break; - - e = new VarExp(loc, this); - e.type = e.type.mutableOf().unSharedOf(); // Hack for mutable ctor on immutable instances - e = new DotVarExp(loc, e, cd.dtor, false); - e = new CallExp(loc, e); - break; - } - - // delete this; - Expression ec; - ec = new VarExp(loc, this); - e = new DeleteExp(loc, ec, true); - e.type = Type.tvoid; - break; - } - } - } - return e; - } - /******************************************* * If variable has a constant expression initializer, get it. * Otherwise, return null. diff --git a/compiler/src/dmd/dsymbolsem.d b/compiler/src/dmd/dsymbolsem.d index f193bb7c36fd..8db82c057ff4 100644 --- a/compiler/src/dmd/dsymbolsem.d +++ b/compiler/src/dmd/dsymbolsem.d @@ -7474,3 +7474,114 @@ bool isGNUABITag(Expression e) return false; return true; } + +/****************************************** + * If a variable has a scope destructor call, return call for it. + * Otherwise, return NULL. + */ +private Expression callScopeDtor(VarDeclaration vd, Scope* sc) +{ + //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); + + // Destruction of STC.field's is handled by buildDtor() + if (vd.storage_class & (STC.nodtor | STC.ref_ | STC.out_ | STC.field)) + { + return null; + } + + if (vd.iscatchvar) + return null; // destructor is built by `void semantic(Catch c, Scope* sc)`, not here + + Expression e = null; + // Destructors for structs and arrays of structs + Type tv = vd.type.baseElemOf(); + if (tv.ty == Tstruct) + { + StructDeclaration sd = (cast(TypeStruct)tv).sym; + if (!sd.dtor || sd.errors) + return null; + + const sz = vd.type.size(); + assert(sz != SIZE_INVALID); + if (!sz) + return null; + + if (vd.type.toBasetype().ty == Tstruct) + { + // v.__xdtor() + e = new VarExp(vd.loc, vd); + + /* This is a hack so we can call destructors on const/immutable objects. + * Need to add things like "const ~this()" and "immutable ~this()" to + * fix properly. + */ + e.type = e.type.mutableOf(); + + // Enable calling destructors on shared objects. + // The destructor is always a single, non-overloaded function, + // and must serve both shared and non-shared objects. + e.type = e.type.unSharedOf; + + e = new DotVarExp(vd.loc, e, sd.dtor, false); + e = new CallExp(vd.loc, e); + } + else + { + // __ArrayDtor(v[0 .. n]) + e = new VarExp(vd.loc, vd); + + const sdsz = sd.type.size(); + assert(sdsz != SIZE_INVALID && sdsz != 0); + const n = sz / sdsz; + SliceExp se = new SliceExp(vd.loc, e, new IntegerExp(vd.loc, 0, Type.tsize_t), + new IntegerExp(vd.loc, n, Type.tsize_t)); + + // Prevent redundant bounds check + se.upperIsInBounds = true; + se.lowerIsLessThanUpper = true; + + // This is a hack so we can call destructors on const/immutable objects. + se.type = sd.type.arrayOf(); + + e = new CallExp(vd.loc, new IdentifierExp(vd.loc, Id.__ArrayDtor), se); + } + return e; + } + // Destructors for classes + if (!(vd.storage_class & (STC.auto_ | STC.scope_) && !(vd.storage_class & STC.parameter))) + return null; + + for (ClassDeclaration cd = vd.type.isClassHandle(); cd; cd = cd.baseClass) + { + /* We can do better if there's a way with onstack + * classes to determine if there's no way the monitor + * could be set. + */ + //if (cd.isInterfaceDeclaration()) + // error("interface `%s` cannot be scope", cd.toChars()); + + if (!vd.onstack) // if any destructors + continue; + // delete'ing C++ classes crashes (and delete is deprecated anyway) + if (cd.classKind == ClassKind.cpp) + { + // Don't call non-existant dtor + if (!cd.dtor) + break; + + e = new VarExp(vd.loc, vd); + e.type = e.type.mutableOf().unSharedOf(); // Hack for mutable ctor on immutable instances + e = new DotVarExp(vd.loc, e, cd.dtor, false); + e = new CallExp(vd.loc, e); + break; + } + + // delete this; + Expression ec; + ec = new VarExp(vd.loc, vd); + e = new DeleteExp(vd.loc, ec, true); + e.type = Type.tvoid; + break; + } + return e; +}