Mercurial > projects > ddmd
view dmd/ReturnStatement.d @ 98:5c859d5fbe27
and more
author | Trass3r |
---|---|
date | Tue, 31 Aug 2010 03:53:49 +0200 |
parents | df6d0f967680 |
children | e28b18c23469 |
line wrap: on
line source
module dmd.ReturnStatement; import dmd.Loc; import dmd.Statement; import dmd.GotoStatement; import dmd.STC; import dmd.CompoundStatement; import dmd.Id; import dmd.AssignExp; import dmd.ExpStatement; import dmd.FuncDeclaration; import dmd.IntegerExp; import dmd.ThisExp; import dmd.StructDeclaration; import dmd.TypeFunction; import dmd.CSX; import dmd.RET; import dmd.TOK; import dmd.Type; import dmd.Expression; import dmd.StructLiteralExp; import dmd.TypeStruct; import dmd.Scope; import dmd.OutBuffer; import dmd.HdrGenState; import dmd.InterState; import dmd.InlineCostState; import dmd.InlineDoState; import dmd.InlineScanState; import dmd.IRState; import dmd.TY; import dmd.WANT; import dmd.VarExp; import dmd.VarDeclaration; import dmd.GlobalExpressions; import dmd.BE; import dmd.codegen.Util; import dmd.backend.Blockx; import dmd.backend.elem; import dmd.backend.TYM; import dmd.backend.Util; import dmd.backend.OPER; import dmd.backend.mTY; import dmd.backend.BC; import core.stdc.string; class ReturnStatement : Statement { Expression exp; this(Loc loc, Expression exp) { super(loc); this.exp = exp; } override Statement syntaxCopy() { Expression e = exp ? exp.syntaxCopy() : null; return new ReturnStatement(loc, e); } override void toCBuffer(OutBuffer buf, HdrGenState* hgs) { buf.printf("return "); if (exp) exp.toCBuffer(buf, hgs); buf.writeByte(';'); buf.writenl(); } override Statement semantic(Scope sc) { //printf("ReturnStatement.semantic() %s\n", toChars()); FuncDeclaration fd = sc.parent.isFuncDeclaration(); Scope scx = sc; int implicit0 = 0; if (sc.fes) { // Find scope of function foreach is in for (; 1; scx = scx.enclosing) { assert(scx); if (scx.func !is fd) { fd = scx.func; // fd is now function enclosing foreach break; } } } Type tret = fd.type.nextOf(); if (fd.tintro) { /* We'll be implicitly casting the return expression to tintro */ tret = fd.tintro.nextOf(); } Type tbret = null; if (tret) { tbret = tret.toBasetype(); } // main() returns 0, even if it returns void if (!exp && (!tbret || tbret.ty == TY.Tvoid) && fd.isMain()) { implicit0 = 1; exp = new IntegerExp(0); } if (sc.incontract || scx.incontract) error("return statements cannot be in contracts"); if (sc.tf || scx.tf) error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); if (fd.isCtorDeclaration()) { // Constructors implicitly do: // return this; if (exp && exp.op != TOK.TOKthis) { error("cannot return expression from constructor"); } exp = new ThisExp(Loc(0)); } if (!exp) { fd.nrvo_can = 0; } if (exp) { fd.hasReturnExp |= 1; exp = exp.semantic(sc); exp = resolveProperties(sc, exp); exp = exp.optimize(WANT.WANTvalue); if (fd.nrvo_can && exp.op == TOK.TOKvar) { VarExp ve = cast(VarExp)exp; VarDeclaration v = ve.var.isVarDeclaration(); if ((cast(TypeFunction)fd.type).isref) { // Function returns a reference fd.nrvo_can = 0; } else if (!v || v.isOut() || v.isRef()) { fd.nrvo_can = 0; } else if (tbret.ty == TY.Tstruct && (cast(TypeStruct)tbret).sym.dtor) { // Struct being returned has destructors fd.nrvo_can = 0; } else if (fd.nrvo_var is null) { if (!v.isDataseg() && !v.isParameter() && v.toParent2() == fd) { //printf("Setting nrvo to %s\n", v.toChars()); fd.nrvo_var = v; } else { fd.nrvo_can = 0; } } else if (fd.nrvo_var != v) { fd.nrvo_can = 0; } } else { fd.nrvo_can = 0; } if (fd.returnLabel && tbret.ty != TY.Tvoid) { ; } else if (fd.inferRetType) { if (fd.type.nextOf()) { if (!exp.type.equals(fd.type.nextOf())) error("mismatched function return type inference of %s and %s", exp.type.toChars(), fd.type.nextOf().toChars()); } else { (cast(TypeFunction)fd.type).next = exp.type; fd.type = fd.type.semantic(loc, sc); if (!fd.tintro) { tret = fd.type.nextOf(); tbret = tret.toBasetype(); } } } else if (tbret.ty != TY.Tvoid) { exp = exp.implicitCastTo(sc, tret); exp = exp.optimize(WANT.WANTvalue); } } else if (fd.inferRetType) { if (fd.type.nextOf()) { if (fd.type.nextOf().ty != TY.Tvoid) { error("mismatched function return type inference of void and %s", fd.type.nextOf().toChars()); } } else { (cast(TypeFunction*)fd.type).next = Type.tvoid; fd.type = fd.type.semantic(loc, sc); if (!fd.tintro) { tret = Type.tvoid; tbret = tret; } } } else if (tbret.ty != TY.Tvoid) {// if non-void return error("return expression expected"); } if (sc.fes) { Statement s; if (exp && !implicit0) { exp = exp.implicitCastTo(sc, tret); } if (!exp || exp.op == TOK.TOKint64 || exp.op == TOK.TOKfloat64 || exp.op == TOK.TOKimaginary80 || exp.op == TOK.TOKcomplex80 || exp.op == TOK.TOKthis || exp.op == TOK.TOKsuper || exp.op == TOK.TOKnull || exp.op == TOK.TOKstring) { sc.fes.cases.push(cast(void*)this); // Construct: return cases.dim+1; s = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); } else if (fd.type.nextOf().toBasetype() == Type.tvoid) { s = new ReturnStatement(Loc(0), null); sc.fes.cases.push(cast(void*)s); // Construct: { exp; return cases.dim + 1; } Statement s1 = new ExpStatement(loc, exp); Statement s2 = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); s = new CompoundStatement(loc, s1, s2); } else { // Construct: return vresult; if (!fd.vresult) { // Declare vresult VarDeclaration v = new VarDeclaration(loc, tret, Id.result, null); v.noauto = true; v.semantic(scx); if (!scx.insert(v)) { assert(0); } v.parent = fd; fd.vresult = v; } s = new ReturnStatement(Loc(0), new VarExp(Loc(0), fd.vresult)); sc.fes.cases.push(cast(void*)s); // Construct: { vresult = exp; return cases.dim + 1; } exp = new AssignExp(loc, new VarExp(Loc(0), fd.vresult), exp); exp.op = TOK.TOKconstruct; exp = exp.semantic(sc); Statement s1 = new ExpStatement(loc, exp); Statement s2 = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); s = new CompoundStatement(loc, s1, s2); } return s; } if (exp) { if (fd.returnLabel && tbret.ty != TY.Tvoid) { assert(fd.vresult); VarExp v = new VarExp(Loc(0), fd.vresult); exp = new AssignExp(loc, v, exp); exp.op = TOK.TOKconstruct; exp = exp.semantic(sc); } if ((cast(TypeFunction)fd.type).isref && !fd.isCtorDeclaration()) { // Function returns a reference if (tbret.isMutable()) exp = exp.modifiableLvalue(sc, exp); else exp = exp.toLvalue(sc, exp); if (exp.op == TOK.TOKvar) { VarExp ve = cast(VarExp)exp; VarDeclaration v = ve.var.isVarDeclaration(); if (v && !v.isDataseg() && !(v.storage_class & (STC.STCref | STC.STCout))) { error("escaping reference to local variable %s", v.toChars()); } } } //exp.dump(0); //exp.print(); exp.checkEscape(); } /* BUG: need to issue an error on: * this * { if (x) return; * super(); * } */ if (sc.callSuper & CSX.CSXany_ctor && !(sc.callSuper & (CSX.CSXthis_ctor | CSX.CSXsuper_ctor))) { error("return without calling constructor"); } sc.callSuper |= CSX.CSXreturn; // See if all returns are instead to be replaced with a goto returnLabel; if (fd.returnLabel) { GotoStatement gs = new GotoStatement(loc, Id.returnLabel); gs.label = fd.returnLabel; if (exp) { /* Replace: return exp; * with: exp; goto returnLabel; */ Statement s = new ExpStatement(Loc(0), exp); return new CompoundStatement(loc, s, gs); } return gs; } if (exp && tbret.ty == Tvoid && !implicit0) { /* Replace: * return exp; * with: * exp; return; */ Statement s = new ExpStatement(loc, exp); exp = null; s = s.semantic(sc); loc = Loc(); return new CompoundStatement(loc, s, this); } return this; } override BE blockExit() { BE result = BE.BEreturn; if (exp && exp.canThrow()) result |= BE.BEthrow; return result; } override Expression interpret(InterState istate) { version (LOG) { printf("ReturnStatement.interpret(%s)\n", exp ? exp.toChars() : ""); } mixin(START!()); if (!exp) return EXP_VOID_INTERPRET; version (LOG) { Expression e = exp.interpret(istate); printf("e = %p\n", e); return e; } else { return exp.interpret(istate); } } override int inlineCost(InlineCostState* ics) { // Can't handle return statements nested in if's if (ics.nested) return COST_MAX; return exp ? exp.inlineCost(ics) : 0; } override Expression doInline(InlineDoState ids) { //printf("ReturnStatement.doInline() '%s'\n", exp ? exp.toChars() : ""); return exp ? exp.doInline(ids) : null; } override Statement inlineScan(InlineScanState* iss) { //printf("ReturnStatement.inlineScan()\n"); if (exp) { exp = exp.inlineScan(iss); } return this; } override void toIR(IRState* irs) { Blockx* blx = irs.blx; incUsage(irs, loc); if (exp) { //printf("%.*s %.*s\n", exp.classinfo.name, exp.toChars()); elem *e; FuncDeclaration func = irs.getFunc(); assert(func); assert(func.type.ty == TY.Tfunction); TypeFunction tf = cast(TypeFunction)(func.type); RET retmethod = tf.retStyle(); if (retmethod == RET.RETstack) { elem* es; /* If returning struct literal, write result * directly into return value */ if (exp.op == TOK.TOKstructliteral) { StructLiteralExp se = cast(StructLiteralExp)exp; enum objectSize = __traits(classInstanceSize, StructLiteralExp); ubyte save[objectSize]; memcpy(save.ptr, cast(void*)se, objectSize); se.sym = irs.shidden; se.soffset = 0; se.fillHoles = 1; e = exp.toElem(irs); memcpy(cast(void*)se, save.ptr, objectSize); } else e = exp.toElem(irs); assert(e); if (exp.op == TOK.TOKstructliteral || (func.nrvo_can && func.nrvo_var)) { // Return value via hidden pointer passed as parameter // Write exp; return shidden; es = e; } else { // Return value via hidden pointer passed as parameter // Write *shidden=exp; return shidden; int op; tym_t ety; ety = e.Ety; es = el_una(OPER.OPind,ety,el_var(irs.shidden)); op = (tybasic(ety) == TYM.TYstruct) ? OPER.OPstreq : OPER.OPeq; es = el_bin(op, ety, es, e); if (op == OPER.OPstreq) es.Enumbytes = cast(uint)exp.type.size(); version (DMDV2) { /* Call postBlit() on *shidden */ Type tb = exp.type.toBasetype(); //if (tb.ty == TY.Tstruct) exp.dump(0); if ((exp.op == TOK.TOKvar || exp.op == TOK.TOKdotvar || exp.op == TOK.TOKstar) && tb.ty == TY.Tstruct) { StructDeclaration sd = (cast(TypeStruct)tb).sym; if (sd.postblit) { FuncDeclaration fd = sd.postblit; elem* ec = el_var(irs.shidden); ec = callfunc(loc, irs, 1, Type.tvoid, ec, tb.pointerTo(), fd, fd.type, null, null); es = el_bin(OPER.OPcomma, ec.Ety, es, ec); } static if (false) { /* It has been moved, so disable destructor */ if (exp.op == TOK.TOKvar) { VarExp ve = cast(VarExp)exp; VarDeclaration v = ve.var.isVarDeclaration(); if (v && v.rundtor) { elem* er = el_var(v.rundtor.toSymbol()); er = el_bin(OPER.OPeq, TYM.TYint, er, el_long(TYM.TYint, 0)); es = el_bin(OPER.OPcomma, TYM.TYint, es, er); } } } } } } e = el_var(irs.shidden); e = el_bin(OPER.OPcomma, e.Ety, es, e); } ///version (DMDV2) { else if (tf.isref) { // Reference return, so convert to a pointer Expression ae = exp.addressOf(null); e = ae.toElem(irs); } ///} else { e = exp.toElem(irs); assert(e); } block_appendexp(blx.curblock, e); block_next(blx, BC.BCretexp, null); } else block_next(blx, BC.BCret, null); } override ReturnStatement isReturnStatement() { return this; } }