2 * Define `enum` declarations and `enum` members.
4 * Specification: $(LINK2 https://dlang.org/spec/enum.html, Enums)
6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/denum.d, _denum.d)
10 * Documentation: https://dlang.org/phobos/dmd_denum.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/denum.d
12 * References: https://dlang.org/spec/enum.html
17 import core
.stdc
.stdio
;
23 import dmd
.declaration
;
26 import dmd
.dsymbolsem
;
27 import dmd
.expression
;
29 import dmd
.identifier
;
36 /***********************************************************
37 * AST node for `EnumDeclaration`
38 * https://dlang.org/spec/enum.html#EnumDeclaration
40 extern (C
++) final class EnumDeclaration
: ScopeDsymbol
42 /* The separate, and distinct, cases are:
44 * 2. enum : memtype { ... }
46 * 4. enum id : memtype { ... }
47 * 5. enum id : memtype;
50 Type type
; // the TypeEnum
51 Type memtype
; // type of the members
53 Visibility visibility
;
56 Expression defaultval
; // default initializer
58 // `bool` fields that are compacted into bit fields in a string mixin
59 private extern (D
) static struct BitFields
66 import dmd
.common
.bitfields
: generateBitFields
;
67 mixin(generateBitFields
!(BitFields
, ubyte));
69 extern (D
) this(const ref Loc loc
, Identifier ident
, Type memtype
)
72 //printf("EnumDeclaration() %p %s : %s\n", this, toChars(), memtype.toChars());
73 type
= new TypeEnum(this);
74 this.memtype
= memtype
;
75 visibility
= Visibility(Visibility
.Kind
.undefined
);
78 override EnumDeclaration
syntaxCopy(Dsymbol s
)
81 auto ed
= new EnumDeclaration(loc
, ident
, memtype ? memtype
.syntaxCopy() : null);
82 ScopeDsymbol
.syntaxCopy(ed
);
86 override void addMember(Scope
* sc
, ScopeDsymbol sds
)
90 printf("EnumDeclaration::addMember() %s\n", toChars());
91 for (size_t i
= 0; i
< members
.length
; i
++)
93 EnumMember em
= (*members
)[i
].isEnumMember();
94 printf(" member %s\n", em
.toChars());
99 ScopeDsymbol
.addMember(sc
, sds
);
102 addEnumMembers(this, sc
, sds
);
105 override void setScope(Scope
* sc
)
107 if (semanticRun
> PASS
.initial
)
109 ScopeDsymbol
.setScope(sc
);
112 override bool oneMember(Dsymbol
* ps
, Identifier ident
)
115 return Dsymbol
.oneMembers(members
, ps
, ident
);
116 return Dsymbol
.oneMember(ps
, ident
);
119 override Type
getType()
124 override const(char)* kind() const
129 override Dsymbol
search(const ref Loc loc
, Identifier ident
, int flags
= SearchLocalsOnly
)
131 //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident.toChars());
134 // Try one last time to resolve this enum
135 dsymbolSemantic(this, _scope
);
138 Dsymbol s
= ScopeDsymbol
.search(loc
, ident
, flags
);
142 // is Dsymbol deprecated?
143 override bool isDeprecated() const
148 override Visibility
visible() pure nothrow @nogc @safe
155 * Determine if enum is a special one.
159 bool isSpecial() const nothrow @nogc
161 return isSpecialEnumIdent(ident
) && memtype
;
164 Expression
getDefaultValue(const ref Loc loc
)
166 Expression
handleErrors(){
167 defaultval
= ErrorExp
.get();
170 //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
171 // https://issues.dlang.org/show_bug.cgi?id=23904
172 // Return defaultval only if it is not ErrorExp.
173 // A speculative context may set defaultval to ErrorExp;
174 // subsequent non-speculative contexts need to be able
175 // to print the error.
176 if (defaultval
&& !defaultval
.isErrorExp())
180 return memtype
.defaultInit(loc
, true);
183 dsymbolSemantic(this, _scope
);
185 return handleErrors();
190 /* Allow these special enums to not need a member list
192 return defaultval
= memtype
.defaultInit(loc
);
195 error(loc
, "%s `%s` is opaque and has no default initializer", kind
, toPrettyChars
);
196 return handleErrors();
199 foreach (const i
; 0 .. members
.length
)
201 EnumMember em
= (*members
)[i
].isEnumMember();
204 if (em
.semanticRun
< PASS
.semanticdone
)
206 error(loc
, "%s `%s` forward reference of `%s.init`", kind
, toPrettyChars
, toChars());
207 return handleErrors();
210 defaultval
= em
.value
;
214 return handleErrors();
217 Type
getMemtype(const ref Loc loc
)
221 /* Enum is forward referenced. We don't need to resolve the whole thing,
226 Loc locx
= loc
.isValid() ? loc
: this.loc
;
227 memtype
= memtype
.typeSemantic(locx
, _scope
);
231 // Run semantic to get the type from a possible first member value
232 dsymbolSemantic(this, _scope
);
237 if (!isAnonymous() && (members || semanticRun
>= PASS
.semanticdone
))
238 memtype
= Type
.tint32
;
241 Loc locx
= loc
.isValid() ? loc
: this.loc
;
242 error(locx
, "is forward referenced looking for base type");
249 override inout(EnumDeclaration
) isEnumDeclaration() inout
256 override void accept(Visitor v
)
262 /***********************************************************
263 * AST node representing a member of an enum.
264 * https://dlang.org/spec/enum.html#EnumMember
265 * https://dlang.org/spec/enum.html#AnonymousEnumMember
267 extern (C
++) final class EnumMember
: VarDeclaration
269 /* Can take the following forms:
274 @property ref value() { return (cast(ExpInitializer
)_init
).exp
; }
276 // A cast() is injected to 'value' after dsymbolSemantic(),
277 // but 'origValue' will preserve the original value,
278 // or previous value + 1 if none was specified.
279 Expression origValue
;
285 extern (D
) this(const ref Loc loc
, Identifier id
, Expression value
, Type origType
)
287 super(loc
, null, id ? id
: Id
.empty
, new ExpInitializer(loc
, value
));
288 this.origValue
= value
;
289 this.origType
= origType
;
292 extern(D
) this(Loc loc
, Identifier id
, Expression value
, Type memtype
,
293 StorageClass
stc, UserAttributeDeclaration uad
, DeprecatedDeclaration
dd)
295 this(loc
, id
, value
, memtype
);
297 userAttribDecl
= uad
;
301 override EnumMember
syntaxCopy(Dsymbol s
)
304 return new EnumMember(
306 value ? value
.syntaxCopy() : null,
307 origType ? origType
.syntaxCopy() : null,
309 userAttribDecl ? userAttribDecl
.syntaxCopy(s
) : null,
310 depdecl ? depdecl
.syntaxCopy(s
) : null);
313 override const(char)* kind() const
315 return "enum member";
318 override inout(EnumMember
) isEnumMember() inout
323 override void accept(Visitor v
)
329 /******************************************
330 * Check for special enum names.
332 * Special enum names are used by the C++ name mangler to represent
333 * C++ types that are not basic D types.
335 * ident = identifier to check for specialness
337 * `true` if it is special
339 bool isSpecialEnumIdent(const Identifier ident
) @nogc nothrow
341 return ident
== Id
.__c_long ||
342 ident
== Id
.__c_ulong ||
343 ident
== Id
.__c_longlong ||
344 ident
== Id
.__c_ulonglong ||
345 ident
== Id
.__c_long_double ||
346 ident
== Id
.__c_wchar_t ||
347 ident
== Id
.__c_complex_float ||
348 ident
== Id
.__c_complex_double ||
349 ident
== Id
.__c_complex_real
;