comparison dmd2/clone.c @ 758:f04dde6e882c

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