Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

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

Closed
wants to merge 1 commit into from

6 participants

Daniel Murphy Walter Bright Alex Rønne Petersen Andrei Alexandrescu Damian Ziemba Hara Kenji
Daniel Murphy
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

Walter Bright
Owner

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

Daniel Murphy
Collaborator

Defer until after the next release or later?

Walter Bright

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

Daniel Murphy
Collaborator

Ok

Alex Rønne Petersen
alexrp commented July 15, 2012

What's the status of this?

Walter Bright
Owner

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

Alex Rønne Petersen
alexrp commented July 15, 2012

@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.

Daniel Murphy
Collaborator

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

Andrei Alexandrescu
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?

Alex Rønne Petersen

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

Andrei Alexandrescu
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.

Damian Ziemba

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

Daniel Murphy
Collaborator

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

Damian Ziemba

@yebblies roger that!

Brad Roberts braddr referenced this pull request from a commit October 21, 2012
Commit has since been removed from the repository and is no longer available.
Daniel Murphy 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
Daniel Murphy yebblies closed this May 07, 2013
Daniel Murphy
Collaborator

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

Hara Kenji
Collaborator
9rnsr commented May 07, 2013

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.

Hara Kenji
Collaborator
9rnsr commented May 07, 2013

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

Daniel Murphy
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.

Hara Kenji
Collaborator
9rnsr commented May 08, 2013

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

Daniel Murphy yebblies deleted the branch November 22, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

May 08, 2013
Daniel Murphy 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
This page is out of date. Refresh to see the latest.
5  src/aggregate.h
@@ -58,7 +58,8 @@ struct AggregateDeclaration : ScopeDsymbol
58 58
     VarDeclaration *vthis;      // 'this' parameter if this aggregate is nested
59 59
 #endif
60 60
     // Special member functions
61  
-    InvariantDeclaration *inv;          // invariant
  61
+    InvariantDeclaration *inv;          // linked list of invariants
  62
+    FuncDeclaration *superInv;          // function to call all invariants
62 63
     NewDeclaration *aggNew;             // allocator
63 64
     DeleteDeclaration *aggDelete;       // deallocator
64 65
 
@@ -91,6 +92,8 @@ struct AggregateDeclaration : ScopeDsymbol
91 92
     FuncDeclaration *buildDtor(Scope *sc);
92 93
     int isNested();
93 94
     int isExport();
  95
+    void addInvariant(InvariantDeclaration *inv);
  96
+    void combineInvariants(Scope *sc);
94 97
 
95 98
     void emitComment(Scope *sc);
96 99
     void toJsonBuffer(OutBuffer *buf);
5  src/class.c
@@ -689,13 +689,10 @@ void ClassDeclaration::semantic(Scope *sc)
689 689
 //    if (dtor && dtor->toParent() != this)
690 690
 //      dtor = NULL;
691 691
 
692  
-//    inv = (InvariantDeclaration *)search(Id::classInvariant, 0);
693  
-//    if (inv && inv->toParent() != this)
694  
-//      inv = NULL;
695  
-
696 692
     // Can be in base class
697 693
     aggNew    = (NewDeclaration *)search(0, Id::classNew, 0);
698 694
     aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
  695
+    combineInvariants(sc);
699 696
 
700 697
     // If this class has no constructor, but base class does, create
701 698
     // a constructor:
2  src/declaration.h
@@ -826,6 +826,8 @@ struct SharedStaticDtorDeclaration : StaticDtorDeclaration
826 826
 
827 827
 struct InvariantDeclaration : FuncDeclaration
