Mercurial > projects > ddmd
annotate dmd/ReturnStatement.d @ 93:df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
and some additional ones I came across
author | Trass3r |
---|---|
date | Mon, 30 Aug 2010 22:50:30 +0200 |
parents | 43073c7c7769 |
children | e28b18c23469 |
rev | line source |
---|---|
0 | 1 module dmd.ReturnStatement; |
2 | |
3 import dmd.Loc; | |
4 import dmd.Statement; | |
5 import dmd.GotoStatement; | |
6 import dmd.STC; | |
7 import dmd.CompoundStatement; | |
8 import dmd.Id; | |
9 import dmd.AssignExp; | |
10 import dmd.ExpStatement; | |
11 import dmd.FuncDeclaration; | |
12 import dmd.IntegerExp; | |
13 import dmd.ThisExp; | |
14 import dmd.StructDeclaration; | |
15 import dmd.TypeFunction; | |
16 import dmd.CSX; | |
17 import dmd.RET; | |
18 import dmd.TOK; | |
19 import dmd.Type; | |
20 import dmd.Expression; | |
21 import dmd.StructLiteralExp; | |
22 import dmd.TypeStruct; | |
23 import dmd.Scope; | |
24 import dmd.OutBuffer; | |
25 import dmd.HdrGenState; | |
26 import dmd.InterState; | |
27 import dmd.InlineCostState; | |
28 import dmd.InlineDoState; | |
29 import dmd.InlineScanState; | |
30 import dmd.IRState; | |
31 import dmd.TY; | |
32 import dmd.WANT; | |
33 import dmd.VarExp; | |
34 import dmd.VarDeclaration; | |
63 | 35 import dmd.GlobalExpressions; |
0 | 36 import dmd.BE; |
67 | 37 |
0 | 38 import dmd.codegen.Util; |
39 | |
40 import dmd.backend.Blockx; | |
41 import dmd.backend.elem; | |
42 import dmd.backend.TYM; | |
43 import dmd.backend.Util; | |
44 import dmd.backend.OPER; | |
45 import dmd.backend.mTY; | |
46 import dmd.backend.BC; | |
47 | |
67 | 48 import core.stdc.string; |
49 | |
0 | 50 class ReturnStatement : Statement |
51 { | |
52 Expression exp; | |
53 | |
54 this(Loc loc, Expression exp) | |
55 { | |
56 super(loc); | |
57 this.exp = exp; | |
58 } | |
59 | |
72 | 60 override Statement syntaxCopy() |
0 | 61 { |
62 Expression e = exp ? exp.syntaxCopy() : null; | |
63 return new ReturnStatement(loc, e); | |
64 } | |
65 | |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
79
diff
changeset
|
66 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 67 { |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
79
diff
changeset
|
68 buf.printf("return "); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
79
diff
changeset
|
69 if (exp) |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
79
diff
changeset
|
70 exp.toCBuffer(buf, hgs); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
79
diff
changeset
|
71 buf.writeByte(';'); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
79
diff
changeset
|
72 buf.writenl(); |
0 | 73 } |
74 | |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
79
diff
changeset
|
75 override Statement semantic(Scope sc) |
0 | 76 { |
77 //printf("ReturnStatement.semantic() %s\n", toChars()); | |
78 | |
79 FuncDeclaration fd = sc.parent.isFuncDeclaration(); | |
80 Scope scx = sc; | |
81 int implicit0 = 0; | |
82 | |
83 if (sc.fes) | |
84 { | |
85 // Find scope of function foreach is in | |
86 for (; 1; scx = scx.enclosing) | |
87 { | |
88 assert(scx); | |
89 if (scx.func !is fd) | |
90 { | |
91 fd = scx.func; // fd is now function enclosing foreach | |
92 break; | |
93 } | |
94 } | |
95 } | |
96 | |
97 Type tret = fd.type.nextOf(); | |
98 if (fd.tintro) { | |
99 /* We'll be implicitly casting the return expression to tintro | |
100 */ | |
101 tret = fd.tintro.nextOf(); | |
102 } | |
103 | |
104 Type tbret = null; | |
105 | |
106 if (tret) { | |
107 tbret = tret.toBasetype(); | |
108 } | |
109 | |
110 // main() returns 0, even if it returns void | |
111 if (!exp && (!tbret || tbret.ty == TY.Tvoid) && fd.isMain()) | |
112 { | |
113 implicit0 = 1; | |
114 exp = new IntegerExp(0); | |
115 } | |
116 | |
117 if (sc.incontract || scx.incontract) | |
118 error("return statements cannot be in contracts"); | |
119 | |
120 if (sc.tf || scx.tf) | |
121 error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); | |
122 | |
123 if (fd.isCtorDeclaration()) | |
124 { | |
125 // Constructors implicitly do: | |
126 // return this; | |
127 if (exp && exp.op != TOK.TOKthis) { | |
128 error("cannot return expression from constructor"); | |
129 } | |
130 | |
131 exp = new ThisExp(Loc(0)); | |
132 } | |
133 | |
134 if (!exp) { | |
135 fd.nrvo_can = 0; | |
136 } | |
137 | |
138 if (exp) | |
139 { | |
140 fd.hasReturnExp |= 1; | |
141 | |
142 exp = exp.semantic(sc); | |
143 exp = resolveProperties(sc, exp); | |
144 exp = exp.optimize(WANT.WANTvalue); | |
145 | |
146 if (fd.nrvo_can && exp.op == TOK.TOKvar) { | |
147 VarExp ve = cast(VarExp)exp; | |
148 VarDeclaration v = ve.var.isVarDeclaration(); | |
149 | |
150 if ((cast(TypeFunction)fd.type).isref) { | |
151 // Function returns a reference | |
152 fd.nrvo_can = 0; | |
153 } else if (!v || v.isOut() || v.isRef()) { | |
154 fd.nrvo_can = 0; | |
155 } else if (tbret.ty == TY.Tstruct && (cast(TypeStruct)tbret).sym.dtor) { | |
156 // Struct being returned has destructors | |
157 fd.nrvo_can = 0; | |
158 } else if (fd.nrvo_var is null) { | |
159 if (!v.isDataseg() && !v.isParameter() && v.toParent2() == fd) { | |
160 //printf("Setting nrvo to %s\n", v.toChars()); | |
161 fd.nrvo_var = v; | |
162 } else { | |
163 fd.nrvo_can = 0; | |
164 } | |
165 } else if (fd.nrvo_var != v) { | |
166 fd.nrvo_can = 0; | |
167 } | |
168 } else { | |
169 fd.nrvo_can = 0; | |
170 } | |
171 | |
172 if (fd.returnLabel && tbret.ty != TY.Tvoid) { | |
173 ; | |
174 } else if (fd.inferRetType) { | |
175 if (fd.type.nextOf()) { | |
176 if (!exp.type.equals(fd.type.nextOf())) | |
177 error("mismatched function return type inference of %s and %s", exp.type.toChars(), fd.type.nextOf().toChars()); | |
178 } | |
179 else | |
180 { | |
181 (cast(TypeFunction)fd.type).next = exp.type; | |
182 fd.type = fd.type.semantic(loc, sc); | |
183 if (!fd.tintro) | |
184 { | |
185 tret = fd.type.nextOf(); | |
186 tbret = tret.toBasetype(); | |
187 } | |
188 } | |
189 } else if (tbret.ty != TY.Tvoid) | |
190 { | |
191 exp = exp.implicitCastTo(sc, tret); | |
192 exp = exp.optimize(WANT.WANTvalue); | |
193 } | |
194 } else if (fd.inferRetType) { | |
195 if (fd.type.nextOf()) | |
196 { | |
197 if (fd.type.nextOf().ty != TY.Tvoid) { | |
198 error("mismatched function return type inference of void and %s", fd.type.nextOf().toChars()); | |
199 } | |
200 } | |
201 else | |
202 { | |
203 (cast(TypeFunction*)fd.type).next = Type.tvoid; | |
204 fd.type = fd.type.semantic(loc, sc); | |
205 if (!fd.tintro) | |
206 { | |
207 tret = Type.tvoid; | |
208 tbret = tret; | |
209 } | |
210 } | |
211 } | |
212 else if (tbret.ty != TY.Tvoid) {// if non-void return | |
213 error("return expression expected"); | |
214 } | |
215 | |
216 if (sc.fes) | |
217 { | |
218 Statement s; | |
219 | |
220 if (exp && !implicit0) | |
221 { | |
222 exp = exp.implicitCastTo(sc, tret); | |
223 } | |
224 if (!exp || exp.op == TOK.TOKint64 || exp.op == TOK.TOKfloat64 || | |
225 exp.op == TOK.TOKimaginary80 || exp.op == TOK.TOKcomplex80 || | |
226 exp.op == TOK.TOKthis || exp.op == TOK.TOKsuper || exp.op == TOK.TOKnull || | |
227 exp.op == TOK.TOKstring) | |
228 { | |
229 sc.fes.cases.push(cast(void*)this); | |
230 // Construct: return cases.dim+1; | |
231 s = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); | |
232 } | |
233 else if (fd.type.nextOf().toBasetype() == Type.tvoid) | |
234 { | |
235 s = new ReturnStatement(Loc(0), null); | |
236 sc.fes.cases.push(cast(void*)s); | |
237 | |
238 // Construct: { exp; return cases.dim + 1; } | |
239 Statement s1 = new ExpStatement(loc, exp); | |
240 Statement s2 = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); | |
241 s = new CompoundStatement(loc, s1, s2); | |
242 } | |
243 else | |
244 { | |
245 // Construct: return vresult; | |
246 if (!fd.vresult) | |
247 { | |
248 // Declare vresult | |
249 VarDeclaration v = new VarDeclaration(loc, tret, Id.result, null); | |
250 v.noauto = true; | |
251 v.semantic(scx); | |
252 if (!scx.insert(v)) { | |
253 assert(0); | |
254 } | |
255 v.parent = fd; | |
256 fd.vresult = v; | |
257 } | |
258 | |
259 s = new ReturnStatement(Loc(0), new VarExp(Loc(0), fd.vresult)); | |
260 sc.fes.cases.push(cast(void*)s); | |
261 | |
262 // Construct: { vresult = exp; return cases.dim + 1; } | |
263 exp = new AssignExp(loc, new VarExp(Loc(0), fd.vresult), exp); | |
264 exp.op = TOK.TOKconstruct; | |
265 exp = exp.semantic(sc); | |
266 Statement s1 = new ExpStatement(loc, exp); | |
267 Statement s2 = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); | |
268 s = new CompoundStatement(loc, s1, s2); | |
269 } | |
270 return s; | |
271 } | |
272 | |
273 if (exp) | |
274 { | |
275 if (fd.returnLabel && tbret.ty != TY.Tvoid) | |
276 { | |
277 assert(fd.vresult); | |
278 VarExp v = new VarExp(Loc(0), fd.vresult); | |
279 | |
280 exp = new AssignExp(loc, v, exp); | |
281 exp.op = TOK.TOKconstruct; | |
282 exp = exp.semantic(sc); | |
283 } | |
284 | |
285 if ((cast(TypeFunction)fd.type).isref && !fd.isCtorDeclaration()) | |
286 { // Function returns a reference | |
287 if (tbret.isMutable()) | |
288 exp = exp.modifiableLvalue(sc, exp); | |
289 else | |
290 exp = exp.toLvalue(sc, exp); | |
291 | |
292 if (exp.op == TOK.TOKvar) | |
293 { | |
294 VarExp ve = cast(VarExp)exp; | |
295 VarDeclaration v = ve.var.isVarDeclaration(); | |
296 if (v && !v.isDataseg() && !(v.storage_class & (STC.STCref | STC.STCout))) { | |
297 error("escaping reference to local variable %s", v.toChars()); | |
298 } | |
299 } | |
300 } | |
301 | |
302 //exp.dump(0); | |
303 //exp.print(); | |
304 exp.checkEscape(); | |
305 } | |
306 | |
307 /* BUG: need to issue an error on: | |
308 * this | |
309 * { if (x) return; | |
310 * super(); | |
311 * } | |
312 */ | |
313 | |
314 if (sc.callSuper & CSX.CSXany_ctor && !(sc.callSuper & (CSX.CSXthis_ctor | CSX.CSXsuper_ctor))) { | |
315 error("return without calling constructor"); | |
316 } | |
317 | |
318 sc.callSuper |= CSX.CSXreturn; | |
319 | |
320 // See if all returns are instead to be replaced with a goto returnLabel; | |
321 if (fd.returnLabel) | |
322 { | |
323 GotoStatement gs = new GotoStatement(loc, Id.returnLabel); | |
324 | |
325 gs.label = fd.returnLabel; | |
326 if (exp) | |
327 { | |
328 /* Replace: return exp; | |
329 * with: exp; goto returnLabel; | |
330 */ | |
331 Statement s = new ExpStatement(Loc(0), exp); | |
332 return new CompoundStatement(loc, s, gs); | |
333 } | |
334 return gs; | |
335 } | |
336 | |
73 | 337 if (exp && tbret.ty == Tvoid && !implicit0) |
0 | 338 { |
339 /* Replace: | |
340 * return exp; | |
341 * with: | |
342 * exp; return; | |
343 */ | |
344 Statement s = new ExpStatement(loc, exp); | |
79 | 345 exp = null; |
346 s = s.semantic(sc); | |
347 loc = Loc(); | |
0 | 348 return new CompoundStatement(loc, s, this); |
349 } | |
350 | |
351 return this; | |
352 } | |
353 | |
72 | 354 override BE blockExit() |
0 | 355 { |
356 BE result = BE.BEreturn; | |
357 if (exp && exp.canThrow()) | |
358 result |= BE.BEthrow; | |
359 | |
360 return result; | |
361 } | |
362 | |
72 | 363 override Expression interpret(InterState istate) |
0 | 364 { |
63 | 365 version (LOG) { |
366 printf("ReturnStatement.interpret(%s)\n", exp ? exp.toChars() : ""); | |
367 } | |
368 mixin(START!()); | |
369 if (!exp) | |
370 return EXP_VOID_INTERPRET; | |
371 version (LOG) { | |
372 Expression e = exp.interpret(istate); | |
373 printf("e = %p\n", e); | |
374 return e; | |
375 } else { | |
376 return exp.interpret(istate); | |
377 } | |
0 | 378 } |
379 | |
72 | 380 override int inlineCost(InlineCostState* ics) |
0 | 381 { |
382 // Can't handle return statements nested in if's | |
383 if (ics.nested) | |
384 return COST_MAX; | |
385 return exp ? exp.inlineCost(ics) : 0; | |
386 } | |
387 | |
72 | 388 override Expression doInline(InlineDoState ids) |
0 | 389 { |
390 //printf("ReturnStatement.doInline() '%s'\n", exp ? exp.toChars() : ""); | |
391 return exp ? exp.doInline(ids) : null; | |
392 } | |
393 | |
72 | 394 override Statement inlineScan(InlineScanState* iss) |
0 | 395 { |
396 //printf("ReturnStatement.inlineScan()\n"); | |
397 if (exp) | |
398 { | |
399 exp = exp.inlineScan(iss); | |
400 } | |
401 return this; | |
402 } | |
403 | |
72 | 404 override void toIR(IRState* irs) |
0 | 405 { |
406 Blockx* blx = irs.blx; | |
68
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
67
diff
changeset
|
407 |
0 | 408 incUsage(irs, loc); |
409 if (exp) | |
410 { | |
68
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
67
diff
changeset
|
411 //printf("%.*s %.*s\n", exp.classinfo.name, exp.toChars()); |
0 | 412 elem *e; |
413 | |
414 FuncDeclaration func = irs.getFunc(); | |
415 assert(func); | |
416 assert(func.type.ty == TY.Tfunction); | |
417 TypeFunction tf = cast(TypeFunction)(func.type); | |
418 | |
419 RET retmethod = tf.retStyle(); | |
420 if (retmethod == RET.RETstack) | |
421 { | |
422 elem* es; | |
423 | |
424 /* If returning struct literal, write result | |
425 * directly into return value | |
426 */ | |
427 if (exp.op == TOK.TOKstructliteral) | |
428 { | |
68
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
67
diff
changeset
|
429 StructLiteralExp se = cast(StructLiteralExp)exp; |
67 | 430 enum objectSize = __traits(classInstanceSize, StructLiteralExp); |
431 ubyte save[objectSize]; | |
432 memcpy(save.ptr, cast(void*)se, objectSize); | |
0 | 433 se.sym = irs.shidden; |
434 se.soffset = 0; | |
435 se.fillHoles = 1; | |
436 e = exp.toElem(irs); | |
67 | 437 memcpy(cast(void*)se, save.ptr, objectSize); |
0 | 438 } |
439 else | |
440 e = exp.toElem(irs); | |
441 | |
442 assert(e); | |
443 | |
444 if (exp.op == TOK.TOKstructliteral || (func.nrvo_can && func.nrvo_var)) | |
445 { | |
446 // Return value via hidden pointer passed as parameter | |
447 // Write exp; return shidden; | |
448 es = e; | |
449 } | |
450 else | |
451 { | |
452 // Return value via hidden pointer passed as parameter | |
453 // Write *shidden=exp; return shidden; | |
454 int op; | |
455 tym_t ety; | |
456 | |
457 ety = e.Ety; | |
458 es = el_una(OPER.OPind,ety,el_var(irs.shidden)); | |
459 op = (tybasic(ety) == TYM.TYstruct) ? OPER.OPstreq : OPER.OPeq; | |
460 es = el_bin(op, ety, es, e); | |
461 if (op == OPER.OPstreq) | |
462 es.Enumbytes = cast(uint)exp.type.size(); | |
463 version (DMDV2) { | |
464 /* Call postBlit() on *shidden | |
465 */ | |
466 Type tb = exp.type.toBasetype(); | |
467 //if (tb.ty == TY.Tstruct) exp.dump(0); | |
468 if ((exp.op == TOK.TOKvar || exp.op == TOK.TOKdotvar || exp.op == TOK.TOKstar) && | |
469 tb.ty == TY.Tstruct) | |
68
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
67
diff
changeset
|
470 { |
ee3a9f34dc48
final bits of codegen implementation to compile Phobos
korDen
parents:
67
diff
changeset
|
471 StructDeclaration sd = (cast(TypeStruct)tb).sym; |
0 | 472 if (sd.postblit) |
473 { | |
474 FuncDeclaration fd = sd.postblit; | |
475 elem* ec = el_var(irs.shidden); | |
476 ec = callfunc(loc, irs, 1, Type.tvoid, ec, tb.pointerTo(), fd, fd.type, null, null); | |
477 es = el_bin(OPER.OPcomma, ec.Ety, es, ec); | |
478 } | |
479 | |
480 static if (false) { | |
481 /* It has been moved, so disable destructor | |
482 */ | |
483 if (exp.op == TOK.TOKvar) | |
484 { | |
485 VarExp ve = cast(VarExp)exp; | |
486 VarDeclaration v = ve.var.isVarDeclaration(); | |
487 if (v && v.rundtor) | |
488 { | |
489 elem* er = el_var(v.rundtor.toSymbol()); | |
490 er = el_bin(OPER.OPeq, TYM.TYint, er, el_long(TYM.TYint, 0)); | |
491 es = el_bin(OPER.OPcomma, TYM.TYint, es, er); | |
492 } | |
493 } | |
494 } | |
495 } | |
496 } | |
497 } | |
498 e = el_var(irs.shidden); | |
499 e = el_bin(OPER.OPcomma, e.Ety, es, e); | |
500 } | |
501 ///version (DMDV2) { | |
502 else if (tf.isref) | |
503 { // Reference return, so convert to a pointer | |
504 Expression ae = exp.addressOf(null); | |
505 e = ae.toElem(irs); | |
506 } | |
507 ///} | |
508 else | |
509 { | |
510 e = exp.toElem(irs); | |
511 assert(e); | |
512 } | |
513 | |
514 block_appendexp(blx.curblock, e); | |
515 block_next(blx, BC.BCretexp, null); | |
516 } | |
517 else | |
518 block_next(blx, BC.BCret, null); | |
519 } | |
520 | |
72 | 521 override ReturnStatement isReturnStatement() { return this; } |
522 } |