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