Mercurial > projects > ddmd
annotate dmd/StructLiteralExp.d @ 84:be2ab491772e
Expressions -> Vector!Expression
author | Eldar Insafutdinov <e.insafutdinov@gmail.com> |
---|---|
date | Mon, 30 Aug 2010 16:12:19 +0100 |
parents | 43073c7c7769 |
children | 8e69d041a99d |
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); | |
168 e = cast(Expression)elements.data[i]; | |
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) | |
183 z.data[q] = cast(void*) e.copy(); | |
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 { | |
203 foreach (size_t i, Dsymbol s; sd.fields) | |
204 { | |
205 VarDeclaration v = s.isVarDeclaration(); | |
206 assert(v); | |
207 | |
208 if (offset == v.offset && type.size() == v.type.size()) | |
209 { | |
210 Expression e = cast(Expression)elements.data[i]; | |
211 if (e) | |
212 { | |
213 return i; | |
214 } | |
215 break; | |
216 } | |
217 } | |
218 } | |
219 return -1; | |
0 | 220 } |
221 | |
72 | 222 override elem* toElem(IRState* irs) |
0 | 223 { |
72 | 224 elem* e; |
225 size_t dim; | |
226 | |
227 //printf("StructLiteralExp.toElem() %s\n", toChars()); | |
228 | |
229 // struct symbol to initialize with the literal | |
230 Symbol* stmp = sym ? sym : symbol_genauto(sd.type.toCtype()); | |
231 | |
232 e = null; | |
233 | |
234 if (fillHoles) | |
235 { | |
236 /* Initialize all alignment 'holes' to zero. | |
237 * Do before initializing fields, as the hole filling process | |
238 * can spill over into the fields. | |
239 */ | |
240 size_t offset = 0; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
241 foreach (VarDeclaration v; sd.fields) |
72 | 242 { |
243 assert(v); | |
244 | |
245 e = el_combine(e, fillHole(stmp, &offset, v.offset, sd.structsize)); | |
246 size_t vend = v.offset + cast(uint)v.type.size(); | |
247 if (offset < vend) | |
248 offset = vend; | |
249 } | |
250 e = el_combine(e, fillHole(stmp, &offset, sd.structsize, sd.structsize)); | |
251 } | |
252 | |
253 if (elements) | |
254 { | |
255 dim = elements.dim; | |
256 assert(dim <= sd.fields.dim); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
257 foreach (size_t i, Expression el; elements) |
72 | 258 { |
259 if (!el) | |
260 continue; | |
261 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
262 VarDeclaration v = sd.fields[i]; |
72 | 263 assert(v); |
264 assert(!v.isThisDeclaration()); | |
265 | |
266 elem* e1; | |
267 if (tybasic(stmp.Stype.Tty) == TYnptr) | |
268 { | |
269 e1 = el_var(stmp); | |
270 e1.EV.sp.Voffset = soffset; | |
271 } | |
272 else | |
273 { | |
274 e1 = el_ptr(stmp); | |
275 if (soffset) | |
276 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset)); | |
277 } | |
278 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); | |
279 elem* ec = e1; // pointer to destination | |
280 | |
281 elem* ep = el.toElem(irs); | |
282 | |
283 Type t1b = v.type.toBasetype(); | |
284 Type t2b = el.type.toBasetype(); | |
285 if (t1b.ty == Tsarray) | |
286 { | |
287 if (t2b.implicitConvTo(t1b)) | |
288 { | |
289 ///version (DMDV2) { | |
290 // Determine if postblit is needed | |
291 int postblit = 0; | |
292 if (needsPostblit(t1b)) | |
293 postblit = 1; | |
294 | |
295 if (postblit) | |
296 { | |
297 /* Generate: | |
298 * _d_arrayctor(ti, From: ep, To: e1) | |
299 */ | |
300 Expression ti = t1b.nextOf().toBasetype().getTypeInfo(null); | |
301 elem* esize = el_long(TYsize_t, (cast(TypeSArray)t1b).dim.toInteger()); | |
302 e1 = el_pair(TYdarray, esize, e1); | |
303 ep = el_pair(TYdarray, el_copytree(esize), array_toPtr(el.type, ep)); | |
304 ep = el_params(e1, ep, ti.toElem(irs), null); | |
305 int rtl = RTLSYM_ARRAYCTOR; | |
306 e1 = el_bin(OPcall, type.totym(), el_var(rtlsym[rtl]), ep); | |
307 } | |
308 else | |
309 ///} | |
310 { | |
311 elem* esize = el_long(TYsize_t, t1b.size()); | |
312 ep = array_toPtr(el.type, ep); | |
313 e1 = el_bin(OPmemcpy, TYnptr, e1, el_param(ep, esize)); | |
314 } | |
315 } | |
316 else | |
317 { | |
318 elem* edim = el_long(TYsize_t, t1b.size() / t2b.size()); | |
319 e1 = setArray(e1, edim, t2b, ep, irs, TOKconstruct); | |
320 } | |
321 } | |
322 else | |
323 { | |
324 tym_t ty = v.type.totym(); | |
325 e1 = el_una(OPind, ty, e1); | |
326 if (tybasic(ty) == TYstruct) | |
327 e1.Enumbytes = cast(uint)v.type.size(); | |
328 e1 = el_bin(OPeq, ty, e1, ep); | |
329 if (tybasic(ty) == TYstruct) | |
330 { | |
331 e1.Eoper = OPstreq; | |
332 e1.Enumbytes = cast(uint)v.type.size(); | |
333 } | |
334 version (DMDV2) { | |
335 /* Call postblit() on e1 | |
336 */ | |
337 StructDeclaration sd = needsPostblit(v.type); | |
338 if (sd) | |
339 { | |
340 FuncDeclaration fd = sd.postblit; | |
341 ec = el_copytree(ec); | |
342 ec = callfunc(loc, irs, 1, Type.tvoid, ec, sd.type.pointerTo(), fd, fd.type, null, null); | |
343 e1 = el_bin(OPcomma, ec.Ety, e1, ec); | |
344 } | |
345 } | |
346 } | |
347 e = el_combine(e, e1); | |
348 } | |
349 } | |
350 | |
79 | 351 version (DMDV2) |
352 { | |
72 | 353 if (sd.isnested) |
354 { // Initialize the hidden 'this' pointer | |
355 assert(sd.fields.dim); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
356 auto s = sd.fields[sd.fields.dim - 1]; |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
357 auto v = s.isThisDeclaration(); |
72 | 358 assert(v); |
359 | |
360 elem* e1; | |
361 if (tybasic(stmp.Stype.Tty) == TYnptr) | |
362 { | |
363 e1 = el_var(stmp); | |
364 e1.EV.sp.Voffset = soffset; | |
365 } | |
366 else | |
367 { | |
368 e1 = el_ptr(stmp); | |
369 if (soffset) | |
370 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset)); | |
371 } | |
372 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); | |
373 e1 = setEthis(loc, irs, e1, sd); | |
374 | |
375 e = el_combine(e, e1); | |
376 } | |
377 } | |
378 | |
379 elem* ev = el_var(stmp); | |
380 ev.Enumbytes = sd.structsize; | |
381 e = el_combine(e, ev); | |
382 el_setLoc(e,loc); | |
67 | 383 return e; |
0 | 384 } |
385 | |
72 | 386 override bool checkSideEffect(int flag) |
0 | 387 { |
79 | 388 bool f = 0; |
389 | |
390 for (size_t i = 0; i < elements.dim; i++) | |
391 { | |
392 Expression e = cast(Expression)elements.data[i]; | |
393 if (!e) | |
394 continue; | |
395 | |
396 f |= e.checkSideEffect(2); | |
397 } | |
398 if (flag == 0 && f == 0) | |
399 Expression.checkSideEffect(0); | |
400 return f; | |
0 | 401 } |
402 | |
72 | 403 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 404 { |
79 | 405 buf.writestring(sd.toChars()); |
406 buf.writeByte('('); | |
407 argsToCBuffer(buf, elements, hgs); | |
408 buf.writeByte(')'); | |
0 | 409 } |
410 | |
72 | 411 override void toMangleBuffer(OutBuffer buf) |
0 | 412 { |
79 | 413 size_t dim = elements ? elements.dim : 0; |
414 buf.printf("S%u", dim); | |
415 for (size_t i = 0; i < dim; i++) | |
416 { | |
417 Expression e = cast(Expression)elements.data[i]; | |
418 if (e) | |
419 e.toMangleBuffer(buf); | |
420 else | |
421 buf.writeByte('v'); // 'v' for void | |
422 } | |
0 | 423 } |
424 | |
72 | 425 override void scanForNestedRef(Scope sc) |
0 | 426 { |
427 assert(false); | |
428 } | |
429 | |
72 | 430 override Expression optimize(int result) |
0 | 431 { |
72 | 432 if (elements) |
433 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
434 foreach (size_t i, Expression e; elements) |
72 | 435 { |
436 if (!e) | |
437 continue; | |
438 e = e.optimize(WANTvalue | (result & WANTinterpret)); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
439 elements[i] = e; |
72 | 440 } |
441 } | |
56 | 442 return this; |
0 | 443 } |
444 | |
72 | 445 override Expression interpret(InterState istate) |
0 | 446 { |
447 assert(false); | |
448 } | |
449 | |
72 | 450 override dt_t** toDt(dt_t** pdt) |
0 | 451 { |
452 assert(false); | |
453 } | |
454 | |
79 | 455 version(DMDV2) |
456 { | |
72 | 457 override int isLvalue() |
0 | 458 { |
79 | 459 return 1; |
0 | 460 } |
79 | 461 } |
0 | 462 |
72 | 463 override Expression toLvalue(Scope sc, Expression e) |
0 | 464 { |
79 | 465 return this; |
0 | 466 } |
467 | |
79 | 468 version(DMDV2) |
469 { | |
72 | 470 override bool canThrow() |
0 | 471 { |
64 | 472 return arrayExpressionCanThrow(elements); |
0 | 473 } |
79 | 474 } |
0 | 475 |
72 | 476 override MATCH implicitConvTo(Type t) |
0 | 477 { |
72 | 478 static if (false) { |
479 printf("StructLiteralExp.implicitConvTo(this=%.*s, type=%.*s, t=%.*s)\n", | |
480 toChars(), type.toChars(), t.toChars()); | |
481 } | |
482 MATCH m = Expression.implicitConvTo(t); | |
483 if (m != MATCHnomatch) | |
484 return m; | |
485 if (type.ty == t.ty && type.ty == Tstruct && (cast(TypeStruct)type).sym == (cast(TypeStruct)t).sym) | |
486 { | |
487 m = MATCHconst; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
488 foreach(e; elements) |
72 | 489 { |
490 Type te = e.type; | |
491 if (t.mod == 0) | |
492 te = te.mutableOf(); | |
493 else | |
494 { | |
495 assert(t.mod == MODinvariant); | |
496 te = te.invariantOf(); | |
497 } | |
498 MATCH m2 = e.implicitConvTo(te); | |
499 //printf("\t%s => %s, match = %d\n", e.toChars(), te.toChars(), m2); | |
500 if (m2 < m) | |
501 m = m2; | |
502 } | |
503 } | |
64 | 504 return m; |
0 | 505 } |
506 | |
72 | 507 override int inlineCost(InlineCostState* ics) |
0 | 508 { |
509 assert(false); | |
510 } | |
511 | |
72 | 512 override Expression doInline(InlineDoState ids) |
0 | 513 { |
514 assert(false); | |
515 } | |
516 | |
72 | 517 override Expression inlineScan(InlineScanState* iss) |
0 | 518 { |
519 assert(false); | |
520 } | |
521 } | |
522 |