828 828
 {
  829
+    InvariantDeclaration *next;
  830
+
829 831
     InvariantDeclaration(Loc loc, Loc endloc);
830 832
     Dsymbol *syntaxCopy(Dsymbol *);
831 833
     void semantic(Scope *sc);
4  src/e2ir.c
@@ -1972,7 +1972,7 @@ elem *AssertExp::toElem(IRState *irs)
1972 1972
         symbol *ts = NULL;
1973 1973
         elem *einv = NULL;
1974 1974
 
1975  
-        InvariantDeclaration *inv = (InvariantDeclaration *)(void *)1;
  1975
+        FuncDeclaration *inv = (InvariantDeclaration *)(void *)1;
1976 1976
 
1977 1977
         // If e1 is a class object, call the class invariant on it
1978 1978
         if (global.params.useInvariants && t1->ty == Tclass &&
@@ -1989,7 +1989,7 @@ elem *AssertExp::toElem(IRState *irs)
1989 1989
         else if (global.params.useInvariants &&
1990 1990
             t1->ty == Tpointer &&
1991 1991
             t1->nextOf()->ty == Tstruct &&
1992  
-            (inv = ((TypeStruct *)t1->nextOf())->sym->inv) != NULL)
  1992
+            (inv = ((TypeStruct *)t1->nextOf())->sym->superInv) != NULL)
1993 1993
         {
1994 1994
             ts = symbol_genauto(t1->toCtype());
1995 1995
             einv = callfunc(loc, irs, 1, inv->type->nextOf(), el_var(ts), e1->type, inv, inv->type, NULL, NULL);
32  src/func.c
@@ -332,8 +332,9 @@ void FuncDeclaration::semantic(Scope *sc)
332 332
             error("special member functions not allowed for %ss", sd->kind());
333 333
         }
334 334
 
335  
-        if (!sd->inv)
336  
-            sd->inv = isInvariantDeclaration();
  335
+        InvariantDeclaration *inv = isInvariantDeclaration();
  336
+        if (inv)
  337
+            sd->addInvariant(inv);
337 338
 
338 339
         if (!sd->aggNew)
339 340
             sd->aggNew = isNewDeclaration();
@@ -408,7 +409,7 @@ void FuncDeclaration::semantic(Scope *sc)
408 409
         inv = isInvariantDeclaration();
409 410
         if (inv)
410 411
         {
411  
-            cd->inv = inv;
  412
+            cd->addInvariant(inv);
412 413
         }
413 414
 
414 415
         if (isNewDeclaration())
@@ -1172,7 +1173,7 @@ void FuncDeclaration::semantic3(Scope *sc)
1172 1173
                 if (isCtorDeclaration())
1173 1174
                 {
1174 1175
                     // Call invariant directly only if it exists
1175  
-                    InvariantDeclaration *inv = ad->inv;
  1176
+                    FuncDeclaration *inv = ad->superInv;
1176 1177
                     ClassDeclaration *cd = ad->isClassDeclaration();
1177 1178
 
1178 1179
                     while (!inv && cd)
@@ -1180,7 +1181,7 @@ void FuncDeclaration::semantic3(Scope *sc)
1180 1181
                         cd = cd->baseClass;
1181 1182
                         if (!cd)
1182 1183
                             break;
1183  
-                        inv = cd->inv;
  1184
+                        inv = cd->superInv;
1184 1185
                     }
1185 1186
                     if (inv)
1186 1187
                     {
@@ -1498,7 +1499,7 @@ void FuncDeclaration::semantic3(Scope *sc)
1498 1499
                 if (isDtorDeclaration())
1499 1500
                 {
1500 1501
                     // Call invariant directly only if it exists
1501  
-                    InvariantDeclaration *inv = ad->inv;
  1502
+                    FuncDeclaration *inv = ad->superInv;
1502 1503
                     ClassDeclaration *cd = ad->isClassDeclaration();
1503 1504
 
1504 1505
                     while (!inv && cd)
@@ -1506,7 +1507,7 @@ void FuncDeclaration::semantic3(Scope *sc)
1506 1507
                         cd = cd->baseClass;
1507 1508
                         if (!cd)
1508 1509
                             break;
1509  
-                        inv = cd->inv;
  1510
+                        inv = cd->superInv;
1510 1511
                     }
1511 1512
                     if (inv)
1512 1513
                     {
@@ -2687,6 +2688,7 @@ int FuncDeclaration::isVirtual()
2687 2688
     return isMember() &&
2688 2689
         !(isStatic() || protection == PROTprivate || protection == PROTpackage) &&
2689 2690
         p->isClassDeclaration() &&
  2691
+        !(p->isAggregateDeclaration() && ((AggregateDeclaration *)p)->superInv == this) &&
2690 2692
         !(p->isInterfaceDeclaration() && isFinal());
2691 2693
 }
2692 2694
 
@@ -2851,6 +2853,7 @@ int FuncDeclaration::addPreInvariant()
2851 2853
 {
2852 2854
     AggregateDeclaration *ad = isThis();
2853 2855
     return (ad &&
  2856
+            ad->superInv != this &&
2854 2857
             //ad->isClassDeclaration() &&
2855 2858
             global.params.useInvariants &&
2856 2859
             (protection == PROTprotected || protection == PROTpublic || protection == PROTexport) &&
@@ -2863,6 +2866,7 @@ int FuncDeclaration::addPostInvariant()
2863 2866
     AggregateDeclaration *ad = isThis();
2864 2867
     return (ad &&
2865 2868
             ad->inv &&
  2869
+            ad->superInv != this &&
2866 2870
             //ad->isClassDeclaration() &&
2867 2871
             global.params.useInvariants &&
2868 2872
             (protection == PROTprotected || protection == PROTpublic || protection == PROTexport) &&
@@ -3708,9 +3712,15 @@ void SharedStaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3708 3712
 
3709 3713
 /********************************* InvariantDeclaration ****************************/
3710 3714
 
  3715
+Identifier *invariantId()
  3716
+{
  3717
+    return Lexer::uniqueId("__invariant_");
  3718
+}
  3719
+
3711 3720
 InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc)
3712  
-    : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL)
  3721
+    : FuncDeclaration(loc, endloc, invariantId(), STCundefined, NULL)
3713 3722
 {
  3723
+    next = NULL;
3714 3724
 }
3715 3725
 
3716 3726
 Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s)
@@ -3734,11 +3744,7 @@ void InvariantDeclaration::semantic(Scope *sc)
3734 3744
         error("invariants are only for struct/union/class definitions");
3735 3745
         return;
3736 3746
     }
3737  
-    else if (ad->inv && ad->inv != this && semanticRun < PASSsemantic)
3738  
-    {
3739  
-        error("more than one invariant for %s", ad->toChars());
3740  
-    }
3741  
-    ad->inv = this;
  3747
+    ad->addInvariant(this);
3742 3748
     if (!type)
3743 3749
         type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd);
