Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Issue 6453 - Allow multiple invariants per struct/class #653

Closed
wants to merge 1 commit into from

6 participants

@yebblies
Collaborator

Build a linked list of invariants and insert a call to the next one at the end of the function.
Invariants are executed in lexical order.

http://d.puremagic.com/issues/show_bug.cgi?id=6453

@WalterBright

I'm going to defer doing enhancements for the time being.

@yebblies
Collaborator

Defer until after the next release or later?

@WalterBright

The implementation of this should parallel what AggregateDeclaration::buildDtor() does, which does the equivalent for destructors.

@yebblies
Collaborator

Ok

@alexrp

What's the status of this?

@WalterBright

The status is that that the highest priorities right now are to make progress on a 64 bit Windows D and to fix regressions.

@alexrp

@WalterBright sorry, I should probably have clarified that this was more directed at @yebblies - I was curious whether he'd done any work regarding your earlier comments.

@yebblies
Collaborator

@alexrp No, I haven't got around to updating this pull request yet.

@andralex
Owner

@WalterBright: we must find a way to scale up, which entails not having work on Win64 block other work by other people. If we don't manage to do so we may as well take our toys and go home. All you need to do at this point is give a yay or nay on the language change, and let others review and merge its implementation. Thanks.

@yebblies: I'm actually not sure about my own yay or nay. This is a language addition. What are the motivating idioms for it? I can think of mixins that add invariants, which is nice, but that's about it. More thoughts?

@alexrp

@andralex I think that's basically the motivation. I find myself needing this a lot when using mixins and DbC.

@andralex
Owner

@alexrp The mixin/DbC connection sounds like reason enough for me. LGTM. @WalterBright please approve the language change (no implementation review needed, you may leave it to others). @alexrp I assume you'll also take care of documenting the feature.

@nazriel

@yebblies this is very neat. Could you in your free time rebase it so pull-tester will catch up with this?
Thanks!

@yebblies
Collaborator

@nazriel Unfortunately this pull request needs a lot more work than a rebase.

@nazriel

@yebblies roger that!

@braddr braddr referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@yebblies yebblies Issue 6453 - Allow multiple invariant per struct/class
Build a linked list of invariants and insert a call to the next one at the end of the function.
Invariants are executed in lexical order.

Fixes Issue 6453
cd2fc99
@yebblies
Collaborator

I'm going to drop this as I don't have the motivation to re-implement it right now.

@yebblies yebblies closed this
@9rnsr
Collaborator

I'm going to drop this as I don't have the motivation to re-implement it right now.

The change of FuncDeclaration::semantic looks big, but it is not so deep. Most of them are the code moving.
I think rebasing is not so difficult.

@9rnsr
Collaborator

Modify: FuncDeclaration::semantic -> FuncDeclaration::semantic3

@yebblies
Collaborator

It's not the rebasing, it's moving it into AggregateDeclaration::buildDtor() as Walter requested. It's so old, I don't really remember how I did it and it's not a priority. If I close this it's possible somebody else will take it over, otherwise I'm sure I'll get to it eventually.

@9rnsr
Collaborator

OK. I opened #1978 to take over your work.

@yebblies yebblies deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 7, 2013
  1. @yebblies

    Issue 6453 - Allow multiple invariant per struct/class

    yebblies authored
    Build a linked list of invariants and insert a call to the next one at the end of the function.
    Invariants are executed in lexical order.
    
    Fixes Issue 6453
