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 }