Allow returning something of type void in a function that returns void
[delight/core.git] / dmd2 / clone.c
blob4bb53b299021c02888d74311d4afaf23197cec3b
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.
11 #include <stdio.h>
12 #include <assert.h>
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"
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.
32 int StructDeclaration::needOpAssign()
34 #define X 0
35 if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars());
36 if (hasIdentityAssign)
37 goto Ldontneed;
39 if (dtor || postblit)
40 goto Lneed;
42 /* If any of the fields need an opAssign, then we
43 * need it too.
45 for (size_t i = 0; i < fields.dim; i++)
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();
55 if (tv->ty == Tstruct)
56 { TypeStruct *ts = (TypeStruct *)tv;
57 StructDeclaration *sd = ts->sym;
58 if (sd->needOpAssign())
59 goto Lneed;
62 Ldontneed:
63 if (X) printf("\tdontneed\n");
64 return 0;
66 Lneed:
67 if (X) printf("\tneed\n");
68 return 1;
69 #undef X
72 /******************************************
73 * Build opAssign for struct.
74 * S* opAssign(S s) { ... }
77 FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
79 if (!needOpAssign())
80 return NULL;
82 //printf("StructDeclaration::buildOpAssign() %s\n", toChars());
84 FuncDeclaration *fop = NULL;
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);
91 fop = new FuncDeclaration(0, 0, Id::assign, STCundefined, ftype);
93 Expression *e = NULL;
94 if (postblit)
95 { /* Swap:
96 * tmp = *this; *this = s; tmp.dtor();
98 //printf("\tswap copy\n");
99 Identifier *idtmp = Lexer::uniqueId("__tmp");
100 VarDeclaration *tmp;
101 AssignExp *ec = NULL;
102 if (dtor)
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);
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)
120 /* Instead of running the destructor on s, run it
121 * on tmp. This avoids needing to copy tmp back in to s.
123 Expression *ec = new DotVarExp(0, new VarExp(0, tmp), dtor, 0);
124 ec = new CallExp(0, ec);
125 e = Expression::combine(e, ec);
128 else
129 { /* Do memberwise copy
131 //printf("\tmemberwise copy\n");
132 for (size_t i = 0; i < fields.dim; i++)
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);
145 Statement *s1 = new ExpStatement(0, e);
147 /* Add:
148 * return this;
150 e = new ThisExp(0);
151 Statement *s2 = new ReturnStatement(0, e);
153 fop->fbody = new CompoundStatement(0, s1, s2);
155 members->push(fop);
156 fop->addMember(sc, this, 1);
158 sc = sc->push();
159 sc->stc = 0;
160 sc->linkage = LINKd;
162 fop->semantic(sc);
164 sc->pop();
166 //printf("-StructDeclaration::buildOpAssign() %s\n", toChars());
168 return fop;
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)
178 * *this = s;
179 * this.postBlit();
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
187 FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
189 //printf("StructDeclaration::buildCpCtor() %s\n", toChars());
190 FuncDeclaration *fcp = NULL;
192 /* Copy constructor is only necessary if there is a postblit function,
193 * otherwise the code generator will just do a bit copy.
195 if (postblit)
197 //printf("generating cpctor\n");
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);
204 fcp = new FuncDeclaration(0, 0, Id::cpctor, STCundefined, ftype);
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);
213 // Build postBlit();
214 e = new VarExp(0, postblit, 0);
215 e = new CallExp(0, e);
217 s = new CompoundStatement(0, s, new ExpStatement(0, e));
218 fcp->fbody = s;
220 members->push(fcp);
222 sc = sc->push();
223 sc->stc = 0;
224 sc->linkage = LINKd;
226 fcp->semantic(sc);
228 sc->pop();
231 return fcp;
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).
242 #if V2
243 FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
245 //printf("StructDeclaration::buildPostBlit() %s\n", toChars());
246 Expression *e = NULL;
248 for (size_t i = 0; i < fields.dim; i++)
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();
260 if (tv->ty == Tstruct)
261 { TypeStruct *ts = (TypeStruct *)tv;
262 StructDeclaration *sd = ts->sym;
263 if (sd->postblit)
264 { Expression *ex;
266 // this.v
267 ex = new ThisExp(0);
268 ex = new DotVarExp(0, ex, v, 0);
270 if (dim == 1)
271 { // this.v.dtor()
272 ex = new DotVarExp(0, ex, sd->postblit, 0);
273 ex = new CallExp(0, ex);
275 else
277 // Typeinfo.postblit(cast(void*)&this.v);
278 Expression *ea = new AddrExp(0, ex);
279 ea = new CastExp(0, ea, Type::tvoid->pointerTo());
281 Expression *et = v->type->getTypeInfo(sc);
282 et = new DotIdExp(0, et, Id::postblit);
284 ex = new CallExp(0, et, ea);
286 e = Expression::combine(e, ex); // combine in forward order
291 /* Build our own "postblit" which executes e
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);
302 switch (postblits.dim)
304 case 0:
305 return NULL;
307 case 1:
308 return (FuncDeclaration *)postblits.data[0];
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);
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;
327 #endif
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).
337 FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc)
339 //printf("AggregateDeclaration::buildDtor() %s\n", toChars());
340 Expression *e = NULL;
342 #if V2
343 for (size_t i = 0; i < fields.dim; i++)
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();
355 if (tv->ty == Tstruct)
356 { TypeStruct *ts = (TypeStruct *)tv;
357 StructDeclaration *sd = ts->sym;
358 if (sd->dtor)
359 { Expression *ex;
361 // this.v
362 ex = new ThisExp(0);
363 ex = new DotVarExp(0, ex, v, 0);
365 if (dim == 1)
366 { // this.v.dtor()
367 ex = new DotVarExp(0, ex, sd->dtor, 0);
368 ex = new CallExp(0, ex);
370 else
372 // Typeinfo.destroy(cast(void*)&this.v);
373 Expression *ea = new AddrExp(0, ex);
374 ea = new CastExp(0, ea, Type::tvoid->pointerTo());
376 Expression *et = v->type->getTypeInfo(sc);
377 et = new DotIdExp(0, et, Id::destroy);
379 ex = new CallExp(0, et, ea);
381 e = Expression::combine(ex, e); // combine in reverse order
386 /* Build our own "destructor" which executes e
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);
396 #endif
398 switch (dtors.dim)
400 case 0:
401 return NULL;
403 case 1:
404 return (FuncDeclaration *)dtors.data[0];
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);
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;