2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2018 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
11 #include "root/dsystem.h"
12 #include "root/root.h"
19 #include "expression.h"
21 #include "declaration.h"
24 Expression
*semantic(Expression
*e
, Scope
*sc
);
26 /********************************* EnumDeclaration ****************************/
28 EnumDeclaration::EnumDeclaration(Loc loc
, Identifier
*id
, Type
*memtype
)
31 //printf("EnumDeclaration() %s\n", toChars());
33 type
= new TypeEnum(this);
34 this->memtype
= memtype
;
40 protection
= Prot(PROTundefined
);
46 Dsymbol
*EnumDeclaration::syntaxCopy(Dsymbol
*s
)
49 EnumDeclaration
*ed
= new EnumDeclaration(loc
, ident
,
50 memtype
? memtype
->syntaxCopy() : NULL
);
51 return ScopeDsymbol::syntaxCopy(ed
);
54 void EnumDeclaration::setScope(Scope
*sc
)
56 if (semanticRun
> PASSinit
)
58 ScopeDsymbol::setScope(sc
);
61 void EnumDeclaration::addMember(Scope
*sc
, ScopeDsymbol
*sds
)
63 /* Anonymous enum members get added to enclosing scope.
65 ScopeDsymbol
*scopesym
= isAnonymous() ? sds
: this;
69 ScopeDsymbol::addMember(sc
, sds
);
72 symtab
= new DsymbolTable();
77 for (size_t i
= 0; i
< members
->dim
; i
++)
79 EnumMember
*em
= (*members
)[i
]->isEnumMember();
81 //printf("add %s to scope %s\n", em->toChars(), scopesym->toChars());
82 em
->addMember(sc
, isAnonymous() ? scopesym
: this);
89 void EnumDeclaration::semantic(Scope
*sc
)
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
)
98 ::error(loc
, "circular reference to enum base type %s", memtype
->toChars());
100 semanticRun
= PASSsemanticdone
;
103 unsigned dprogress_save
= Module::dprogress
;
109 scx
= _scope
; // save so we don't make redundant copies
114 type
= type
->semantic(loc
, sc
);
116 protection
= sc
->protection
;
117 if (sc
->stc
& STCdeprecated
)
119 userAttribDecl
= sc
->userAttribDecl
;
121 semanticRun
= PASSsemantic
;
123 if (!members
&& !memtype
) // enum ident;
125 semanticRun
= PASSsemanticdone
;
130 symtab
= new DsymbolTable();
132 /* The separate, and distinct, cases are:
134 * 2. enum : memtype { ... }
135 * 3. enum ident { ... }
136 * 4. enum ident : memtype { ... }
137 * 5. enum ident : memtype;
143 memtype
= memtype
->semantic(loc
, sc
);
145 /* Check to see if memtype is forward referenced
147 if (memtype
->ty
== Tenum
)
149 EnumDeclaration
*sym
= (EnumDeclaration
*)memtype
->toDsymbol(sc
);
150 if (!sym
->memtype
|| !sym
->members
|| !sym
->symtab
|| sym
->_scope
)
152 // memtype is forward referenced, so try again later
153 _scope
= scx
? scx
: sc
->copy();
155 _scope
->_module
->addDeferredSemantic(this);
156 Module::dprogress
= dprogress_save
;
157 //printf("\tdeferring %s\n", toChars());
158 semanticRun
= PASSinit
;
162 if (memtype
->ty
== Tvoid
)
164 error("base type must not be void");
165 memtype
= Type::terror
;
167 if (memtype
->ty
== Terror
)
172 for (size_t i
= 0; i
< members
->dim
; i
++)
174 Dsymbol
*s
= (*members
)[i
];
175 s
->errors
= true; // poison all the members
178 semanticRun
= PASSsemanticdone
;
183 semanticRun
= PASSsemanticdone
;
185 if (!members
) // enum ident : memtype;
188 if (members
->dim
== 0)
190 error("enum %s must have at least one member", toChars());
202 sce
= sc
->push(this);
205 sce
= sce
->startCTFE();
206 sce
->setNoFree(); // needed for getMaxMinValue()
208 /* Each enum member gets the sce scope
210 for (size_t i
= 0; i
< members
->dim
; i
++)
212 EnumMember
*em
= (*members
)[i
]->isEnumMember();
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
223 ScopeDsymbol
*scopesym
= NULL
;
226 /* Anonymous enum members get added to enclosing scope.
228 for (Scope
*sct
= sce
; 1; sct
= sct
->enclosing
)
233 scopesym
= sct
->scopesym
;
234 if (!sct
->scopesym
->symtab
)
235 sct
->scopesym
->symtab
= new DsymbolTable();
242 // Otherwise enum members are in the EnumDeclaration's symbol table
246 for (size_t i
= 0; i
< members
->dim
; i
++)
248 EnumMember
*em
= (*members
)[i
]->isEnumMember();
252 em
->addMember(sc
, scopesym
);
257 for (size_t i
= 0; i
< members
->dim
; i
++)
259 EnumMember
*em
= (*members
)[i
]->isEnumMember();
261 em
->semantic(em
->_scope
);
263 //printf("defaultval = %lld\n", defaultval);
265 //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars());
266 //printf("members = %s\n", members->toChars());
269 /******************************
270 * Get the value of the .max/.min property as an Expression
272 * id Id::max or Id::min
275 Expression
*EnumDeclaration::getMaxMinValue(Loc loc
, Identifier
*id
)
277 //printf("EnumDeclaration::getMaxValue()\n");
280 Expression
**pval
= (id
== Id::max
) ? &maxval
: &minval
;
284 error(loc
, "recursive definition of .%s property", id
->toChars());
294 if (semanticRun
== PASSinit
|| !members
)
298 /* Allow these special enums to not need a member list
300 return memtype
->getProperty(loc
, id
, 0);
303 error("is forward referenced looking for .%s", id
->toChars());
306 if (!(memtype
&& memtype
->isintegral()))
308 error(loc
, "has no .%s property because base type %s is not an integral type",
310 memtype
? memtype
->toChars() : "");
314 for (size_t i
= 0; i
< members
->dim
; i
++)
316 EnumMember
*em
= (*members
)[i
]->isEnumMember();
322 Expression
*e
= em
->value();
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.
340 Expression
*ec
= new CmpExp(id
== Id::max
? TOKgt
: TOKlt
, em
->loc
, e
, *pval
);
342 ec
= ::semantic(ec
, em
->_scope
);
344 ec
= ec
->ctfeInterpret();
351 Expression
*e
= *pval
;
352 if (e
->op
!= TOKerror
)
361 *pval
= new ErrorExp();
366 * Determine if enum is a 'special' one.
370 bool EnumDeclaration::isSpecial() const
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
;
379 Expression
*EnumDeclaration::getDefaultValue(Loc loc
)
381 //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
389 if (semanticRun
== PASSinit
|| !members
)
393 /* Allow these special enums to not need a member list
395 return memtype
->defaultInit(loc
);
398 error(loc
, "forward reference of %s.init", toChars());
402 for (size_t i
= 0; i
< members
->dim
; i
++)
404 EnumMember
*em
= (*members
)[i
]->isEnumMember();
407 defaultval
= em
->value();
413 defaultval
= new ErrorExp();
417 Type
*EnumDeclaration::getMemtype(Loc loc
)
423 /* Enum is forward referenced. We don't need to resolve the whole thing,
427 memtype
= memtype
->semantic(loc
, _scope
);
430 if (!isAnonymous() && members
)
431 memtype
= Type::tint32
;
436 if (!isAnonymous() && members
)
437 memtype
= Type::tint32
;
440 error(loc
, "is forward referenced looking for base type");
447 bool EnumDeclaration::oneMember(Dsymbol
**ps
, Identifier
*ident
)
450 return Dsymbol::oneMembers(members
, ps
, ident
);
451 return Dsymbol::oneMember(ps
, ident
);
454 Type
*EnumDeclaration::getType()
459 const char *EnumDeclaration::kind() const
464 bool EnumDeclaration::isDeprecated()
469 Prot
EnumDeclaration::prot()
474 Dsymbol
*EnumDeclaration::search(const Loc
&loc
, Identifier
*ident
, int flags
)
476 //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars());
479 // Try one last time to resolve this enum
483 if (!members
|| !symtab
|| _scope
)
485 error("is forward referenced when looking for '%s'", ident
->toChars());
490 Dsymbol
*s
= ScopeDsymbol::search(loc
, ident
, flags
);
494 /********************************* EnumMember ****************************/
496 EnumMember::EnumMember(Loc loc
, Identifier
*id
, Expression
*value
, Type
*origType
)
497 : VarDeclaration(loc
, NULL
, id
? id
: Id::empty
, new ExpInitializer(loc
, value
))
500 this->origValue
= value
;
501 this->origType
= origType
;
504 Expression
*&EnumMember::value()
506 return ((ExpInitializer
*)_init
)->exp
;
509 Dsymbol
*EnumMember::syntaxCopy(Dsymbol
*s
)
512 return new EnumMember(loc
, ident
,
513 value() ? value()->syntaxCopy() : NULL
,
514 origType
? origType
->syntaxCopy() : NULL
);
517 const char *EnumMember::kind() const
519 return "enum member";
522 void EnumMember::semantic(Scope
*sc
)
524 //printf("EnumMember::semantic() %s\n", toChars());
525 if (errors
|| semanticRun
>= PASSsemanticdone
)
527 if (semanticRun
== PASSsemantic
)
529 error("circular reference to enum member");
532 semanticRun
= PASSsemanticdone
;
540 if (errors
|| semanticRun
>= PASSsemanticdone
)
548 semanticRun
= PASSsemantic
;
550 protection
= ed
->isAnonymous() ? ed
->protection
: Prot(PROTpublic
);
552 storage_class
= STCmanifest
;
553 userAttribDecl
= ed
->isAnonymous() ? ed
->userAttribDecl
: NULL
;
555 // The first enum member is special
556 bool first
= (this == (*ed
->members
)[0]);
560 origType
= origType
->semantic(loc
, sc
);
562 assert(value()); // "type id;" is not a valid enum member declaration
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
)
574 if (first
&& !ed
->memtype
&& !ed
->isAnonymous())
576 ed
->memtype
= e
->type
;
577 if (ed
->memtype
->ty
== Terror
)
582 if (ed
->memtype
->ty
!= Terror
)
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.
588 for (size_t i
= 0; i
< ed
->members
->dim
; i
++)
590 EnumMember
*em
= (*ed
->members
)[i
]->isEnumMember();
591 if (!em
|| em
== this || em
->semanticRun
< PASSsemanticdone
|| em
->origType
)
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
)
605 ed
->memtype
= Type::terror
;
611 if (ed
->memtype
&& !origType
)
613 e
= e
->implicitCastTo(sc
, ed
->memtype
);
614 e
= e
->ctfeInterpret();
616 // save origValue for better json output
619 if (!ed
->isAnonymous())
621 e
= e
->castTo(sc
, ed
->type
);
622 e
= e
->ctfeInterpret();
627 e
= e
->implicitCastTo(sc
, origType
);
628 e
= e
->ctfeInterpret();
629 assert(ed
->isAnonymous());
631 // save origValue for better json output
644 if (!ed
->isAnonymous())
647 Expression
*e
= new IntegerExp(loc
, 0, Type::tint32
);
648 e
= e
->implicitCastTo(sc
, t
);
649 e
= e
->ctfeInterpret();
651 // save origValue for better json output
654 if (!ed
->isAnonymous())
656 e
= e
->castTo(sc
, ed
->type
);
657 e
= e
->ctfeInterpret();
663 /* Find the previous enum member,
664 * and set this to be the previous value + 1
666 EnumMember
*emprev
= NULL
;
667 for (size_t i
= 0; i
< ed
->members
->dim
; i
++)
669 EnumMember
*em
= (*ed
->members
)[i
]->isEnumMember();
678 if (emprev
->semanticRun
< PASSsemanticdone
) // if forward reference
679 emprev
->semantic(emprev
->_scope
); // resolve it
683 Expression
*eprev
= emprev
->value();
684 Type
*tprev
= eprev
->type
->equals(ed
->type
) ? ed
->memtype
: eprev
->type
;
686 Expression
*emax
= tprev
->getProperty(ed
->loc
, Id::max
, 0);
687 emax
= ::semantic(emax
, sc
);
688 emax
= emax
->ctfeInterpret();
690 // Set value to (eprev + 1).
691 // But first check that (eprev != emax)
693 Expression
*e
= new EqualExp(TOKequal
, loc
, eprev
, emax
);
694 e
= ::semantic(e
, sc
);
695 e
= e
->ctfeInterpret();
698 error("initialization with (%s.%s + 1) causes overflow for type '%s'", emprev
->ed
->toChars(), emprev
->toChars(), ed
->type
->toBasetype()->toChars());
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();
708 // save origValue (without cast) for better json output
709 if (e
->op
!= TOKerror
) // avoid duplicate diagnostics
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();
717 if (e
->op
== TOKerror
)
719 if (e
->type
->isfloating())
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())
727 error("has inexact value, due to loss of precision");
734 type
= value()->type
;
737 semanticRun
= PASSsemanticdone
;
740 Expression
*EnumMember::getVarExp(Loc loc
, Scope
*sc
)
744 return new ErrorExp();
745 Expression
*e
= new VarExp(loc
, this);
746 return ::semantic(e
, sc
);