1 /** 2 * Defines initializers of variables, e.g. the array literal in `int[3] x = [0, 1, 2]`. 3 * 4 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/init.d, _init.d) 8 * Documentation: https://dlang.org/phobos/dmd_init.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/init.d 10 */ 11 12 module dmd.init; 13 14 import core.stdc.stdio; 15 import core.checkedint; 16 17 import dmd.arraytypes; 18 import dmd.ast_node; 19 import dmd.dsymbol; 20 import dmd.expression; 21 import dmd.globals; 22 import dmd.hdrgen; 23 import dmd.identifier; 24 import dmd.mtype; 25 import dmd.root.outbuffer; 26 import dmd.root.rootobject; 27 import dmd.tokens; 28 import dmd.visitor; 29 30 enum NeedInterpret : int 31 { 32 INITnointerpret, 33 INITinterpret, 34 } 35 36 alias INITnointerpret = NeedInterpret.INITnointerpret; 37 alias INITinterpret = NeedInterpret.INITinterpret; 38 39 /************* 40 * Discriminant for which kind of initializer 41 */ 42 enum InitKind : ubyte 43 { 44 void_, 45 error, 46 struct_, 47 array, 48 exp, 49 } 50 51 /*********************************************************** 52 */ 53 extern (C++) class Initializer : ASTNode 54 { 55 Loc loc; 56 InitKind kind; 57 58 59 extern (D) this(const ref Loc loc, InitKind kind) 60 { 61 this.loc = loc; 62 this.kind = kind; 63 } 64 65 override final const(char)* toChars() const 66 { 67 OutBuffer buf; 68 HdrGenState hgs; 69 .toCBuffer(this, &buf, &hgs); 70 return buf.extractChars(); 71 } 72 73 final inout(ErrorInitializer) isErrorInitializer() inout pure 74 { 75 // Use void* cast to skip dynamic casting call 76 return kind == InitKind.error ? cast(inout ErrorInitializer)cast(void*)this : null; 77 } 78 79 final inout(VoidInitializer) isVoidInitializer() inout pure 80 { 81 return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null; 82 } 83 84 final inout(StructInitializer) isStructInitializer() inout pure 85 { 86 return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null; 87 } 88 89 final inout(ArrayInitializer) isArrayInitializer() inout pure 90 { 91 return kind == InitKind.array ? cast(inout ArrayInitializer)cast(void*)this : null; 92 } 93 94 final inout(ExpInitializer) isExpInitializer() inout pure 95 { 96 return kind == InitKind.exp ? cast(inout ExpInitializer)cast(void*)this : null; 97 } 98 99 override void accept(Visitor v) 100 { 101 v.visit(this); 102 } 103 } 104 105 /*********************************************************** 106 */ 107 extern (C++) final class VoidInitializer : Initializer 108 { 109 Type type; // type that this will initialize to 110 111 extern (D) this(const ref Loc loc) 112 { 113 super(loc, InitKind.void_); 114 } 115 116 override void accept(Visitor v) 117 { 118 v.visit(this); 119 } 120 } 121 122 /*********************************************************** 123 */ 124 extern (C++) final class ErrorInitializer : Initializer 125 { 126 extern (D) this() 127 { 128 super(Loc.initial, InitKind.error); 129 } 130 131 override void accept(Visitor v) 132 { 133 v.visit(this); 134 } 135 } 136 137 /*********************************************************** 138 */ 139 extern (C++) final class StructInitializer : Initializer 140 { 141 Identifiers field; // of Identifier *'s 142 Initializers value; // parallel array of Initializer *'s 143 144 extern (D) this(const ref Loc loc) 145 { 146 super(loc, InitKind.struct_); 147 } 148 149 extern (D) void addInit(Identifier field, Initializer value) 150 { 151 //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value); 152 this.field.push(field); 153 this.value.push(value); 154 } 155 156 override void accept(Visitor v) 157 { 158 v.visit(this); 159 } 160 } 161 162 /*********************************************************** 163 */ 164 extern (C++) final class ArrayInitializer : Initializer 165 { 166 Expressions index; // indices 167 Initializers value; // of Initializer *'s 168 uint dim; // length of array being initialized 169 Type type; // type that array will be used to initialize 170 bool sem; // true if semantic() is run 171 172 extern (D) this(const ref Loc loc) 173 { 174 super(loc, InitKind.array); 175 } 176 177 extern (D) void addInit(Expression index, Initializer value) 178 { 179 this.index.push(index); 180 this.value.push(value); 181 dim = 0; 182 type = null; 183 } 184 185 bool isAssociativeArray() const pure 186 { 187 foreach (idx; index) 188 { 189 if (idx) 190 return true; 191 } 192 return false; 193 } 194 195 override void accept(Visitor v) 196 { 197 v.visit(this); 198 } 199 } 200 201 /*********************************************************** 202 */ 203 extern (C++) final class ExpInitializer : Initializer 204 { 205 bool expandTuples; 206 Expression exp; 207 208 extern (D) this(const ref Loc loc, Expression exp) 209 { 210 super(loc, InitKind.exp); 211 this.exp = exp; 212 } 213 214 override void accept(Visitor v) 215 { 216 v.visit(this); 217 } 218 } 219 220 version (all) 221 { 222 extern (C++) bool hasNonConstPointers(Expression e) 223 { 224 static bool checkArray(Expressions* elems) 225 { 226 foreach (e; *elems) 227 { 228 if (e && hasNonConstPointers(e)) 229 return true; 230 } 231 return false; 232 } 233 234 if (e.type.ty == Terror) 235 return false; 236 if (e.op == TOK.null_) 237 return false; 238 if (auto se = e.isStructLiteralExp()) 239 { 240 return checkArray(se.elements); 241 } 242 if (auto ae = e.isArrayLiteralExp()) 243 { 244 if (!ae.type.nextOf().hasPointers()) 245 return false; 246 return checkArray(ae.elements); 247 } 248 if (auto ae = e.isAssocArrayLiteralExp()) 249 { 250 if (ae.type.nextOf().hasPointers() && checkArray(ae.values)) 251 return true; 252 if ((cast(TypeAArray)ae.type).index.hasPointers()) 253 return checkArray(ae.keys); 254 return false; 255 } 256 if (auto ae = e.isAddrExp()) 257 { 258 if (auto se = ae.e1.isStructLiteralExp()) 259 { 260 if (!(se.stageflags & stageSearchPointers)) 261 { 262 const old = se.stageflags; 263 se.stageflags |= stageSearchPointers; 264 bool ret = checkArray(se.elements); 265 se.stageflags = old; 266 return ret; 267 } 268 else 269 { 270 return false; 271 } 272 } 273 return true; 274 } 275 if (e.type.ty == Tpointer && e.type.nextOf().ty != Tfunction) 276 { 277 if (e.op == TOK.symbolOffset) // address of a global is OK 278 return false; 279 if (e.op == TOK.int64) // cast(void *)int is OK 280 return false; 281 if (e.op == TOK.string_) // "abc".ptr is OK 282 return false; 283 return true; 284 } 285 return false; 286 } 287 } 288 289 290 /**************************************** 291 * Copy the AST for Initializer. 292 * Params: 293 * inx = Initializer AST to copy 294 * Returns: 295 * the copy 296 */ 297 Initializer syntaxCopy(Initializer inx) 298 { 299 static Initializer copyStruct(StructInitializer vi) 300 { 301 auto si = new StructInitializer(vi.loc); 302 assert(vi.field.dim == vi.value.dim); 303 si.field.setDim(vi.field.dim); 304 si.value.setDim(vi.value.dim); 305 foreach (const i; 0 .. vi.field.dim) 306 { 307 si.field[i] = vi.field[i]; 308 si.value[i] = vi.value[i].syntaxCopy(); 309 } 310 return si; 311 } 312 313 static Initializer copyArray(ArrayInitializer vi) 314 { 315 auto ai = new ArrayInitializer(vi.loc); 316 assert(vi.index.dim == vi.value.dim); 317 ai.index.setDim(vi.index.dim); 318 ai.value.setDim(vi.value.dim); 319 foreach (const i; 0 .. vi.value.dim) 320 { 321 ai.index[i] = vi.index[i] ? vi.index[i].syntaxCopy() : null; 322 ai.value[i] = vi.value[i].syntaxCopy(); 323 } 324 return ai; 325 } 326 327 final switch (inx.kind) 328 { 329 case InitKind.void_: return new VoidInitializer(inx.loc); 330 case InitKind.error: return inx; 331 case InitKind.struct_: return copyStruct(cast(StructInitializer)inx); 332 case InitKind.array: return copyArray(cast(ArrayInitializer)inx); 333 case InitKind.exp: return new ExpInitializer(inx.loc, (cast(ExpInitializer)inx).exp.syntaxCopy()); 334 } 335 }