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