]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/denum.c
d: Merge upstream dmd 7132b3537
[thirdparty/gcc.git] / gcc / d / dmd / denum.c
1
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2021 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 "attrib.h"
17 #include "mtype.h"
18 #include "scope.h"
19 #include "id.h"
20 #include "expression.h"
21 #include "module.h"
22 #include "declaration.h"
23 #include "init.h"
24
25 /********************************* EnumDeclaration ****************************/
26
27 EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
28 : ScopeDsymbol(id)
29 {
30 //printf("EnumDeclaration() %s\n", toChars());
31 this->loc = loc;
32 type = new TypeEnum(this);
33 this->memtype = memtype;
34 maxval = NULL;
35 minval = NULL;
36 defaultval = NULL;
37 sinit = NULL;
38 isdeprecated = false;
39 protection = Prot(Prot::undefined);
40 parent = NULL;
41 added = false;
42 inuse = 0;
43 }
44
45 Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
46 {
47 assert(!s);
48 EnumDeclaration *ed = new EnumDeclaration(loc, ident,
49 memtype ? memtype->syntaxCopy() : NULL);
50 return ScopeDsymbol::syntaxCopy(ed);
51 }
52
53 void EnumDeclaration::setScope(Scope *sc)
54 {
55 if (semanticRun > PASSinit)
56 return;
57 ScopeDsymbol::setScope(sc);
58 }
59
60 void EnumDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
61 {
62 /* Anonymous enum members get added to enclosing scope.
63 */
64 ScopeDsymbol *scopesym = isAnonymous() ? sds : this;
65
66 if (!isAnonymous())
67 {
68 ScopeDsymbol::addMember(sc, sds);
69
70 if (!symtab)
71 symtab = new DsymbolTable();
72 }
73
74 if (members)
75 {
76 for (size_t i = 0; i < members->length; i++)
77 {
78 EnumMember *em = (*members)[i]->isEnumMember();
79 em->ed = this;
80 //printf("add %s to scope %s\n", em->toChars(), scopesym->toChars());
81 em->addMember(sc, isAnonymous() ? scopesym : this);
82 }
83 }
84 added = true;
85 }
86
87 /******************************
88 * Get the value of the .max/.min property as an Expression
89 * Input:
90 * id Id::max or Id::min
91 */
92
93 Expression *EnumDeclaration::getMaxMinValue(Loc loc, Identifier *id)
94 {
95 //printf("EnumDeclaration::getMaxValue()\n");
96 bool first = true;
97
98 Expression **pval = (id == Id::max) ? &maxval : &minval;
99
100 if (inuse)
101 {
102 error(loc, "recursive definition of .%s property", id->toChars());
103 goto Lerrors;
104 }
105 if (*pval)
106 goto Ldone;
107
108 if (_scope)
109 dsymbolSemantic(this, _scope);
110 if (errors)
111 goto Lerrors;
112 if (semanticRun == PASSinit || !members)
113 {
114 if (isSpecial())
115 {
116 /* Allow these special enums to not need a member list
117 */
118 return memtype->getProperty(loc, id, 0);
119 }
120
121 error("is forward referenced looking for .%s", id->toChars());
122 goto Lerrors;
123 }
124 if (!(memtype && memtype->isintegral()))
125 {
126 error(loc, "has no .%s property because base type %s is not an integral type",
127 id->toChars(),
128 memtype ? memtype->toChars() : "");
129 goto Lerrors;
130 }
131
132 for (size_t i = 0; i < members->length; i++)
133 {
134 EnumMember *em = (*members)[i]->isEnumMember();
135 if (!em)
136 continue;
137 if (em->errors)
138 goto Lerrors;
139
140 Expression *e = em->value();
141 if (first)
142 {
143 *pval = e;
144 first = false;
145 }
146 else
147 {
148 /* In order to work successfully with UDTs,
149 * build expressions to do the comparisons,
150 * and let the semantic analyzer and constant
151 * folder give us the result.
152 */
153
154 /* Compute:
155 * if (e > maxval)
156 * maxval = e;
157 */
158 Expression *ec = new CmpExp(id == Id::max ? TOKgt : TOKlt, em->loc, e, *pval);
159 inuse++;
160 ec = expressionSemantic(ec, em->_scope);
161 inuse--;
162 ec = ec->ctfeInterpret();
163 if (ec->toInteger())
164 *pval = e;
165 }
166 }
167 Ldone:
168 {
169 Expression *e = *pval;
170 if (e->op != TOKerror)
171 {
172 e = e->copy();
173 e->loc = loc;
174 }
175 return e;
176 }
177
178 Lerrors:
179 *pval = new ErrorExp();
180 return *pval;
181 }
182
183 /****************
184 * Determine if enum is a 'special' one.
185 * Returns:
186 * true if special
187 */
188 bool EnumDeclaration::isSpecial() const
189 {
190 return (ident == Id::__c_long ||
191 ident == Id::__c_ulong ||
192 ident == Id::__c_longlong ||
193 ident == Id::__c_ulonglong ||
194 ident == Id::__c_long_double) && memtype;
195 }
196
197 Expression *EnumDeclaration::getDefaultValue(Loc loc)
198 {
199 //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
200 if (defaultval)
201 return defaultval;
202
203 if (_scope)
204 dsymbolSemantic(this, _scope);
205 if (errors)
206 goto Lerrors;
207 if (semanticRun == PASSinit || !members)
208 {
209 if (isSpecial())
210 {
211 /* Allow these special enums to not need a member list
212 */
213 return memtype->defaultInit(loc);
214 }
215
216 error(loc, "forward reference of %s.init", toChars());
217 goto Lerrors;
218 }
219
220 for (size_t i = 0; i < members->length; i++)
221 {
222 EnumMember *em = (*members)[i]->isEnumMember();
223 if (em)
224 {
225 defaultval = em->value();
226 return defaultval;
227 }
228 }
229
230 Lerrors:
231 defaultval = new ErrorExp();
232 return defaultval;
233 }
234
235 Type *EnumDeclaration::getMemtype(Loc loc)
236 {
237 if (loc.linnum == 0)
238 loc = this->loc;
239 if (_scope)
240 {
241 /* Enum is forward referenced. We don't need to resolve the whole thing,
242 * just the base type
243 */
244 if (memtype)
245 memtype = typeSemantic(memtype, loc, _scope);
246 else
247 {
248 if (!isAnonymous() && members)
249 memtype = Type::tint32;
250 }
251 }
252 if (!memtype)
253 {
254 if (!isAnonymous() && members)
255 memtype = Type::tint32;
256 else
257 {
258 error(loc, "is forward referenced looking for base type");
259 return Type::terror;
260 }
261 }
262 return memtype;
263 }
264
265 bool EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
266 {
267 if (isAnonymous())
268 return Dsymbol::oneMembers(members, ps, ident);
269 return Dsymbol::oneMember(ps, ident);
270 }
271
272 Type *EnumDeclaration::getType()
273 {
274 return type;
275 }
276
277 const char *EnumDeclaration::kind() const
278 {
279 return "enum";
280 }
281
282 bool EnumDeclaration::isDeprecated()
283 {
284 return isdeprecated;
285 }
286
287 Prot EnumDeclaration::prot()
288 {
289 return protection;
290 }
291
292 Dsymbol *EnumDeclaration::search(const Loc &loc, Identifier *ident, int flags)
293 {
294 //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars());
295 if (_scope)
296 {
297 // Try one last time to resolve this enum
298 dsymbolSemantic(this, _scope);
299 }
300
301 if (!members || !symtab || _scope)
302 {
303 error("is forward referenced when looking for `%s`", ident->toChars());
304 //*(char*)0=0;
305 return NULL;
306 }
307
308 Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
309 return s;
310 }
311
312 /********************************* EnumMember ****************************/
313
314 EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *origType)
315 : VarDeclaration(loc, NULL, id ? id : Id::empty, new ExpInitializer(loc, value))
316 {
317 this->ed = NULL;
318 this->origValue = value;
319 this->origType = origType;
320 }
321
322 EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *memType,
323 StorageClass stc, UserAttributeDeclaration *uad, DeprecatedDeclaration *dd)
324 : VarDeclaration(loc, NULL, id ? id : Id::empty, new ExpInitializer(loc, value))
325 {
326 this->ed = NULL;
327 this->origValue = value;
328 this->origType = memType;
329 this->storage_class = stc;
330 this->userAttribDecl = uad;
331 this->depdecl = dd;
332 }
333
334 Expression *&EnumMember::value()
335 {
336 return ((ExpInitializer*)_init)->exp;
337 }
338
339 Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
340 {
341 assert(!s);
342 return new EnumMember(loc, ident,
343 value() ? value()->syntaxCopy() : NULL,
344 origType ? origType->syntaxCopy() : NULL);
345 }
346
347 const char *EnumMember::kind() const
348 {
349 return "enum member";
350 }
351
352 Expression *EnumMember::getVarExp(Loc loc, Scope *sc)
353 {
354 dsymbolSemantic(this, sc);
355 if (errors)
356 return new ErrorExp();
357 checkDisabled(loc, sc);
358
359 if (depdecl && !depdecl->_scope)
360 depdecl->_scope = sc;
361 checkDeprecated(loc, sc);
362
363 if (errors)
364 return new ErrorExp();
365 Expression *e = new VarExp(loc, this);
366 return expressionSemantic(e, sc);
367 }