diff --git a/src/ddmd/aggregate.d b/src/ddmd/aggregate.d index 00321de5721f..a134b7181c65 100644 --- a/src/ddmd/aggregate.d +++ b/src/ddmd/aggregate.d @@ -97,6 +97,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol FuncDeclarations dtors; // Array of destructors FuncDeclaration dtor; // aggregate destructor + FuncDeclaration fieldDtor; // aggregate destructor for just the fields Expression getRTInfo; // pointer to GC info generated by object.RTInfo(this) diff --git a/src/ddmd/aggregate.h b/src/ddmd/aggregate.h index 324597370fd6..024c23b6be45 100644 --- a/src/ddmd/aggregate.h +++ b/src/ddmd/aggregate.h @@ -115,6 +115,7 @@ class AggregateDeclaration : public ScopeDsymbol FuncDeclarations dtors; // Array of destructors FuncDeclaration *dtor; // aggregate destructor + FuncDeclaration *fieldDtor; // aggregate destructor for just the fields Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this) diff --git a/src/ddmd/clone.d b/src/ddmd/clone.d index 0421d5a602e0..9b22142bf33c 100644 --- a/src/ddmd/clone.d +++ b/src/ddmd/clone.d @@ -1081,6 +1081,7 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) ad.dtors.shift(dd); ad.members.push(dd); dd.semantic(sc); + ad.fieldDtor = dd; } FuncDeclaration xdtor = null; diff --git a/src/ddmd/func.d b/src/ddmd/func.d index c2ca44a4a13b..ebe63efe0087 100644 --- a/src/ddmd/func.d +++ b/src/ddmd/func.d @@ -1093,7 +1093,7 @@ extern (C++) class FuncDeclaration : Declaration } // Do the semantic analysis on the internals of the function. - override final void semantic3(Scope* sc) + override void semantic3(Scope* sc) { VarDeclaration _arguments = null; @@ -4678,6 +4678,35 @@ extern (C++) final class CtorDeclaration : FuncDeclaration } } + override final void semantic3(Scope* sc) + { + if (semanticRun >= PASSsemantic3) + return; + + /* If any of the fields of the struct have a destructor, add + * scope (failure) { this.fieldDtor(); } + * as the first statement. It is not necessary to add it after + * each initialization of a field, because destruction of .init constructed + * structs should be benign. + */ + AggregateDeclaration ad = toParent2().isAggregateDeclaration(); + if (ad && ad.fieldDtor) + { + /* Generate: + * scope (failure) { this.fieldDtor(); } + */ + Expression e = new ThisExp(loc); + e.type = ad.type.mutableOf(); + e = new DotVarExp(loc, e, ad.fieldDtor, false); + e = new CallExp(loc, e); + auto sexp = new ExpStatement(loc, e); + auto s = new OnScopeStatement(loc, TOKon_scope_failure, sexp); + + fbody = new CompoundStatement(loc, s, fbody); + } + FuncDeclaration.semantic3(sc); + } + override const(char)* kind() const { return "constructor"; diff --git a/test/runnable/sdtor.d b/test/runnable/sdtor.d index e073c5bbb745..e5ebdc6b3757 100644 --- a/test/runnable/sdtor.d +++ b/test/runnable/sdtor.d @@ -4195,6 +4195,38 @@ int test14860() } static assert(test14860()); +/**********************************/ +// https://issues.dlang.org/show_bug.cgi?id=14246 + +struct A14246 { + int a = 3; + static string s; + this( int var ) { printf("A()\n"); a += var; s ~= "a"; } + + ~this() { printf("~A()\n"); s ~= "b"; } +} + +struct B14246 { + int i; + A14246 a; + + this( int var ) { + A14246.s ~= "c"; + a = A14246(var+1); + throw new Exception("An exception"); + } +} + +void test14246() { + try { + auto b = B14246(2); + } catch( Exception ex ) { + printf("Caught ex\n"); + A14246.s ~= "d"; + } + assert(A14246.s == "cabd"); +} + /**********************************/ // 14696 @@ -4577,6 +4609,7 @@ int main() test14815(); test16197(); test14860(); + test14246(); test14696(); test14838(); test63();