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