This page is out of date. Refresh to see the latest.
View
5 src/aggregate.h
@@ -58,7 +58,8 @@ struct AggregateDeclaration : ScopeDsymbol
VarDeclaration *vthis; // 'this' parameter if this aggregate is nested
#endif
// Special member functions
- InvariantDeclaration *inv; // invariant
+ InvariantDeclaration *inv; // linked list of invariants
+ FuncDeclaration *superInv; // function to call all invariants
NewDeclaration *aggNew; // allocator
DeleteDeclaration *aggDelete; // deallocator
@@ -91,6 +92,8 @@ struct AggregateDeclaration : ScopeDsymbol
FuncDeclaration *buildDtor(Scope *sc);
int isNested();
int isExport();
+ void addInvariant(InvariantDeclaration *inv);
+ void combineInvariants(Scope *sc);
void emitComment(Scope *sc);
void toJsonBuffer(OutBuffer *buf);
View
5 src/class.c
@@ -689,13 +689,10 @@ void ClassDeclaration::semantic(Scope *sc)
// if (dtor && dtor->toParent() != this)
// dtor = NULL;
-// inv = (InvariantDeclaration *)search(Id::classInvariant, 0);
-// if (inv && inv->toParent() != this)
-// inv = NULL;
-
// Can be in base class
aggNew = (NewDeclaration *)search(0, Id::classNew, 0);
aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
+ combineInvariants(sc);
// If this class has no constructor, but base class does, create
// a constructor:
View
2  src/declaration.h
@@ -826,6 +826,8 @@ struct SharedStaticDtorDeclaration : StaticDtorDeclaration
struct InvariantDeclaration : FuncDeclaration
{
+ InvariantDeclaration *next;
+
InvariantDeclaration(Loc loc, Loc endloc);
Dsymbol *syntaxCopy(Dsymbol *);
void semantic(Scope *sc);
View
4 src/e2ir.c
@@ -1972,7 +1972,7 @@ elem *AssertExp::toElem(IRState *irs)
symbol *ts = NULL;
elem *einv = NULL;
- InvariantDeclaration *inv = (InvariantDeclaration *)(void *)1;
+ FuncDeclaration *inv = (InvariantDeclaration *)(void *)1;
// If e1 is a class object, call the class invariant on it
if (global.params.useInvariants && t1->ty == Tclass &&
@@ -1989,7 +1989,7 @@ elem *AssertExp::toElem(IRState *irs)
else if (global.params.useInvariants &&
t1->ty == Tpointer &&
t1->nextOf()->ty == Tstruct &&
- (inv = ((TypeStruct *)t1->nextOf())->sym->inv) != NULL)
+ (inv = ((TypeStruct *)t1->nextOf())->sym->superInv) != NULL)
{
ts = symbol_genauto(t1->toCtype());
einv = callfunc(loc, irs, 1, inv->type->nextOf(), el_var(ts), e1->type, inv, inv->type, NULL, NULL);
View
32 src/func.c
@@ -332,8 +332,9 @@ void FuncDeclaration::semantic(Scope *sc)
error("special member functions not allowed for %ss", sd->kind());
}
- if (!sd->inv)
- sd->inv = isInvariantDeclaration();
+ InvariantDeclaration *inv = isInvariantDeclaration();
+ if (inv)
+ sd->addInvariant(inv);
if (!sd->aggNew)
sd->aggNew = isNewDeclaration();
@@ -408,7 +409,7 @@ void FuncDeclaration::semantic(Scope *sc)
inv = isInvariantDeclaration();
if (inv)
{
- cd->inv = inv;
+ cd->addInvariant(inv);
}
if (isNewDeclaration())
@@ -1172,7 +1173,7 @@ void FuncDeclaration::semantic3(Scope *sc)
if (isCtorDeclaration())
{
// Call invariant directly only if it exists
- InvariantDeclaration *inv = ad->inv;
+ FuncDeclaration *inv = ad->superInv;
ClassDeclaration *cd = ad->isClassDeclaration();
while (!inv && cd)
@@ -1180,7 +1181,7 @@ void FuncDeclaration::semantic3(Scope *sc)
cd = cd->baseClass;
if (!cd)
break;
- inv = cd->inv;
+ inv = cd->superInv;
}
if (inv)
{
@@ -1498,7 +1499,7 @@ void FuncDeclaration::semantic3(Scope *sc)
if (isDtorDeclaration())
{
// Call invariant directly only if it exists
- InvariantDeclaration *inv = ad->inv;
+ FuncDeclaration *inv = ad->superInv;
ClassDeclaration *cd = ad->isClassDeclaration();
while (!inv && cd)
@@ -1506,7 +1507,7 @@ void FuncDeclaration::semantic3(Scope *sc)
cd = cd->baseClass;
if (!cd)
break;
- inv = cd->inv;
+ inv = cd->superInv;
}
if (inv)
{
@@ -2687,6 +2688,7 @@ int FuncDeclaration::isVirtual()
return isMember() &&
!(isStatic() || protection == PROTprivate || protection == PROTpackage) &&
p->isClassDeclaration() &&
+ !(p->isAggregateDeclaration() && ((AggregateDeclaration *)p)->superInv == this) &&
!(p->isInterfaceDeclaration() && isFinal());
}
@@ -2851,6 +2853,7 @@ int FuncDeclaration::addPreInvariant()
{
AggregateDeclaration *ad = isThis();
return (ad &&
+ ad->superInv != this &&
//ad->isClassDeclaration() &&
global.params.useInvariants &&
(protection == PROTprotected || protection == PROTpublic || protection == PROTexport) &&
@@ -2863,6 +2866,7 @@ int FuncDeclaration::addPostInvariant()
AggregateDeclaration *ad = isThis();
return (ad &&
ad->inv &&
+ ad->superInv != this &&
//ad->isClassDeclaration() &&
global.params.useInvariants &&
(protection == PROTprotected || protection == PROTpublic || protection == PROTexport) &&
@@ -3708,9 +3712,15 @@ void SharedStaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
/********************************* InvariantDeclaration ****************************/
+Identifier *invariantId()
+{
+ return Lexer::uniqueId("__invariant_");
+}
+
InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc)
- : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL)
+ : FuncDeclaration(loc, endloc, invariantId(), STCundefined, NULL)
{
+ next = NULL;
}
Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s)
@@ -3734,11 +3744,7 @@ void InvariantDeclaration::semantic(Scope *sc)
error("invariants are only for struct/union/class definitions");
return;
}
- else if (ad->inv && ad->inv != this && semanticRun < PASSsemantic)
- {
- error("more than one invariant for %s", ad->toChars());
- }
- ad->inv = this;
+ ad->addInvariant(this);
if (!type)
type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd);
View
3  src/identifier.c
@@ -51,7 +51,6 @@ const char *Identifier::toHChars2()
if (this == Id::ctor) p = "this";
else if (this == Id::dtor) p = "~this";
- else if (this == Id::classInvariant) p = "invariant";
else if (this == Id::unitTest) p = "unittest";
else if (this == Id::dollar) p = "$";
else if (this == Id::withSym) p = "with";
@@ -65,6 +64,8 @@ const char *Identifier::toHChars2()
p = "static this";
else if (memcmp(p, "_staticDtor", 11) == 0)
p = "static ~this";
+ else if (memcmp(p, Id::classInvariant->toChars(), strlen(Id::classInvariant->toChars())) == 0)
+ p = "invariant";
}
}
View
46 src/struct.c
@@ -42,6 +42,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
deferred = NULL;
isdeprecated = 0;
inv = NULL;
+ superInv = NULL;
aggNew = NULL;
aggDelete = NULL;
@@ -141,6 +142,48 @@ int AggregateDeclaration::isExport()
return protection == PROTexport;
}
+void AggregateDeclaration::addInvariant(InvariantDeclaration *inv)
+{
+ inv->next = this->inv;
+ this->inv = inv;
+}
+
+void AggregateDeclaration::combineInvariants(Scope *sc)
+{
+ if (!inv)
+ return;
+
+ assert(!superInv);
+ InvariantDeclaration *xinv = inv;
+
+ // Define a new function to call all the invariants
+ superInv = new FuncDeclaration(loc, 0, Id::classInvariant, STCundefined, inv->type);
+
+ Expression *call = new CallExp(loc, new DsymbolExp(loc, xinv));
+ Statement *body = new ExpStatement(loc, call);
+ xinv = xinv->next;
+
+ while (xinv)
+ {
+ call = new CallExp(loc, new DsymbolExp(loc, xinv));
+ body = new CompoundStatement(loc, new ExpStatement(loc, call), body);
+ xinv = xinv->next;
+ }
+ superInv->fbody = body;
+
+ members->push(superInv);
+ superInv->addMember(sc, this, 0);
+
+ sc = sc->push();
+ sc->stc &= ~STCstatic; // not a static invariant
+ sc->incontract++;
+ sc->linkage = LINKd;
+
+ superInv->semantic(sc);
+
+ sc->pop();
+}
+
/****************************
* Do byte or word alignment as necessary.
* Align sizes of 0, as we may not know array sizes yet.
@@ -614,6 +657,8 @@ void StructDeclaration::semantic(Scope *sc)
xeq = buildXopEquals(sc2);
#endif
+ combineInvariants(sc2);
+
sc2->pop();
/* Look for special member functions.
@@ -621,7 +666,6 @@ void StructDeclaration::semantic(Scope *sc)
#if DMDV2
ctor = search(0, Id::ctor, 0);
#endif
- inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0);
aggNew = (NewDeclaration *)search(0, Id::classNew, 0);
aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
View
4 src/toobj.c
@@ -542,8 +542,8 @@ void ClassDeclaration::toObjFile(int multiobj)
dtsize_t(&dt, 0);
// invariant
- if (inv)
- dtxoff(&dt, inv->toSymbol(), 0, TYnptr);
+ if (superInv)
+ dtxoff(&dt, superInv->toSymbol(), 0, TYnptr);
else
dtsize_t(&dt, 0);
View
53 test/runnable/testinvariant.d
@@ -12,7 +12,7 @@ class Foo : Object
}
}
-int main()
+int testinvariant()
{
printf("hello\n");
Foo f = new Foo();
@@ -24,3 +24,54 @@ int main()
printf("world\n");
return 0;
}
+
+/***************************************************/
+
+void test6453()
+{
+ static class C
+ {
+ static uint called;
+ invariant() { called += 1; }
+ invariant() { called += 4; }
+ invariant() { called += 16; }
+
+ void publicmember() {}
+ }
+
+ static struct S
+ {
+ static uint called;
+ invariant() { called += 1; }
+ invariant() { called += 4; }
+ invariant() { called += 16; }
+
+ void publicmember() {}
+ }
+
+ auto c = new C();
+ C.called = 0;
+ c.publicmember();
+ assert(C.called == 42);
+
+ C.called = 0;
+ c.__invariant();
+ assert(C.called == 21);
+
+ auto s = new S();
+ S.called = 0;
+ s.publicmember();
+ assert(S.called == 42);
+
+ S.called = 0;
+ s.__invariant();
+ assert(S.called == 21);
+}
+
+/***************************************************/
+
+void main()
+{
+ testinvariant();
+ test6453();
+}
Something went wrong with that request. Please try again.