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 }