diff --git a/src/dmd/clone.d b/src/dmd/clone.d index e1a53d72061e..9f6fd26f9fb3 100644 --- a/src/dmd/clone.d +++ b/src/dmd/clone.d @@ -773,6 +773,7 @@ extern (C++) FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc) * all the members. * Note the close similarity with AggregateDeclaration::buildDtor(), * and the ordering changes (runs forward instead of backwards). + * buildInv() should be run first. */ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) { @@ -1099,6 +1100,12 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) switch (ad.dtors.dim) { case 0: + /* If running invariant, need a destructor to hang it on, + * but only do for root modules, as ones in the library may not + * have been compiled with useInvariants + */ + if (global.params.useInvariants && ad.inv && sc._module.isRoot()) + goto default; break; case 1: diff --git a/src/dmd/dsymbolsem.d b/src/dmd/dsymbolsem.d index 2f1b214650fa..8b3cec697964 100644 --- a/src/dmd/dsymbolsem.d +++ b/src/dmd/dsymbolsem.d @@ -3878,6 +3878,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor */ sd.aggNew = cast(NewDeclaration)sd.search(Loc(), Id.classNew); sd.aggDelete = cast(DeleteDeclaration)sd.search(Loc(), Id.classDelete); + sd.inv = buildInv(sd, sc2); // Look for the constructor sd.ctor = sd.searchCtor(); @@ -3895,8 +3896,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sd.xhash = buildXtoHash(sd, sc2); } - sd.inv = buildInv(sd, sc2); - Module.dprogress++; sd.semanticRun = PASS.semanticdone; //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); @@ -4435,6 +4434,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Can be in base class cldec.aggNew = cast(NewDeclaration)cldec.search(Loc(), Id.classNew); cldec.aggDelete = cast(DeleteDeclaration)cldec.search(Loc(), Id.classDelete); + cldec.inv = buildInv(cldec, sc2); // Look for the constructor cldec.ctor = cldec.searchCtor(); @@ -4485,6 +4485,29 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } + version (none) // Controversial - see Bugzilla 519 + { + /* If class has no constructor, but does have an invariant, create a default constructor merely + * as a place where the invariant call will be added. + */ + if (!ctor && global.params.useInvariants && inv && !isCPPclass()) + { + auto tf = new TypeFunction(null, null, 0, LINKd, inv.storage_class); + auto btf = cast(TypeFunction)inv.type; + tf.purity = btf.purity; + tf.isnothrow = btf.isnothrow; + tf.isnogc = btf.isnogc; + tf.trust = btf.trust; + auto ctor = new CtorDeclaration(loc, Loc(), 0, tf); + ctor.fbody = new CompoundStatement(Loc(), new Statements()); + members.push(ctor); + ctor.addMember(sc, this, 1); + ctor.semantic(sc2); + this.ctor = ctor; + defaultCtor = ctor; + } + } + cldec.dtor = buildDtor(cldec, sc2); if (auto f = hasIdentityOpAssign(cldec, sc2)) @@ -4493,8 +4516,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor cldec.error(f.loc, "identity assignment operator overload is illegal"); } - cldec.inv = buildInv(cldec, sc2); - Module.dprogress++; cldec.semanticRun = PASS.semanticdone; //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); diff --git a/src/dmd/e2ir.d b/src/dmd/e2ir.d index c34945169f48..60b8e09e2de0 100644 --- a/src/dmd/e2ir.d +++ b/src/dmd/e2ir.d @@ -5678,6 +5678,18 @@ private elem *toElemStructLit(StructLiteralExp sle, IRState *irs, TOK op, Symbol e = el_combine(e, e1); } + if (global.params.useInvariants && sle.sd.inv) + { + /* Should only call invariant if this is not a default initialization of the struct. + */ + if (dim) + { + FuncDeclaration inv = sle.sd.inv; + elem *einv = callfunc(sle.loc, irs, 1, inv.type.nextOf(), el_ptr(stmp), sle.sd.type.pointerTo(), inv, inv.type, null, null); + e = el_combine(e, einv); + } + } + elem *ev = el_var(stmp); ev.ET = Type_toCtype(sle.sd.type); e = el_combine(e, ev); diff --git a/test/runnable/testdstress.d b/test/runnable/testdstress.d index ee36d345b1d8..f6160116409b 100644 --- a/test/runnable/testdstress.d +++ b/test/runnable/testdstress.d @@ -809,10 +809,12 @@ class Parent40{ invariant() { - assert(!checked40); + if (!checked40) + { checked40=true; // even number assert((x&1u)==0); + } } } diff --git a/test/runnable/testinvariant.d b/test/runnable/testinvariant.d index 93d66efd21ae..0d36e683dc94 100644 --- a/test/runnable/testinvariant.d +++ b/test/runnable/testinvariant.d @@ -25,6 +25,88 @@ int testinvariant() return 0; } +/***************************************************/ +// 519 + +class C519 +{ + invariant + { + printf("C519.invariant\n"); + ++x; + } + __gshared int x; +} + +struct S519 +{ + invariant() + { + printf("S519.invariant\n"); + ++x; + } + __gshared int x; +} + +struct S519c +{ + invariant() + { + printf("S519c.invariant\n"); + ++x; + } + __gshared int x; + int y; +} + +void test519() +{ + //printf("test1\n"); + { + auto foo = new C519(); + assert(C519.x == 0); + printf("lifetime of foo\n"); + destroy(foo); + assert(C519.x == 1); + } + { + scope auto foo = new C519(); + assert(C519.x == 1); + printf("lifetime of foo\n"); + } + assert(C519.x == 2); + + //printf("test2\n"); + { + auto foo = new S519(); + assert(S519.x == 0); + printf("lifetime of foo\n"); + destroy(*foo); + assert(S519.x == 1); + } + { + auto foo = S519(); + assert(S519.x == 1); + printf("lifetime of foo\n"); + } + assert(S519.x == 2); + + //printf("test3\n"); + { + auto foo = new S519c(1); + assert(S519c.x == 1); + printf("lifetime of foo\n"); + destroy(*foo); + assert(S519c.x == 2); + } + { + auto foo = S519c(1); + assert(S519c.x == 3); + printf("lifetime of foo\n"); + } + assert(S519c.x == 4); +} + /***************************************************/ // 6453 @@ -182,6 +264,7 @@ void test13147() void main() { testinvariant(); + test519(); test6453(); test13113(); test13147();