1 /** 2 * Define `enum` declarations and `enum` members. 3 * 4 * Specification: $(LINK2 https://dlang.org/spec/enum.html, Enums) 5 * 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 13 */ 14 15 module dmd.denum; 16 17 import core.stdc.stdio; 18 19 import dmd.astenums; 20 import dmd.attrib; 21 import dmd.errors; 22 import dmd.gluelayer; 23 import dmd.declaration; 24 import dmd.dscope; 25 import dmd.dsymbol; 26 import dmd.dsymbolsem; 27 import dmd.expression; 28 import dmd.id; 29 import dmd.identifier; 30 import dmd.init; 31 import dmd.location; 32 import dmd.mtype; 33 import dmd.typesem; 34 import dmd.visitor; 35 36 /*********************************************************** 37 * AST node for `EnumDeclaration` 38 * https://dlang.org/spec/enum.html#EnumDeclaration 39 */ 40 extern (C++) final class EnumDeclaration : ScopeDsymbol 41 { 42 /* The separate, and distinct, cases are: 43 * 1. enum { ... } 44 * 2. enum : memtype { ... } 45 * 3. enum id { ... } 46 * 4. enum id : memtype { ... } 47 * 5. enum id : memtype; 48 * 6. enum id; 49 */ 50 Type type; // the TypeEnum 51 Type memtype; // type of the members 52 53 Visibility visibility; 54 Expression maxval; 55 Expression minval; 56 Expression defaultval; // default initializer 57 58 // `bool` fields that are compacted into bit fields in a string mixin 59 private extern (D) static struct BitFields 60 { 61 bool isdeprecated; 62 bool added; 63 bool inuse; 64 } 65 66 import dmd.common.bitfields : generateBitFields; 67 mixin(generateBitFields!(BitFields, ubyte)); 68 69 extern (D) this(const ref Loc loc, Identifier ident, Type memtype) 70 { 71 super(loc, ident); 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); 76 } 77 78 override EnumDeclaration syntaxCopy(Dsymbol s) 79 { 80 assert(!s); 81 auto ed = new EnumDeclaration(loc, ident, memtype ? memtype.syntaxCopy() : null); 82 ScopeDsymbol.syntaxCopy(ed); 83 return ed; 84 } 85 86 override void addMember(Scope* sc, ScopeDsymbol sds) 87 { 88 version (none) 89 { 90 printf("EnumDeclaration::addMember() %s\n", toChars()); 91 for (size_t i = 0; i < members.length; i++) 92 { 93 EnumMember em = (*members)[i].isEnumMember(); 94 printf(" member %s\n", em.toChars()); 95 } 96 } 97 if (!isAnonymous()) 98 { 99 ScopeDsymbol.addMember(sc, sds); 100 } 101 102 addEnumMembersToSymtab(this, sc, sds); 103 } 104 105 override void setScope(Scope* sc) 106 { 107 if (semanticRun > PASS.initial) 108 return; 109 ScopeDsymbol.setScope(sc); 110 } 111 112 override bool oneMember(Dsymbol* ps, Identifier ident) 113 { 114 if (isAnonymous()) 115 return Dsymbol.oneMembers(members, ps, ident); 116 return Dsymbol.oneMember(ps, ident); 117 } 118 119 override Type getType() 120 { 121 return type; 122 } 123 124 override const(char)* kind() const 125 { 126 return "enum"; 127 } 128 129 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) 130 { 131 //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident.toChars()); 132 if (_scope) 133 { 134 // Try one last time to resolve this enum 135 dsymbolSemantic(this, _scope); 136 } 137 138 Dsymbol s = ScopeDsymbol.search(loc, ident, flags); 139 return s; 140 } 141 142 // is Dsymbol deprecated? 143 override bool isDeprecated() const 144 { 145 return isdeprecated; 146 } 147 148 override Visibility visible() pure nothrow @nogc @safe 149 { 150 return visibility; 151 } 152 153 154 /**************** 155 * Determine if enum is a special one. 156 * Returns: 157 * `true` if special 158 */ 159 bool isSpecial() const nothrow @nogc 160 { 161 return isSpecialEnumIdent(ident) && memtype; 162 } 163 164 Expression getDefaultValue(const ref Loc loc) 165 { 166 Expression handleErrors(){ 167 defaultval = ErrorExp.get(); 168 return defaultval; 169 } 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()) 177 return defaultval; 178 179 if (isCsymbol()) 180 return memtype.defaultInit(loc, true); 181 182 if (_scope) 183 dsymbolSemantic(this, _scope); 184 if (errors) 185 return handleErrors(); 186 if (!members) 187 { 188 if (isSpecial()) 189 { 190 /* Allow these special enums to not need a member list 191 */ 192 return defaultval = memtype.defaultInit(loc); 193 } 194 195 error(loc, "%s `%s` is opaque and has no default initializer", kind, toPrettyChars); 196 return handleErrors(); 197 } 198 199 foreach (const i; 0 .. members.length) 200 { 201 EnumMember em = (*members)[i].isEnumMember(); 202 if (em) 203 { 204 if (em.semanticRun < PASS.semanticdone) 205 { 206 error(loc, "%s `%s` forward reference of `%s.init`", kind, toPrettyChars, toChars()); 207 return handleErrors(); 208 } 209 210 defaultval = em.value; 211 return defaultval; 212 } 213 } 214 return handleErrors(); 215 } 216 217 Type getMemtype(const ref Loc loc) 218 { 219 if (_scope) 220 { 221 /* Enum is forward referenced. We don't need to resolve the whole thing, 222 * just the base type 223 */ 224 if (memtype) 225 { 226 Loc locx = loc.isValid() ? loc : this.loc; 227 memtype = memtype.typeSemantic(locx, _scope); 228 } 229 else 230 { 231 // Run semantic to get the type from a possible first member value 232 dsymbolSemantic(this, _scope); 233 } 234 } 235 if (!memtype) 236 { 237 if (!isAnonymous() && (members || semanticRun >= PASS.semanticdone)) 238 memtype = Type.tint32; 239 else 240 { 241 Loc locx = loc.isValid() ? loc : this.loc; 242 error(locx, "is forward referenced looking for base type"); 243 return Type.terror; 244 } 245 } 246 return memtype; 247 } 248 249 override inout(EnumDeclaration) isEnumDeclaration() inout 250 { 251 return this; 252 } 253 254 Symbol* sinit; 255 256 override void accept(Visitor v) 257 { 258 v.visit(this); 259 } 260 } 261 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 266 */ 267 extern (C++) final class EnumMember : VarDeclaration 268 { 269 /* Can take the following forms: 270 * 1. id 271 * 2. id = value 272 * 3. type id = value 273 */ 274 @property ref value() { return (cast(ExpInitializer)_init).exp; } 275 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; 280 281 Type origType; 282 283 EnumDeclaration ed; 284 285 extern (D) this(const ref Loc loc, Identifier id, Expression value, Type origType) 286 { 287 super(loc, null, id ? id : Id.empty, new ExpInitializer(loc, value)); 288 this.origValue = value; 289 this.origType = origType; 290 } 291 292 extern(D) this(Loc loc, Identifier id, Expression value, Type memtype, 293 StorageClass stc, UserAttributeDeclaration uad, DeprecatedDeclaration dd) 294 { 295 this(loc, id, value, memtype); 296 storage_class = stc; 297 userAttribDecl = uad; 298 depdecl = dd; 299 } 300 301 override EnumMember syntaxCopy(Dsymbol s) 302 { 303 assert(!s); 304 return new EnumMember( 305 loc, ident, 306 value ? value.syntaxCopy() : null, 307 origType ? origType.syntaxCopy() : null, 308 storage_class, 309 userAttribDecl ? userAttribDecl.syntaxCopy(s) : null, 310 depdecl ? depdecl.syntaxCopy(s) : null); 311 } 312 313 override const(char)* kind() const 314 { 315 return "enum member"; 316 } 317 318 override inout(EnumMember) isEnumMember() inout 319 { 320 return this; 321 } 322 323 override void accept(Visitor v) 324 { 325 v.visit(this); 326 } 327 } 328 329 /****************************************** 330 * Check for special enum names. 331 * 332 * Special enum names are used by the C++ name mangler to represent 333 * C++ types that are not basic D types. 334 * Params: 335 * ident = identifier to check for specialness 336 * Returns: 337 * `true` if it is special 338 */ 339 bool isSpecialEnumIdent(const Identifier ident) @nogc nothrow 340 { 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; 350 }