root/branches/dmdfe-2.0/clone.c

Revision 883, 10.5 kB (checked in by Gregor, 9 months ago)

MERGE: DMD 2.012

  • Property svn:eol-style set to native
Line 
1 // Compiler implementation of the D programming language
2 // Copyright (c) 1999-2008 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     Type *tv = v->type->toBasetype();
50     while (tv->ty == Tsarray)
51     {   TypeSArray *ta = (TypeSArray *)tv;
52         tv = tv->nextOf()->toBasetype();
53     }
54     if (tv->ty == Tstruct)
55     {   TypeStruct *ts = (TypeStruct *)tv;
56         StructDeclaration *sd = ts->sym;
57         if (sd->needOpAssign())
58         goto Lneed;
59     }
60     }
61 Ldontneed:
62     if (X) printf("\tdontneed\n");
63     return 0;
64
65 Lneed:
66     if (X) printf("\tneed\n");
67     return 1;
68 #undef X
69 }
70
71 /******************************************
72  * Build opAssign for struct.
73  *  S* opAssign(S s) { ... }
74  */
75
76 FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
77 {
78     if (!needOpAssign())
79     return NULL;
80
81     //printf("StructDeclaration::buildOpAssign() %s\n", toChars());
82
83     FuncDeclaration *fop = NULL;
84
85     Argument *param = new Argument(STCnodtor, type, Id::p, NULL);
86     Arguments *fparams = new Arguments;
87     fparams->push(param);
88     Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd);
89
90     fop = new FuncDeclaration(0, 0, Id::assign, STCundefined, ftype);
91
92     Expression *e = NULL;
93     if (postblit)
94     {   /* Swap:
95      *    tmp = *this; *this = s; tmp.dtor();
96      */
97     //printf("\tswap copy\n");
98     Identifier *idtmp = Lexer::uniqueId("__tmp");
99     VarDeclaration *tmp;
100     AssignExp *ec = NULL;
101     if (dtor)
102     {
103         tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0));
104         tmp->noauto = 1;
105         e = new DeclarationExp(0, tmp);
106         ec = new AssignExp(0,
107         new VarExp(0, tmp),
108         new PtrExp(0, new ThisExp(0)));
109         ec->op = TOKblit;
110         e = Expression::combine(e, ec);
111     }
112     ec = new AssignExp(0,
113         new PtrExp(0, new ThisExp(0)),
114         new IdentifierExp(0, Id::p));
115     ec->op = TOKblit;
116     e = Expression::combine(e, ec);
117     if (dtor)
118     {
119         /* Instead of running the destructor on s, run it
120          * on tmp. This avoids needing to copy tmp back in to s.
121          */
122         Expression *ec = new DotVarExp(0, new VarExp(0, tmp), dtor, 0);
123         ec = new CallExp(0, ec);
124         e = Expression::combine(e, ec);
125     }
126     }
127     else
128     {   /* Do memberwise copy
129      */
130     //printf("\tmemberwise copy\n");
131     for (size_t i = 0; i < fields.dim; i++)
132     {
133         Dsymbol *s = (Dsymbol *)fields.data[i];
134         VarDeclaration *v = s->isVarDeclaration();
135         assert(v && v->storage_class & STCfield);
136         // this.v = s.v;
137         AssignExp *ec = new AssignExp(0,
138         new DotVarExp(0, new ThisExp(0), v, 0),
139         new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0));
140         ec->op = TOKblit;
141         e = Expression::combine(e, ec);
142     }
143     }
144     Statement *s1 = new ExpStatement(0, e);
145
146     /* Add:
147      *   return this;
148      */
149     e = new ThisExp(0);
150     Statement *s2 = new ReturnStatement(0, e);
151
152     fop->fbody = new CompoundStatement(0, s1, s2);
153
154     members->push(fop);
155     fop->addMember(sc, this, 1);
156
157     sc = sc->push();
158     sc->stc = 0;
159     sc->linkage = LINKd;
160
161     fop->semantic(sc);
162
163     sc->pop();
164
165     //printf("-StructDeclaration::buildOpAssign() %s\n", toChars());
166
167     return fop;
168 }
169
170 /*******************************************
171  * Build copy constructor for struct.
172  * Copy constructors are compiler generated only, and are only
173  * callable from the compiler. They are not user accessible.
174  * A copy constructor is:
175  *    void cpctpr(ref S s)
176  *    {
177  *  *this = s;
178  *  this.postBlit();
179  *    }
180  * This is done so:
181  *  - postBlit() never sees uninitialized data
182  *  - memcpy can be much more efficient than memberwise copy
183  *  - no fields are overlooked
184  */
185
186 FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
187 {
188     //printf("StructDeclaration::buildCpCtor() %s\n", toChars());
189     FuncDeclaration *fcp = NULL;
190
191     /* Copy constructor is only necessary if there is a postblit function,
192      * otherwise the code generator will just do a bit copy.
193      */
194     if (postblit)
195     {
196     //printf("generating cpctor\n");
197
198     Argument *param = new Argument(STCref, type, Id::p, NULL);
199     Arguments *fparams = new Arguments;
200     fparams->push(param);
201     Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd);
202
203     fcp = new FuncDeclaration(0, 0, Id::cpctor, STCundefined, ftype);
204
205     // Build *this = p;
206     Expression *e = new ThisExp(0);
207     e = new PtrExp(0, e);
208     AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p));
209     ea->op = TOKblit;
210     Statement *s = new ExpStatement(0, ea);
211
212     // Build postBlit();
213     e = new VarExp(0, postblit, 0);
214     e = new CallExp(0, e);
215
216     s = new CompoundStatement(0, s, new ExpStatement(0, e));
217     fcp->fbody = s;
218
219     members->push(fcp);
220
221     sc = sc->push();
222     sc->stc = 0;
223     sc->linkage = LINKd;
224
225     fcp->semantic(sc);
226
227     sc->pop();
228     }
229
230     return fcp;
231 }
232
233 /*****************************************
234  * Create inclusive postblit for struct by aggregating
235  * all the postblits in postblits[] with the postblits for
236  * all the members.
237  * Note the close similarity with AggregateDeclaration::buildDtor(),
238  * and the ordering changes (runs forward instead of backwards).
239  */
240
241 #if V2
242 FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
243 {
244     //printf("StructDeclaration::buildPostBlit() %s\n", toChars());
245     Expression *e = NULL;
246
247     for (size_t i = 0; i < fields.dim; i++)
248     {
249     Dsymbol *s = (Dsymbol *)fields.data[i];
250     VarDeclaration *v = s->isVarDeclaration();
251     assert(v && v->storage_class & STCfield);
252     Type *tv = v->type->toBasetype();
253     size_t dim = 1;
254     while (tv->ty == Tsarray)
255     {   TypeSArray *ta = (TypeSArray *)tv;
256         dim *= ((TypeSArray *)tv)->dim->toInteger();
257         tv = tv->nextOf()->toBasetype();
258     }
259     if (tv->ty == Tstruct)
260     {   TypeStruct *ts = (TypeStruct *)tv;
261         StructDeclaration *sd = ts->sym;
262         if (sd->postblit)
263         {   Expression *ex;
264
265         // this.v
266         ex = new ThisExp(0);
267         ex = new DotVarExp(0, ex, v, 0);
268
269         if (dim == 1)
270         {   // this.v.dtor()
271             ex = new DotVarExp(0, ex, sd->postblit, 0);
272             ex = new CallExp(0, ex);
273         }
274         else
275         {
276             // Typeinfo.postblit(cast(void*)&this.v);
277             Expression *ea = new AddrExp(0, ex);
278             ea = new CastExp(0, ea, Type::tvoid->pointerTo());
279
280             Expression *et = v->type->getTypeInfo(sc);
281             et = new DotIdExp(0, et, Id::postblit);
282
283             ex = new CallExp(0, et, ea);
284         }
285         e = Expression::combine(e, ex); // combine in forward order
286         }
287     }
288     }
289
290     /* Build our own "postblit" which executes e
291      */
292     if (e)
293     {   //printf("Building __fieldPostBlit()\n");
294     PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__fieldPostBlit"));
295     dd->fbody = new ExpStatement(0, e);
296     dtors.push(dd);
297     members->push(dd);
298     dd->semantic(sc);
299     }
300
301     switch (postblits.dim)
302     {
303     case 0:
304         return NULL;
305
306     case 1:
307         return (FuncDeclaration *)postblits.data[0];
308
309     default:
310         e = NULL;
311         for (size_t i = 0; i < postblits.dim; i++)
312         {   FuncDeclaration *fd = (FuncDeclaration *)postblits.data[i];
313         Expression *ex = new ThisExp(0);
314         ex = new DotVarExp(0, ex, fd, 0);
315         ex = new CallExp(0, ex);
316         e = Expression::combine(e, ex);
317         }
318         PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__aggrPostBlit"));
319         dd->fbody = new ExpStatement(0, e);
320         members->push(dd);
321         dd->semantic(sc);
322         return dd;
323     }
324 }
325
326 #endif
327
328 /*****************************************
329  * Create inclusive destructor for struct/class by aggregating
330  * all the destructors in dtors[] with the destructors for
331  * all the members.
332  * Note the close similarity with StructDeclaration::buildPostBlit(),
333  * and the ordering changes (runs backward instead of forwards).
334  */
335
336 FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc)
337 {
338     //printf("AggregateDeclaration::buildDtor() %s\n", toChars());
339     Expression *e = NULL;
340
341 #if V2
342     for (size_t i = 0; i < fields.dim; i++)
343     {
344     Dsymbol *s = (Dsymbol *)fields.data[i];
345     VarDeclaration *v = s->isVarDeclaration();
346     assert(v && v->storage_class & STCfield);
347     Type *tv = v->type->toBasetype();
348     size_t dim = 1;
349     while (tv->ty == Tsarray)
350     {   TypeSArray *ta = (TypeSArray *)tv;
351         dim *= ((TypeSArray *)tv)->dim->toInteger();
352         tv = tv->nextOf()->toBasetype();
353     }
354     if (tv->ty == Tstruct)
355     {   TypeStruct *ts = (TypeStruct *)tv;
356         StructDeclaration *sd = ts->sym;
357         if (sd->dtor)
358         {   Expression *ex;
359
360         // this.v
361         ex = new ThisExp(0);
362         ex = new DotVarExp(0, ex, v, 0);
363
364         if (dim == 1)
365         {   // this.v.dtor()
366             ex = new DotVarExp(0, ex, sd->dtor, 0);
367             ex = new CallExp(0, ex);
368         }
369         else
370         {
371             // Typeinfo.destroy(cast(void*)&this.v);
372             Expression *ea = new AddrExp(0, ex);
373             ea = new CastExp(0, ea, Type::tvoid->pointerTo());
374
375             Expression *et = v->type->getTypeInfo(sc);
376             et = new DotIdExp(0, et, Id::destroy);
377
378             ex = new CallExp(0, et, ea);
379         }
380         e = Expression::combine(ex, e); // combine in reverse order
381         }
382     }
383     }
384
385     /* Build our own "destructor" which executes e
386      */
387     if (e)
388     {   //printf("Building __fieldDtor()\n");
389     DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__fieldDtor"));
390     dd->fbody = new ExpStatement(0, e);
391     dtors.shift(dd);
392     members->push(dd);
393     dd->semantic(sc);
394     }
395 #endif
396
397     switch (dtors.dim)
398     {
399     case 0:
400         return NULL;
401
402     case 1:
403         return (FuncDeclaration *)dtors.data[0];
404
405     default:
406         e = NULL;
407         for (size_t i = 0; i < dtors.dim; i++)
408         {   FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i];
409         Expression *ex = new ThisExp(0);
410         ex = new DotVarExp(0, ex, fd, 0);
411         ex = new CallExp(0, ex);
412         e = Expression::combine(ex, e);
413         }
414         DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor"));
415         dd->fbody = new ExpStatement(0, e);
416         members->push(dd);
417         dd->semantic(sc);
418         return dd;
419     }
420 }
Note: See TracBrowser for help on using the browser.