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