1 // Compiler implementation of the D programming language 2 // Copyright (c) 1999-2016 by Digital Mars 3 // All Rights Reserved 4 // written by Walter Bright 5 // http://www.digitalmars.com 6 // Distributed under the Boost Software License, Version 1.0. 7 // http://www.boost.org/LICENSE_1_0.txt 8 9 module ddmd.dstruct; 10 11 import core.stdc.stdio; 12 import ddmd.aggregate; 13 import ddmd.argtypes; 14 import ddmd.arraytypes; 15 import ddmd.clone; 16 import ddmd.declaration; 17 import ddmd.dmodule; 18 import ddmd.dscope; 19 import ddmd.dsymbol; 20 import ddmd.dtemplate; 21 import ddmd.errors; 22 import ddmd.expression; 23 import ddmd.func; 24 import ddmd.globals; 25 import ddmd.id; 26 import ddmd.identifier; 27 import ddmd.mtype; 28 import ddmd.opover; 29 import ddmd.tokens; 30 import ddmd.typinf; 31 import ddmd.visitor; 32 33 /*************************************** 34 * Search toString member function for TypeInfo_Struct. 35 * string toString(); 36 */ 37 extern (C++) FuncDeclaration search_toString(StructDeclaration sd) 38 { 39 Dsymbol s = search_function(sd, Id.tostring); 40 FuncDeclaration fd = s ? s.isFuncDeclaration() : null; 41 if (fd) 42 { 43 static __gshared TypeFunction tftostring; 44 if (!tftostring) 45 { 46 tftostring = new TypeFunction(null, Type.tstring, 0, LINKd); 47 tftostring = cast(TypeFunction)tftostring.merge(); 48 } 49 fd = fd.overloadExactMatch(tftostring); 50 } 51 return fd; 52 } 53 54 /*************************************** 55 * Request additonal semantic analysis for TypeInfo generation. 56 */ 57 extern (C++) void semanticTypeInfo(Scope* sc, Type t) 58 { 59 extern (C++) final class FullTypeInfoVisitor : Visitor 60 { 61 alias visit = super.visit; 62 public: 63 Scope* sc; 64 65 override void visit(Type t) 66 { 67 Type tb = t.toBasetype(); 68 if (tb != t) 69 tb.accept(this); 70 } 71 72 override void visit(TypeNext t) 73 { 74 if (t.next) 75 t.next.accept(this); 76 } 77 78 override void visit(TypeBasic t) 79 { 80 } 81 82 override void visit(TypeVector t) 83 { 84 t.basetype.accept(this); 85 } 86 87 override void visit(TypeAArray t) 88 { 89 t.index.accept(this); 90 visit(cast(TypeNext)t); 91 } 92 93 override void visit(TypeFunction t) 94 { 95 visit(cast(TypeNext)t); 96 // Currently TypeInfo_Function doesn't store parameter types. 97 } 98 99 override void visit(TypeStruct t) 100 { 101 StructDeclaration sd = t.sym; 102 103 /* Step 1: create TypeInfoDeclaration 104 */ 105 if (!sc) // inline may request TypeInfo. 106 { 107 Scope scx; 108 scx._module = sd.getModule(); 109 getTypeInfoType(t, &scx); 110 sd.requestTypeInfo = true; 111 } 112 else if (!sc.minst) 113 { 114 // don't yet have to generate TypeInfo instance if 115 // the typeid(T) expression exists in speculative scope. 116 } 117 else 118 { 119 getTypeInfoType(t, sc); 120 sd.requestTypeInfo = true; 121 122 // Bugzilla 15149, if the typeid operand type comes from a 123 // result of auto function, it may be yet speculative. 124 unSpeculative(sc, sd); 125 } 126 127 /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later. 128 * This should be done even if typeid(T) exists in speculative scope. 129 * Because it may appear later in non-speculative scope. 130 */ 131 if (!sd.members) 132 return; // opaque struct 133 if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd)) 134 return; // none of TypeInfo-specific members 135 136 // If the struct is in a non-root module, run semantic3 to get 137 // correct symbols for the member function. 138 if (sd.semanticRun >= PASSsemantic3) 139 { 140 // semantic3 is already done 141 } 142 else if (TemplateInstance ti = sd.isInstantiated()) 143 { 144 if (ti.minst && !ti.minst.isRoot()) 145 Module.addDeferredSemantic3(sd); 146 } 147 else 148 { 149 if (sd.inNonRoot()) 150 { 151 //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd->toChars(), sd->inNonRoot()); 152 Module.addDeferredSemantic3(sd); 153 } 154 } 155 } 156 157 override void visit(TypeClass t) 158 { 159 } 160 161 override void visit(TypeTuple t) 162 { 163 if (t.arguments) 164 { 165 for (size_t i = 0; i < t.arguments.dim; i++) 166 { 167 Type tprm = (*t.arguments)[i].type; 168 if (tprm) 169 tprm.accept(this); 170 } 171 } 172 } 173 } 174 175 if (sc) 176 { 177 if (!sc.func) 178 return; 179 if (sc.intypeof) 180 return; 181 if (sc.flags & (SCOPEctfe | SCOPEcompile)) 182 return; 183 } 184 185 scope FullTypeInfoVisitor v = new FullTypeInfoVisitor(); 186 v.sc = sc; 187 t.accept(v); 188 } 189 190 struct StructFlags 191 { 192 alias Type = uint; 193 194 enum Enum : int 195 { 196 hasPointers = 0x1, // NB: should use noPointers as in ClassFlags 197 } 198 199 alias hasPointers = Enum.hasPointers; 200 } 201 202 enum StructPOD : int 203 { 204 ISPODno, // struct is not POD 205 ISPODyes, // struct is POD 206 ISPODfwd, // POD not yet computed 207 } 208 209 alias ISPODno = StructPOD.ISPODno; 210 alias ISPODyes = StructPOD.ISPODyes; 211 alias ISPODfwd = StructPOD.ISPODfwd; 212 213 /*********************************************************** 214 */ 215 extern (C++) class StructDeclaration : AggregateDeclaration 216 { 217 int zeroInit; // !=0 if initialize with 0 fill 218 bool hasIdentityAssign; // true if has identity opAssign 219 bool hasIdentityEquals; // true if has identity opEquals 220 FuncDeclarations postblits; // Array of postblit functions 221 FuncDeclaration postblit; // aggregate postblit 222 223 FuncDeclaration xeq; // TypeInfo_Struct.xopEquals 224 FuncDeclaration xcmp; // TypeInfo_Struct.xopCmp 225 FuncDeclaration xhash; // TypeInfo_Struct.xtoHash 226 extern (C++) static __gshared FuncDeclaration xerreq; // object.xopEquals 227 extern (C++) static __gshared FuncDeclaration xerrcmp; // object.xopCmp 228 229 structalign_t alignment; // alignment applied outside of the struct 230 StructPOD ispod; // if struct is POD 231 232 // For 64 bit Efl function call/return ABI 233 Type arg1type; 234 Type arg2type; 235 236 // Even if struct is defined as non-root symbol, some built-in operations 237 // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo. 238 // For those, today TypeInfo_Struct is generated in COMDAT. 239 bool requestTypeInfo; 240 241 final extern (D) this(Loc loc, Identifier id) 242 { 243 super(loc, id); 244 zeroInit = 0; // assume false until we do semantic processing 245 ispod = ISPODfwd; 246 // For forward references 247 type = new TypeStruct(this); 248 if (id == Id.ModuleInfo && !Module.moduleinfo) 249 Module.moduleinfo = this; 250 } 251 252 override Dsymbol syntaxCopy(Dsymbol s) 253 { 254 StructDeclaration sd = 255 s ? cast(StructDeclaration)s 256 : new StructDeclaration(loc, ident); 257 return ScopeDsymbol.syntaxCopy(sd); 258 } 259 260 override final void semantic(Scope* sc) 261 { 262 //printf("StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, toPrettyChars(), sizeok); 263 264 //static int count; if (++count == 20) assert(0); 265 266 if (semanticRun >= PASSsemanticdone) 267 return; 268 int errors = global.errors; 269 270 //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, toPrettyChars(), sizeok); 271 Scope* scx = null; 272 if (_scope) 273 { 274 sc = _scope; 275 scx = _scope; // save so we don't make redundant copies 276 _scope = null; 277 } 278 279 if (!parent) 280 { 281 assert(sc.parent && sc.func); 282 parent = sc.parent; 283 } 284 assert(parent && !isAnonymous()); 285 286 if (this.errors) 287 type = Type.terror; 288 type = type.semantic(loc, sc); 289 if (type.ty == Tstruct && (cast(TypeStruct)type).sym != this) 290 { 291 auto ti = (cast(TypeStruct)type).sym.isInstantiated(); 292 if (ti && isError(ti)) 293 (cast(TypeStruct)type).sym = this; 294 } 295 296 // Ungag errors when not speculative 297 Ungag ungag = ungagSpeculative(); 298 299 if (semanticRun == PASSinit) 300 { 301 protection = sc.protection; 302 303 alignment = sc.alignment(); 304 305 storage_class |= sc.stc; 306 if (storage_class & STCdeprecated) 307 isdeprecated = true; 308 if (storage_class & STCabstract) 309 error("structs, unions cannot be abstract"); 310 311 userAttribDecl = sc.userAttribDecl; 312 } 313 else if (symtab && !scx) 314 { 315 semanticRun = PASSsemanticdone; 316 return; 317 } 318 semanticRun = PASSsemantic; 319 320 if (!members) // if opaque declaration 321 { 322 semanticRun = PASSsemanticdone; 323 return; 324 } 325 if (!symtab) 326 { 327 symtab = new DsymbolTable(); 328 329 for (size_t i = 0; i < members.dim; i++) 330 { 331 auto s = (*members)[i]; 332 //printf("adding member '%s' to '%s'\n", s.toChars(), this.toChars()); 333 s.addMember(sc, this); 334 } 335 } 336 337 auto sc2 = newScope(sc); 338 339 /* Set scope so if there are forward references, we still might be able to 340 * resolve individual members like enums. 341 */ 342 for (size_t i = 0; i < members.dim; i++) 343 { 344 auto s = (*members)[i]; 345 //printf("struct: setScope %s %s\n", s.kind(), s.toChars()); 346 s.setScope(sc2); 347 } 348 349 for (size_t i = 0; i < members.dim; i++) 350 { 351 auto s = (*members)[i]; 352 s.importAll(sc2); 353 } 354 355 for (size_t i = 0; i < members.dim; i++) 356 { 357 auto s = (*members)[i]; 358 s.semantic(sc2); 359 } 360 361 if (!determineFields()) 362 { 363 assert(type.ty == Terror); 364 sc2.pop(); 365 return; 366 } 367 /* Following special member functions creation needs semantic analysis 368 * completion of sub-structs in each field types. For example, buildDtor 369 * needs to check existence of elaborate dtor in type of each fields. 370 * See the case in compilable/test14838.d 371 */ 372 foreach (v; fields) 373 { 374 Type tb = v.type.baseElemOf(); 375 if (tb.ty != Tstruct) 376 continue; 377 auto sd = (cast(TypeStruct)tb).sym; 378 if (sd.semanticRun >= PASSsemanticdone) 379 continue; 380 381 sc2.pop(); 382 383 _scope = scx ? scx : sc.copy(); 384 _scope.setNoFree(); 385 _scope._module.addDeferredSemantic(this); 386 //printf("\tdeferring %s\n", toChars()); 387 return; 388 } 389 390 /* Look for special member functions. 391 */ 392 aggNew = cast(NewDeclaration)search(Loc(), Id.classNew); 393 aggDelete = cast(DeleteDeclaration)search(Loc(), Id.classDelete); 394 395 // Look for the constructor 396 ctor = searchCtor(); 397 398 dtor = buildDtor(this, sc2); 399 postblit = buildPostBlit(this, sc2); 400 401 buildOpAssign(this, sc2); 402 buildOpEquals(this, sc2); 403 404 xeq = buildXopEquals(this, sc2); 405 xcmp = buildXopCmp(this, sc2); 406 xhash = buildXtoHash(this, sc2); 407 408 inv = buildInv(this, sc2); 409 410 Module.dprogress++; 411 semanticRun = PASSsemanticdone; 412 //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); 413 414 sc2.pop(); 415 416 if (ctor) 417 { 418 Dsymbol scall = search(Loc(), Id.call); 419 if (scall) 420 { 421 uint xerrors = global.startGagging(); 422 sc = sc.push(); 423 sc.tinst = null; 424 sc.minst = null; 425 auto fcall = resolveFuncCall(loc, sc, scall, null, null, null, 1); 426 sc = sc.pop(); 427 global.endGagging(xerrors); 428 429 if (fcall && fcall.isStatic()) 430 { 431 error(fcall.loc, "static opCall is hidden by constructors and can never be called"); 432 errorSupplemental(fcall.loc, "Please use a factory method instead, or replace all constructors with static opCall."); 433 } 434 } 435 } 436 437 if (global.errors != errors) 438 { 439 // The type is no good. 440 type = Type.terror; 441 this.errors = true; 442 if (deferred) 443 deferred.errors = true; 444 } 445 446 if (deferred && !global.gag) 447 { 448 deferred.semantic2(sc); 449 deferred.semantic3(sc); 450 } 451 452 version (none) 453 { 454 if (type.ty == Tstruct && (cast(TypeStruct)type).sym != this) 455 { 456 printf("this = %p %s\n", this, this.toChars()); 457 printf("type = %d sym = %p\n", type.ty, (cast(TypeStruct)type).sym); 458 } 459 } 460 assert(type.ty != Tstruct || (cast(TypeStruct)type).sym == this); 461 } 462 463 final void semanticTypeInfoMembers() 464 { 465 if (xeq && 466 xeq._scope && 467 xeq.semanticRun < PASSsemantic3done) 468 { 469 uint errors = global.startGagging(); 470 xeq.semantic3(xeq._scope); 471 if (global.endGagging(errors)) 472 xeq = xerreq; 473 } 474 475 if (xcmp && 476 xcmp._scope && 477 xcmp.semanticRun < PASSsemantic3done) 478 { 479 uint errors = global.startGagging(); 480 xcmp.semantic3(xcmp._scope); 481 if (global.endGagging(errors)) 482 xcmp = xerrcmp; 483 } 484 485 FuncDeclaration ftostr = search_toString(this); 486 if (ftostr && 487 ftostr._scope && 488 ftostr.semanticRun < PASSsemantic3done) 489 { 490 ftostr.semantic3(ftostr._scope); 491 } 492 493 if (xhash && 494 xhash._scope && 495 xhash.semanticRun < PASSsemantic3done) 496 { 497 xhash.semantic3(xhash._scope); 498 } 499 500 if (postblit && 501 postblit._scope && 502 postblit.semanticRun < PASSsemantic3done) 503 { 504 postblit.semantic3(postblit._scope); 505 } 506 507 if (dtor && 508 dtor._scope && 509 dtor.semanticRun < PASSsemantic3done) 510 { 511 dtor.semantic3(dtor._scope); 512 } 513 } 514 515 override final Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) 516 { 517 //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags); 518 if (_scope && !symtab) 519 semantic(_scope); 520 521 if (!members || !symtab) // opaque or semantic() is not yet called 522 { 523 error("is forward referenced when looking for '%s'", ident.toChars()); 524 return null; 525 } 526 527 return ScopeDsymbol.search(loc, ident, flags); 528 } 529 530 override const(char)* kind() const 531 { 532 return "struct"; 533 } 534 535 override final void finalizeSize() 536 { 537 //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok); 538 assert(sizeok != SIZEOKdone); 539 540 //printf("+StructDeclaration::finalizeSize() %s, fields.dim = %d, sizeok = %d\n", toChars(), fields.dim, sizeok); 541 542 fields.setDim(0); // workaround 543 544 // Set the offsets of the fields and determine the size of the struct 545 uint offset = 0; 546 bool isunion = isUnionDeclaration() !is null; 547 for (size_t i = 0; i < members.dim; i++) 548 { 549 Dsymbol s = (*members)[i]; 550 s.setFieldOffset(this, &offset, isunion); 551 } 552 if (type.ty == Terror) 553 return; 554 555 // 0 sized struct's are set to 1 byte 556 if (structsize == 0) 557 { 558 structsize = 1; 559 alignsize = 1; 560 } 561 562 // Round struct size up to next alignsize boundary. 563 // This will ensure that arrays of structs will get their internals 564 // aligned properly. 565 if (alignment == STRUCTALIGN_DEFAULT) 566 structsize = (structsize + alignsize - 1) & ~(alignsize - 1); 567 else 568 structsize = (structsize + alignment - 1) & ~(alignment - 1); 569 570 sizeok = SIZEOKdone; 571 572 //printf("-StructDeclaration::finalizeSize() %s, fields.dim = %d, structsize = %d\n", toChars(), fields.dim, structsize); 573 574 // Calculate fields[i].overlapped 575 checkOverlappedFields(); 576 577 // Determine if struct is all zeros or not 578 zeroInit = 1; 579 foreach (vd; fields) 580 { 581 if (vd._init) 582 { 583 // Should examine init to see if it is really all 0's 584 zeroInit = 0; 585 break; 586 } 587 else if (!vd.type.isZeroInit(loc)) 588 { 589 zeroInit = 0; 590 break; 591 } 592 } 593 594 auto tt = toArgTypes(type); 595 size_t dim = tt.arguments.dim; 596 if (dim >= 1) 597 { 598 assert(dim <= 2); 599 arg1type = (*tt.arguments)[0].type; 600 if (dim == 2) 601 arg2type = (*tt.arguments)[1].type; 602 } 603 } 604 605 /*************************************** 606 * Fit elements[] to the corresponding type of field[]. 607 * Input: 608 * loc 609 * sc 610 * elements The explicit arguments that given to construct object. 611 * stype The constructed object type. 612 * Returns false if any errors occur. 613 * Otherwise, returns true and elements[] are rewritten for the output. 614 */ 615 final bool fit(Loc loc, Scope* sc, Expressions* elements, Type stype) 616 { 617 if (!elements) 618 return true; 619 620 size_t nfields = fields.dim - isNested(); 621 size_t offset = 0; 622 for (size_t i = 0; i < elements.dim; i++) 623 { 624 Expression e = (*elements)[i]; 625 if (!e) 626 continue; 627 628 e = resolveProperties(sc, e); 629 if (i >= nfields) 630 { 631 if (i == fields.dim - 1 && isNested() && e.op == TOKnull) 632 { 633 // CTFE sometimes creates null as hidden pointer; we'll allow this. 634 continue; 635 } 636 .error(loc, "more initializers than fields (%d) of %s", nfields, toChars()); 637 return false; 638 } 639 VarDeclaration v = fields[i]; 640 if (v.offset < offset) 641 { 642 .error(loc, "overlapping initialization for %s", v.toChars()); 643 return false; 644 } 645 offset = cast(uint)(v.offset + v.type.size()); 646 647 Type t = v.type; 648 if (stype) 649 t = t.addMod(stype.mod); 650 Type origType = t; 651 Type tb = t.toBasetype(); 652 653 /* Look for case of initializing a static array with a too-short 654 * string literal, such as: 655 * char[5] foo = "abc"; 656 * Allow this by doing an explicit cast, which will lengthen the string 657 * literal. 658 */ 659 if (e.op == TOKstring && tb.ty == Tsarray) 660 { 661 StringExp se = cast(StringExp)e; 662 Type typeb = se.type.toBasetype(); 663 TY tynto = tb.nextOf().ty; 664 if (!se.committed && 665 (typeb.ty == Tarray || typeb.ty == Tsarray) && 666 (tynto == Tchar || tynto == Twchar || tynto == Tdchar) && 667 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger()) 668 { 669 e = se.castTo(sc, t); 670 goto L1; 671 } 672 } 673 674 while (!e.implicitConvTo(t) && tb.ty == Tsarray) 675 { 676 /* Static array initialization, as in: 677 * T[3][5] = e; 678 */ 679 t = tb.nextOf(); 680 tb = t.toBasetype(); 681 } 682 if (!e.implicitConvTo(t)) 683 t = origType; // restore type for better diagnostic 684 685 e = e.implicitCastTo(sc, t); 686 L1: 687 if (e.op == TOKerror) 688 return false; 689 690 (*elements)[i] = doCopyOrMove(sc, e); 691 } 692 return true; 693 } 694 695 /*************************************** 696 * Return true if struct is POD (Plain Old Data). 697 * This is defined as: 698 * not nested 699 * no postblits, destructors, or assignment operators 700 * no 'ref' fields or fields that are themselves non-POD 701 * The idea being these are compatible with C structs. 702 */ 703 final bool isPOD() 704 { 705 // If we've already determined whether this struct is POD. 706 if (ispod != ISPODfwd) 707 return (ispod == ISPODyes); 708 709 ispod = ISPODyes; 710 711 if (enclosing || postblit || dtor) 712 ispod = ISPODno; 713 714 // Recursively check all fields are POD. 715 for (size_t i = 0; i < fields.dim; i++) 716 { 717 VarDeclaration v = fields[i]; 718 if (v.storage_class & STCref) 719 { 720 ispod = ISPODno; 721 break; 722 } 723 724 Type tv = v.type.baseElemOf(); 725 if (tv.ty == Tstruct) 726 { 727 TypeStruct ts = cast(TypeStruct)tv; 728 StructDeclaration sd = ts.sym; 729 if (!sd.isPOD()) 730 { 731 ispod = ISPODno; 732 break; 733 } 734 } 735 } 736 737 return (ispod == ISPODyes); 738 } 739 740 override final inout(StructDeclaration) isStructDeclaration() inout 741 { 742 return this; 743 } 744 745 override void accept(Visitor v) 746 { 747 v.visit(this); 748 } 749 } 750 751 /*********************************************************** 752 */ 753 extern (C++) final class UnionDeclaration : StructDeclaration 754 { 755 extern (D) this(Loc loc, Identifier id) 756 { 757 super(loc, id); 758 } 759 760 override Dsymbol syntaxCopy(Dsymbol s) 761 { 762 assert(!s); 763 auto ud = new UnionDeclaration(loc, ident); 764 return StructDeclaration.syntaxCopy(ud); 765 } 766 767 override const(char)* kind() const 768 { 769 return "union"; 770 } 771 772 override inout(UnionDeclaration) isUnionDeclaration() inout 773 { 774 return this; 775 } 776 777 override void accept(Visitor v) 778 { 779 v.visit(this); 780 } 781 }