diff --git a/dmd/declaration.d b/dmd/declaration.d index 40a3d14db6..af34c376b4 100644 --- a/dmd/declaration.d +++ b/dmd/declaration.d @@ -1143,7 +1143,7 @@ extern (C++) class VarDeclaration : Declaration bool onstack; version (IN_LLVM) { - bool onstackWithDtor; /// it is a class that was allocated on the stack and needs destruction + bool onstackWithMatchingDynType; /// and dynamic type is equivalent to static type } bool overlapped; /// if it is a field and has overlapping diff --git a/dmd/declaration.h b/dmd/declaration.h index 5f0b214339..7cceba2cf2 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -267,8 +267,8 @@ public: bool onstack() const; // it is a class that was allocated on the stack bool onstack(bool v); #if IN_LLVM - bool onstackWithDtor() const; // it is a class that was allocated on the stack and needs destruction - bool onstackWithDtor(bool v); + bool onstackWithMatchingDynType() const; // and dynamic type is equivalent to static type + bool onstackWithMatchingDynType(bool v); #endif bool overlapped() const; // if it is a field and has overlapping bool overlapped(bool v); diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 3c8e41dac8..91ce4c2aa4 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -1062,17 +1062,17 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym.onstack = true; version (IN_LLVM) { - bool hasDtor = false; - auto cd = (cast(TypeClass) ne.newtype).sym; - for (; cd; cd = cd.baseClass) + auto tcStatic = dsym.type.toBasetype().isTypeClass(); + auto tcDynamic = ne.newtype.toBasetype().isTypeClass(); + if (!tcDynamic) { - if (cd.dtor) - { - hasDtor = true; - break; - } + //printf(".: resolving %s\n", ne.newtype.toPrettyChars()); + ne.newtype = ne.newtype.typeSemantic(dsym.loc, sc); + tcDynamic = ne.newtype.toBasetype().isTypeClass(); + assert(tcDynamic); } - dsym.onstackWithDtor = hasDtor; + + dsym.onstackWithMatchingDynType = tcStatic.sym is tcDynamic.sym; } } } diff --git a/gen/classes.cpp b/gen/classes.cpp index 5fecad4ae9..00a1d594bd 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -187,9 +187,25 @@ void DtoFinalizeClass(const Loc &loc, LLValue *inst) { //////////////////////////////////////////////////////////////////////////////// -void DtoFinalizeScopeClass(const Loc &loc, DValue* dval, bool hasDtor) { - llvm::Value* inst = DtoRVal(dval); - if (!isOptimizationEnabled() || hasDtor) { +void DtoFinalizeScopeClass(const Loc &loc, DValue *dval, + bool dynTypeMatchesStaticType) { + llvm::Value *inst = DtoRVal(dval); + + if (!isOptimizationEnabled() || !dynTypeMatchesStaticType) { + DtoFinalizeClass(loc, inst); + return; + } + + bool hasDtor = false; + auto cd = dval->type->toBasetype()->isTypeClass()->sym; + for (; cd; cd = cd->baseClass) { + if (cd->dtor) { + hasDtor = true; + break; + } + } + + if (hasDtor) { DtoFinalizeClass(loc, inst); return; } @@ -199,9 +215,10 @@ void DtoFinalizeScopeClass(const Loc &loc, DValue* dval, bool hasDtor) { llvm::BasicBlock *ifbb = gIR->insertBB("if"); llvm::BasicBlock *endbb = gIR->insertBBAfter(ifbb, "endif"); - llvm::StructType *st = getIrAggr(static_cast(dval->type)->sym) - ->getLLStructType(); - const auto monitor = DtoLoad(st->getElementType(1), DtoGEP(st, inst, 0, 1), ".monitor"); + llvm::StructType *st = + getIrAggr(static_cast(dval->type)->sym)->getLLStructType(); + const auto monitor = + DtoLoad(st->getElementType(1), DtoGEP(st, inst, 0, 1), ".monitor"); const auto hasMonitor = gIR->ir->CreateICmp(llvm::CmpInst::ICMP_NE, monitor, getNullValue(monitor->getType()), ".hasMonitor"); diff --git a/gen/classes.h b/gen/classes.h index 6725556eaa..1408c86668 100644 --- a/gen/classes.h +++ b/gen/classes.h @@ -29,7 +29,8 @@ void DtoResolveClass(ClassDeclaration *cd); DValue *DtoNewClass(const Loc &loc, TypeClass *type, NewExp *newexp); void DtoInitClass(TypeClass *tc, llvm::Value *dst); void DtoFinalizeClass(const Loc &loc, llvm::Value *inst); -void DtoFinalizeScopeClass(const Loc &loc, DValue* dval, bool hasDtor); +void DtoFinalizeScopeClass(const Loc &loc, DValue *dval, + bool dynTypeMatchesStaticType); DValue *DtoCastClass(const Loc &loc, DValue *val, Type *to); DValue *DtoDynamicCastObject(const Loc &loc, DValue *val, Type *to); diff --git a/gen/toir.cpp b/gen/toir.cpp index 3d96730949..0d81ebe3e0 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1644,7 +1644,8 @@ public: } else if (auto ve = e->e1->isVarExp()) { if (auto vd = ve->var->isVarDeclaration()) { if (vd->onstack()) { - DtoFinalizeScopeClass(e->loc, dval, vd->onstackWithDtor()); + DtoFinalizeScopeClass(e->loc, dval, + vd->onstackWithMatchingDynType()); onstack = true; } } diff --git a/tests/codegen/gh2515.d b/tests/codegen/gh2515.d index 65a5d2f34f..925500121a 100644 --- a/tests/codegen/gh2515.d +++ b/tests/codegen/gh2515.d @@ -17,12 +17,6 @@ class WithDtor : Base ~this() {} } -class WithImplicitDtor : Base -{ - static struct S { int val; ~this() {} } - S s; -} - // CHECK: define{{.*}} void @{{.*}}_D6gh251516noDtor_noMonitorFZv void noDtor_noMonitor() { @@ -46,7 +40,18 @@ void noDtor_withMonitor() // CHECK: define{{.*}} void @{{.*}}_D6gh25158withDtorFZv void withDtor() { - scope Base b = new WithDtor(); + scope b = new WithDtor(); + b.foo(); + printf("%d\n", b.val); + // CHECK: _d_callfinalizer + // CHECK: ret void +} + +// CHECK: define{{.*}} void @{{.*}}_D6gh251517withInheritedDtorFZv +void withInheritedDtor() +{ + static class WithInheritedDtor : WithDtor {} + scope b = new WithInheritedDtor(); b.foo(); printf("%d\n", b.val); // CHECK: _d_callfinalizer @@ -56,7 +61,13 @@ void withDtor() // CHECK: define{{.*}} void @{{.*}}_D6gh251516withImplicitDtorFZv void withImplicitDtor() { - scope Base b = new WithImplicitDtor(); + static class WithImplicitDtor : Base + { + static struct S { int val; ~this() {} } + S s; + } + + scope b = new WithImplicitDtor(); b.foo(); printf("%d\n", b.val); // CHECK: _d_callfinalizer @@ -64,6 +75,30 @@ void withImplicitDtor() } +/* Test static vs. dynamic type mismatches. */ + +// CHECK: define{{.*}} void @{{.*}}_D6gh251529staticAndDynamicTypesMismatchFZv +void staticAndDynamicTypesMismatch() // not optimized +{ + static class NoDtor : Base {} + + scope Base b = new NoDtor(); + b.foo(); + printf("%d\n", b.val); + // CHECK: _d_callfinalizer + // CHECK: ret void +} + +// CHECK: define{{.*}} void @{{.*}}_D6gh251526typesMatchModuloQualifiersFZv +void typesMatchModuloQualifiers() // different qualifiers don't prevent optimization +{ + scope shared Base b = new Base(); + printf("%d\n", b.val); + // CHECK-NOT: _d_callfinalizer + // CHECK: ret void +} + + /* Test a C++ class as well, which as of 2.077 isn't implicitly delete()d. */ extern(C++) class CppClass