Mercurial > projects > ddmd
annotate dmd/StructLiteralExp.d @ 114:e28b18c23469
added a module dmd.common for commonly used stuff
it currently holds code for consistency checking of predefined versions
also added a VisualD project file
author | Trass3r |
---|---|
date | Wed, 01 Sep 2010 18:21:58 +0200 |
parents | ceda59b4d255 |
children | 9e39c7de8438 |
rev | line source |
---|---|
72 | 1 module dmd.StructLiteralExp; |
2 | |
114 | 3 import dmd.common; |
72 | 4 import dmd.Expression; |
5 import dmd.MOD; | |
6 import dmd.TypeStruct; | |
7 import dmd.TypeSArray; | |
8 import dmd.expression.Util; | |
9 import dmd.ErrorExp; | |
10 import dmd.Dsymbol; | |
11 import dmd.VarDeclaration; | |
12 import dmd.StructDeclaration; | |
13 import dmd.FuncDeclaration; | |
14 import dmd.ThisDeclaration; | |
15 import dmd.backend.elem; | |
16 import dmd.InterState; | |
17 import dmd.MATCH; | |
18 import dmd.WANT; | |
19 import dmd.TY; | |
20 import dmd.Type; | |
21 import dmd.OutBuffer; | |
22 import dmd.Loc; | |
23 import dmd.Scope; | |
109 | 24 import dmd.Initializer; |
72 | 25 import dmd.InlineCostState; |
26 import dmd.IRState; | |
27 import dmd.InlineDoState; | |
28 import dmd.backend.Symbol; | |
29 import dmd.HdrGenState; | |
30 import dmd.backend.dt_t; | |
31 import dmd.InlineScanState; | |
79 | 32 import dmd.ArrayLiteralExp; |
72 | 33 import dmd.ArrayTypes; |
34 import dmd.TOK; | |
35 | |
36 import dmd.codegen.Util; | |
37 import dmd.backend.Util; | |
38 import dmd.backend.RTLSYM; | |
39 import dmd.backend.TYM; | |
40 import dmd.backend.mTY; | |
41 import dmd.backend.OPER; | |
42 | |
43 | |
0 | 44 class StructLiteralExp : Expression |
45 { | |
72 | 46 StructDeclaration sd; // which aggregate this is for |
79 | 47 Expressions elements; // parallels sd.fields[] with |
72 | 48 // NULL entries for fields to skip |
49 | |
50 Symbol* sym; // back end symbol to initialize with literal | |
51 size_t soffset; // offset from start of s | |
0 | 52 int fillHoles; // fill alignment 'holes' with zero |
53 | |
54 this(Loc loc, StructDeclaration sd, Expressions elements) | |
55 { | |
72 | 56 super(loc, TOKstructliteral, StructLiteralExp.sizeof); |
57 this.sd = sd; | |
58 this.elements = elements; | |
59 this.sym = null; | |
60 this.soffset = 0; | |
61 this.fillHoles = 1; | |
0 | 62 } |
63 | |
72 | 64 override Expression syntaxCopy() |
0 | 65 { |
66 assert(false); | |
67 } | |
68 | |
72 | 69 override Expression semantic(Scope sc) |
0 | 70 { |
72 | 71 Expression e; |
72 int nfields = sd.fields.dim - sd.isnested; | |
73 | |
74 version (LOGSEMANTIC) { | |
75 printf("StructLiteralExp.semantic('%s')\n", toChars()); | |
76 } | |
77 if (type) | |
78 return this; | |
79 | |
80 // Run semantic() on each element | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
81 foreach(size_t i, Expression e; elements) |
72 | 82 { |
83 if (!e) | |
84 continue; | |
85 e = e.semantic(sc); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
86 elements[i] = e; |
72 | 87 } |
88 expandTuples(elements); | |
89 size_t offset = 0; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
90 foreach(size_t i, Expression e; elements) |
72 | 91 { |
92 if (!e) | |
93 continue; | |
94 | |
95 if (!e.type) | |
96 error("%s has no value", e.toChars()); | |
97 e = resolveProperties(sc, e); | |
98 if (i >= nfields) | |
99 { | |
100 error("more initializers than fields of %s", sd.toChars()); | |
101 return new ErrorExp(); | |
102 } | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
103 auto s = sd.fields[i]; |
72 | 104 VarDeclaration v = s.isVarDeclaration(); |
105 assert(v); | |
106 if (v.offset < offset) | |
107 error("overlapping initialization for %s", v.toChars()); | |
108 offset = v.offset + cast(uint)v.type.size(); | |
109 | |
110 Type telem = v.type; | |
111 while (!e.implicitConvTo(telem) && telem.toBasetype().ty == Tsarray) | |
112 { | |
113 /* Static array initialization, as in: | |
114 * T[3][5] = e; | |
115 */ | |
116 telem = telem.toBasetype().nextOf(); | |
117 } | |
118 | |
119 e = e.implicitCastTo(sc, telem); | |
120 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
121 elements[i] = e; |
72 | 122 } |
123 | |
124 /* Fill out remainder of elements[] with default initializers for fields[] | |
125 */ | |
126 for (size_t i = elements.dim; i < nfields; i++) | |
127 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
128 VarDeclaration v = sd.fields[i]; |
72 | 129 assert(v); |
130 assert(!v.isThisDeclaration()); | |
131 | |
132 if (v.offset < offset) | |
133 { | |
134 e = null; | |
135 sd.hasUnions = 1; | |
136 } | |
137 else | |
138 { | |
139 if (v.init) | |
140 { | |
141 e = v.init.toExpression(); | |
142 if (!e) | |
109 | 143 { |
72 | 144 error("cannot make expression out of initializer for %s", v.toChars()); |
109 | 145 e = new ErrorExp(); |
146 } | |
147 else if (v.scope_) | |
148 { | |
149 // Do deferred semantic anaylsis | |
150 Initializer i2 = v.init.syntaxCopy(); | |
151 i2 = i2.semantic(v.scope_, v.type); | |
152 e = i2.toExpression(); | |
153 v.scope_ = null; | |
154 } | |
72 | 155 } |
156 else | |
157 { | |
158 e = v.type.defaultInit(Loc(0)); | |
159 e.loc = loc; | |
160 } | |
161 offset = v.offset + cast(uint)v.type.size(); | |
162 } | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
163 elements.push(e); |
72 | 164 } |
165 | |
166 type = sd.type; | |
63 | 167 return this; |
0 | 168 } |
169 | |
109 | 170 /************************************** |
171 * Gets expression at offset of type. | |
172 * Returns null if not found. | |
173 */ | |
0 | 174 Expression getField(Type type, uint offset) |
175 { | |
79 | 176 //printf("StructLiteralExp.getField(this = %s, type = %s, offset = %u)\n", |
177 // /*toChars()*/"", type.toChars(), offset); | |
178 Expression e = null; | |
179 int i = getFieldIndex(type, offset); | |
180 | |
181 if (i != -1) | |
182 { | |
183 //printf("\ti = %d\n", i); | |
184 assert(i < elements.dim); | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
85
diff
changeset
|
185 e = elements[i]; |
79 | 186 if (e) |
187 { | |
188 //writef("e = %s, e.type = %s\n", e.toChars(), e.type.toChars()); | |
189 | |
190 /* If type is a static array, and e is an initializer for that array, | |
191 * then the field initializer should be an array literal of e. | |
192 */ | |
193 if (e.type != type && type.ty == Tsarray) | |
194 { | |
195 TypeSArray tsa = cast(TypeSArray)type; | |
196 size_t length = cast(size_t) tsa.dim.toInteger(); | |
197 Expressions z = new Expressions; | |
198 z.setDim(length); | |
199 for (int q = 0; q < length; ++q) | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
85
diff
changeset
|
200 z[q] = e.copy(); |
79 | 201 e = new ArrayLiteralExp(loc, z); |
202 e.type = type; | |
203 } | |
204 else | |
205 { | |
206 e = e.copy(); | |
207 e.type = type; | |
208 } | |
209 } | |
210 } | |
211 return e; | |
0 | 212 } |
213 | |
214 int getFieldIndex(Type type, uint offset) | |
215 { | |
79 | 216 /* Find which field offset is by looking at the field offsets |
217 */ | |
218 if (elements.dim) | |
219 { | |
85
8e69d041a99d
Previous commit didn't compile. Fixed.
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
220 foreach (size_t i, VarDeclaration v; sd.fields) |
79 | 221 { |
222 assert(v); | |
223 | |
224 if (offset == v.offset && type.size() == v.type.size()) | |
225 { | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
85
diff
changeset
|
226 auto e = elements[i]; |
79 | 227 if (e) |
228 { | |
229 return i; | |
230 } | |
231 break; | |
232 } | |
233 } | |
234 } | |
235 return -1; | |
0 | 236 } |
237 | |
72 | 238 override elem* toElem(IRState* irs) |
0 | 239 { |
72 | 240 elem* e; |
241 size_t dim; | |
242 | |
243 //printf("StructLiteralExp.toElem() %s\n", toChars()); | |
244 | |
245 // struct symbol to initialize with the literal | |
246 Symbol* stmp = sym ? sym : symbol_genauto(sd.type.toCtype()); | |
247 | |
248 e = null; | |
249 | |
250 if (fillHoles) | |
251 { | |
252 /* Initialize all alignment 'holes' to zero. | |
253 * Do before initializing fields, as the hole filling process | |
254 * can spill over into the fields. | |
255 */ | |
256 size_t offset = 0; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
257 foreach (VarDeclaration v; sd.fields) |
72 | 258 { |
259 assert(v); | |
260 | |
261 e = el_combine(e, fillHole(stmp, &offset, v.offset, sd.structsize)); | |
262 size_t vend = v.offset + cast(uint)v.type.size(); | |
263 if (offset < vend) | |
264 offset = vend; | |
265 } | |
266 e = el_combine(e, fillHole(stmp, &offset, sd.structsize, sd.structsize)); | |
267 } | |
268 | |
269 if (elements) | |
270 { | |
271 dim = elements.dim; | |
272 assert(dim <= sd.fields.dim); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
273 foreach (size_t i, Expression el; elements) |
72 | 274 { |
275 if (!el) | |
276 continue; | |
277 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
278 VarDeclaration v = sd.fields[i]; |
72 | 279 assert(v); |
280 assert(!v.isThisDeclaration()); | |
281 | |
282 elem* e1; | |
283 if (tybasic(stmp.Stype.Tty) == TYnptr) | |
284 { | |
285 e1 = el_var(stmp); | |
286 e1.EV.sp.Voffset = soffset; | |
287 } | |
288 else | |
289 { | |
290 e1 = el_ptr(stmp); | |
291 if (soffset) | |
292 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset)); | |
293 } | |
294 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); | |
295 elem* ec = e1; // pointer to destination | |
296 | |
297 elem* ep = el.toElem(irs); | |
298 | |
299 Type t1b = v.type.toBasetype(); | |
300 Type t2b = el.type.toBasetype(); | |
301 if (t1b.ty == Tsarray) | |
302 { | |
303 if (t2b.implicitConvTo(t1b)) | |
304 { | |
305 ///version (DMDV2) { | |
306 // Determine if postblit is needed | |
307 int postblit = 0; | |
308 if (needsPostblit(t1b)) | |
309 postblit = 1; | |
310 | |
311 if (postblit) | |
312 { | |
313 /* Generate: | |
314 * _d_arrayctor(ti, From: ep, To: e1) | |
315 */ | |
316 Expression ti = t1b.nextOf().toBasetype().getTypeInfo(null); | |
317 elem* esize = el_long(TYsize_t, (cast(TypeSArray)t1b).dim.toInteger()); | |
318 e1 = el_pair(TYdarray, esize, e1); | |
319 ep = el_pair(TYdarray, el_copytree(esize), array_toPtr(el.type, ep)); | |
320 ep = el_params(e1, ep, ti.toElem(irs), null); | |
321 int rtl = RTLSYM_ARRAYCTOR; | |
322 e1 = el_bin(OPcall, type.totym(), el_var(rtlsym[rtl]), ep); | |
323 } | |
324 else | |
325 ///} | |
326 { | |
327 elem* esize = el_long(TYsize_t, t1b.size()); | |
328 ep = array_toPtr(el.type, ep); | |
329 e1 = el_bin(OPmemcpy, TYnptr, e1, el_param(ep, esize)); | |
330 } | |
331 } | |
332 else | |
333 { | |
334 elem* edim = el_long(TYsize_t, t1b.size() / t2b.size()); | |
335 e1 = setArray(e1, edim, t2b, ep, irs, TOKconstruct); | |
336 } | |
337 } | |
338 else | |
339 { | |
340 tym_t ty = v.type.totym(); | |
341 e1 = el_una(OPind, ty, e1); | |
342 if (tybasic(ty) == TYstruct) | |
343 e1.Enumbytes = cast(uint)v.type.size(); | |
344 e1 = el_bin(OPeq, ty, e1, ep); | |
345 if (tybasic(ty) == TYstruct) | |
346 { | |
347 e1.Eoper = OPstreq; | |
348 e1.Enumbytes = cast(uint)v.type.size(); | |
349 } | |
350 version (DMDV2) { | |
351 /* Call postblit() on e1 | |
352 */ | |
353 StructDeclaration sd = needsPostblit(v.type); | |
354 if (sd) | |
355 { | |
356 FuncDeclaration fd = sd.postblit; | |
357 ec = el_copytree(ec); | |
358 ec = callfunc(loc, irs, 1, Type.tvoid, ec, sd.type.pointerTo(), fd, fd.type, null, null); | |
359 e1 = el_bin(OPcomma, ec.Ety, e1, ec); | |
360 } | |
361 } | |
362 } | |
363 e = el_combine(e, e1); | |
364 } | |
365 } | |
366 | |
79 | 367 version (DMDV2) |
368 { | |
72 | 369 if (sd.isnested) |
370 { // Initialize the hidden 'this' pointer | |
371 assert(sd.fields.dim); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
372 auto s = sd.fields[sd.fields.dim - 1]; |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
373 auto v = s.isThisDeclaration(); |
72 | 374 assert(v); |
375 | |
376 elem* e1; | |
377 if (tybasic(stmp.Stype.Tty) == TYnptr) | |
378 { | |
379 e1 = el_var(stmp); | |
380 e1.EV.sp.Voffset = soffset; | |
381 } | |
382 else | |
383 { | |
384 e1 = el_ptr(stmp); | |
385 if (soffset) | |
386 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset)); | |
387 } | |
388 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); | |
389 e1 = setEthis(loc, irs, e1, sd); | |
390 | |
391 e = el_combine(e, e1); | |
392 } | |
393 } | |
394 | |
395 elem* ev = el_var(stmp); | |
396 ev.Enumbytes = sd.structsize; | |
397 e = el_combine(e, ev); | |
398 el_setLoc(e,loc); | |
67 | 399 return e; |
0 | 400 } |
401 | |
72 | 402 override bool checkSideEffect(int flag) |
0 | 403 { |
79 | 404 bool f = 0; |
405 | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
85
diff
changeset
|
406 foreach (e; elements) |
79 | 407 { |
408 if (!e) | |
409 continue; | |
410 | |
411 f |= e.checkSideEffect(2); | |
412 } | |
413 if (flag == 0 && f == 0) | |
414 Expression.checkSideEffect(0); | |
415 return f; | |
0 | 416 } |
417 | |
72 | 418 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 419 { |
79 | 420 buf.writestring(sd.toChars()); |
421 buf.writeByte('('); | |
422 argsToCBuffer(buf, elements, hgs); | |
423 buf.writeByte(')'); | |
0 | 424 } |
425 | |
72 | 426 override void toMangleBuffer(OutBuffer buf) |
0 | 427 { |
79 | 428 size_t dim = elements ? elements.dim : 0; |
429 buf.printf("S%u", dim); | |
430 for (size_t i = 0; i < dim; i++) | |
431 { | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
85
diff
changeset
|
432 auto e = elements[i]; |
79 | 433 if (e) |
434 e.toMangleBuffer(buf); | |
435 else | |
436 buf.writeByte('v'); // 'v' for void | |
437 } | |
0 | 438 } |
439 | |
72 | 440 override void scanForNestedRef(Scope sc) |
0 | 441 { |
442 assert(false); | |
443 } | |
444 | |
72 | 445 override Expression optimize(int result) |
0 | 446 { |
72 | 447 if (elements) |
448 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
449 foreach (size_t i, Expression e; elements) |
72 | 450 { |
451 if (!e) | |
452 continue; | |
453 e = e.optimize(WANTvalue | (result & WANTinterpret)); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
454 elements[i] = e; |
72 | 455 } |
456 } | |
56 | 457 return this; |
0 | 458 } |
459 | |
72 | 460 override Expression interpret(InterState istate) |
0 | 461 { |
462 assert(false); | |
463 } | |
464 | |
72 | 465 override dt_t** toDt(dt_t** pdt) |
0 | 466 { |
467 assert(false); | |
468 } | |
469 | |
79 | 470 version(DMDV2) |
471 { | |
72 | 472 override int isLvalue() |
0 | 473 { |
79 | 474 return 1; |
0 | 475 } |
79 | 476 } |
0 | 477 |
72 | 478 override Expression toLvalue(Scope sc, Expression e) |
0 | 479 { |
79 | 480 return this; |
0 | 481 } |
482 | |
79 | 483 version(DMDV2) |
484 { | |
72 | 485 override bool canThrow() |
0 | 486 { |
64 | 487 return arrayExpressionCanThrow(elements); |
0 | 488 } |
79 | 489 } |
0 | 490 |
72 | 491 override MATCH implicitConvTo(Type t) |
0 | 492 { |
72 | 493 static if (false) { |
494 printf("StructLiteralExp.implicitConvTo(this=%.*s, type=%.*s, t=%.*s)\n", | |
495 toChars(), type.toChars(), t.toChars()); | |
496 } | |
497 MATCH m = Expression.implicitConvTo(t); | |
498 if (m != MATCHnomatch) | |
499 return m; | |
500 if (type.ty == t.ty && type.ty == Tstruct && (cast(TypeStruct)type).sym == (cast(TypeStruct)t).sym) | |
501 { | |
502 m = MATCHconst; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
503 foreach(e; elements) |
72 | 504 { |
505 Type te = e.type; | |
506 if (t.mod == 0) | |
507 te = te.mutableOf(); | |
508 else | |
509 { | |
510 assert(t.mod == MODinvariant); | |
511 te = te.invariantOf(); | |
512 } | |
513 MATCH m2 = e.implicitConvTo(te); | |
514 //printf("\t%s => %s, match = %d\n", e.toChars(), te.toChars(), m2); | |
515 if (m2 < m) | |
516 m = m2; | |
517 } | |
518 } | |
64 | 519 return m; |
0 | 520 } |
521 | |
72 | 522 override int inlineCost(InlineCostState* ics) |
0 | 523 { |
524 assert(false); | |
525 } | |
526 | |
72 | 527 override Expression doInline(InlineDoState ids) |
0 | 528 { |
529 assert(false); | |
530 } | |
531 | |
72 | 532 override Expression inlineScan(InlineScanState* iss) |
0 | 533 { |
534 assert(false); | |
535 } | |
536 } | |
537 |