Mercurial > projects > ddmd
diff dmd/CallExp.d @ 72:2e2a5c3f943a
reduced warnings by adding override to the methods
think this also normalizes different line endings used all over the place
author | Trass3r |
---|---|
date | Sat, 28 Aug 2010 16:19:48 +0200 |
parents | efb1e5bdf63c |
children | ef02e2e203c2 |
line wrap: on
line diff
--- a/dmd/CallExp.d Sat Aug 28 16:14:07 2010 +0200 +++ b/dmd/CallExp.d Sat Aug 28 16:19:48 2010 +0200 @@ -1,85 +1,85 @@ -module dmd.CallExp; - -import dmd.Expression; -import dmd.Cast; -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; - -import std.stdio; - +module dmd.CallExp; + +import dmd.Expression; +import dmd.Cast; +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; + +import std.stdio; + class CallExp : UnaExp { Expressions arguments; this(Loc loc, Expression e, Expressions exps) { - super(loc, TOK.TOKcall, CallExp.sizeof, e); + super(loc, TOK.TOKcall, CallExp.sizeof, e); this.arguments = exps; } @@ -90,1051 +90,1051 @@ 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; - + 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) - { - super(loc, TOK.TOKcall, CallExp.sizeof, e); + { + super(loc, TOK.TOKcall, CallExp.sizeof, e); - Expressions arguments = new Expressions(); - arguments.setDim(2); - arguments.data[0] = cast(void*)earg1; - arguments.data[1] = cast(void*)earg2; - + Expressions arguments = new Expressions(); + arguments.setDim(2); + arguments.data[0] = cast(void*)earg1; + arguments.data[1] = cast(void*)earg2; + this.arguments = arguments; } - Expression syntaxCopy() + override 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; + override 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) + override 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()); - } - } - } - + //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) + override Expression interpret(InterState istate) { - Expression e = EXP_CANT_INTERPRET; - -version (LOG) { - printf("CallExp.interpret() %.*s\n", toChars()); -} - if (e1.op == TOKdotvar) - { - Expression pthis = (cast(DotVarExp)e1).e1; - FuncDeclaration fd = (cast(DotVarExp)e1).var.isFuncDeclaration(); - TypeFunction tf = fd ? cast(TypeFunction)fd.type : null; - if (tf) - { - // Member function call - if(pthis.op == TOKthis) - pthis = istate.localThis; - Expression eresult = fd.interpret(istate, arguments, pthis); - if (eresult) - e = eresult; - else if (fd.type.toBasetype().nextOf().ty == Tvoid && !global.errors) - e = EXP_VOID_INTERPRET; - else - error("cannot evaluate %s at compile time", toChars()); - return e; - } - error("cannot evaluate %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - if (e1.op == TOKvar) - { - FuncDeclaration fd = (cast(VarExp)e1).var.isFuncDeclaration(); - if (fd) - { -///version (DMDV2) { - BUILTIN b = fd.isBuiltin(); - if (b) - { - scope Expressions args = new Expressions(); - args.setDim(arguments.dim); - for (size_t i = 0; i < args.dim; i++) - { - Expression earg = cast(Expression)arguments.data[i]; - earg = earg.interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return earg; - args.data[i] = cast(void*)earg; - } - e = eval_builtin(b, args); - if (!e) - e = EXP_CANT_INTERPRET; - } - else -///} - // Inline .dup - if (fd.ident == Id.adDup && arguments && arguments.dim == 2) - { - e = cast(Expression)arguments.data[1]; - e = e.interpret(istate); - if (e !is EXP_CANT_INTERPRET) - { - e = expType(type, e); - } - } - else - { - Expression eresult = fd.interpret(istate, arguments); - if (eresult) - e = eresult; - else if (fd.type.toBasetype().nextOf().ty == Tvoid && !global.errors) - e = EXP_VOID_INTERPRET; - else - error("cannot evaluate %s at compile time", toChars()); - } - } - } + Expression e = EXP_CANT_INTERPRET; + +version (LOG) { + printf("CallExp.interpret() %.*s\n", toChars()); +} + if (e1.op == TOKdotvar) + { + Expression pthis = (cast(DotVarExp)e1).e1; + FuncDeclaration fd = (cast(DotVarExp)e1).var.isFuncDeclaration(); + TypeFunction tf = fd ? cast(TypeFunction)fd.type : null; + if (tf) + { + // Member function call + if(pthis.op == TOKthis) + pthis = istate.localThis; + Expression eresult = fd.interpret(istate, arguments, pthis); + if (eresult) + e = eresult; + else if (fd.type.toBasetype().nextOf().ty == Tvoid && !global.errors) + e = EXP_VOID_INTERPRET; + else + error("cannot evaluate %s at compile time", toChars()); + return e; + } + error("cannot evaluate %s at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + if (e1.op == TOKvar) + { + FuncDeclaration fd = (cast(VarExp)e1).var.isFuncDeclaration(); + if (fd) + { +///version (DMDV2) { + BUILTIN b = fd.isBuiltin(); + if (b) + { + scope Expressions args = new Expressions(); + args.setDim(arguments.dim); + for (size_t i = 0; i < args.dim; i++) + { + Expression earg = cast(Expression)arguments.data[i]; + earg = earg.interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return earg; + args.data[i] = cast(void*)earg; + } + e = eval_builtin(b, args); + if (!e) + e = EXP_CANT_INTERPRET; + } + else +///} + // Inline .dup + if (fd.ident == Id.adDup && arguments && arguments.dim == 2) + { + e = cast(Expression)arguments.data[1]; + e = e.interpret(istate); + if (e !is EXP_CANT_INTERPRET) + { + e = expType(type, e); + } + } + else + { + Expression eresult = fd.interpret(istate, arguments); + if (eresult) + e = eresult; + else if (fd.type.toBasetype().nextOf().ty == Tvoid && !global.errors) + e = EXP_VOID_INTERPRET; + else + error("cannot evaluate %s at compile time", toChars()); + } + } + } return e; } - bool checkSideEffect(int flag) + override 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; -} +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) + override void toCBuffer(OutBuffer buf, HdrGenState* hgs) { - int i; - expToCBuffer(buf, hgs, e1, precedence[op]); - buf.writeByte('('); - argsToCBuffer(buf, arguments, hgs); + int i; + expToCBuffer(buf, hgs, e1, precedence[op]); + buf.writeByte('('); + argsToCBuffer(buf, arguments, hgs); buf.writeByte(')'); } - void dump(int indent) + override void dump(int indent) { assert(false); } - elem* toElem(IRState* irs) + override 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); + //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) + override void scanForNestedRef(Scope sc) { - //printf("CallExp.scanForNestedRef(Scope *sc): %s\n", toChars()); - e1.scanForNestedRef(sc); + //printf("CallExp.scanForNestedRef(Scope *sc): %s\n", toChars()); + e1.scanForNestedRef(sc); arrayExpressionScanForNestedRef(sc, arguments); - } + } version (DMDV2) { - int isLvalue() + override 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 + // 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) + override Expression toLvalue(Scope sc, Expression e) { - if (isLvalue()) - return this; + if (isLvalue()) + return this; return Expression.toLvalue(sc, e); - } + } version (DMDV2) { - bool canThrow() + override 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; - + //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) + override int inlineCost(InlineCostState* ics) { return 1 + e1.inlineCost(ics) + arrayInlineCost(ics, arguments); } - Expression doInline(InlineDoState ids) + override Expression doInline(InlineDoState ids) { - CallExp ce = cast(CallExp)copy(); - ce.e1 = e1.doInline(ids); - ce.arguments = arrayExpressiondoInline(arguments, ids); + CallExp ce = cast(CallExp)copy(); + ce.e1 = e1.doInline(ids); + ce.arguments = arrayExpressiondoInline(arguments, ids); return ce; } - Expression inlineScan(InlineScanState* iss) + override 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); - } - } - + 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; } }