Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/dmd/clone.d
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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:
Expand Down
29 changes: 25 additions & 4 deletions src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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());
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -4485,6 +4485,29 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}

version (none) // Controversial - see Bugzilla 519
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So are we going to do it, or not?

Copy link
Contributor

@wilzbach wilzbach Jan 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this decision is the only thing holding this PR up. How about splitting it of into a separate PR?

{
/* 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))
Expand All @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions src/dmd/e2ir.d
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inserting the invariant call here seems strange. Everywhere else it is controlled by addPostInvariant

{
/* 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);
Expand Down
4 changes: 3 additions & 1 deletion test/runnable/testdstress.d
Original file line number Diff line number Diff line change
Expand Up @@ -809,10 +809,12 @@ class Parent40{

invariant()
{
assert(!checked40);
if (!checked40)
{
checked40=true;
// even number
assert((x&1u)==0);
}
}
}

Expand Down
83 changes: 83 additions & 0 deletions test/runnable/testinvariant.d
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -182,6 +264,7 @@ void test13147()
void main()
{
testinvariant();
test519();
test6453();
test13113();
test13147();
Expand Down