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