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