1: 
  2: // Copyright (c) 1999-2010 by Digital Mars
  3: // All Rights Reserved
  4: // written by Walter Bright
  5: // http://www.digitalmars.com
  6: // License for redistribution is by either the Artistic License
  7: // in artistic.txt, or the GNU General Public License in gnu.txt.
  8: // See the included readme.txt for details.
  9: 
 10: #include <stdio.h>
 11: static char __file__[] = __FILE__;      /* for tassert.h                */
 12: #include        "tassert.h"
 13: 
 14: #include "root.h"
 15: #include "enum.h"
 16: #include "mtype.h"
 17: #include "scope.h"
 18: #include "id.h"
 19: #include "expression.h"
 20: #include "module.h"
 21: #include "declaration.h"
 22: 
 23: /********************************* EnumDeclaration ****************************/
 24: 
 25: EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
 26:     : ScopeDsymbol(id)
 27: {
 28:     this->loc = loc;
 29:     type = new TypeEnum(this);
 30:     this->memtype = memtype;
 31:     maxval = NULL;
 32:     minval = NULL;
 33:     defaultval = NULL;
 34:     sinit = NULL;
 35:     isdeprecated = 0;
 36:     isdone = 0;
 37: }
 38: 
 39: Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
 40: {
 41:     Type *t = NULL;
 42:     if (memtype)
 43:         t = memtype->syntaxCopy();
 44: 
 45:     EnumDeclaration *ed;
 46:     if (s)
 47:     {   ed = (EnumDeclaration *)s;
 48:         ed->memtype = t;
 49:     }
 50:     else
 51:         ed = new EnumDeclaration(loc, ident, t);
 52:     ScopeDsymbol::syntaxCopy(ed);
 53:     return ed;
 54: }
 55: 
 56: void EnumDeclaration::semantic0(Scope *sc)
 57: {
 58:     /* This function is a hack to get around a significant problem.
 59:      * The members of anonymous enums, like:
 60:      *  enum { A, B, C }
 61:      * don't get installed into the symbol table until after they are
 62:      * semantically analyzed, yet they're supposed to go into the enclosing
 63:      * scope's table. Hence, when forward referenced, they come out as
 64:      * 'undefined'. The real fix is to add them in at addSymbol() time.
 65:      * But to get code to compile, we'll just do this quick hack at the moment
 66:      * to compile it if it doesn't depend on anything else.
 67:      */
 68: 
 69:     if (isdone || !scope)
 70:         return;
 71:     if (!isAnonymous() || memtype)
 72:         return;
 73:     for (int i = 0; i < members->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
74: { 75: EnumMember *em = (members->tdata()[i])->isEnumMember(); 76: if (em && (em->type || em->value)) 77: return; 78: } 79: 80: // Can do it 81: semantic(sc); 82: } 83: 84: void EnumDeclaration::semantic(Scope *sc) 85: { 86: Type *t; 87: Scope *sce; 88: 89: //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars()); 90: //printf("EnumDeclaration::semantic() %s\n", toChars()); 91: if (!members) // enum ident; 92: return; 93: 94: if (!memtype && !isAnonymous()) 95: { // Set memtype if we can to reduce fwd reference errors 96: memtype = Type::tint32; // case 1) enum ident { ... } 97: } 98: 99: if (symtab) // if already done 100: { if (isdone || !scope) 101: return; // semantic() already completed 102: } 103: else 104: symtab = new DsymbolTable(); 105: 106: Scope *scx = NULL; 107: if (scope) 108: { sc = scope; 109: scx = scope; // save so we don't make redundant copies 110: scope = NULL; 111: } 112: 113: unsigned dprogress_save = Module::dprogress; 114: 115: if (sc->stc & STCdeprecated) 116: isdeprecated = 1; 117: 118: parent = sc->parent; 119: 120: /* The separate, and distinct, cases are: 121: * 1. enum { ... } 122: * 2. enum : memtype { ... } 123: * 3. enum ident { ... } 124: * 4. enum ident : memtype { ... } 125: */ 126: 127: if (memtype) 128: { 129: memtype = memtype->semantic(loc, sc); 130: 131: /* Check to see if memtype is forward referenced 132: */ 133: if (memtype->ty == Tenum) 134: { EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc); 135: if (!sym->memtype || !sym->members || !sym->symtab || sym->scope) 136: { // memtype is forward referenced, so try again later 137: scope = scx ? scx : new Scope(*sc); 138: scope->setNoFree(); 139: scope->module->addDeferredSemantic(this); 140: Module::dprogress = dprogress_save; 141: //printf("\tdeferring %s\n", toChars()); 142: return; 143: } 144: } 145: #if 0 // Decided to abandon this restriction for D 2.0 146: if (!memtype->isintegral()) 147: { error("base type must be of integral type, not %s", memtype->toChars()); 148: memtype = Type::tint32; 149: } 150: #endif 151: } 152: 153: isdone = 1; 154: Module::dprogress++; 155: 156: type = type->semantic(loc, sc); 157: if (isAnonymous()) 158: sce = sc; 159: else 160: { sce = sc->push(this); 161: sce->parent = this; 162: } 163: if (members->dim == 0) 164: error("enum %s must have at least one member", toChars()); 165: int first = 1; 166: Expression *elast = NULL; 167: for (int i = 0; i < members->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
168: { 169: EnumMember *em = (members->tdata()[i])->isEnumMember(); 170: Expression *e; 171: 172: if (!em) 173: /* The e->semantic(sce) can insert other symbols, such as 174: * template instances and function literals. 175: */ 176: continue; 177: 178: //printf(" Enum member '%s'\n",em->toChars()); 179: if (em->type) 180: em->type = em->type->semantic(em->loc, sce); 181: e = em->value; 182: if (e) 183: { 184: assert(e->dyncast() == DYNCAST_EXPRESSION); 185: e = e->semantic(sce); 186: e = e->optimize(WANTvalue | WANTinterpret); 187: if (memtype) 188: { 189: e = e->implicitCastTo(sce, memtype); 190: e = e->optimize(WANTvalue | WANTinterpret); 191: if (!isAnonymous()) 192: e = e->castTo(sce, type); 193: t = memtype; 194: } 195: else if (em->type) 196: { 197: e = e->implicitCastTo(sce, em->type); 198: e = e->optimize(WANTvalue | WANTinterpret); 199: assert(isAnonymous()); 200: t = e->type; 201: } 202: else 203: t = e->type; 204: } 205: else if (first) 206: { 207: if (memtype) 208: t = memtype; 209: else if (em->type) 210: t = em->type; 211: else 212: t = Type::tint32; 213: e = new IntegerExp(em->loc, 0, Type::tint32);
warning C6211: Leaking memory 'e' due to an exception. Consider using a local catch block to clean up memory: Lines: 86, 87, 91, 94, 96, 99, 100, 106, 107, 108, 109, 110, 113, 115, 116, 118, 127, 129, 133, 153, 154, 156, 157, 158, 163, 165, 166, 167, 169, 170, 172, 167, 169, 170, 172, 179, 180, 181, 182, 205, 207, 208, 213, 214, 215, 216, 217, 236, 237, 240, 244, 246, 248, 249
214: e = e->implicitCastTo(sce, t); 215: e = e->optimize(WANTvalue | WANTinterpret); 216: if (!isAnonymous()) 217: e = e->castTo(sce, type); 218: } 219: else 220: { 221: // Set value to (elast + 1). 222: // But first check that (elast != t.max) 223: assert(elast); 224: e = new EqualExp(TOKequal, em->loc, elast, t->getProperty(0, Id::max)); 225: e = e->semantic(sce); 226: e = e->optimize(WANTvalue | WANTinterpret); 227: if (e->toInteger()) 228: error("overflow of enum value %s", elast->toChars()); 229: 230: // Now set e to (elast + 1) 231: e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32)); 232: e = e->semantic(sce); 233: e = e->castTo(sce, elast->type); 234: e = e->optimize(WANTvalue | WANTinterpret); 235: } 236: elast = e; 237: em->value = e; 238: 239: // Add to symbol table only after evaluating 'value' 240: if (isAnonymous()) 241: { 242: /* Anonymous enum members get added to enclosing scope. 243: */ 244: for (Scope *scx = sce; scx; scx = scx->enclosing)
warning C6246: Local declaration of 'scx' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '106' of 'c:\projects\extern\d\dmd\src\enum.c': Lines: 106
245: { 246: if (scx->scopesym) 247: { 248: if (!scx->scopesym->symtab) 249: scx->scopesym->symtab = new DsymbolTable(); 250: em->addMember(sce, scx->scopesym, 1); 251: break; 252: } 253: } 254: } 255: else 256: em->addMember(sc, this, 1); 257: 258: /* Compute .min, .max and .default values. 259: * If enum doesn't have a name, we can never identify the enum type, 260: * so there is no purpose for a .min, .max or .default 261: */ 262: if (!isAnonymous()) 263: { 264: if (first) 265: { defaultval = e; 266: minval = e; 267: maxval = e; 268: } 269: else 270: { Expression *ec; 271: 272: /* In order to work successfully with UDTs, 273: * build expressions to do the comparisons, 274: * and let the semantic analyzer and constant 275: * folder give us the result. 276: */ 277: 278: // Compute if(e < minval) 279: ec = new CmpExp(TOKlt, em->loc, e, minval);
warning C6211: Leaking memory 'ec' due to an exception. Consider using a local catch block to clean up memory: Lines: 86, 87, 91, 94, 96, 99, 100, 106, 107, 108, 109, 110, 113, 115, 116, 118, 127, 129, 133, 153, 154, 156, 157, 158, 163, 165, 166, 167, 169, 170, 172, 179, 180, 181, 182, 184, 185, 186, 187, 189, 190, 191, 192, 193, 236, 237, 240, 244, 246,248, 249, 250, 262, 264, 265, 266, 267, 292, 167, 169, 170, 172, 179, 180, 181, 182, 184, 185, 186, 187, 189, 190, 191, 192, 193, 236, 237, 240, 244, 246, 248, 250, 262, 264, 270, 279, 280, 281, 282, 283, 285
280: ec = ec->semantic(sce); 281: ec = ec->optimize(WANTvalue | WANTinterpret); 282: if (ec->toInteger()) 283: minval = e; 284: 285: ec = new CmpExp(TOKgt, em->loc, e, maxval); 286: ec = ec->semantic(sce); 287: ec = ec->optimize(WANTvalue | WANTinterpret); 288: if (ec->toInteger()) 289: maxval = e; 290: } 291: } 292: first = 0; 293: } 294: //printf("defaultval = %lld\n", defaultval); 295: 296: //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars()); 297: if (sc != sce) 298: sce->pop(); 299: //members->print(); 300: } 301: 302: int EnumDeclaration::oneMember(Dsymbol **ps) 303: { 304: if (isAnonymous()) 305: return Dsymbol::oneMembers(members, ps); 306: return Dsymbol::oneMember(ps); 307: } 308: 309: void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) 310: { int i; 311: 312: buf->writestring("enum "); 313: if (ident) 314: { buf->writestring(ident->toChars()); 315: buf->writeByte(' '); 316: } 317: if (memtype) 318: { 319: buf->writestring(": "); 320: memtype->toCBuffer(buf, NULL, hgs); 321: } 322: if (!members) 323: { 324: buf->writeByte(';'); 325: buf->writenl(); 326: return; 327: } 328: buf->writenl(); 329: buf->writeByte('{'); 330: buf->writenl(); 331: for (i = 0; i < members->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
332: { 333: EnumMember *em = (members->tdata()[i])->isEnumMember(); 334: if (!em) 335: continue; 336: //buf->writestring(" "); 337: em->toCBuffer(buf, hgs); 338: buf->writeByte(','); 339: buf->writenl(); 340: } 341: buf->writeByte('}'); 342: buf->writenl(); 343: } 344: 345: Type *EnumDeclaration::getType() 346: { 347: return type; 348: } 349: 350: const char *EnumDeclaration::kind() 351: { 352: return "enum"; 353: } 354: 355: int EnumDeclaration::isDeprecated() 356: { 357: return isdeprecated; 358: } 359: 360: Dsymbol *EnumDeclaration::search(Loc loc, Identifier *ident, int flags) 361: { 362: //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars()); 363: if (scope) 364: // Try one last time to resolve this enum 365: semantic(scope); 366: 367: if (!members || !symtab || scope) 368: { error("is forward referenced when looking for '%s'", ident->toChars()); 369: //*(char*)0=0; 370: return NULL; 371: } 372: 373: Dsymbol *s = ScopeDsymbol::search(loc, ident, flags); 374: return s; 375: } 376: 377: /********************************* EnumMember ****************************/ 378: 379: EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *type) 380: : Dsymbol(id) 381: { 382: this->value = value; 383: this->type = type; 384: this->loc = loc; 385: } 386: 387: Dsymbol *EnumMember::syntaxCopy(Dsymbol *s) 388: { 389: Expression *e = NULL; 390: if (value) 391: e = value->syntaxCopy(); 392: 393: Type *t = NULL; 394: if (type) 395: t = type->syntaxCopy(); 396: 397: EnumMember *em; 398: if (s) 399: { em = (EnumMember *)s; 400: em->loc = loc; 401: em->value = e; 402: em->type = t; 403: } 404: else 405: em = new EnumMember(loc, ident, e, t); 406: return em; 407: } 408: 409: void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs) 410: { 411: if (type) 412: type->toCBuffer(buf, ident, hgs); 413: else 414: buf->writestring(ident->toChars()); 415: if (value) 416: { 417: buf->writestring(" = "); 418: value->toCBuffer(buf, hgs); 419: } 420: } 421: 422: const char *EnumMember::kind() 423: { 424: return "enum member"; 425: } 426: 427: 428: