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