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