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: