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