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