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