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