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