1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _denum.d) 9 */ 10 11 module ddmd.denum; 12 13 import core.stdc.stdio; 14 import ddmd.gluelayer; 15 import ddmd.declaration; 16 import ddmd.dmodule; 17 import ddmd.dscope; 18 import ddmd.dsymbol; 19 import ddmd.errors; 20 import ddmd.expression; 21 import ddmd.globals; 22 import ddmd.id; 23 import ddmd.identifier; 24 import ddmd.init; 25 import ddmd.mtype; 26 import ddmd.tokens; 27 import ddmd.visitor; 28 29 /*********************************************************** 30 */ 31 extern (C++) final class EnumDeclaration : ScopeDsymbol 32 { 33 /* The separate, and distinct, cases are: 34 * 1. enum { ... } 35 * 2. enum : memtype { ... } 36 * 3. enum id { ... } 37 * 4. enum id : memtype { ... } 38 * 5. enum id : memtype; 39 * 6. enum id; 40 */ 41 Type type; // the TypeEnum 42 Type memtype; // type of the members 43 Prot protection; 44 Expression maxval; 45 Expression minval; 46 Expression defaultval; // default initializer 47 bool isdeprecated; 48 bool added; 49 int inuse; 50 51 extern (D) this(Loc loc, Identifier id, Type memtype) 52 { 53 super(id); 54 //printf("EnumDeclaration() %s\n", toChars()); 55 this.loc = loc; 56 type = new TypeEnum(this); 57 this.memtype = memtype; 58 protection = Prot(PROTundefined); 59 } 60 61 override Dsymbol syntaxCopy(Dsymbol s) 62 { 63 assert(!s); 64 auto ed = new EnumDeclaration(loc, ident, memtype ? memtype.syntaxCopy() : null); 65 return ScopeDsymbol.syntaxCopy(ed); 66 } 67 68 override void addMember(Scope* sc, ScopeDsymbol sds) 69 { 70 version (none) 71 { 72 printf("EnumDeclaration::addMember() %s\n", toChars()); 73 for (size_t i = 0; i < members.dim; i++) 74 { 75 EnumMember em = (*members)[i].isEnumMember(); 76 printf(" member %s\n", em.toChars()); 77 } 78 } 79 80 /* Anonymous enum members get added to enclosing scope. 81 */ 82 ScopeDsymbol scopesym = isAnonymous() ? sds : this; 83 84 if (!isAnonymous()) 85 { 86 ScopeDsymbol.addMember(sc, sds); 87 if (!symtab) 88 symtab = new DsymbolTable(); 89 } 90 91 if (members) 92 { 93 for (size_t i = 0; i < members.dim; i++) 94 { 95 EnumMember em = (*members)[i].isEnumMember(); 96 em.ed = this; 97 //printf("add %s to scope %s\n", em->toChars(), scopesym->toChars()); 98 em.addMember(sc, isAnonymous() ? scopesym : this); 99 } 100 } 101 added = true; 102 } 103 104 override void setScope(Scope* sc) 105 { 106 if (semanticRun > PASSinit) 107 return; 108 ScopeDsymbol.setScope(sc); 109 } 110 111 override void semantic(Scope* sc) 112 { 113 //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars()); 114 //printf("EnumDeclaration::semantic() %p %s\n", this, toChars()); 115 if (semanticRun >= PASSsemanticdone) 116 return; // semantic() already completed 117 if (semanticRun == PASSsemantic) 118 { 119 assert(memtype); 120 .error(loc, "circular reference to enum base type %s", memtype.toChars()); 121 errors = true; 122 semanticRun = PASSsemanticdone; 123 return; 124 } 125 uint dprogress_save = Module.dprogress; 126 127 Scope* scx = null; 128 if (_scope) 129 { 130 sc = _scope; 131 scx = _scope; // save so we don't make redundant copies 132 _scope = null; 133 } 134 135 parent = sc.parent; 136 type = type.semantic(loc, sc); 137 138 protection = sc.protection; 139 if (sc.stc & STCdeprecated) 140 isdeprecated = true; 141 userAttribDecl = sc.userAttribDecl; 142 143 semanticRun = PASSsemantic; 144 145 if (!members && !memtype) // enum ident; 146 { 147 semanticRun = PASSsemanticdone; 148 return; 149 } 150 151 if (!symtab) 152 symtab = new DsymbolTable(); 153 154 /* The separate, and distinct, cases are: 155 * 1. enum { ... } 156 * 2. enum : memtype { ... } 157 * 3. enum ident { ... } 158 * 4. enum ident : memtype { ... } 159 * 5. enum ident : memtype; 160 * 6. enum ident; 161 */ 162 163 if (memtype) 164 { 165 memtype = memtype.semantic(loc, sc); 166 167 /* Check to see if memtype is forward referenced 168 */ 169 if (memtype.ty == Tenum) 170 { 171 EnumDeclaration sym = cast(EnumDeclaration)memtype.toDsymbol(sc); 172 if (!sym.memtype || !sym.members || !sym.symtab || sym._scope) 173 { 174 // memtype is forward referenced, so try again later 175 _scope = scx ? scx : sc.copy(); 176 _scope.setNoFree(); 177 _scope._module.addDeferredSemantic(this); 178 Module.dprogress = dprogress_save; 179 //printf("\tdeferring %s\n", toChars()); 180 semanticRun = PASSinit; 181 return; 182 } 183 } 184 if (memtype.ty == Tvoid) 185 { 186 error("base type must not be void"); 187 memtype = Type.terror; 188 } 189 if (memtype.ty == Terror) 190 { 191 errors = true; 192 if (members) 193 { 194 for (size_t i = 0; i < members.dim; i++) 195 { 196 Dsymbol s = (*members)[i]; 197 s.errors = true; // poison all the members 198 } 199 } 200 semanticRun = PASSsemanticdone; 201 return; 202 } 203 } 204 205 semanticRun = PASSsemanticdone; 206 207 if (!members) // enum ident : memtype; 208 return; 209 210 if (members.dim == 0) 211 { 212 error("enum %s must have at least one member", toChars()); 213 errors = true; 214 return; 215 } 216 217 Module.dprogress++; 218 219 Scope* sce; 220 if (isAnonymous()) 221 sce = sc; 222 else 223 { 224 sce = sc.push(this); 225 sce.parent = this; 226 } 227 sce = sce.startCTFE(); 228 sce.setNoFree(); // needed for getMaxMinValue() 229 230 /* Each enum member gets the sce scope 231 */ 232 for (size_t i = 0; i < members.dim; i++) 233 { 234 EnumMember em = (*members)[i].isEnumMember(); 235 if (em) 236 em._scope = sce; 237 } 238 239 if (!added) 240 { 241 /* addMember() is not called when the EnumDeclaration appears as a function statement, 242 * so we have to do what addMember() does and install the enum members in the right symbol 243 * table 244 */ 245 ScopeDsymbol scopesym = null; 246 if (isAnonymous()) 247 { 248 /* Anonymous enum members get added to enclosing scope. 249 */ 250 for (Scope* sct = sce; 1; sct = sct.enclosing) 251 { 252 assert(sct); 253 if (sct.scopesym) 254 { 255 scopesym = sct.scopesym; 256 if (!sct.scopesym.symtab) 257 sct.scopesym.symtab = new DsymbolTable(); 258 break; 259 } 260 } 261 } 262 else 263 { 264 // Otherwise enum members are in the EnumDeclaration's symbol table 265 scopesym = this; 266 } 267 268 for (size_t i = 0; i < members.dim; i++) 269 { 270 EnumMember em = (*members)[i].isEnumMember(); 271 if (em) 272 { 273 em.ed = this; 274 em.addMember(sc, scopesym); 275 } 276 } 277 } 278 279 for (size_t i = 0; i < members.dim; i++) 280 { 281 EnumMember em = (*members)[i].isEnumMember(); 282 if (em) 283 em.semantic(em._scope); 284 } 285 //printf("defaultval = %lld\n", defaultval); 286 287 //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars()); 288 //printf("members = %s\n", members->toChars()); 289 } 290 291 override bool oneMember(Dsymbol* ps, Identifier ident) 292 { 293 if (isAnonymous()) 294 return Dsymbol.oneMembers(members, ps, ident); 295 return Dsymbol.oneMember(ps, ident); 296 } 297 298 override Type getType() 299 { 300 return type; 301 } 302 303 override const(char)* kind() const 304 { 305 return "enum"; 306 } 307 308 override Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) 309 { 310 //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars()); 311 if (_scope) 312 { 313 // Try one last time to resolve this enum 314 semantic(_scope); 315 } 316 317 if (!members || !symtab || _scope) 318 { 319 error("is forward referenced when looking for '%s'", ident.toChars()); 320 //*(char*)0=0; 321 return null; 322 } 323 324 Dsymbol s = ScopeDsymbol.search(loc, ident, flags); 325 return s; 326 } 327 328 // is Dsymbol deprecated? 329 override bool isDeprecated() 330 { 331 return isdeprecated; 332 } 333 334 override Prot prot() 335 { 336 return protection; 337 } 338 339 /****************************** 340 * Get the value of the .max/.min property as an Expression. 341 * Lazily computes the value and caches it in maxval/minval. 342 * Reports any errors. 343 * Params: 344 * loc = location to use for error messages 345 * id = Id::max or Id::min 346 * Returns: 347 * corresponding value of .max/.min 348 */ 349 Expression getMaxMinValue(Loc loc, Identifier id) 350 { 351 //printf("EnumDeclaration::getMaxValue()\n"); 352 bool first = true; 353 354 Expression* pval = (id == Id.max) ? &maxval : &minval; 355 356 Expression errorReturn() 357 { 358 *pval = new ErrorExp(); 359 return *pval; 360 } 361 362 if (inuse) 363 { 364 error(loc, "recursive definition of .%s property", id.toChars()); 365 return errorReturn(); 366 } 367 if (*pval) 368 goto Ldone; 369 370 if (_scope) 371 semantic(_scope); 372 if (errors) 373 return errorReturn(); 374 if (semanticRun == PASSinit || !members) 375 { 376 error("is forward referenced looking for .%s", id.toChars()); 377 return errorReturn(); 378 } 379 if (!(memtype && memtype.isintegral())) 380 { 381 error(loc, "has no .%s property because base type %s is not an integral type", id.toChars(), memtype ? memtype.toChars() : ""); 382 return errorReturn(); 383 } 384 385 for (size_t i = 0; i < members.dim; i++) 386 { 387 EnumMember em = (*members)[i].isEnumMember(); 388 if (!em) 389 continue; 390 if (em.errors) 391 return errorReturn(); 392 393 Expression e = em.value; 394 if (first) 395 { 396 *pval = e; 397 first = false; 398 } 399 else 400 { 401 /* In order to work successfully with UDTs, 402 * build expressions to do the comparisons, 403 * and let the semantic analyzer and constant 404 * folder give us the result. 405 */ 406 407 /* Compute: 408 * if (e > maxval) 409 * maxval = e; 410 */ 411 Expression ec = new CmpExp(id == Id.max ? TOKgt : TOKlt, em.loc, e, *pval); 412 inuse++; 413 ec = ec.semantic(em._scope); 414 inuse--; 415 ec = ec.ctfeInterpret(); 416 if (ec.toInteger()) 417 *pval = e; 418 } 419 } 420 Ldone: 421 Expression e = *pval; 422 if (e.op != TOKerror) 423 { 424 e = e.copy(); 425 e.loc = loc; 426 } 427 return e; 428 } 429 430 Expression getDefaultValue(Loc loc) 431 { 432 //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars()); 433 if (defaultval) 434 return defaultval; 435 436 if (_scope) 437 semantic(_scope); 438 if (errors) 439 goto Lerrors; 440 if (semanticRun == PASSinit || !members) 441 { 442 error(loc, "forward reference of %s.init", toChars()); 443 goto Lerrors; 444 } 445 446 for (size_t i = 0; i < members.dim; i++) 447 { 448 EnumMember em = (*members)[i].isEnumMember(); 449 if (!em) 450 continue; 451 defaultval = em.value; 452 return defaultval; 453 } 454 455 Lerrors: 456 defaultval = new ErrorExp(); 457 return defaultval; 458 } 459 460 Type getMemtype(Loc loc) 461 { 462 if (loc.linnum == 0) 463 loc = this.loc; 464 if (_scope) 465 { 466 /* Enum is forward referenced. We don't need to resolve the whole thing, 467 * just the base type 468 */ 469 if (memtype) 470 memtype = memtype.semantic(loc, _scope); 471 else 472 { 473 if (!isAnonymous() && members) 474 memtype = Type.tint32; 475 } 476 } 477 if (!memtype) 478 { 479 if (!isAnonymous() && members) 480 memtype = Type.tint32; 481 else 482 { 483 error(loc, "is forward referenced looking for base type"); 484 return Type.terror; 485 } 486 } 487 return memtype; 488 } 489 490 override inout(EnumDeclaration) isEnumDeclaration() inout 491 { 492 return this; 493 } 494 495 Symbol* sinit; 496 497 override void accept(Visitor v) 498 { 499 v.visit(this); 500 } 501 } 502 503 /*********************************************************** 504 */ 505 extern (C++) final class EnumMember : VarDeclaration 506 { 507 /* Can take the following forms: 508 * 1. id 509 * 2. id = value 510 * 3. type id = value 511 */ 512 @property ref value() { return (cast(ExpInitializer)_init).exp; } 513 514 // A cast() is injected to 'value' after semantic(), 515 // but 'origValue' will preserve the original value, 516 // or previous value + 1 if none was specified. 517 Expression origValue; 518 519 Type origType; 520 521 EnumDeclaration ed; 522 523 extern (D) this(Loc loc, Identifier id, Expression value, Type origType) 524 { 525 super(loc, null, id ? id : Id.empty, new ExpInitializer(loc, value)); 526 this.origValue = value; 527 this.origType = origType; 528 } 529 530 override Dsymbol syntaxCopy(Dsymbol s) 531 { 532 assert(!s); 533 return new EnumMember(loc, ident, value ? value.syntaxCopy() : null, origType ? origType.syntaxCopy() : null); 534 } 535 536 override const(char)* kind() const 537 { 538 return "enum member"; 539 } 540 541 override void semantic(Scope* sc) 542 { 543 //printf("EnumMember::semantic() %s\n", toChars()); 544 545 void errorReturn() 546 { 547 errors = true; 548 semanticRun = PASSsemanticdone; 549 } 550 551 if (errors || semanticRun >= PASSsemanticdone) 552 return; 553 if (semanticRun == PASSsemantic) 554 { 555 error("circular reference to enum member"); 556 return errorReturn(); 557 } 558 assert(ed); 559 ed.semantic(sc); 560 if (ed.errors) 561 return errorReturn(); 562 if (errors || semanticRun >= PASSsemanticdone) 563 return; 564 565 if (_scope) 566 sc = _scope; 567 568 protection = ed.isAnonymous() ? ed.protection : Prot(PROTpublic); 569 linkage = LINKd; 570 storage_class = STCmanifest; 571 userAttribDecl = ed.isAnonymous() ? ed.userAttribDecl : null; 572 573 semanticRun = PASSsemantic; 574 575 // The first enum member is special 576 bool first = (this == (*ed.members)[0]); 577 578 if (origType) 579 { 580 origType = origType.semantic(loc, sc); 581 type = origType; 582 assert(value); // "type id;" is not a valid enum member declaration 583 } 584 585 if (value) 586 { 587 Expression e = value; 588 assert(e.dyncast() == DYNCAST_EXPRESSION); 589 e = e.semantic(sc); 590 e = resolveProperties(sc, e); 591 e = e.ctfeInterpret(); 592 if (e.op == TOKerror) 593 return errorReturn(); 594 if (first && !ed.memtype && !ed.isAnonymous()) 595 { 596 ed.memtype = e.type; 597 if (ed.memtype.ty == Terror) 598 { 599 ed.errors = true; 600 return errorReturn(); 601 } 602 if (ed.memtype.ty != Terror) 603 { 604 /* Bugzilla 11746: All of named enum members should have same type 605 * with the first member. If the following members were referenced 606 * during the first member semantic, their types should be unified. 607 */ 608 for (size_t i = 0; i < ed.members.dim; i++) 609 { 610 EnumMember em = (*ed.members)[i].isEnumMember(); 611 if (!em || em == this || em.semanticRun < PASSsemanticdone || em.origType) 612 continue; 613 614 //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun); 615 Expression ev = em.value; 616 ev = ev.implicitCastTo(sc, ed.memtype); 617 ev = ev.ctfeInterpret(); 618 ev = ev.castTo(sc, ed.type); 619 if (ev.op == TOKerror) 620 ed.errors = true; 621 em.value = ev; 622 } 623 if (ed.errors) 624 { 625 ed.memtype = Type.terror; 626 return errorReturn(); 627 } 628 } 629 } 630 631 if (ed.memtype && !origType) 632 { 633 e = e.implicitCastTo(sc, ed.memtype); 634 e = e.ctfeInterpret(); 635 636 // save origValue for better json output 637 origValue = e; 638 639 if (!ed.isAnonymous()) 640 { 641 e = e.castTo(sc, ed.type); 642 e = e.ctfeInterpret(); 643 } 644 } 645 else if (origType) 646 { 647 e = e.implicitCastTo(sc, origType); 648 e = e.ctfeInterpret(); 649 assert(ed.isAnonymous()); 650 651 // save origValue for better json output 652 origValue = e; 653 } 654 value = e; 655 } 656 else if (first) 657 { 658 Type t; 659 if (ed.memtype) 660 t = ed.memtype; 661 else 662 { 663 t = Type.tint32; 664 if (!ed.isAnonymous()) 665 ed.memtype = t; 666 } 667 Expression e = new IntegerExp(loc, 0, Type.tint32); 668 e = e.implicitCastTo(sc, t); 669 e = e.ctfeInterpret(); 670 671 // save origValue for better json output 672 origValue = e; 673 674 if (!ed.isAnonymous()) 675 { 676 e = e.castTo(sc, ed.type); 677 e = e.ctfeInterpret(); 678 } 679 value = e; 680 } 681 else 682 { 683 /* Find the previous enum member, 684 * and set this to be the previous value + 1 685 */ 686 EnumMember emprev = null; 687 for (size_t i = 0; i < ed.members.dim; i++) 688 { 689 EnumMember em = (*ed.members)[i].isEnumMember(); 690 if (em) 691 { 692 if (em == this) 693 break; 694 emprev = em; 695 } 696 } 697 assert(emprev); 698 if (emprev.semanticRun < PASSsemanticdone) // if forward reference 699 emprev.semantic(emprev._scope); // resolve it 700 if (emprev.errors) 701 return errorReturn(); 702 703 Expression eprev = emprev.value; 704 Type tprev = eprev.type.equals(ed.type) ? ed.memtype : eprev.type; 705 706 Expression emax = tprev.getProperty(ed.loc, Id.max, 0); 707 emax = emax.semantic(sc); 708 emax = emax.ctfeInterpret(); 709 710 // Set value to (eprev + 1). 711 // But first check that (eprev != emax) 712 assert(eprev); 713 Expression e = new EqualExp(TOKequal, loc, eprev, emax); 714 e = e.semantic(sc); 715 e = e.ctfeInterpret(); 716 if (e.toInteger()) 717 { 718 error("initialization with (%s.%s + 1) causes overflow for type '%s'", 719 emprev.ed.toChars(), emprev.toChars(), ed.memtype.toChars()); 720 return errorReturn(); 721 } 722 723 // Now set e to (eprev + 1) 724 e = new AddExp(loc, eprev, new IntegerExp(loc, 1, Type.tint32)); 725 e = e.semantic(sc); 726 e = e.castTo(sc, eprev.type); 727 e = e.ctfeInterpret(); 728 729 // save origValue (without cast) for better json output 730 if (e.op != TOKerror) // avoid duplicate diagnostics 731 { 732 assert(emprev.origValue); 733 origValue = new AddExp(loc, emprev.origValue, new IntegerExp(loc, 1, Type.tint32)); 734 origValue = origValue.semantic(sc); 735 origValue = origValue.ctfeInterpret(); 736 } 737 738 if (e.op == TOKerror) 739 return errorReturn(); 740 if (e.type.isfloating()) 741 { 742 // Check that e != eprev (not always true for floats) 743 Expression etest = new EqualExp(TOKequal, loc, e, eprev); 744 etest = etest.semantic(sc); 745 etest = etest.ctfeInterpret(); 746 if (etest.toInteger()) 747 { 748 error("has inexact value, due to loss of precision"); 749 return errorReturn(); 750 } 751 } 752 value = e; 753 } 754 if (!origType) 755 type = value.type; 756 757 assert(origValue); 758 semanticRun = PASSsemanticdone; 759 } 760 761 Expression getVarExp(Loc loc, Scope* sc) 762 { 763 semantic(sc); 764 if (errors) 765 return new ErrorExp(); 766 Expression e = new VarExp(loc, this); 767 return e.semantic(sc); 768 } 769 770 override inout(EnumMember) isEnumMember() inout 771 { 772 return this; 773 } 774 775 override void accept(Visitor v) 776 { 777 v.visit(this); 778 } 779 }