Mercurial > projects > ddmd
diff dmd/CallExp.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | cab4c37afb89 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CallExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1056 @@ +module dmd.CallExp; + +import dmd.Expression; +import dmd.WANT; +import dmd.BUILTIN; +import dmd.TypeFunction; +import dmd.ScopeDsymbol; +import dmd.CastExp; +import dmd.GlobalExpressions; +import dmd.TypePointer; +import dmd.ThisExp; +import dmd.OverExp; +import dmd.Dsymbol; +import dmd.CSX; +import dmd.AggregateDeclaration; +import dmd.TypeDelegate; +import dmd.ClassDeclaration; +import dmd.DsymbolExp; +import dmd.DotExp; +import dmd.TemplateExp; +import dmd.TypeStruct; +import dmd.TypeClass; +import dmd.Identifier; +import dmd.Lexer; +import dmd.VarDeclaration; +import dmd.DeclarationExp; +import dmd.CtorDeclaration; +import dmd.PtrExp; +import dmd.TemplateDeclaration; +import dmd.StructLiteralExp; +import dmd.StructDeclaration; +import dmd.DotTemplateExp; +import dmd.CommaExp; +import dmd.AggregateDeclaration; +import dmd.FuncDeclaration; +import dmd.Type; +import dmd.ScopeExp; +import dmd.VarExp; +import dmd.STC; +import dmd.LINK; +import dmd.Global; +import dmd.DotTemplateInstanceExp; +import dmd.TemplateInstance; +import dmd.DelegateExp; +import dmd.IdentifierExp; +import dmd.DotVarExp; +import dmd.DotIdExp; +import dmd.TY; +import dmd.Id; +import dmd.TypeAArray; +import dmd.RemoveExp; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.IRState; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.ArrayTypes; +import dmd.TOK; +import dmd.PREC; +import dmd.expression.Util; +import dmd.backend.Symbol; +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.codegen.Util; + +class CallExp : UnaExp +{ + Expressions arguments; + + this(Loc loc, Expression e, Expressions exps) + { + super(loc, TOK.TOKcall, CallExp.sizeof, e); + this.arguments = exps; + } + + this(Loc loc, Expression e) + { + super(loc, TOK.TOKcall, CallExp.sizeof, e); + } + + this(Loc loc, Expression e, Expression earg1) + { + super(loc, TOK.TOKcall, CallExp.sizeof, e); + + Expressions arguments = new Expressions(); + arguments.setDim(1); + arguments.data[0] = cast(void*)earg1; + + this.arguments = arguments; + } + + this(Loc loc, Expression e, Expression earg1, Expression earg2) + { + assert(false); + super(loc, TOK.init, 0, e); + } + + Expression syntaxCopy() + { + return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments)); + } + + Expression semantic(Scope sc) + { + TypeFunction tf; + FuncDeclaration f; + int i; + Type t1; + int istemp; + Objects targsi; // initial list of template arguments + TemplateInstance tierror; + +version (LOGSEMANTIC) { + printf("CallExp.semantic() %s\n", toChars()); +} + if (type) + return this; // semantic() already run + +static if (false) { + if (arguments && arguments.dim) + { + Expression earg = cast(Expression)arguments.data[0]; + earg.print(); + if (earg.type) earg.type.print(); + } +} + + if (e1.op == TOK.TOKdelegate) + { + DelegateExp de = cast(DelegateExp)e1; + + e1 = new DotVarExp(de.loc, de.e1, de.func); + return semantic(sc); + } + + /* Transform: + * array.id(args) into .id(array,args) + * aa.remove(arg) into delete aa[arg] + */ + if (e1.op == TOK.TOKdot) + { + // BUG: we should handle array.a.b.c.e(args) too + + DotIdExp dotid = cast(DotIdExp)(e1); + dotid.e1 = dotid.e1.semantic(sc); + assert(dotid.e1); + if (dotid.e1.type) + { + TY e1ty = dotid.e1.type.toBasetype().ty; + if (e1ty == TY.Taarray && dotid.ident == Id.remove) + { + if (!arguments || arguments.dim != 1) + { + error("expected key as argument to aa.remove()"); + goto Lagain; + } + Expression key = cast(Expression)arguments.data[0]; + key = key.semantic(sc); + key = resolveProperties(sc, key); + key.rvalue(); + + TypeAArray taa = cast(TypeAArray)dotid.e1.type.toBasetype(); + key = key.implicitCastTo(sc, taa.index); + + return new RemoveExp(loc, dotid.e1, key); + } + else if (e1ty == TY.Tarray || e1ty == TY.Tsarray || e1ty == TY.Taarray) + { + if (!arguments) + arguments = new Expressions(); + arguments.shift(cast(void*)dotid.e1); +version (DMDV2) { + e1 = new DotIdExp(dotid.loc, new IdentifierExp(dotid.loc, Id.empty), dotid.ident); +} else { + e1 = new IdentifierExp(dotid.loc, dotid.ident); +} + } + } + } + +static if (true) { + /* This recognizes: + * foo!(tiargs)(funcargs) + */ + if (e1.op == TOK.TOKimport && !e1.type) + { + ScopeExp se = cast(ScopeExp)e1; + TemplateInstance ti = se.sds.isTemplateInstance(); + if (ti && !ti.semanticRun) + { + /* Attempt to instantiate ti. If that works, go with it. + * If not, go with partial explicit specialization. + */ + ti.semanticTiargs(sc); + uint errors = global.errors; + global.gag++; + ti.semantic(sc); + global.gag--; + if (errors != global.errors) + { + /* Didn't work, go with partial explicit specialization + */ + global.errors = errors; + targsi = ti.tiargs; + tierror = ti; // for error reporting + e1 = new IdentifierExp(loc, ti.name); + } + } + } + + /* This recognizes: + * expr.foo!(tiargs)(funcargs) + */ + if (e1.op == TOK.TOKdotti && !e1.type) + { + DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)e1; + TemplateInstance ti = se.ti; + if (!ti.semanticRun) + { + /* Attempt to instantiate ti. If that works, go with it. + * If not, go with partial explicit specialization. + */ + ti.semanticTiargs(sc); + Expression etmp = e1.trySemantic(sc); + if (etmp) + e1 = etmp; // it worked + else // didn't work + { + targsi = ti.tiargs; + tierror = ti; // for error reporting + e1 = new DotIdExp(loc, se.e1, ti.name); + } + } + } +} + + istemp = 0; + Lagain: + //printf("Lagain: %s\n", toChars()); + f = null; + if (e1.op == TOK.TOKthis || e1.op == TOK.TOKsuper) + { + // semantic() run later for these + } + else + { + UnaExp.semantic(sc); + + /* Look for e1 being a lazy parameter + */ + if (e1.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)e1; + + if (ve.var.storage_class & STC.STClazy) + { + TypeFunction tff = new TypeFunction(null, ve.var.type, 0, LINK.LINKd); + TypeDelegate t = new TypeDelegate(tff); + ve.type = t.semantic(loc, sc); + } + } + + if (e1.op == TOK.TOKimport) + { + // Perhaps this should be moved to ScopeExp.semantic() + ScopeExp se = cast(ScopeExp)e1; + e1 = new DsymbolExp(loc, se.sds); + e1 = e1.semantic(sc); + } +///static if (true) { // patch for #540 by Oskar Linde + else if (e1.op == TOK.TOKdotexp) + { + DotExp de = cast(DotExp)e1; + + if (de.e2.op == TOK.TOKimport) + { + // This should *really* be moved to ScopeExp.semantic() + ScopeExp se = cast(ScopeExp)de.e2; + de.e2 = new DsymbolExp(loc, se.sds); + de.e2 = de.e2.semantic(sc); + } + + if (de.e2.op == TOK.TOKtemplate) + { + TemplateExp te = cast(TemplateExp)de.e2; + e1 = new DotTemplateExp(loc,de.e1,te.td); + } + } +///} + } + + if (e1.op == TOK.TOKcomma) + { + CommaExp ce = cast(CommaExp)e1; + + e1 = ce.e2; + e1.type = ce.type; + ce.e2 = this; + ce.type = null; + return ce.semantic(sc); + } + + t1 = null; + if (e1.type) + t1 = e1.type.toBasetype(); + + // Check for call operator overload + if (t1) + { + AggregateDeclaration ad; + + if (t1.ty == TY.Tstruct) + { + ad = (cast(TypeStruct)t1).sym; +version (DMDV2) { + // First look for constructor + if (ad.ctor && arguments && arguments.dim) + { + // Create variable that will get constructed + Identifier idtmp = Lexer.uniqueId("__ctmp"); + VarDeclaration tmp = new VarDeclaration(loc, t1, idtmp, null); + Expression av = new DeclarationExp(loc, tmp); + av = new CommaExp(loc, av, new VarExp(loc, tmp)); + + Expression e; + CtorDeclaration cf = ad.ctor.isCtorDeclaration(); + if (cf) + e = new DotVarExp(loc, av, cf, 1); + else + { + TemplateDeclaration td = ad.ctor.isTemplateDeclaration(); + assert(td); + e = new DotTemplateExp(loc, av, td); + } + e = new CallExp(loc, e, arguments); + version (STRUCTTHISREF) { + } else { + /* Constructors return a pointer to the instance + */ + e = new PtrExp(loc, e); + } + e = e.semantic(sc); + return e; + } +} + // No constructor, look for overload of opCall + if (search_function(ad, Id.call)) + goto L1; // overload of opCall, therefore it's a call + + if (e1.op != TOK.TOKtype) + error("%s %s does not overload ()", ad.kind(), ad.toChars()); + + /* It's a struct literal + */ + Expression e = new StructLiteralExp(loc, cast(StructDeclaration)ad, arguments); + e = e.semantic(sc); + e.type = e1.type; // in case e1.type was a typedef + return e; + } + else if (t1.ty == TY.Tclass) + { + ad = (cast(TypeClass)t1).sym; + goto L1; + L1: + // Rewrite as e1.call(arguments) + Expression e = new DotIdExp(loc, e1, Id.call); + e = new CallExp(loc, e, arguments); + e = e.semantic(sc); + return e; + } + } + + arrayExpressionSemantic(arguments, sc); + preFunctionArguments(loc, sc, arguments); + + if (e1.op == TOK.TOKdotvar && t1.ty == TY.Tfunction || + e1.op == TOK.TOKdottd) + { + DotVarExp dve; + DotTemplateExp dte; + AggregateDeclaration ad; + UnaExp ue = cast(UnaExp)e1; + + if (e1.op == TOK.TOKdotvar) + { + // Do overload resolution + dve = cast(DotVarExp)e1; + + f = dve.var.isFuncDeclaration(); + assert(f); + f = f.overloadResolve(loc, ue.e1, arguments); + + ad = f.toParent().isAggregateDeclaration(); + } + else + { + dte = cast(DotTemplateExp)e1; + TemplateDeclaration td = dte.td; + assert(td); + + if (!arguments) + // Should fix deduceFunctionTemplate() so it works on null argument + arguments = new Expressions(); + + f = td.deduceFunctionTemplate(sc, loc, targsi, ue.e1, arguments); + if (!f) + { + type = Type.terror; + return this; + } + ad = td.toParent().isAggregateDeclaration(); + } + + if (f.needThis()) + { + ue.e1 = getRightThis(loc, sc, ad, ue.e1, f); + } + + /* Cannot call public functions from inside invariant + * (because then the invariant would have infinite recursion) + */ + if (sc.func && sc.func.isInvariantDeclaration() && + ue.e1.op == TOK.TOKthis && f.addPostInvariant()) + { + error("cannot call public/export function %s from invariant", f.toChars()); + } + + checkDeprecated(sc, f); + version (DMDV2) { + checkPurity(sc, f); + } + accessCheck(loc, sc, ue.e1, f); + if (!f.needThis()) + { + VarExp ve = new VarExp(loc, f); + e1 = new CommaExp(loc, ue.e1, ve); + e1.type = f.type; + } + else + { + if (e1.op == TOK.TOKdotvar) + dve.var = f; + else + e1 = new DotVarExp(loc, dte.e1, f); + + e1.type = f.type; +static if (false) { + printf("ue.e1 = %s\n", ue.e1.toChars()); + printf("f = %s\n", f.toChars()); + printf("t = %s\n", t.toChars()); + printf("e1 = %s\n", e1.toChars()); + printf("e1.type = %s\n", e1.type.toChars()); +} + // Const member function can take const/immutable/mutable this + if (!(f.type.isConst())) + { + // Check for const/immutable compatibility + Type tthis = ue.e1.type.toBasetype(); + if (tthis.ty == TY.Tpointer) + tthis = tthis.nextOf().toBasetype(); + + static if (false) { // this checking should have been already done + if (f.type.isInvariant()) + { + if (tthis.mod != MOD.MODinvariant) + error("%s can only be called with an immutable object", e1.toChars()); + } + else if (f.type.isShared()) + { + if (tthis.mod != MOD.MODinvariant && tthis.mod != MOD.MODshared && tthis.mod != (MOD.MODshared | MOD.MODconst)) + error("shared %s can only be called with a shared or immutable object", e1.toChars()); + } + else + { + if (tthis.mod != MOD.MODundefined) + { + //printf("mod = %x\n", tthis.mod); + error("%s can only be called with a mutable object, not %s", e1.toChars(), tthis.toChars()); + } + } + } + /* Cannot call mutable method on a final struct + */ + if (tthis.ty == TY.Tstruct && + ue.e1.op == TOK.TOKvar) + { + VarExp v = cast(VarExp)ue.e1; + if (v.var.storage_class & STC.STCfinal) + error("cannot call mutable method on final struct"); + } + } + + // See if we need to adjust the 'this' pointer + AggregateDeclaration add = f.isThis(); + ClassDeclaration cd = ue.e1.type.isClassHandle(); + if (add && cd && add.isClassDeclaration() && add != cd && ue.e1.op != TOK.TOKsuper) + { + ue.e1 = ue.e1.castTo(sc, add.type); //new CastExp(loc, ue.e1, add.type); + ue.e1 = ue.e1.semantic(sc); + } + } + t1 = e1.type; + } + else if (e1.op == TOK.TOKsuper) + { + // Base class constructor call + ClassDeclaration cd = null; + + if (sc.func) + cd = sc.func.toParent().isClassDeclaration(); + if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration()) + { + error("super class constructor call must be in a constructor"); + type = Type.terror; + return this; + } + else + { + if (!cd.baseClass.ctor) + { + error("no super class constructor for %s", cd.baseClass.toChars()); + type = Type.terror; + return this; + } + else + { + if (!sc.intypeof) + { +static if (false) { + if (sc.callSuper & (CSX.CSXthis | CSX.CSXsuper)) + error("reference to this before super()"); +} + if (sc.noctor || sc.callSuper & CSX.CSXlabel) + error("constructor calls not allowed in loops or after labels"); + if (sc.callSuper & (CSX.CSXsuper_ctor | CSX.CSXthis_ctor)) + error("multiple constructor calls"); + sc.callSuper |= CSX.CSXany_ctor | CSX.CSXsuper_ctor; + } + + f = resolveFuncCall(sc, loc, cd.baseClass.ctor, null, null, arguments, 0); + checkDeprecated(sc, f); +version (DMDV2) { + checkPurity(sc, f); +} + e1 = new DotVarExp(e1.loc, e1, f); + e1 = e1.semantic(sc); + t1 = e1.type; + } + } + } + else if (e1.op == TOK.TOKthis) + { + // same class constructor call + AggregateDeclaration cd = null; + + if (sc.func) + cd = sc.func.toParent().isAggregateDeclaration(); + if (!cd || !sc.func.isCtorDeclaration()) + { + error("constructor call must be in a constructor"); + type = Type.terror; + return this; + } + else + { + if (!sc.intypeof) + { +static if (false) { + if (sc.callSuper & (CSXthis | CSXsuper)) + error("reference to this before super()"); +} + if (sc.noctor || sc.callSuper & CSX.CSXlabel) + error("constructor calls not allowed in loops or after labels"); + if (sc.callSuper & (CSX.CSXsuper_ctor | CSX.CSXthis_ctor)) + error("multiple constructor calls"); + sc.callSuper |= CSX.CSXany_ctor | CSX.CSXthis_ctor; + } + + f = resolveFuncCall(sc, loc, cd.ctor, null, null, arguments, 0); + checkDeprecated(sc, f); +version (DMDV2) { + checkPurity(sc, f); +} + e1 = new DotVarExp(e1.loc, e1, f); + e1 = e1.semantic(sc); + t1 = e1.type; + + // BUG: this should really be done by checking the static + // call graph + if (f == sc.func) + error("cyclic constructor call"); + } + } + else if (e1.op == TOK.TOKoverloadset) + { + OverExp eo = cast(OverExp)e1; + FuncDeclaration ff = null; + for (int j = 0; j < eo.vars.a.dim; j++) + { + Dsymbol s = cast(Dsymbol)eo.vars.a.data[j]; + FuncDeclaration f2 = s.isFuncDeclaration(); + if (f2) + { + f2 = f2.overloadResolve(loc, null, arguments, 1); + } + else + { + TemplateDeclaration td = s.isTemplateDeclaration(); + assert(td); + f2 = td.deduceFunctionTemplate(sc, loc, targsi, null, arguments, 1); + } + if (f2) + { + if (ff) + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol.multiplyDefined(loc, ff, f2); + else + ff = f2; + } + } + if (!ff) + { + /* No overload matches, just set ff and rely on error + * message being generated later. + */ + ff = cast(FuncDeclaration)eo.vars.a.data[0]; + } + e1 = new VarExp(loc, ff); + goto Lagain; + } + else if (!t1) + { + error("function expected before (), not '%s'", e1.toChars()); + type = Type.terror; + return this; + } + else if (t1.ty != TY.Tfunction) + { + if (t1.ty == TY.Tdelegate) + { + TypeDelegate td = cast(TypeDelegate)t1; + assert(td.next.ty == TY.Tfunction); + tf = cast(TypeFunction)(td.next); + if (sc.func && sc.func.isPure() && !tf.ispure) + { + error("pure function '%s' cannot call impure delegate '%s'", sc.func.toChars(), e1.toChars()); + } + goto Lcheckargs; + } + else if (t1.ty == TY.Tpointer && (cast(TypePointer)t1).next.ty == TY.Tfunction) + { + Expression e = new PtrExp(loc, e1); + t1 = (cast(TypePointer)t1).next; + if (sc.func && sc.func.isPure() && !(cast(TypeFunction)t1).ispure) + { + error("pure function '%s' cannot call impure function pointer '%s'", sc.func.toChars(), e1.toChars()); + } + e.type = t1; + e1 = e; + } + else if (e1.op == TOK.TOKtemplate) + { + TemplateExp te = cast(TemplateExp)e1; + f = te.td.deduceFunctionTemplate(sc, loc, targsi, null, arguments); + if (!f) + { + if (tierror) + tierror.error("errors instantiating template"); // give better error message + type = Type.terror; + return this; + } + if (f.needThis() && hasThis(sc)) + { + // Supply an implicit 'this', as in + // this.ident + + e1 = new DotTemplateExp(loc, (new ThisExp(loc)).semantic(sc), te.td); + goto Lagain; + } + + e1 = new VarExp(loc, f); + goto Lagain; + } + else + { + error("function expected before (), not %s of type %s", e1.toChars(), e1.type.toChars()); + type = Type.terror; + return this; + } + } + else if (e1.op == TOK.TOKvar) + { + // Do overload resolution + VarExp ve = cast(VarExp)e1; + + f = ve.var.isFuncDeclaration(); + assert(f); + + if (ve.hasOverloads) + f = f.overloadResolve(loc, null, arguments); + + checkDeprecated(sc, f); +version (DMDV2) { + checkPurity(sc, f); +} + + if (f.needThis() && hasThis(sc)) + { + // Supply an implicit 'this', as in + // this.ident + + e1 = new DotVarExp(loc, new ThisExp(loc), f); + goto Lagain; + } + + accessCheck(loc, sc, null, f); + + ve.var = f; + // ve.hasOverloads = 0; + ve.type = f.type; + t1 = f.type; + } + assert(t1.ty == TY.Tfunction); + tf = cast(TypeFunction)t1; + + Lcheckargs: + assert(tf.ty == TY.Tfunction); + type = tf.next; + + if (!arguments) + arguments = new Expressions(); + + functionArguments(loc, sc, tf, arguments); + + if (!type) + { + error("forward reference to inferred return type of function call %s", toChars()); + type = Type.terror; + } + + if (f && f.tintro) + { + Type t = type; + int offset = 0; + TypeFunction tff = cast(TypeFunction)f.tintro; + + if (tff.next.isBaseOf(t, &offset) && offset) + { + type = tff.next; + return castTo(sc, t); + } + } + + return this; + } + + Expression optimize(int result) + { + //printf("CallExp::optimize(result = %d) %s\n", result, toChars()); + Expression e = this; + + // Optimize parameters + if (arguments) + { + for (size_t i = 0; i < arguments.dim; i++) + { + Expression ee = cast(Expression)arguments.data[i]; + + ee = ee.optimize(WANT.WANTvalue); + arguments.data[i] = cast(void*)ee; + } + } + + e1 = e1.optimize(result); + if (e1.op == TOK.TOKvar) + { + FuncDeclaration fd = (cast(VarExp)e1).var.isFuncDeclaration(); + if (fd) + { + BUILTIN b = fd.isBuiltin(); + if (b) + { + e = eval_builtin(b, arguments); + if (!e) // failed + e = this; // evaluate at runtime + } + else if (result & WANT.WANTinterpret) + { + Expression eresult = fd.interpret(null, arguments); + if (eresult && eresult !is EXP_VOID_INTERPRET) + e = eresult; + else + error("cannot evaluate %s at compile time", toChars()); + } + } + } + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + bool checkSideEffect(int flag) + { +version (DMDV2) { + if (flag != 2) + return true; + + if (e1.checkSideEffect(2)) + return true; + + /* If any of the arguments have side effects, this expression does + */ + for (size_t i = 0; i < arguments.dim; i++) + { + Expression e = cast(Expression)arguments.data[i]; + + if (e.checkSideEffect(2)) + return true; + } + + /* If calling a function or delegate that is typed as pure, + * then this expression has no side effects. + */ + Type t = e1.type.toBasetype(); + if (t.ty == TY.Tfunction && (cast(TypeFunction)t).ispure) + return false; + if (t.ty == TY.Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).ispure) + return false; +} + return true; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + int i; + expToCBuffer(buf, hgs, e1, precedence[op]); + buf.writeByte('('); + argsToCBuffer(buf, arguments, hgs); + buf.writeByte(')'); + } + + void dump(int indent) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + //printf("CallExp::toElem('%s')\n", toChars()); + assert(e1.type); + elem* ec; + int directcall; + FuncDeclaration fd; + Type t1 = e1.type.toBasetype(); + Type ectype = t1; + + elem* ehidden = irs.ehidden; + irs.ehidden = null; + + directcall = 0; + fd = null; + if (e1.op == TOK.TOKdotvar && t1.ty != TY.Tdelegate) + { + DotVarExp dve = cast(DotVarExp)e1; + + fd = dve.var.isFuncDeclaration(); + Expression ex = dve.e1; + while (1) + { + switch (ex.op) + { + case TOK.TOKsuper: // super.member() calls directly + case TOK.TOKdottype: // type.member() calls directly + directcall = 1; + break; + + case TOK.TOKcast: + ex = (cast(CastExp)ex).e1; + continue; + + default: + //ex.dump(0); + break; + } + break; + } + ec = dve.e1.toElem(irs); + ectype = dve.e1.type.toBasetype(); + } + else if (e1.op == TOK.TOKvar) + { + fd = (cast(VarExp)e1).var.isFuncDeclaration(); + + if (fd && fd.ident == Id.alloca && !fd.fbody && fd.linkage == LINK.LINKc && arguments && arguments.dim == 1) + { + Expression arg = cast(Expression)arguments.data[0]; + arg = arg.optimize(WANT.WANTvalue); + if (arg.isConst() && arg.type.isintegral()) + { + long sz = arg.toInteger(); + if (sz > 0 && sz < 0x40000) + { + // It's an alloca(sz) of a fixed amount. + // Replace with an array allocated on the stack + // of the same size: char[sz] tmp; + + Symbol* stmp; + .type* t; + + assert(!ehidden); + t = type_allocn(TYM.TYarray, tschar); + t.Tdim = cast(uint)sz; + stmp = symbol_genauto(t); + ec = el_ptr(stmp); + el_setLoc(ec,loc); + return ec; + } + } + } + + ec = e1.toElem(irs); + } + else + { + ec = e1.toElem(irs); + } + ec = callfunc(loc, irs, directcall, type, ec, ectype, fd, t1, ehidden, arguments); + el_setLoc(ec,loc); + return ec; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + +version (DMDV2) { + int isLvalue() + { + // if (type.toBasetype().ty == Tstruct) + // return 1; + Type tb = e1.type.toBasetype(); + if (tb.ty == Tfunction && (cast(TypeFunction)tb).isref) + return 1; // function returns a reference + return 0; + } +} + Expression toLvalue(Scope sc, Expression e) + { + if (isLvalue()) + return this; + return Expression.toLvalue(sc, e); + } + +version (DMDV2) { + bool canThrow() + { + //printf("CallExp::canThrow() %s\n", toChars()); + if (e1.canThrow()) + return true; + + /* If any of the arguments can throw, then this expression can throw + */ + for (size_t i = 0; i < arguments.dim; i++) + { + Expression e = cast(Expression)arguments.data[i]; + + if (e && e.canThrow()) + return true; + } + + if (global.errors && !e1.type) + return false; // error recovery + + /* If calling a function or delegate that is typed as nothrow, + * then this expression cannot throw. + * Note that pure functions can throw. + */ + Type t = e1.type.toBasetype(); + if (t.ty == TY.Tfunction && (cast(TypeFunction)t).isnothrow) + return false; + if (t.ty == TY.Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).isnothrow) + return false; + + return true; + } +} + int inlineCost(InlineCostState* ics) + { + return 1 + e1.inlineCost(ics) + arrayInlineCost(ics, arguments); + } + + Expression doInline(InlineDoState ids) + { + CallExp ce = cast(CallExp)copy(); + ce.e1 = e1.doInline(ids); + ce.arguments = arrayExpressiondoInline(arguments, ids); + return ce; + } + + Expression inlineScan(InlineScanState* iss) + { + Expression e = this; + + //printf("CallExp.inlineScan()\n"); + e1 = e1.inlineScan(iss); + arrayInlineScan(iss, arguments); + + if (e1.op == TOKvar) + { + VarExp ve = cast(VarExp)e1; + FuncDeclaration fd = ve.var.isFuncDeclaration(); + + if (fd && fd != iss.fd && fd.canInline(0)) + { + e = fd.doInline(iss, null, arguments); + } + } + else if (e1.op == TOKdotvar) + { + DotVarExp dve = cast(DotVarExp)e1; + FuncDeclaration fd = dve.var.isFuncDeclaration(); + + if (fd && fd != iss.fd && fd.canInline(1)) + { + if (dve.e1.op == TOKcall && + dve.e1.type.toBasetype().ty == Tstruct) + { + /* To create ethis, we'll need to take the address + * of dve.e1, but this won't work if dve.e1 is + * a function call. + */ + ; + } + else + e = fd.doInline(iss, dve.e1, arguments); + } + } + + return e; + } +} +