root/trunk/src/clone.c

Revision 639, 16.3 kB (checked in by walter, 2 years ago)

Issue 2716 - Confusion of auto and scope as the class attribute

  • Property svn:eol-style set to native
Line 
1 // Compiler implementation of the D programming language
2 // Copyright (c) 1999-2010 by Digital Mars
3 // All Rights Reserved
4 // written by Walter Bright
5 // http://www.digitalmars.com
6 // License for redistribution is by either the Artistic License
7 // in artistic.txt, or the GNU General Public License in gnu.txt.
8 // See the included readme.txt for details.
9
10 #include <stdio.h>
11 #include <assert.h>
12
13 #include "root.h"
14 #include "aggregate.h"
15 #include "scope.h"
16 #include "mtype.h"
17 #include "declaration.h"
18 #include "module.h"
19 #include "id.h"
20 #include "expression.h"
21 #include "statement.h"
22 #include "init.h"
23
24
25 /*******************************************
26  * We need an opAssign for the struct if
27  * it has a destructor or a postblit.
28  * We need to generate one if a user-specified one does not exist.
29  */
30
31 int StructDeclaration::needOpAssign()
32 {
33 #define X 0
34     if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars());
35     if (hasIdentityAssign)
36         goto Ldontneed;
37
38     if (dtor || postblit)
39         goto Lneed;
40
41     /* If any of the fields need an opAssign, then we
42      * need it too.
43      */
44     for (size_t i = 0; i < fields.dim; i++)
45     {
46         Dsymbol *s = (Dsymbol *)fields.data[i];
47         VarDeclaration *v = s->isVarDeclaration();
48         assert(v && v->storage_class & STCfield);
49         if (v->storage_class & STCref)
50             continue;
51         Type *tv = v->type->toBasetype();
52         while (tv->ty == Tsarray)
53         {   TypeSArray *ta = (TypeSArray *)tv;
54             tv = tv->nextOf()->toBasetype();
55         }
56         if (tv->ty == Tstruct)
57         {   TypeStruct *ts = (TypeStruct *)tv;
58             StructDeclaration *sd = ts->sym;
59             if (sd->needOpAssign())
60                 goto Lneed;
61         }
62     }
63 Ldontneed:
64     if (X) printf("\tdontneed\n");
65     return 0;
66
67 Lneed:
68     if (X) printf("\tneed\n");
69     return 1;
70 #undef X
71 }
72
73 /*******************************************
74  * We need an opEquals for the struct if
75  * any fields has an opEquals.
76  * Generate one if a user-specified one does not exist.
77  */
78
79 int StructDeclaration::needOpEquals()
80 {
81 #define X 0
82     if (X) printf("StructDeclaration::needOpEquals() %s\n", toChars());
83
84     /* If any of the fields has an opEquals, then we
85      * need it too.
86      */
87     for (size_t i = 0; i < fields.dim; i++)
88     {
89         Dsymbol *s = (Dsymbol *)fields.data[i];
90         VarDeclaration *v = s->isVarDeclaration();
91         assert(v && v->storage_class & STCfield);
92         if (v->storage_class & STCref)
93             continue;
94         Type *tv = v->type->toBasetype();
95         while (tv->ty == Tsarray)
96         {   TypeSArray *ta = (TypeSArray *)tv;
97             tv = tv->nextOf()->toBasetype();
98         }
99         if (tv->ty == Tstruct)
100         {   TypeStruct *ts = (TypeStruct *)tv;
101             StructDeclaration *sd = ts->sym;
102             if (sd->eq)
103                 goto Lneed;
104         }
105     }
106 Ldontneed:
107     if (X) printf("\tdontneed\n");
108     return 0;
109
110 Lneed:
111     if (X) printf("\tneed\n");
112     return 1;
113 #undef X
114 }
115
116 /******************************************
117  * Build opAssign for struct.
118  *      S* opAssign(S s) { ... }
119  *
120  * Note that s will be constructed onto the stack, probably copy-constructed.
121  * Then, the body is:
122  *      S tmp = *this;  // bit copy
123  *      *this = s;      // bit copy
124  *      tmp.dtor();
125  * Instead of running the destructor on s, run it on tmp instead.
126  */
127
128 FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
129 {
130     if (!needOpAssign())
131         return NULL;
132
133     //printf("StructDeclaration::buildOpAssign() %s\n", toChars());
134
135     FuncDeclaration *fop = NULL;
136
137     Parameter *param = new Parameter(STCnodtor, type, Id::p, NULL);
138     Parameters *fparams = new Parameters;
139     fparams->push(param);
140     Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd);
141 #if STRUCTTHISREF
142     ((TypeFunction *)ftype)->isref = 1;
143 #endif
144
145     fop = new FuncDeclaration(0, 0, Id::assign, STCundefined, ftype);
146
147     Expression *e = NULL;
148     if (postblit)
149     {   /* Swap:
150          *    tmp = *this; *this = s; tmp.dtor();
151          */
152         //printf("\tswap copy\n");
153         Identifier *idtmp = Lexer::uniqueId("__tmp");
154         VarDeclaration *tmp;
155         AssignExp *ec = NULL;
156         if (dtor)
157         {
158             tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0));
159             tmp->noscope = 1;
160             tmp->storage_class |= STCctfe;
161             e = new DeclarationExp(0, tmp);
162             ec = new AssignExp(0,
163                 new VarExp(0, tmp),
164 #if STRUCTTHISREF
165                 new ThisExp(0)
166 #else
167                 new PtrExp(0, new ThisExp(0))
168 #endif
169                 );
170             ec->op = TOKblit;
171             e = Expression::combine(e, ec);
172         }
173         ec = new AssignExp(0,
174 #if STRUCTTHISREF
175                 new ThisExp(0),
176 #else
177                 new PtrExp(0, new ThisExp(0)),
178 #endif
179                 new IdentifierExp(0, Id::p));
180         ec->op = TOKblit;
181         e = Expression::combine(e, ec);
182         if (dtor)
183         {
184             /* Instead of running the destructor on s, run it
185              * on tmp. This avoids needing to copy tmp back in to s.
186              */
187             Expression *ec = new DotVarExp(0, new VarExp(0, tmp), dtor, 0);
188             ec = new CallExp(0, ec);
189             e = Expression::combine(e, ec);
190         }
191     }
192     else
193     {   /* Do memberwise copy
194          */
195         //printf("\tmemberwise copy\n");
196         for (size_t i = 0; i < fields.dim; i++)
197         {
198             Dsymbol *s = (Dsymbol *)fields.data[i];
199             VarDeclaration *v = s->isVarDeclaration();
200             assert(v && v->storage_class & STCfield);
201             // this.v = s.v;
202             AssignExp *ec = new AssignExp(0,
203                 new DotVarExp(0, new ThisExp(0), v, 0),
204                 new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0));
205             ec->op = TOKblit;
206             e = Expression::combine(e, ec);
207         }
208     }
209     Statement *s1 = new ExpStatement(0, e);
210
211     /* Add:
212      *   return this;
213      */
214     e = new ThisExp(0);
215     Statement *s2 = new ReturnStatement(0, e);
216
217     fop->fbody = new CompoundStatement(0, s1, s2);
218
219     members->push(fop);
220     fop->addMember(sc, this, 1);
221
222     sc = sc->push();
223     sc->stc = 0;
224     sc->linkage = LINKd;
225
226     fop->semantic(sc);
227
228     sc->pop();
229
230     //printf("-StructDeclaration::buildOpAssign() %s\n", toChars());
231
232     return fop;
233 }
234
235 /******************************************
236  * Build opEquals for struct.
237  *      const bool opEquals(const ref S s) { ... }
238  */
239
240 FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc)
241 {
242     if (!needOpEquals())
243         return NULL;
244     //printf("StructDeclaration::buildOpEquals() %s\n", toChars());
245     Loc loc = this->loc;
246
247     Parameters *parameters = new Parameters;
248 #if STRUCTTHISREF
249     // bool opEquals(ref const T) const;
250     Parameter *param = new Parameter(STCref, type->constOf(), Id::p, NULL);
251 #else
252     // bool opEquals(const T*) const;
253     Parameter *param = new Parameter(STCin, type->pointerTo(), Id::p, NULL);
254 #endif
255
256     parameters->push(param);
257     TypeFunction *ftype = new TypeFunction(parameters, Type::tbool, 0, LINKd);
258     ftype->mod = MODconst;
259     ftype = (TypeFunction *)ftype->semantic(loc, sc);
260
261     FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, ftype);
262
263     Expression *e = NULL;
264     /* Do memberwise compare
265      */
266     //printf("\tmemberwise compare\n");
267     for (size_t i = 0; i < fields.dim; i++)
268     {
269         Dsymbol *s = (Dsymbol *)fields.data[i];
270         VarDeclaration *v = s->isVarDeclaration();
271         assert(v && v->storage_class & STCfield);
272         if (v->storage_class & STCref)
273             assert(0);                  // what should we do with this?
274         // this.v == s.v;
275         EqualExp *ec = new EqualExp(TOKequal, loc,
276             new DotVarExp(loc, new ThisExp(loc), v, 0),
277             new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0));
278         if (e)
279             e = new AndAndExp(loc, e, ec);
280         else
281             e = ec;
282     }
283     if (!e)
284         e = new IntegerExp(loc, 1, Type::tbool);
285     fop->fbody = new ReturnStatement(loc, e);
286
287     members->push(fop);
288     fop->addMember(sc, this, 1);
289
290     sc = sc->push();
291     sc->stc = 0;
292     sc->linkage = LINKd;
293
294     fop->semantic(sc);
295
296     sc->pop();
297
298     //printf("-StructDeclaration::buildOpEquals() %s\n", toChars());
299
300     return fop;
301 }
302
303
304 /*******************************************
305  * Build copy constructor for struct.
306  * Copy constructors are compiler generated only, and are only
307  * callable from the compiler. They are not user accessible.
308  * A copy constructor is:
309  *    void cpctpr(ref S s)
310  *    {
311  *      *this = s;
312  *      this.postBlit();
313  *    }
314  * This is done so:
315  *      - postBlit() never sees uninitialized data
316  *      - memcpy can be much more efficient than memberwise copy
317  *      - no fields are overlooked
318  */
319
320 FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
321 {
322     //printf("StructDeclaration::buildCpCtor() %s\n", toChars());
323     FuncDeclaration *fcp = NULL;
324
325     /* Copy constructor is only necessary if there is a postblit function,
326      * otherwise the code generator will just do a bit copy.
327      */
328     if (postblit)
329     {
330         //printf("generating cpctor\n");
331
332         Parameter *param = new Parameter(STCref, type, Id::p, NULL);
333         Parameters *fparams = new Parameters;
334         fparams->push(param);
335         Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd);
336
337         fcp = new FuncDeclaration(0, 0, Id::cpctor, STCundefined, ftype);
338         fcp->storage_class |= postblit->storage_class & STCdisable;
339
340         // Build *this = p;
341         Expression *e = new ThisExp(0);
342 #if !STRUCTTHISREF
343         e = new PtrExp(0, e);
344 #endif
345         AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p));
346         ea->op = TOKblit;
347         Statement *s = new ExpStatement(0, ea);
348
349         // Build postBlit();
350         e = new VarExp(0, postblit, 0);
351         e = new CallExp(0, e);
352
353         s = new CompoundStatement(0, s, new ExpStatement(0, e));
354         fcp->fbody = s;
355
356         members->push(fcp);
357
358         sc = sc->push();
359         sc->stc = 0;
360         sc->linkage = LINKd;
361
362         fcp->semantic(sc);
363
364         sc->pop();
365     }
366
367     return fcp;
368 }
369
370 /*****************************************
371  * Create inclusive postblit for struct by aggregating
372  * all the postblits in postblits[] with the postblits for
373  * all the members.
374  * Note the close similarity with AggregateDeclaration::buildDtor(),
375  * and the ordering changes (runs forward instead of backwards).
376  */
377
378 #if DMDV2
379 FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
380 {
381     //printf("StructDeclaration::buildPostBlit() %s\n", toChars());
382     Expression *e = NULL;
383     StorageClass stc = 0;
384
385     for (size_t i = 0; i < fields.dim; i++)
386     {
387         Dsymbol *s = (Dsymbol *)fields.data[i];
388         VarDeclaration *v = s->isVarDeclaration();
389         assert(v && v->storage_class & STCfield);
390         if (v->storage_class & STCref)
391             continue;
392         Type *tv = v->type->toBasetype();
393         size_t dim = 1;
394         while (tv->ty == Tsarray)
395         {   TypeSArray *ta = (TypeSArray *)tv;
396             dim *= ((TypeSArray *)tv)->dim->toInteger();
397             tv = tv->nextOf()->toBasetype();
398         }
399         if (tv->ty == Tstruct)
400         {   TypeStruct *ts = (TypeStruct *)tv;
401             StructDeclaration *sd = ts->sym;
402             if (sd->postblit)
403             {   Expression *ex;
404
405                 stc |= sd->postblit->storage_class & STCdisable;
406
407                 // this.v
408                 ex = new ThisExp(0);
409                 ex = new DotVarExp(0, ex, v, 0);
410
411                 if (dim == 1)
412                 {   // this.v.postblit()
413                     ex = new DotVarExp(0, ex, sd->postblit, 0);
414                     ex = new CallExp(0, ex);
415                 }
416                 else
417                 {
418                     // Typeinfo.postblit(cast(void*)&this.v);
419                     Expression *ea = new AddrExp(0, ex);
420                     ea = new CastExp(0, ea, Type::tvoid->pointerTo());
421
422                     Expression *et = v->type->getTypeInfo(sc);
423                     et = new DotIdExp(0, et, Id::postblit);
424
425                     ex = new CallExp(0, et, ea);
426                 }
427                 e = Expression::combine(e, ex); // combine in forward order
428             }
429         }
430     }
431
432     /* Build our own "postblit" which executes e
433      */
434     if (e)
435     {   //printf("Building __fieldPostBlit()\n");
436         PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__fieldPostBlit"));
437         dd->storage_class |= stc;
438         dd->fbody = new ExpStatement(0, e);
439         postblits.shift(dd);
440         members->push(dd);
441         dd->semantic(sc);
442     }
443
444     switch (postblits.dim)
445     {
446         case 0:
447             return NULL;
448
449         case 1:
450             return (FuncDeclaration *)postblits.data[0];
451
452         default:
453             e = NULL;
454             for (size_t i = 0; i < postblits.dim; i++)
455             {   FuncDeclaration *fd = (FuncDeclaration *)postblits.data[i];
456                 stc |= fd->storage_class & STCdisable;
457                 Expression *ex = new ThisExp(0);
458                 ex = new DotVarExp(0, ex, fd, 0);
459                 ex = new CallExp(0, ex);
460                 e = Expression::combine(e, ex);
461             }
462             PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__aggrPostBlit"));
463             dd->storage_class |= stc;
464             dd->fbody = new ExpStatement(0, e);
465             members->push(dd);
466             dd->semantic(sc);
467             return dd;
468     }
469 }
470
471 #endif
472
473 /*****************************************
474  * Create inclusive destructor for struct/class by aggregating
475  * all the destructors in dtors[] with the destructors for
476  * all the members.
477  * Note the close similarity with StructDeclaration::buildPostBlit(),
478  * and the ordering changes (runs backward instead of forwards).
479  */
480
481 FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc)
482 {
483     //printf("AggregateDeclaration::buildDtor() %s\n", toChars());
484     Expression *e = NULL;
485
486 #if DMDV2
487     for (size_t i = 0; i < fields.dim; i++)
488     {
489         Dsymbol *s = (Dsymbol *)fields.data[i];
490         VarDeclaration *v = s->isVarDeclaration();
491         assert(v && v->storage_class & STCfield);
492         if (v->storage_class & STCref)
493             continue;
494         Type *tv = v->type->toBasetype();
495         size_t dim = 1;
496         while (tv->ty == Tsarray)
497         {   TypeSArray *ta = (TypeSArray *)tv;
498             dim *= ((TypeSArray *)tv)->dim->toInteger();
499             tv = tv->nextOf()->toBasetype();
500         }
501         if (tv->ty == Tstruct)
502         {   TypeStruct *ts = (TypeStruct *)tv;
503             StructDeclaration *sd = ts->sym;
504             if (sd->dtor)
505             {   Expression *ex;
506
507                 // this.v
508                 ex = new ThisExp(0);
509                 ex = new DotVarExp(0, ex, v, 0);
510
511                 if (dim == 1)
512                 {   // this.v.dtor()
513                     ex = new DotVarExp(0, ex, sd->dtor, 0);
514                     ex = new CallExp(0, ex);
515                 }
516                 else
517                 {
518                     // Typeinfo.destroy(cast(void*)&this.v);
519                     Expression *ea = new AddrExp(0, ex);
520                     ea = new CastExp(0, ea, Type::tvoid->pointerTo());
521
522                     Expression *et = v->type->getTypeInfo(sc);
523                     et = new DotIdExp(0, et, Id::destroy);
524
525                     ex = new CallExp(0, et, ea);
526                 }
527                 e = Expression::combine(ex, e); // combine in reverse order
528             }
529         }
530     }
531
532     /* Build our own "destructor" which executes e
533      */
534     if (e)
535     {   //printf("Building __fieldDtor()\n");
536         DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__fieldDtor"));
537         dd->fbody = new ExpStatement(0, e);
538         dtors.shift(dd);
539         members->push(dd);
540         dd->semantic(sc);
541     }
542 #endif
543
544     switch (dtors.dim)
545     {
546         case 0:
547             return NULL;
548
549         case 1:
550             return (FuncDeclaration *)dtors.data[0];
551
552         default:
553             e = NULL;
554             for (size_t i = 0; i < dtors.dim; i++)
555             {   FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i];
556                 Expression *ex = new ThisExp(0);
557                 ex = new DotVarExp(0, ex, fd, 0);
558                 ex = new CallExp(0, ex);
559                 e = Expression::combine(ex, e);
560             }
561             DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor"));
562             dd->fbody = new ExpStatement(0, e);
563             members->push(dd);
564             dd->semantic(sc);
565             return dd;
566     }
567 }
Note: See TracBrowser for help on using the browser.