1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _aggregate.d) 9 */ 10 11 module ddmd.aggregate; 12 13 import core.stdc.stdio; 14 import ddmd.arraytypes; 15 import ddmd.gluelayer; 16 import ddmd.declaration; 17 import ddmd.dscope; 18 import ddmd.dstruct; 19 import ddmd.dsymbol; 20 import ddmd.dtemplate; 21 import ddmd.errors; 22 import ddmd.expression; 23 import ddmd.func; 24 import ddmd.globals; 25 import ddmd.id; 26 import ddmd.identifier; 27 import ddmd.mtype; 28 import ddmd.tokens; 29 import ddmd.visitor; 30 31 enum Sizeok : int 32 { 33 SIZEOKnone, // size of aggregate is not yet able to compute 34 SIZEOKfwd, // size of aggregate is ready to compute 35 SIZEOKdone, // size of aggregate is set correctly 36 } 37 38 alias SIZEOKnone = Sizeok.SIZEOKnone; 39 alias SIZEOKdone = Sizeok.SIZEOKdone; 40 alias SIZEOKfwd = Sizeok.SIZEOKfwd; 41 42 enum Baseok : int 43 { 44 BASEOKnone, // base classes not computed yet 45 BASEOKin, // in process of resolving base classes 46 BASEOKdone, // all base classes are resolved 47 BASEOKsemanticdone, // all base classes semantic done 48 } 49 50 alias BASEOKnone = Baseok.BASEOKnone; 51 alias BASEOKin = Baseok.BASEOKin; 52 alias BASEOKdone = Baseok.BASEOKdone; 53 alias BASEOKsemanticdone = Baseok.BASEOKsemanticdone; 54 55 /*********************************************************** 56 */ 57 extern (C++) abstract class AggregateDeclaration : ScopeDsymbol 58 { 59 Type type; 60 StorageClass storage_class; 61 Prot protection; 62 uint structsize; // size of struct 63 uint alignsize; // size of struct for alignment purposes 64 VarDeclarations fields; // VarDeclaration fields 65 Sizeok sizeok; // set when structsize contains valid data 66 Dsymbol deferred; // any deferred semantic2() or semantic3() symbol 67 bool isdeprecated; // true if deprecated 68 69 /* !=null if is nested 70 * pointing to the dsymbol that directly enclosing it. 71 * 1. The function that enclosing it (nested struct and class) 72 * 2. The class that enclosing it (nested class only) 73 * 3. If enclosing aggregate is template, its enclosing dsymbol. 74 * See AggregateDeclaraton::makeNested for the details. 75 */ 76 Dsymbol enclosing; 77 78 VarDeclaration vthis; // 'this' parameter if this aggregate is nested 79 80 // Special member functions 81 FuncDeclarations invs; // Array of invariants 82 FuncDeclaration inv; // invariant 83 NewDeclaration aggNew; // allocator 84 DeleteDeclaration aggDelete; // deallocator 85 86 // CtorDeclaration or TemplateDeclaration 87 Dsymbol ctor; 88 89 // default constructor - should have no arguments, because 90 // it would be stored in TypeInfo_Class.defaultConstructor 91 CtorDeclaration defaultCtor; 92 93 Dsymbol aliasthis; // forward unresolved lookups to aliasthis 94 bool noDefaultCtor; // no default construction 95 96 FuncDeclarations dtors; // Array of destructors 97 FuncDeclaration dtor; // aggregate destructor 98 99 Expression getRTInfo; // pointer to GC info generated by object.RTInfo(this) 100 101 final extern (D) this(Loc loc, Identifier id) 102 { 103 super(id); 104 this.loc = loc; 105 protection = Prot(PROTpublic); 106 sizeok = SIZEOKnone; // size not determined yet 107 } 108 109 /*************************************** 110 * Create a new scope from sc. 111 * semantic, semantic2 and semantic3 will use this for aggregate members. 112 */ 113 Scope* newScope(Scope* sc) 114 { 115 auto sc2 = sc.push(this); 116 sc2.stc &= STCsafe | STCtrusted | STCsystem; 117 sc2.parent = this; 118 if (isUnionDeclaration()) 119 sc2.inunion = 1; 120 sc2.protection = Prot(PROTpublic); 121 sc2.explicitProtection = 0; 122 sc2.aligndecl = null; 123 sc2.userAttribDecl = null; 124 return sc2; 125 } 126 127 override final void semantic2(Scope* sc) 128 { 129 //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), type.toChars(), errors); 130 if (!members) 131 return; 132 133 if (_scope) 134 { 135 error("has forward references"); 136 return; 137 } 138 139 auto sc2 = newScope(sc); 140 141 determineSize(loc); 142 143 for (size_t i = 0; i < members.dim; i++) 144 { 145 Dsymbol s = (*members)[i]; 146 //printf("\t[%d] %s\n", i, s.toChars()); 147 s.semantic2(sc2); 148 } 149 150 sc2.pop(); 151 } 152 153 override final void semantic3(Scope* sc) 154 { 155 //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", toChars(), type.toChars(), errors); 156 if (!members) 157 return; 158 159 StructDeclaration sd = isStructDeclaration(); 160 if (!sc) // from runDeferredSemantic3 for TypeInfo generation 161 { 162 assert(sd); 163 sd.semanticTypeInfoMembers(); 164 return; 165 } 166 167 auto sc2 = newScope(sc); 168 169 for (size_t i = 0; i < members.dim; i++) 170 { 171 Dsymbol s = (*members)[i]; 172 s.semantic3(sc2); 173 } 174 175 sc2.pop(); 176 177 // don't do it for unused deprecated types 178 // or error types 179 if (!getRTInfo && Type.rtinfo && (!isDeprecated() || global.params.useDeprecated) && (type && type.ty != Terror)) 180 { 181 // Evaluate: RTinfo!type 182 auto tiargs = new Objects(); 183 tiargs.push(type); 184 auto ti = new TemplateInstance(loc, Type.rtinfo, tiargs); 185 186 Scope* sc3 = ti.tempdecl._scope.startCTFE(); 187 sc3.tinst = sc.tinst; 188 sc3.minst = sc.minst; 189 if (isDeprecated()) 190 sc3.stc |= STCdeprecated; 191 192 ti.semantic(sc3); 193 ti.semantic2(sc3); 194 ti.semantic3(sc3); 195 auto e = DsymbolExp.resolve(Loc(), sc3, ti.toAlias(), false); 196 197 sc3.endCTFE(); 198 199 e = e.ctfeInterpret(); 200 getRTInfo = e; 201 } 202 if (sd) 203 sd.semanticTypeInfoMembers(); 204 } 205 206 /*************************************** 207 * Find all instance fields, then push them into `fields`. 208 * 209 * Runs semantic() for all instance field variables, but also 210 * the field types can reamin yet not resolved forward references, 211 * except direct recursive definitions. 212 * After the process sizeok is set to SIZEOKfwd. 213 * 214 * Returns: 215 * false if any errors occur. 216 */ 217 final bool determineFields() 218 { 219 if (sizeok != SIZEOKnone) 220 return true; 221 222 //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim); 223 224 extern (C++) static int func(Dsymbol s, void* param) 225 { 226 auto v = s.isVarDeclaration(); 227 if (!v) 228 return 0; 229 if (v.storage_class & STCmanifest) 230 return 0; 231 232 if (v._scope) 233 v.semantic(null); 234 if (v.aliassym) 235 return 0; // If this variable was really a tuple, skip it. 236 237 if (v.storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCctfe | STCtemplateparameter)) 238 return 0; 239 if (!v.isField() || v.semanticRun < PASSsemanticdone) 240 return 1; // unresolvable forward reference 241 242 auto ad = cast(AggregateDeclaration)param; 243 ad.fields.push(v); 244 245 if (v.storage_class & STCref) 246 return 0; 247 auto tv = v.type.baseElemOf(); 248 if (tv.ty != Tstruct) 249 return 0; 250 if (ad == (cast(TypeStruct)tv).sym) 251 { 252 const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : ""; 253 ad.error("cannot have field %s with %ssame struct type", v.toChars(), psz); 254 ad.type = Type.terror; 255 ad.errors = true; 256 return 1; 257 } 258 return 0; 259 } 260 261 fields.setDim(0); 262 263 for (size_t i = 0; i < members.dim; i++) 264 { 265 auto s = (*members)[i]; 266 if (s.apply(&func, cast(void*)this)) 267 return false; 268 } 269 270 if (sizeok != SIZEOKdone) 271 sizeok = SIZEOKfwd; 272 273 return true; 274 } 275 276 /*************************************** 277 * Collect all instance fields, then determine instance size. 278 * Returns: 279 * false if failed to determine the size. 280 */ 281 final bool determineSize(Loc loc) 282 { 283 //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok); 284 285 // The previous instance size finalizing had: 286 if (type.ty == Terror) 287 return false; // failed already 288 if (sizeok == SIZEOKdone) 289 return true; // succeeded 290 291 if (!members) 292 { 293 error(loc, "unknown size"); 294 return false; 295 } 296 297 if (_scope) 298 semantic(null); 299 300 // Determine the instance size of base class first. 301 if (auto cd = isClassDeclaration()) 302 { 303 cd = cd.baseClass; 304 if (cd && !cd.determineSize(loc)) 305 goto Lfail; 306 } 307 308 // Determine instance fields when sizeok == SIZEOKnone 309 if (!determineFields()) 310 goto Lfail; 311 if (sizeok != SIZEOKdone) 312 finalizeSize(); 313 314 // this aggregate type has: 315 if (type.ty == Terror) 316 return false; // marked as invalid during the finalizing. 317 if (sizeok == SIZEOKdone) 318 return true; // succeeded to calculate instance size. 319 320 Lfail: 321 // There's unresolvable forward reference. 322 if (type != Type.terror) 323 error(loc, "no size because of forward reference"); 324 type = Type.terror; 325 errors = true; 326 return false; 327 } 328 329 abstract void finalizeSize(); 330 331 override final d_uns64 size(Loc loc) 332 { 333 //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok); 334 bool ok = determineSize(loc); 335 //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok); 336 return ok ? structsize : SIZE_INVALID; 337 } 338 339 /*************************************** 340 * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit 341 * field initializers have unique memory space on instance. 342 * Returns: 343 * true if any errors happen. 344 */ 345 final bool checkOverlappedFields() 346 { 347 //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars()); 348 assert(sizeok == SIZEOKdone); 349 size_t nfields = fields.dim; 350 if (isNested()) 351 { 352 auto cd = isClassDeclaration(); 353 if (!cd || !cd.baseClass || !cd.baseClass.isNested()) 354 nfields--; 355 } 356 bool errors = false; 357 358 // Fill in missing any elements with default initializers 359 foreach (i; 0 .. nfields) 360 { 361 auto vd = fields[i]; 362 if (vd.errors) 363 continue; 364 365 auto vx = vd; 366 if (vd._init && vd._init.isVoidInitializer()) 367 vx = null; 368 369 // Find overlapped fields with the hole [vd->offset .. vd->offset->size()]. 370 foreach (j; 0 .. nfields) 371 { 372 if (i == j) 373 continue; 374 auto v2 = fields[j]; 375 if (!vd.isOverlappedWith(v2)) 376 continue; 377 378 // vd and v2 are overlapping. 379 vd.overlapped = true; 380 v2.overlapped = true; 381 382 if (!MODimplicitConv(vd.type.mod, v2.type.mod)) 383 v2.overlapUnsafe = true; 384 if (!MODimplicitConv(v2.type.mod, vd.type.mod)) 385 vd.overlapUnsafe = true; 386 387 if (!vx) 388 continue; 389 if (v2._init && v2._init.isVoidInitializer()) 390 continue; 391 392 if (vx._init && v2._init) 393 { 394 .error(loc, "overlapping default initialization for field %s and %s", v2.toChars(), vd.toChars()); 395 errors = true; 396 } 397 } 398 } 399 return errors; 400 } 401 402 /*************************************** 403 * Fill out remainder of elements[] with default initializers for fields[]. 404 * Params: 405 * loc = location 406 * elements = explicit arguments which given to construct object. 407 * ctorinit = true if the elements will be used for default initialization. 408 * Returns: 409 * false if any errors occur. 410 * Otherwise, returns true and the missing arguments will be pushed in elements[]. 411 */ 412 final bool fill(Loc loc, Expressions* elements, bool ctorinit) 413 { 414 //printf("AggregateDeclaration::fill() %s\n", toChars()); 415 assert(sizeok == SIZEOKdone); 416 assert(elements); 417 size_t nfields = fields.dim - isNested(); 418 bool errors = false; 419 420 size_t dim = elements.dim; 421 elements.setDim(nfields); 422 foreach (size_t i; dim .. nfields) 423 (*elements)[i] = null; 424 425 // Fill in missing any elements with default initializers 426 foreach (i; 0 .. nfields) 427 { 428 if ((*elements)[i]) 429 continue; 430 431 auto vd = fields[i]; 432 auto vx = vd; 433 if (vd._init && vd._init.isVoidInitializer()) 434 vx = null; 435 436 // Find overlapped fields with the hole [vd->offset .. vd->offset->size()]. 437 size_t fieldi = i; 438 foreach (j; 0 .. nfields) 439 { 440 if (i == j) 441 continue; 442 auto v2 = fields[j]; 443 if (!vd.isOverlappedWith(v2)) 444 continue; 445 446 if ((*elements)[j]) 447 { 448 vx = null; 449 break; 450 } 451 if (v2._init && v2._init.isVoidInitializer()) 452 continue; 453 454 version (all) 455 { 456 /* Prefer first found non-void-initialized field 457 * union U { int a; int b = 2; } 458 * U u; // Error: overlapping initialization for field a and b 459 */ 460 if (!vx) 461 { 462 vx = v2; 463 fieldi = j; 464 } 465 else if (v2._init) 466 { 467 .error(loc, "overlapping initialization for field %s and %s", v2.toChars(), vd.toChars()); 468 errors = true; 469 } 470 } 471 else 472 { 473 // Will fix Bugzilla 1432 by enabling this path always 474 475 /* Prefer explicitly initialized field 476 * union U { int a; int b = 2; } 477 * U u; // OK (u.b == 2) 478 */ 479 if (!vx || !vx._init && v2._init) 480 { 481 vx = v2; 482 fieldi = j; 483 } 484 else if (vx != vd && !vx.isOverlappedWith(v2)) 485 { 486 // Both vx and v2 fills vd, but vx and v2 does not overlap 487 } 488 else if (vx._init && v2._init) 489 { 490 .error(loc, "overlapping default initialization for field %s and %s", 491 v2.toChars(), vd.toChars()); 492 errors = true; 493 } 494 else 495 assert(vx._init || !vx._init && !v2._init); 496 } 497 } 498 if (vx) 499 { 500 Expression e; 501 if (vx.type.size() == 0) 502 { 503 e = null; 504 } 505 else if (vx._init) 506 { 507 assert(!vx._init.isVoidInitializer()); 508 e = vx.getConstInitializer(false); 509 } 510 else 511 { 512 if ((vx.storage_class & STCnodefaultctor) && !ctorinit) 513 { 514 .error(loc, "field %s.%s must be initialized because it has no default constructor", 515 type.toChars(), vx.toChars()); 516 errors = true; 517 } 518 /* Bugzilla 12509: Get the element of static array type. 519 */ 520 Type telem = vx.type; 521 if (telem.ty == Tsarray) 522 { 523 /* We cannot use Type::baseElemOf() here. 524 * If the bottom of the Tsarray is an enum type, baseElemOf() 525 * will return the base of the enum, and its default initializer 526 * would be different from the enum's. 527 */ 528 while (telem.toBasetype().ty == Tsarray) 529 telem = (cast(TypeSArray)telem.toBasetype()).next; 530 if (telem.ty == Tvoid) 531 telem = Type.tuns8.addMod(telem.mod); 532 } 533 if (telem.needsNested() && ctorinit) 534 e = telem.defaultInit(loc); 535 else 536 e = telem.defaultInitLiteral(loc); 537 } 538 (*elements)[fieldi] = e; 539 } 540 } 541 foreach (e; *elements) 542 { 543 if (e && e.op == TOKerror) 544 return false; 545 } 546 547 return !errors; 548 } 549 550 /**************************** 551 * Do byte or word alignment as necessary. 552 * Align sizes of 0, as we may not know array sizes yet. 553 * 554 * alignment: struct alignment that is in effect 555 * size: alignment requirement of field 556 */ 557 static void alignmember(structalign_t alignment, uint size, uint* poffset) 558 { 559 //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset); 560 switch (alignment) 561 { 562 case cast(structalign_t)1: 563 // No alignment 564 break; 565 566 case cast(structalign_t)STRUCTALIGN_DEFAULT: 567 // Alignment in Target::fieldalignsize must match what the 568 // corresponding C compiler's default alignment behavior is. 569 assert(size > 0 && !(size & (size - 1))); 570 *poffset = (*poffset + size - 1) & ~(size - 1); 571 break; 572 573 default: 574 // Align on alignment boundary, which must be a positive power of 2 575 assert(alignment > 0 && !(alignment & (alignment - 1))); 576 *poffset = (*poffset + alignment - 1) & ~(alignment - 1); 577 break; 578 } 579 } 580 581 /**************************************** 582 * Place a member (mem) into an aggregate (agg), which can be a struct, union or class 583 * Returns: 584 * offset to place field at 585 * 586 * nextoffset: next location in aggregate 587 * memsize: size of member 588 * memalignsize: size of member for alignment purposes 589 * alignment: alignment in effect for this member 590 * paggsize: size of aggregate (updated) 591 * paggalignsize: size of aggregate for alignment purposes (updated) 592 * isunion: the aggregate is a union 593 */ 594 static uint placeField(uint* nextoffset, uint memsize, uint memalignsize, 595 structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion) 596 { 597 uint ofs = *nextoffset; 598 alignmember(alignment, memalignsize, &ofs); 599 uint memoffset = ofs; 600 ofs += memsize; 601 if (ofs > *paggsize) 602 *paggsize = ofs; 603 if (!isunion) 604 *nextoffset = ofs; 605 606 if (alignment == STRUCTALIGN_DEFAULT) 607 { 608 if (global.params.is64bit && memalignsize == 16) 609 { 610 } 611 else if (8 < memalignsize) 612 memalignsize = 8; 613 } 614 else 615 { 616 if (memalignsize < alignment) 617 memalignsize = alignment; 618 } 619 620 if (*paggalignsize < memalignsize) 621 *paggalignsize = memalignsize; 622 623 return memoffset; 624 } 625 626 override final Type getType() 627 { 628 return type; 629 } 630 631 // is aggregate deprecated? 632 override final bool isDeprecated() 633 { 634 return isdeprecated; 635 } 636 637 /**************************************** 638 * Returns true if there's an extra member which is the 'this' 639 * pointer to the enclosing context (enclosing aggregate or function) 640 */ 641 final bool isNested() 642 { 643 return enclosing !is null; 644 } 645 646 /* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested. 647 */ 648 final void makeNested() 649 { 650 if (enclosing) // if already nested 651 return; 652 if (sizeok == SIZEOKdone) 653 return; 654 if (isUnionDeclaration() || isInterfaceDeclaration()) 655 return; 656 if (storage_class & STCstatic) 657 return; 658 659 // If nested struct, add in hidden 'this' pointer to outer scope 660 auto s = toParent2(); 661 if (!s) 662 return; 663 Type t = null; 664 if (auto fd = s.isFuncDeclaration()) 665 { 666 enclosing = fd; 667 668 /* Bugzilla 14422: If a nested class parent is a function, its 669 * context pointer (== `outer`) should be void* always. 670 */ 671 t = Type.tvoidptr; 672 } 673 else if (auto ad = s.isAggregateDeclaration()) 674 { 675 if (isClassDeclaration() && ad.isClassDeclaration()) 676 { 677 enclosing = ad; 678 } 679 else if (isStructDeclaration()) 680 { 681 if (auto ti = ad.parent.isTemplateInstance()) 682 { 683 enclosing = ti.enclosing; 684 } 685 } 686 t = ad.handleType(); 687 } 688 if (enclosing) 689 { 690 //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars()); 691 assert(t); 692 if (t.ty == Tstruct) 693 t = Type.tvoidptr; // t should not be a ref type 694 695 assert(!vthis); 696 vthis = new ThisDeclaration(loc, t); 697 //vthis->storage_class |= STCref; 698 699 // Emulate vthis.addMember() 700 members.push(vthis); 701 702 // Emulate vthis.semantic() 703 vthis.storage_class |= STCfield; 704 vthis.parent = this; 705 vthis.protection = Prot(PROTpublic); 706 vthis.alignment = t.alignment(); 707 vthis.semanticRun = PASSsemanticdone; 708 709 if (sizeok == SIZEOKfwd) 710 fields.push(vthis); 711 } 712 } 713 714 override final bool isExport() 715 { 716 return protection.kind == PROTexport; 717 } 718 719 /******************************************* 720 * Look for constructor declaration. 721 */ 722 final Dsymbol searchCtor() 723 { 724 auto s = search(Loc(), Id.ctor); 725 if (s) 726 { 727 if (!(s.isCtorDeclaration() || 728 s.isTemplateDeclaration() || 729 s.isOverloadSet())) 730 { 731 s.error("is not a constructor; identifiers starting with __ are reserved for the implementation"); 732 errors = true; 733 s = null; 734 } 735 } 736 if (s && s.toParent() != this) 737 s = null; // search() looks through ancestor classes 738 if (s) 739 { 740 // Finish all constructors semantics to determine this->noDefaultCtor. 741 struct SearchCtor 742 { 743 extern (C++) static int fp(Dsymbol s, void* ctxt) 744 { 745 auto f = s.isCtorDeclaration(); 746 if (f && f.semanticRun == PASSinit) 747 f.semantic(null); 748 return 0; 749 } 750 } 751 752 for (size_t i = 0; i < members.dim; i++) 753 { 754 auto sm = (*members)[i]; 755 sm.apply(&SearchCtor.fp, null); 756 } 757 } 758 return s; 759 } 760 761 override final Prot prot() 762 { 763 return protection; 764 } 765 766 // 'this' type 767 final Type handleType() 768 { 769 return type; 770 } 771 772 // Back end 773 Symbol* stag; // tag symbol for debug data 774 Symbol* sinit; 775 776 override final inout(AggregateDeclaration) isAggregateDeclaration() inout 777 { 778 return this; 779 } 780 781 override void accept(Visitor v) 782 { 783 v.visit(this); 784 } 785 }