3744 3750
 
3  src/identifier.c
@@ -51,7 +51,6 @@ const char *Identifier::toHChars2()
51 51
 
52 52
     if (this == Id::ctor) p = "this";
53 53
     else if (this == Id::dtor) p = "~this";
54  
-    else if (this == Id::classInvariant) p = "invariant";
55 54
     else if (this == Id::unitTest) p = "unittest";
56 55
     else if (this == Id::dollar) p = "$";
57 56
     else if (this == Id::withSym) p = "with";
@@ -65,6 +64,8 @@ const char *Identifier::toHChars2()
65 64
                 p = "static this";
66 65
             else if (memcmp(p, "_staticDtor", 11) == 0)
67 66
                 p = "static ~this";
  67
+            else if (memcmp(p, Id::classInvariant->toChars(), strlen(Id::classInvariant->toChars())) == 0)
  68
+                p = "invariant";
68 69
         }
69 70
     }
70 71
 
46  src/struct.c
@@ -42,6 +42,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
42 42
     deferred = NULL;
43 43
     isdeprecated = 0;
44 44
     inv = NULL;
  45
+    superInv = NULL;
45 46
     aggNew = NULL;
46 47
     aggDelete = NULL;
47 48
 
@@ -141,6 +142,48 @@ int AggregateDeclaration::isExport()
141 142
     return protection == PROTexport;
142 143
 }
143 144
 
  145
+void AggregateDeclaration::addInvariant(InvariantDeclaration *inv)
  146
+{
  147
+    inv->next = this->inv;
  148
+    this->inv = inv;
  149
+}
  150
+
  151
+void AggregateDeclaration::combineInvariants(Scope *sc)
  152
