Mercurial > projects > ldc
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 |