Mercurial > projects > ddmd
annotate dmd/VarDeclaration.d @ 178:e3afd1303184
Many small bugs fixed
Made all classes derive from TObject to detect memory leaks (functionality is disabled for now)
Began work on overriding backend memory allocations (to avoid memory leaks)
author | korDen |
---|---|
date | Sun, 17 Oct 2010 07:42:00 +0400 |
parents | b7b61140701d |
children | cd48cb899aee |
rev | line source |
---|---|
0 | 1 module dmd.VarDeclaration; |
2 | |
114 | 3 import dmd.common; |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
77
diff
changeset
|
4 import dmd.Array; |
0 | 5 import dmd.Declaration; |
6 import dmd.SliceExp; | |
7 import dmd.ClassDeclaration; | |
8 import dmd.DeleteExp; | |
9 import dmd.SymOffExp; | |
10 import dmd.DotIdExp; | |
11 import dmd.PtrExp; | |
12 import dmd.CallExp; | |
13 import dmd.DotVarExp; | |
14 import dmd.CommaExp; | |
15 import dmd.CastExp; | |
16 import dmd.WANT; | |
17 import dmd.StructDeclaration; | |
68
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
18 import dmd.StorageClassDeclaration; |
0 | 19 import dmd.DsymbolExp; |
20 import dmd.TypeSArray; | |
21 import dmd.IntegerExp; | |
22 import dmd.VarExp; | |
23 import dmd.AssignExp; | |
24 import dmd.TypeTypedef; | |
25 import dmd.ArrayInitializer; | |
26 import dmd.StructInitializer; | |
27 import dmd.NewExp; | |
28 import dmd.TupleDeclaration; | |
29 import dmd.AggregateDeclaration; | |
30 import dmd.InterfaceDeclaration; | |
31 import dmd.TemplateInstance; | |
32 import dmd.Id; | |
33 import dmd.Initializer; | |
34 import dmd.TypeStruct; | |
35 import dmd.TypeTuple; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
36 import dmd.Parameter; |
0 | 37 import dmd.ExpInitializer; |
38 import dmd.ArrayTypes; | |
39 import dmd.Dsymbol; | |
40 import dmd.Expression; | |
41 import dmd.Loc; | |
42 import dmd.STC; | |
43 import dmd.TOK; | |
44 import dmd.TupleExp; | |
45 import dmd.Global; | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
16
diff
changeset
|
46 import dmd.Module; |
0 | 47 import dmd.FuncDeclaration; |
48 import dmd.Type; | |
49 import dmd.TY; | |
50 import dmd.LINK; | |
51 import dmd.Scope; | |
52 import dmd.Identifier; | |
53 import dmd.OutBuffer; | |
54 import dmd.HdrGenState; | |
55 import dmd.PROT; | |
73 | 56 import dmd.expression.Util; |
0 | 57 |
58 import dmd.backend.Symbol; | |
59 import dmd.backend.TYM; | |
60 import dmd.backend.FL; | |
61 import dmd.backend.DT; | |
62 import dmd.backend.mTY; | |
63 import dmd.backend.SC; | |
64 import dmd.backend.mTYman; | |
65 import dmd.backend.TYPE; | |
66 import dmd.backend.Util; | |
67 import dmd.backend.LIST; | |
68 | |
69 import std.stdio : writef; | |
70 import std.string : toStringz; | |
71 | |
72 class VarDeclaration : Declaration | |
73 { | |
74 Initializer init; | |
75 uint offset; | |
76 bool noauto; // no auto semantics | |
77 version (DMDV2) { | |
98 | 78 FuncDeclarations nestedrefs; // referenced by these lexically nested functions |
79 bool isargptr = false; // if parameter that _argptr points to | |
0 | 80 } else { |
81 int nestedref; // referenced by a lexically nested function | |
82 } | |
83 int ctorinit; // it has been initialized in a ctor | |
84 int onstack; // 1: it has been allocated on the stack | |
85 // 2: on stack, run destructor anyway | |
86 int canassign; // it can be assigned to | |
87 Dsymbol aliassym; // if redone as alias to another symbol | |
88 Expression value; // when interpreting, this is the value | |
89 // (null if value not determinable) | |
90 version (DMDV2) { | |
91 VarDeclaration rundtor; // if !null, rundtor is tested at runtime to see | |
92 // if the destructor should be run. Used to prevent | |
93 // dtor calls on postblitted vars | |
94 } | |
95 | |
96 this(Loc loc, Type type, Identifier id, Initializer init) | |
97 { | |
178 | 98 register(); |
0 | 99 super(id); |
100 | |
98 | 101 debug |
102 { | |
0 | 103 if (!type && !init) |
104 { | |
105 writef("VarDeclaration('%s')\n", id.toChars()); | |
106 //*(char*)0=0; | |
107 } | |
108 } | |
109 assert(type || init); | |
110 this.type = type; | |
111 this.init = init; | |
98 | 112 version(_DH) |
113 { | |
114 this.htype = null; | |
115 this.hinit = null; | |
116 } | |
0 | 117 this.loc = loc; |
118 | |
98 | 119 /* TODO: |
120 #if DMDV1 | |
121 nestedref = 0; | |
122 #endif | |
123 ctorinit = 0; | |
124 aliassym = NULL; | |
125 onstack = 0; | |
126 canassign = 0; | |
127 value = NULL; | |
128 rundtor = NULL; | |
129 */ | |
0 | 130 nestedrefs = new FuncDeclarations(); |
131 } | |
132 | |
72 | 133 override Dsymbol syntaxCopy(Dsymbol s) |
0 | 134 { |
135 //printf("VarDeclaration.syntaxCopy(%s)\n", toChars()); | |
136 | |
137 VarDeclaration sv; | |
138 if (s) | |
139 { | |
140 sv = cast(VarDeclaration)s; | |
141 } | |
142 else | |
143 { | |
144 Initializer init = null; | |
145 if (this.init) | |
146 { | |
147 init = this.init.syntaxCopy(); | |
148 //init.isExpInitializer().exp.print(); | |
149 //init.isExpInitializer().exp.dump(0); | |
150 } | |
151 | |
152 sv = new VarDeclaration(loc, type ? type.syntaxCopy() : null, ident, init); | |
153 sv.storage_class = storage_class; | |
154 } | |
155 | |
156 version (_DH) { | |
157 // Syntax copy for header file | |
158 if (!htype) // Don't overwrite original | |
159 { | |
160 if (type) // Make copy for both old and new instances | |
161 { htype = type.syntaxCopy(); | |
162 sv.htype = type.syntaxCopy(); | |
163 } | |
164 } | |
165 else // Make copy of original for new instance | |
166 sv.htype = htype.syntaxCopy(); | |
167 if (!hinit) | |
168 { | |
169 if (init) | |
170 { | |
171 hinit = init.syntaxCopy(); | |
172 sv.hinit = init.syntaxCopy(); | |
173 } | |
174 } | |
175 else | |
176 sv.hinit = hinit.syntaxCopy(); | |
177 } | |
178 return sv; | |
179 } | |
180 | |
72 | 181 override void semantic(Scope sc) |
0 | 182 { |
183 static if (false) { | |
184 printf("VarDeclaration.semantic('%s', parent = '%s')\n", toChars(), sc.parent.toChars()); | |
185 printf(" type = %s\n", type ? type.toChars() : "null"); | |
186 printf(" stc = x%x\n", sc.stc); | |
187 printf(" storage_class = x%x\n", storage_class); | |
188 printf("linkage = %d\n", sc.linkage); | |
189 //if (strcmp(toChars(), "mul") == 0) halt(); | |
190 } | |
191 | |
192 storage_class |= sc.stc; | |
193 if (storage_class & STC.STCextern && init) | |
194 error("extern symbols cannot have initializers"); | |
195 | |
196 /* If auto type inference, do the inference | |
197 */ | |
198 int inferred = 0; | |
199 if (!type) | |
157
b7b61140701d
* added all missing default cases in switch statements
trass3r
parents:
135
diff
changeset
|
200 { |
0 | 201 inuse++; |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
202 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
203 ArrayInitializer ai = init.isArrayInitializer(); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
204 if (ai) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
205 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
206 Expression e; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
207 if (ai.isAssociativeArray()) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
208 e = ai.toAssocArrayLiteral(); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
209 else |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
210 e = init.toExpression(); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
211 init = new ExpInitializer(e.loc, e); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
212 type = init.inferType(sc); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
213 if (type.ty == TY.Tsarray) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
214 type = type.nextOf().arrayOf(); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
215 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
216 else |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
217 type = init.inferType(sc); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
218 |
0 | 219 inuse--; |
220 inferred = 1; | |
221 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
222 if (init.isArrayInitializer() && type.toBasetype().ty == TY.Tsarray) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
223 { // Prefer array literals to give a T[] type rather than a T[dim] |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
224 type = type.toBasetype().nextOf().arrayOf(); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
225 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
226 |
0 | 227 /* This is a kludge to support the existing syntax for RAII |
228 * declarations. | |
229 */ | |
230 storage_class &= ~STC.STCauto; | |
231 originalType = type; | |
232 } | |
233 else | |
234 { | |
235 if (!originalType) | |
236 originalType = type; | |
237 | |
238 type = type.semantic(loc, sc); | |
239 } | |
240 //printf(" semantic type = %s\n", type ? type.toChars() : "null"); | |
241 | |
242 type.checkDeprecated(loc, sc); | |
243 linkage = sc.linkage; | |
244 this.parent = sc.parent; | |
245 //printf("this = %p, parent = %p, '%s'\n", this, parent, parent.toChars()); | |
246 protection = sc.protection; | |
247 //printf("sc.stc = %x\n", sc.stc); | |
248 //printf("storage_class = x%x\n", storage_class); | |
249 | |
250 version (DMDV2) { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
251 static if (true) { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
252 if (storage_class & STC.STCgshared && sc.func && sc.func.isSafe()) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
253 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
254 error("__gshared not allowed in safe functions; use shared"); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
255 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
256 } else { |
0 | 257 if (storage_class & STC.STCgshared && global.params.safe && !sc.module_.safe) |
258 { | |
259 error("__gshared not allowed in safe mode; use shared"); | |
260 } | |
261 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
262 } |
0 | 263 |
264 Dsymbol parent = toParent(); | |
265 FuncDeclaration fd = parent.isFuncDeclaration(); | |
266 | |
267 Type tb = type.toBasetype(); | |
268 if (tb.ty == TY.Tvoid && !(storage_class & STC.STClazy)) | |
269 { error("voids have no value"); | |
270 type = Type.terror; | |
271 tb = type; | |
272 } | |
273 if (tb.ty == TY.Tfunction) | |
274 { error("cannot be declared to be a function"); | |
275 type = Type.terror; | |
276 tb = type; | |
277 } | |
278 if (tb.ty == TY.Tstruct) | |
279 { TypeStruct ts = cast(TypeStruct)tb; | |
280 | |
281 if (!ts.sym.members) | |
282 { | |
283 error("no definition of struct %s", ts.toChars()); | |
284 } | |
285 } | |
286 | |
287 if (tb.ty == TY.Ttuple) | |
288 { /* Instead, declare variables for each of the tuple elements | |
289 * and add those. | |
290 */ | |
291 TypeTuple tt = cast(TypeTuple)tb; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
292 size_t nelems = Parameter.dim(tt.arguments); |
0 | 293 Objects exps = new Objects(); |
294 exps.setDim(nelems); | |
295 Expression ie = init ? init.toExpression() : null; | |
296 | |
297 for (size_t i = 0; i < nelems; i++) | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
298 { auto arg = Parameter.getNth(tt.arguments, i); |
0 | 299 |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
300 auto buf = new OutBuffer(); |
53 | 301 ///buf.printf("_%s_field_%zu", ident.toChars(), i); |
302 buf.printf("_%s_field_%s", ident.toChars(), i); | |
0 | 303 buf.writeByte(0); |
304 string name = buf.extractString(); | |
305 Identifier id = new Identifier(name, TOK.TOKidentifier); | |
306 | |
307 Expression einit = ie; | |
308 if (ie && ie.op == TOK.TOKtuple) | |
113
3482c73a991b
More cleanup for arrays
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
110
diff
changeset
|
309 { einit = (cast(TupleExp)ie).exps[i]; |
0 | 310 } |
311 Initializer ti = init; | |
312 if (einit) | |
313 { ti = new ExpInitializer(einit.loc, einit); | |
314 } | |
315 | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
316 auto v = new VarDeclaration(loc, arg.type, id, ti); |
0 | 317 //printf("declaring field %s of type %s\n", v.toChars(), v.type.toChars()); |
318 v.semantic(sc); | |
319 | |
320 if (sc.scopesym) | |
321 { //printf("adding %s to %s\n", v.toChars(), sc.scopesym.toChars()); | |
322 if (sc.scopesym.members) | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
323 sc.scopesym.members.push(v); |
0 | 324 } |
325 | |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
88
diff
changeset
|
326 auto e = new DsymbolExp(loc, v); |
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
88
diff
changeset
|
327 exps[i] = e; |
0 | 328 } |
94
3a0b150c9841
Objects -> Vector!Object iteration 1
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
88
diff
changeset
|
329 auto v2 = new TupleDeclaration(loc, ident, exps); |
0 | 330 v2.isexp = 1; |
331 aliassym = v2; | |
332 return; | |
333 } | |
334 | |
335 Lagain: | |
336 /* Storage class can modify the type | |
337 */ | |
338 type = type.addStorageClass(storage_class); | |
339 | |
340 /* Adjust storage class to reflect type | |
341 */ | |
342 if (type.isConst()) | |
343 { storage_class |= STC.STCconst; | |
344 if (type.isShared()) | |
345 storage_class |= STC.STCshared; | |
346 } | |
135 | 347 else if (type.isImmutable()) |
0 | 348 storage_class |= STC.STCimmutable; |
349 else if (type.isShared()) | |
350 storage_class |= STC.STCshared; | |
135 | 351 else if (type.isWild()) |
352 storage_class |= STC.STCwild; | |
0 | 353 |
354 if (isSynchronized()) | |
355 { | |
356 error("variable %s cannot be synchronized", toChars()); | |
357 } | |
358 else if (isOverride()) | |
359 { | |
360 error("override cannot be applied to variable"); | |
361 } | |
362 else if (isAbstract()) | |
363 { | |
364 error("abstract cannot be applied to variable"); | |
365 } | |
366 else if (storage_class & STC.STCfinal) | |
367 { | |
368 error("final cannot be applied to variable"); | |
369 } | |
370 | |
371 if (storage_class & (STC.STCstatic | STC.STCextern | STC.STCmanifest | STC.STCtemplateparameter | STC.STCtls | STC.STCgshared)) | |
372 { | |
373 } | |
374 else | |
375 { | |
376 AggregateDeclaration aad = sc.anonAgg; | |
377 if (!aad) | |
378 aad = parent.isAggregateDeclaration(); | |
379 if (aad) | |
380 { | |
381 ///version (DMDV2) { | |
382 assert(!(storage_class & (STC.STCextern | STC.STCstatic | STC.STCtls | STC.STCgshared))); | |
383 | |
384 if (storage_class & (STC.STCconst | STC.STCimmutable) && init) | |
385 { | |
386 if (!type.toBasetype().isTypeBasic()) | |
387 storage_class |= STC.STCstatic; | |
388 } | |
389 else | |
390 ///} | |
391 aad.addField(sc, this); | |
392 } | |
393 | |
394 InterfaceDeclaration id = parent.isInterfaceDeclaration(); | |
395 if (id) | |
396 { | |
397 error("field not allowed in interface"); | |
398 } | |
399 | |
400 /* Templates cannot add fields to aggregates | |
401 */ | |
402 TemplateInstance ti = parent.isTemplateInstance(); | |
403 if (ti) | |
404 { | |
405 // Take care of nested templates | |
406 while (1) | |
407 { | |
408 TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); | |
409 if (!ti2) | |
410 break; | |
411 ti = ti2; | |
412 } | |
413 | |
414 // If it's a member template | |
415 AggregateDeclaration ad = ti.tempdecl.isMember(); | |
416 if (ad && storage_class != STC.STCundefined) | |
417 { | |
418 error("cannot use template to add field to aggregate '%s'", ad.toChars()); | |
419 } | |
420 } | |
421 } | |
422 | |
423 version (DMDV2) { | |
424 if ((storage_class & (STC.STCref | STC.STCparameter | STC.STCforeach)) == STC.STCref && ident != Id.This) | |
425 { | |
426 error("only parameters or foreach declarations can be ref"); | |
427 } | |
135 | 428 |
429 if ((storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest) || | |
430 isDataseg()) && | |
431 type.hasWild()) | |
432 { | |
433 error("only fields, parameters or stack based variables can be inout"); | |
434 } | |
0 | 435 } |
436 | |
437 if (type.isauto() && !noauto) | |
438 { | |
439 if (storage_class & (STC.STCfield | STC.STCout | STC.STCref | STC.STCstatic | STC.STCmanifest | STC.STCtls | STC.STCgshared) || !fd) | |
440 { | |
441 error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope"); | |
442 } | |
443 | |
444 if (!(storage_class & (STC.STCauto | STC.STCscope))) | |
445 { | |
446 if (!(storage_class & STC.STCparameter) && ident != Id.withSym) | |
447 error("reference to scope class must be scope"); | |
448 } | |
449 } | |
450 | |
135 | 451 if ((isConst() || isImmutable()) && !init && !fd) |
0 | 452 { |
453 // Initialize by constructor only | |
454 storage_class |= STC.STCctorinit; | |
455 } | |
456 | |
457 if (init) | |
458 storage_class |= STC.STCinit; // remember we had an explicit initializer | |
459 else if (storage_class & STC.STCmanifest) | |
460 error("manifest constants must have initializers"); | |
461 | |
462 TOK op = TOK.TOKconstruct; | |
463 if (!init && !sc.inunion && !isStatic() && fd && | |
464 (!(storage_class & (STC.STCfield | STC.STCin | STC.STCforeach | STC.STCparameter)) || (storage_class & STC.STCout)) && | |
465 type.size() != 0) | |
466 { | |
467 // Provide a default initializer | |
468 //printf("Providing default initializer for '%s'\n", toChars()); | |
469 if (type.ty == TY.Tstruct && | |
470 (cast(TypeStruct)type).sym.zeroInit) | |
471 { /* If a struct is all zeros, as a special case | |
472 * set it's initializer to the integer 0. | |
473 * In AssignExp.toElem(), we check for this and issue | |
474 * a memset() to initialize the struct. | |
475 * Must do same check in interpreter. | |
476 */ | |
477 Expression e = new IntegerExp(loc, 0, Type.tint32); | |
478 Expression e1; | |
479 e1 = new VarExp(loc, this); | |
480 e = new AssignExp(loc, e1, e); | |
481 e.op = TOK.TOKconstruct; | |
482 e.type = e1.type; // don't type check this, it would fail | |
483 init = new ExpInitializer(loc, e); | |
484 return; | |
485 } | |
486 else if (type.ty == TY.Ttypedef) | |
487 { TypeTypedef td = cast(TypeTypedef)type; | |
488 if (td.sym.init) | |
489 { init = td.sym.init; | |
490 ExpInitializer ie = init.isExpInitializer(); | |
491 if (ie) | |
492 // Make copy so we can modify it | |
493 init = new ExpInitializer(ie.loc, ie.exp); | |
494 } | |
495 else | |
496 init = getExpInitializer(); | |
497 } | |
498 else | |
499 { | |
500 init = getExpInitializer(); | |
501 } | |
502 // Default initializer is always a blit | |
503 op = TOK.TOKblit; | |
504 } | |
505 | |
506 if (init) | |
507 { | |
508 sc = sc.push(); | |
509 sc.stc &= ~(STC.STC_TYPECTOR | STC.STCpure | STC.STCnothrow | STC.STCref); | |
510 | |
511 ArrayInitializer ai = init.isArrayInitializer(); | |
512 if (ai && tb.ty == TY.Taarray) | |
513 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
514 Expression e = ai.toAssocArrayLiteral(); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
515 init = new ExpInitializer(e.loc, e); |
0 | 516 } |
517 | |
518 StructInitializer si = init.isStructInitializer(); | |
519 ExpInitializer ei = init.isExpInitializer(); | |
520 | |
521 // See if initializer is a NewExp that can be allocated on the stack | |
522 if (ei && isScope() && ei.exp.op == TOK.TOKnew) | |
523 { NewExp ne = cast(NewExp)ei.exp; | |
524 if (!(ne.newargs && ne.newargs.dim)) | |
525 { ne.onstack = 1; | |
526 onstack = 1; | |
527 if (type.isBaseOf(ne.newtype.semantic(loc, sc), null)) | |
528 onstack = 2; | |
529 } | |
530 } | |
531 | |
532 // If inside function, there is no semantic3() call | |
533 if (sc.func) | |
534 { | |
535 // If local variable, use AssignExp to handle all the various | |
536 // possibilities. | |
537 if (fd && | |
538 !(storage_class & (STC.STCmanifest | STC.STCstatic | STC.STCtls | STC.STCgshared | STC.STCextern)) && | |
539 !init.isVoidInitializer()) | |
540 { | |
541 //printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars()); | |
542 if (!ei) | |
543 { | |
544 Expression e = init.toExpression(); | |
545 if (!e) | |
546 { | |
547 init = init.semantic(sc, type); | |
548 e = init.toExpression(); | |
549 if (!e) | |
550 { error("is not a static and cannot have static initializer"); | |
551 return; | |
552 } | |
553 } | |
554 ei = new ExpInitializer(init.loc, e); | |
555 init = ei; | |
556 } | |
557 | |
558 Expression e1 = new VarExp(loc, this); | |
559 | |
560 Type t = type.toBasetype(); | |
561 if (t.ty == TY.Tsarray && !(storage_class & (STC.STCref | STC.STCout))) | |
562 { | |
563 ei.exp = ei.exp.semantic(sc); | |
564 if (!ei.exp.implicitConvTo(type)) | |
565 { | |
566 int dim = cast(int)(cast(TypeSArray)t).dim.toInteger(); /// | |
567 // If multidimensional static array, treat as one large array | |
568 while (1) | |
569 { | |
570 t = t.nextOf().toBasetype(); | |
571 if (t.ty != TY.Tsarray) | |
572 break; | |
573 dim *= (cast(TypeSArray)t).dim.toInteger(); | |
574 e1.type = new TypeSArray(t.nextOf(), new IntegerExp(Loc(0), dim, Type.tindex)); | |
575 } | |
576 } | |
577 e1 = new SliceExp(loc, e1, null, null); | |
578 } | |
579 else if (t.ty == TY.Tstruct) | |
580 { | |
581 ei.exp = ei.exp.semantic(sc); | |
98 | 582 ei.exp = resolveProperties(sc, ei.exp); |
583 StructDeclaration sd = (cast(TypeStruct)t).sym; | |
584 version (DMDV2) | |
585 { | |
0 | 586 /* Look to see if initializer is a call to the constructor |
587 */ | |
588 if (sd.ctor && // there are constructors | |
589 ei.exp.type.ty == TY.Tstruct && // rvalue is the same struct | |
590 (cast(TypeStruct)ei.exp.type).sym == sd && | |
591 ei.exp.op == TOK.TOKstar) | |
592 { | |
593 /* Look for form of constructor call which is: | |
594 * *__ctmp.ctor(arguments...) | |
595 */ | |
596 PtrExp pe = cast(PtrExp)ei.exp; | |
597 if (pe.e1.op == TOK.TOKcall) | |
598 { CallExp ce = cast(CallExp)pe.e1; | |
599 if (ce.e1.op == TOK.TOKdotvar) | |
600 { DotVarExp dve = cast(DotVarExp)ce.e1; | |
601 if (dve.var.isCtorDeclaration()) | |
602 { /* It's a constructor call, currently constructing | |
603 * a temporary __ctmp. | |
604 */ | |
605 /* Before calling the constructor, initialize | |
606 * variable with a bit copy of the default | |
607 * initializer | |
608 */ | |
609 Expression e = new AssignExp(loc, new VarExp(loc, this), t.defaultInit(loc)); | |
610 e.op = TOK.TOKblit; | |
611 e.type = t; | |
612 ei.exp = new CommaExp(loc, e, ei.exp); | |
613 | |
614 /* Replace __ctmp being constructed with e1 | |
615 */ | |
616 dve.e1 = e1; | |
617 return; | |
618 } | |
619 } | |
620 } | |
621 } | |
622 } | |
623 if (!ei.exp.implicitConvTo(type)) | |
73 | 624 { |
103 | 625 Type ti = ei.exp.type.toBasetype(); |
98 | 626 // Look for constructor first |
627 if (sd.ctor && | |
628 /* Initializing with the same type is done differently | |
629 */ | |
630 !(ti.ty == Tstruct && t.toDsymbol(sc) == ti.toDsymbol(sc))) | |
631 { | |
632 // Rewrite as e1.ctor(arguments) | |
633 Expression ector = new DotIdExp(loc, e1, Id.ctor); | |
634 ei.exp = new CallExp(loc, ector, ei.exp); | |
635 } | |
636 else | |
73 | 637 /* Look for opCall |
638 * See bugzilla 2702 for more discussion | |
639 */ | |
98 | 640 |
73 | 641 // Don't cast away invariant or mutability in initializer |
642 if (search_function(sd, Id.call) && | |
643 /* Initializing with the same type is done differently | |
644 */ | |
645 !(ti.ty == Tstruct && t.toDsymbol(sc) == ti.toDsymbol(sc))) | |
646 { // Rewrite as e1.call(arguments) | |
647 Expression eCall = new DotIdExp(loc, e1, Id.call); | |
648 ei.exp = new CallExp(loc, eCall, ei.exp); | |
649 } | |
0 | 650 } |
651 } | |
652 ei.exp = new AssignExp(loc, e1, ei.exp); | |
653 ei.exp.op = op; | |
654 canassign++; | |
655 ei.exp = ei.exp.semantic(sc); | |
656 canassign--; | |
657 ei.exp.optimize(WANT.WANTvalue); | |
658 } | |
659 else | |
660 { | |
661 init = init.semantic(sc, type); | |
662 } | |
663 } | |
664 else if (storage_class & (STC.STCconst | STC.STCimmutable | STC.STCmanifest) || | |
135 | 665 type.isConst() || type.isImmutable() || |
98 | 666 parent.isAggregateDeclaration()) |
0 | 667 { |
668 /* Because we may need the results of a const declaration in a | |
669 * subsequent type, such as an array dimension, before semantic2() | |
670 * gets ordinarily run, try to run semantic2() now. | |
671 * Ignore failure. | |
672 */ | |
673 | |
674 if (!global.errors && !inferred) | |
675 { | |
676 uint errors = global.errors; | |
677 global.gag++; | |
678 //printf("+gag\n"); | |
679 Expression e; | |
680 Initializer i2 = init; | |
681 inuse++; | |
682 if (ei) | |
683 { | |
684 e = ei.exp.syntaxCopy(); | |
685 e = e.semantic(sc); | |
686 e = e.implicitCastTo(sc, type); | |
687 } | |
688 else if (si || ai) | |
689 { i2 = init.syntaxCopy(); | |
690 i2 = i2.semantic(sc, type); | |
691 } | |
692 inuse--; | |
693 global.gag--; | |
694 //printf("-gag\n"); | |
695 if (errors != global.errors) // if errors happened | |
696 { | |
697 if (global.gag == 0) | |
698 global.errors = errors; // act as if nothing happened | |
699 version (DMDV2) { | |
700 /* Save scope for later use, to try again | |
701 */ | |
87
b17640f0e4e8
Fixed a bug with a Scope.this(Scope enclosing) being called instead of Scope.clone() method (as a copy ctor replacement)
korDen
parents:
77
diff
changeset
|
702 scope_ = sc.clone(); |
0 | 703 scope_.setNoFree(); |
704 } | |
705 } | |
706 else if (ei) | |
707 { | |
708 if (isDataseg()) | |
709 /* static const/invariant does CTFE | |
710 */ | |
711 e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); | |
712 else | |
713 e = e.optimize(WANT.WANTvalue); | |
714 if (e.op == TOK.TOKint64 || e.op == TOK.TOKstring || e.op == TOK.TOKfloat64) | |
715 { | |
716 ei.exp = e; // no errors, keep result | |
717 } | |
718 ///version (DMDV2) { | |
719 else | |
720 { | |
721 /* Save scope for later use, to try again | |
722 */ | |
87
b17640f0e4e8
Fixed a bug with a Scope.this(Scope enclosing) being called instead of Scope.clone() method (as a copy ctor replacement)
korDen
parents:
77
diff
changeset
|
723 scope_ = sc.clone(); |
0 | 724 scope_.setNoFree(); |
725 } | |
726 ///} | |
727 } | |
728 else | |
729 init = i2; // no errors, keep result | |
730 } | |
731 } | |
732 sc = sc.pop(); | |
733 } | |
734 } | |
735 | |
72 | 736 override void semantic2(Scope sc) |
0 | 737 { |
738 //printf("VarDeclaration.semantic2('%s')\n", toChars()); | |
739 if (init && !toParent().isFuncDeclaration()) | |
740 { | |
741 inuse++; | |
742 static if (false) { | |
743 ExpInitializer ei = init.isExpInitializer(); | |
744 if (ei) | |
745 { | |
746 ei.exp.dump(0); | |
747 printf("type = %p\n", ei.exp.type); | |
748 } | |
749 } | |
750 init = init.semantic(sc, type); | |
751 inuse--; | |
752 } | |
753 } | |
754 | |
72 | 755 override string kind() |
0 | 756 { |
757 return "variable"; | |
758 } | |
759 | |
72 | 760 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 761 { |
68
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
762 StorageClassDeclaration.stcToCBuffer(buf, storage_class); |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
763 |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
764 /* If changing, be sure and fix CompoundDeclarationStatement.toCBuffer() |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
765 * too. |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
766 */ |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
767 if (type) |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
768 type.toCBuffer(buf, ident, hgs); |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
769 else |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
770 buf.writestring(ident.toChars()); |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
771 if (init) |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
772 { |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
773 buf.writestring(" = "); |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
774 ///version (DMDV2) { |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
775 ExpInitializer ie = init.isExpInitializer(); |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
776 if (ie && (ie.exp.op == TOKconstruct || ie.exp.op == TOKblit)) |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
777 (cast(AssignExp)ie.exp).e2.toCBuffer(buf, hgs); |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
778 else |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
779 ///} |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
780 init.toCBuffer(buf, hgs); |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
781 } |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
782 buf.writeByte(';'); |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
53
diff
changeset
|
783 buf.writenl(); |
0 | 784 } |
785 | |
786 version (_DH) { | |
787 Type htype; | |
788 Initializer hinit; | |
789 } | |
72 | 790 override bool needThis() |
0 | 791 { |
792 //printf("VarDeclaration.needThis(%s, x%x)\n", toChars(), storage_class); | |
793 return (storage_class & STC.STCfield) != 0; | |
794 } | |
795 | |
72 | 796 override bool isImportedSymbol() |
0 | 797 { |
798 if (protection == PROT.PROTexport && !init && (storage_class & STC.STCstatic || parent.isModule())) | |
799 return true; | |
800 | |
801 return false; | |
802 } | |
803 | |
72 | 804 override bool isDataseg() |
0 | 805 { |
806 static if (false) { | |
807 printf("VarDeclaration.isDataseg(%p, '%s')\n", this, toChars()); | |
135 | 808 printf("%llx, isModule: %p, isTemplateInstance: %p\n", storage_class & (STC.STCstatic | STC.STCconst), parent.isModule(), parent.isTemplateInstance()); |
0 | 809 printf("parent = '%s'\n", parent.toChars()); |
810 } | |
811 if (storage_class & STC.STCmanifest) | |
812 return false; | |
813 | |
814 Dsymbol parent = this.toParent(); | |
815 if (!parent && !(storage_class & STC.STCstatic)) | |
816 { | |
817 error("forward referenced"); | |
818 type = Type.terror; | |
819 return false; | |
820 } | |
821 | |
822 return canTakeAddressOf() && (storage_class & (STC.STCstatic | STC.STCextern | STC.STCtls | STC.STCgshared) || toParent().isModule() || toParent().isTemplateInstance()); | |
823 } | |
824 | |
72 | 825 override bool isThreadlocal() |
0 | 826 { |
827 //printf("VarDeclaration.isThreadlocal(%p, '%s')\n", this, toChars()); | |
828 static if (false) { /// || TARGET_OSX | |
829 /* To be thread-local, must use the __thread storage class. | |
830 * BUG: OSX doesn't support thread local yet. | |
831 */ | |
832 return isDataseg() && (storage_class & (STC.STCtls | STC.STCconst | STC.STCimmutable | STC.STCshared | STC.STCgshared)) == STC.STCtls; | |
833 } else { | |
834 /* Data defaults to being thread-local. It is not thread-local | |
835 * if it is immutable, const or shared. | |
836 */ | |
837 bool i = isDataseg() && !(storage_class & (STC.STCimmutable | STC.STCconst | STC.STCshared | STC.STCgshared)); | |
838 //printf("\treturn %d\n", i); | |
839 return i; | |
840 } | |
841 } | |
842 | |
135 | 843 /******************************************** |
844 * Can variable be read and written by CTFE? | |
845 */ | |
846 | |
847 int isCTFE() | |
848 { | |
849 return (storage_class & STCctfe) || !isDataseg(); | |
850 } | |
851 | |
72 | 852 override bool hasPointers() |
0 | 853 { |
854 //printf("VarDeclaration.hasPointers() %s, ty = %d\n", toChars(), type.ty); | |
855 return (!isDataseg() && type.hasPointers()); | |
856 } | |
857 | |
858 version (DMDV2) { | |
859 bool canTakeAddressOf() | |
860 { | |
861 static if (false) { | |
862 /* Global variables and struct/class fields of the form: | |
863 * const int x = 3; | |
864 * are not stored and hence cannot have their address taken. | |
865 */ | |
135 | 866 if ((isConst() || isImmutable()) && (storage_class & STC.STCinit) && (!(storage_class & (STC.STCstatic | STC.STCextern)) || (storage_class & STC.STCfield)) && |
0 | 867 (!parent || toParent().isModule() || toParent().isTemplateInstance()) && type.toBasetype().isTypeBasic()) |
868 { | |
869 return false; | |
870 } | |
871 } else { | |
872 if (storage_class & STC.STCmanifest) | |
873 return false; | |
874 } | |
875 return true; | |
876 } | |
877 | |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
878 /****************************************** |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
879 * Return TRUE if variable needs to call the destructor. |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
880 */ |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
881 bool needsAutoDtor() |
0 | 882 { |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
883 //printf("VarDeclaration.needsAutoDtor() %s\n", toChars()); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
884 |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
885 if (noauto || storage_class & STCnodtor) |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
886 return false; |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
887 |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
888 // Destructors for structs and arrays of structs |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
889 Type tv = type.toBasetype(); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
890 while (tv.ty == Tsarray) |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
891 { |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
892 TypeSArray ta = cast(TypeSArray)tv; |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
893 tv = tv.nextOf().toBasetype(); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
894 } |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
895 if (tv.ty == Tstruct) |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
896 { |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
897 TypeStruct ts = cast(TypeStruct)tv; |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
898 StructDeclaration sd = ts.sym; |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
899 if (sd.dtor) |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
900 return true; |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
901 } |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
902 |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
903 // Destructors for classes |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
904 if (storage_class & (STCauto | STCscope)) |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
905 { |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
906 if (type.isClassHandle()) |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
907 return true; |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
908 } |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
909 return false; |
0 | 910 } |
911 } | |
912 | |
913 /****************************************** | |
914 * If a variable has an auto destructor call, return call for it. | |
915 * Otherwise, return null. | |
916 */ | |
917 Expression callAutoDtor(Scope sc) | |
918 { | |
919 Expression e = null; | |
920 | |
921 //printf("VarDeclaration.callAutoDtor() %s\n", toChars()); | |
922 | |
923 if (noauto || storage_class & STC.STCnodtor) | |
924 return null; | |
925 | |
926 // Destructors for structs and arrays of structs | |
927 bool array = false; | |
928 Type tv = type.toBasetype(); | |
929 while (tv.ty == TY.Tsarray) | |
930 { | |
931 TypeSArray ta = cast(TypeSArray)tv; | |
932 array = true; | |
933 tv = tv.nextOf().toBasetype(); | |
934 } | |
935 if (tv.ty == TY.Tstruct) | |
936 { | |
937 TypeStruct ts = cast(TypeStruct)tv; | |
938 StructDeclaration sd = ts.sym; | |
939 if (sd.dtor) | |
940 { | |
941 if (array) | |
942 { | |
943 // Typeinfo.destroy(cast(void*)&v); | |
944 Expression ea = new SymOffExp(loc, this, 0, 0); | |
945 ea = new CastExp(loc, ea, Type.tvoid.pointerTo()); | |
946 Expressions args = new Expressions(); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
77
diff
changeset
|
947 args.push(ea); |
0 | 948 |
949 Expression et = type.getTypeInfo(sc); | |
950 et = new DotIdExp(loc, et, Id.destroy); | |
951 | |
952 e = new CallExp(loc, et, args); | |
953 } | |
954 else | |
955 { | |
956 e = new VarExp(loc, this); | |
957 e = new DotVarExp(loc, e, sd.dtor, 0); | |
958 e = new CallExp(loc, e); | |
959 } | |
960 return e; | |
961 } | |
962 } | |
963 | |
964 // Destructors for classes | |
965 if (storage_class & (STC.STCauto | STC.STCscope)) | |
966 { | |
967 for (ClassDeclaration cd = type.isClassHandle(); cd; cd = cd.baseClass) | |
968 { | |
969 /* We can do better if there's a way with onstack | |
970 * classes to determine if there's no way the monitor | |
971 * could be set. | |
972 */ | |
973 //if (cd.isInterfaceDeclaration()) | |
974 //error("interface %s cannot be scope", cd.toChars()); | |
975 if (1 || onstack || cd.dtors.dim) // if any destructors | |
976 { | |
977 // delete this; | |
978 Expression ec = new VarExp(loc, this); | |
979 e = new DeleteExp(loc, ec); | |
980 e.type = Type.tvoid; | |
981 break; | |
982 } | |
983 } | |
984 } | |
985 return e; | |
986 } | |
987 | |
988 /**************************** | |
989 * Get ExpInitializer for a variable, if there is one. | |
990 */ | |
991 ExpInitializer getExpInitializer() | |
992 { | |
993 ExpInitializer ei; | |
994 | |
995 if (init) | |
996 ei = init.isExpInitializer(); | |
997 else | |
998 { | |
999 Expression e = type.defaultInit(loc); | |
1000 if (e) | |
1001 ei = new ExpInitializer(loc, e); | |
1002 else | |
1003 ei = null; | |
1004 } | |
1005 return ei; | |
1006 } | |
1007 | |
1008 /******************************************* | |
1009 * If variable has a constant expression initializer, get it. | |
1010 * Otherwise, return null. | |
1011 */ | |
1012 Expression getConstInitializer() | |
1013 { | |
135 | 1014 if ((isConst() || isImmutable() || storage_class & STC.STCmanifest) && storage_class & STC.STCinit) |
0 | 1015 { |
1016 ExpInitializer ei = getExpInitializer(); | |
1017 if (ei) | |
1018 return ei.exp; | |
1019 } | |
1020 | |
1021 return null; | |
1022 } | |
1023 | |
72 | 1024 override void checkCtorConstInit() |
0 | 1025 { |
1026 static if (false) { /* doesn't work if more than one static ctor */ | |
1027 if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) | |
1028 error("missing initializer in static constructor for const variable"); | |
1029 } | |
1030 } | |
1031 | |
1032 /************************************ | |
1033 * Check to see if this variable is actually in an enclosing function | |
1034 * rather than the current one. | |
1035 */ | |
1036 void checkNestedReference(Scope sc, Loc loc) | |
1037 { | |
1038 if (parent && !isDataseg() && parent != sc.parent && !(storage_class & STC.STCmanifest)) | |
1039 { | |
1040 // The function that this variable is in | |
1041 FuncDeclaration fdv = toParent().isFuncDeclaration(); | |
1042 // The current function | |
1043 FuncDeclaration fdthis = sc.parent.isFuncDeclaration(); | |
1044 | |
1045 if (fdv && fdthis && fdv !is fdthis) | |
1046 { | |
1047 if (loc.filename) | |
1048 fdthis.getLevel(loc, fdv); | |
1049 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
77
diff
changeset
|
1050 foreach (f; nestedrefs) |
0 | 1051 { |
1052 if (f == fdthis) | |
1053 goto L1; | |
1054 } | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
1055 nestedrefs.push(fdthis); |
0 | 1056 L1: ; |
1057 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
77
diff
changeset
|
1058 foreach (s; fdv.closureVars) |
0 | 1059 { |
1060 if (s == this) | |
1061 goto L2; | |
1062 } | |
1063 | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
1064 fdv.closureVars.push(this); |
0 | 1065 L2: ; |
1066 | |
1067 //printf("fdthis is %s\n", fdthis.toChars()); | |
1068 //printf("var %s in function %s is nested ref\n", toChars(), fdv.toChars()); | |
1069 } | |
1070 } | |
1071 } | |
1072 | |
72 | 1073 override Dsymbol toAlias() |
0 | 1074 { |
1075 //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); | |
1076 assert(this !is aliassym); | |
1077 return aliassym ? aliassym.toAlias() : this; | |
1078 } | |
1079 | |
72 | 1080 override Symbol* toSymbol() |
0 | 1081 { |
1082 //printf("VarDeclaration.toSymbol(%s)\n", toChars()); | |
1083 //if (needThis()) *(char*)0=0; | |
1084 assert(!needThis()); | |
1085 if (!csym) | |
1086 { | |
1087 Symbol* s; | |
1088 TYPE* t; | |
1089 string id; | |
1090 | |
1091 if (isDataseg()) | |
1092 id = mangle(); | |
1093 else | |
1094 id = ident.toChars(); | |
1095 | |
1096 s = symbol_calloc(toStringz(id)); | |
1097 | |
1098 if (storage_class & (STC.STCout | STC.STCref)) | |
1099 { | |
1100 if (global.params.symdebug && storage_class & STC.STCparameter) | |
1101 { | |
1102 t = type_alloc(TYM.TYnptr); // should be TYref, but problems in back end | |
1103 t.Tnext = type.toCtype(); | |
1104 t.Tnext.Tcount++; | |
1105 } | |
1106 else | |
1107 t = type_fake(TYM.TYnptr); | |
1108 } | |
1109 else if (storage_class & STC.STClazy) | |
1110 t = type_fake(TYM.TYdelegate); // Tdelegate as C type | |
1111 else if (isParameter()) | |
1112 t = type.toCParamtype(); | |
1113 else | |
1114 t = type.toCtype(); | |
1115 | |
1116 t.Tcount++; | |
1117 | |
1118 if (isDataseg()) | |
1119 { | |
1120 if (isThreadlocal()) | |
1121 { | |
1122 /* Thread local storage | |
1123 */ | |
1124 TYPE* ts = t; | |
1125 ts.Tcount++; // make sure a different t is allocated | |
1126 type_setty(&t, t.Tty | mTY.mTYthread); | |
1127 ts.Tcount--; | |
1128 | |
1129 if (global.params.vtls) | |
1130 { | |
1131 string p = loc.toChars(); | |
1132 writef("%s: %s is thread local\n", p ? p : "", toChars()); | |
1133 } | |
1134 } | |
1135 | |
1136 s.Sclass = SC.SCextern; | |
1137 s.Sfl = FL.FLextern; | |
1138 slist_add(s); | |
1139 } | |
1140 else | |
1141 { | |
1142 s.Sclass = SC.SCauto; | |
1143 s.Sfl = FL.FLauto; | |
1144 | |
1145 if (nestedrefs.dim) | |
1146 { | |
1147 /* Symbol is accessed by a nested function. Make sure | |
1148 * it is not put in a register, and that the optimizer | |
1149 * assumes it is modified across function calls and pointer | |
1150 * dereferences. | |
1151 */ | |
1152 //printf("\tnested ref, not register\n"); | |
1153 type_setcv(&t, t.Tty | mTY.mTYvolatile); | |
1154 } | |
1155 } | |
1156 | |
1157 mangle_t m = 0; | |
1158 switch (linkage) | |
1159 { | |
1160 case LINK.LINKwindows: | |
1161 m = mTYman.mTYman_std; | |
1162 break; | |
1163 | |
1164 case LINK.LINKpascal: | |
1165 m = mTYman.mTYman_pas; | |
1166 break; | |
1167 | |
1168 case LINK.LINKc: | |
1169 m = mTYman.mTYman_c; | |
1170 break; | |
1171 | |
1172 case LINK.LINKd: | |
1173 m = mTYman.mTYman_d; | |
1174 break; | |
1175 | |
1176 case LINK.LINKcpp: | |
1177 m = mTYman.mTYman_cpp; | |
1178 break; | |
1179 | |
1180 default: | |
1181 writef("linkage = %d\n", linkage); | |
1182 assert(0); | |
1183 } | |
1184 type_setmangle(&t, m); | |
1185 s.Stype = t; | |
1186 | |
1187 csym = s; | |
1188 } | |
1189 return csym; | |
1190 } | |
1191 | |
72 | 1192 override void toObjFile(int multiobj) // compile to .obj file |
0 | 1193 { |
1194 Symbol* s; | |
1195 uint sz; | |
1196 Dsymbol parent; | |
1197 | |
1198 //printf("VarDeclaration.toObjFile(%p '%s' type=%s) protection %d\n", this, toChars(), type.toChars(), protection); | |
1199 //printf("\talign = %d\n", type.alignsize()); | |
1200 | |
1201 if (aliassym) | |
1202 { | |
1203 toAlias().toObjFile(0); | |
1204 return; | |
1205 } | |
1206 | |
1207 version (DMDV2) { | |
1208 // Do not store variables we cannot take the address of | |
1209 if (!canTakeAddressOf()) | |
1210 { | |
1211 return; | |
1212 } | |
1213 } | |
1214 | |
1215 if (isDataseg() && !(storage_class & STC.STCextern)) | |
1216 { | |
1217 s = toSymbol(); | |
1218 sz = cast(uint)type.size(); | |
1219 | |
1220 parent = this.toParent(); | |
1221 /// version (DMDV1) { /* private statics should still get a global symbol, in case | |
1222 /// * another module inlines a function that references it. | |
1223 /// */ | |
1224 /// if (/*protection == PROT.PROTprivate ||*/ | |
1225 /// !parent || parent.ident == null || parent.isFuncDeclaration()) | |
1226 /// { | |
1227 /// s.Sclass = SC.SCstatic; | |
1228 /// } | |
1229 /// else | |
1230 /// } | |
1231 { | |
1232 if (storage_class & STC.STCcomdat) | |
1233 s.Sclass = SC.SCcomdat; | |
1234 else | |
1235 s.Sclass = SC.SCglobal; | |
1236 | |
1237 do | |
1238 { | |
1239 /* Global template data members need to be in comdat's | |
1240 * in case multiple .obj files instantiate the same | |
1241 * template with the same types. | |
1242 */ | |
1243 if (parent.isTemplateInstance() && !parent.isTemplateMixin()) | |
1244 { | |
1245 version (DMDV1) { | |
1246 /* These symbol constants have already been copied, | |
1247 * so no reason to output them. | |
1248 * Note that currently there is no way to take | |
1249 * the address of such a const. | |
1250 */ | |
1251 if (isConst() && type.toBasetype().ty != TY.Tsarray && init && init.isExpInitializer()) | |
1252 return; | |
1253 } | |
1254 s.Sclass = SC.SCcomdat; | |
1255 break; | |
1256 } | |
1257 parent = parent.parent; | |
1258 } while (parent); | |
1259 } | |
1260 | |
1261 s.Sfl = FL.FLdata; | |
1262 | |
1263 if (init) | |
1264 { | |
1265 s.Sdt = init.toDt(); | |
1266 | |
1267 // Look for static array that is block initialized | |
1268 Type tb; | |
1269 ExpInitializer ie = init.isExpInitializer(); | |
1270 | |
1271 tb = type.toBasetype(); | |
1272 if (tb.ty == TY.Tsarray && ie | |
1273 && !tb.nextOf().equals(ie.exp.type.toBasetype().nextOf()) | |
1274 && ie.exp.implicitConvTo(tb.nextOf())) | |
1275 { | |
1276 int dim = cast(int)(cast(TypeSArray)tb).dim.toInteger(); | |
1277 | |
1278 // Duplicate Sdt 'dim-1' times, as we already have the first one | |
1279 while (--dim > 0) | |
1280 { | |
1281 ie.exp.toDt(&s.Sdt); | |
1282 } | |
1283 } | |
1284 } | |
1285 else if (storage_class & STC.STCextern) | |
1286 { | |
1287 s.Sclass = SC.SCextern; | |
1288 s.Sfl = FL.FLextern; | |
1289 s.Sdt = null; | |
1290 // BUG: if isExport(), shouldn't we make it dllimport? | |
1291 return; | |
1292 } | |
1293 else | |
1294 { | |
1295 type.toDt(&s.Sdt); | |
1296 } | |
1297 dt_optimize(s.Sdt); | |
1298 | |
1299 // See if we can convert a comdat to a comdef, | |
1300 // which saves on exe file space. | |
1301 if (s.Sclass == SC.SCcomdat && | |
1302 s.Sdt && | |
1303 s.Sdt.dt == DT.DT_azeros && | |
1304 s.Sdt.DTnext is null && | |
1305 !isThreadlocal()) | |
1306 { | |
1307 s.Sclass = SC.SCglobal; | |
1308 s.Sdt.dt = DT.DT_common; | |
1309 } | |
1310 | |
1311 version (ELFOBJ_OR_MACHOBJ) { // Burton | |
1312 if (s.Sdt && s.Sdt.dt == DT.DT_azeros && s.Sdt.DTnext is null) | |
1313 s.Sseg = Segment.UDATA; | |
1314 else | |
1315 s.Sseg = Segment.DATA; | |
1316 } | |
1317 if (sz) | |
1318 { | |
1319 outdata(s); | |
1320 if (isExport()) | |
1321 obj_export(s, 0); | |
1322 } | |
1323 } | |
1324 } | |
1325 | |
72 | 1326 override int cvMember(ubyte* p) |
0 | 1327 { |
1328 assert(false); | |
1329 } | |
1330 | |
1331 // Eliminate need for dynamic_cast | |
72 | 1332 override VarDeclaration isVarDeclaration() { return this; } |
16
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
1333 } |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
77
diff
changeset
|
1334 |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
77
diff
changeset
|
1335 alias Vector!VarDeclaration VarDeclarations; |