+{
  153
+    if (!inv)
  154
+        return;
  155
+
  156
+    assert(!superInv);
  157
+    InvariantDeclaration *xinv = inv;
  158
+
  159
+    // Define a new function to call all the invariants
  160
+    superInv = new FuncDeclaration(loc, 0, Id::classInvariant, STCundefined, inv->type);
  161
+
  162
+    Expression *call = new CallExp(loc, new DsymbolExp(loc, xinv));
  163
+    Statement *body = new ExpStatement(loc, call);
  164
+    xinv = xinv->next;
  165
+
  166
+    while (xinv)
  167
+    {
  168
+        call = new CallExp(loc, new DsymbolExp(loc, xinv));
  169
+        body = new CompoundStatement(loc, new ExpStatement(loc, call), body);
  170
+        xinv = xinv->next;
  171
+    }
  172
+    superInv->fbody = body;
  173
+
  174
+    members->push(superInv);
  175
+    superInv->addMember(sc, this, 0);
  176
+
  177
+    sc = sc->push();
  178
+    sc->stc &= ~STCstatic;              // not a static invariant
  179
+    sc->incontract++;
  180
+    sc->linkage = LINKd;
  181
+
  182
+    superInv->semantic(sc);
  183
+
  184
+    sc->pop();
  185
+}
  186
+
144 187
 /****************************
145 188
  * Do byte or word alignment as necessary.
146 189
  * Align sizes of 0, as we may not know array sizes yet.
@@ -614,6 +657,8 @@ void StructDeclaration::semantic(Scope *sc)
614 657
     xeq = buildXopEquals(sc2);
615 658
 #endif
616 659
 
  660
+    combineInvariants(sc2);
  661
+
617 662
     sc2->pop();
618 663
 
619 664
     /* Look for special member functions.
@@ -621,7 +666,6 @@ void StructDeclaration::semantic(Scope *sc)
621 666
 #if DMDV2
622 667
     ctor = search(0, Id::ctor, 0);
623 668
 #endif
624  
-    inv =    (InvariantDeclaration *)search(0, Id::classInvariant, 0);
625 669
     aggNew =       (NewDeclaration *)search(0, Id::classNew,       0);
626 670
     aggDelete = (DeleteDeclaration *)search(0, Id::classDelete,    0);
627 671
 
4  src/toobj.c
@@ -542,8 +542,8 @@ void ClassDeclaration::toObjFile(int multiobj)
542 542
         dtsize_t(&dt, 0);
543 543
 
544 544
     // invariant
545  
-    if (inv)
546  
-        dtxoff(&dt, inv->toSymbol(), 0, TYnptr);
  545
+    if (superInv)
  546
+        dtxoff(&dt, superInv->toSymbol(), 0, TYnptr);
547 547
     else
548 548
         dtsize_t(&dt, 0);
549 549
 
53  test/runnable/testinvariant.d
@@ -12,7 +12,7 @@ class Foo : Object
12 12
     }
13 13
 }
14 14
 
15  
-int main()
  15
+int testinvariant()
16 16
 {
17 17
     printf("hello\n");
18 18
     Foo f = new Foo();
@@ -24,3 +24,54 @@ int main()
24 24
     printf("world\n");
25 25
     return 0;
26 26
 }
  27
+
  28
+/***************************************************/
  29
+
  30
+void test6453()
  31
+{
  32
+    static class C
  33
+    {
  34
+        static uint called;
  35
+        invariant() { called += 1; }
  36
+        invariant() { called += 4; }
  37
+        invariant() { called += 16; }
  38
+
  39
+        void publicmember() {}
  40
+    }
  41
+
  42
+    static struct S
  43
+    {
  44
+        static uint called;
  45
+        invariant() { called += 1; }
  46
+        invariant() { called += 4; }
  47
+        invariant() { called += 16; }
  48
+
  49
+        void publicmember() {}
  50
+    }
  51
+
  52
+    auto c = new C();
  53
+    C.called = 0;
  54
+    c.publicmember();
  55
+    assert(C.called == 42);
  56
+
  57
+    C.called = 0;
  58
+    c.__invariant();
  59
+    assert(C.called == 21);
  60
+
  61
+    auto s = new S();
  62
+    S.called = 0;
  63
+    s.publicmember();
  64
+    assert(S.called == 42);
  65
+
  66
+    S.called = 0;
  67
+    s.__invariant();
  68
+    assert(S.called == 21);
  69
+}
  70
+
  71
+/***************************************************/
  72
+
  73
+void main()
  74
+{
  75
+    testinvariant();
  76
+    test6453();
  77
+}
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.