Mercurial > projects > ddmd
view dmd/VarExp.d @ 178:e3afd1303184
Many small bugs fixed
Made all classes derive from TObject to detect memory leaks (functionality is disabled for now)
Began work on overriding backend memory allocations (to avoid memory leaks)
author | korDen |
---|---|
date | Sun, 17 Oct 2010 07:42:00 +0400 |
parents | 0c8cc2a10f99 |
children | b0d41ff5e0df |
line wrap: on
line source
module dmd.VarExp; import dmd.common; import dmd.Expression; import dmd.Declaration; import dmd.InterState; import dmd.OutBuffer; import dmd.Loc; import dmd.Scope; import dmd.InlineCostState; import dmd.FuncLiteralDeclaration; import dmd.VarDeclaration; import dmd.Dsymbol; import dmd.FuncDeclaration; import dmd.InlineDoState; import dmd.HdrGenState; import dmd.TOK; import dmd.TY; import dmd.STC; import dmd.SymbolDeclaration; import dmd.SymbolExp; import dmd.Type; import dmd.interpret.Util; import dmd.backend.Util; import dmd.backend.dt_t; import dmd.expression.Util; //! Variable class VarExp : SymbolExp { this(Loc loc, Declaration var, bool hasOverloads = false) { register(); super(loc, TOK.TOKvar, VarExp.sizeof, var, hasOverloads); //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars()); //if (strcmp(var.ident.toChars(), "func") == 0) halt(); this.type = var.type; } override bool equals(Object o) { VarExp ne; if ( this == o || ((cast(Expression)o).op == TOKvar && ((ne = cast(VarExp)o), type.toHeadMutable().equals(ne.type.toHeadMutable())) && var == ne.var)) return true; return false; } override Expression semantic(Scope sc) { FuncLiteralDeclaration fd; version (LOGSEMANTIC) { printf("VarExp.semantic(%s)\n", toChars()); } if (!type) { type = var.type; static if (false) { if (var.storage_class & STC.STClazy) { TypeFunction tf = new TypeFunction(null, type, 0, LINK.LINKd); type = new TypeDelegate(tf); type = type.semantic(loc, sc); } } } /* Fix for 1161 doesn't work because it causes protection * problems when instantiating imported templates passing private * variables as alias template parameters. */ //accessCheck(loc, sc, null, var); VarDeclaration v = var.isVarDeclaration(); if (v) { static if (false) { if ((v.isConst() || v.isImmutable()) && type.toBasetype().ty != TY.Tsarray && v.init) { ExpInitializer ei = v.init.isExpInitializer(); if (ei) { //ei.exp.implicitCastTo(sc, type).print(); return ei.exp.implicitCastTo(sc, type); } } } v.checkNestedReference(sc, loc); version (DMDV2) { static if (true) { if (sc.func && !sc.intypeof) { /* Given: * void f() * { int fx; * pure void g() * { int gx; * void h() * { int hx; * void i() { } * } * } * } * i() can modify hx and gx but not fx */ /* Determine if sc.func is pure or if any function that * encloses it is also pure. */ bool hasPureParent = false; for (FuncDeclaration outerfunc = sc.func; outerfunc;) { if (outerfunc.isPure()) { hasPureParent = true; break; } Dsymbol parent = outerfunc.toParent2(); if (!parent) break; outerfunc = parent.isFuncDeclaration(); } /* If ANY of its enclosing functions are pure, * it cannot do anything impure. * If it is pure, it cannot access any mutable variables other * than those inside itself */ if (hasPureParent && v.isDataseg() && !v.isImmutable()) { error("pure function '%s' cannot access mutable static data '%s'", sc.func.toChars(), v.toChars()); } else if (sc.func.isPure() && sc.parent != v.parent && !v.isImmutable() && !(v.storage_class & STC.STCmanifest)) { error("pure nested function '%s' cannot access mutable data '%s'", sc.func.toChars(), v.toChars()); if (v.isEnumDeclaration()) error("enum"); } /* Do not allow safe functions to access __gshared data */ if (sc.func.isSafe() && v.storage_class & STCgshared) error("safe function '%s' cannot access __gshared data '%s'", sc.func.toChars(), v.toChars()); } } else { if (sc.func && sc.func.isPure() && !sc.intypeof) { if (v.isDataseg() && !v.isImmutable()) error("pure function '%s' cannot access mutable static data '%s'", sc.func.toChars(), v.toChars()); } } } } else { static if (false) { if ((fd = var.isFuncLiteralDeclaration()) !is null) { Expression e = new FuncExp(loc, fd); e.type = type; return e; } } } return this; } override Expression optimize(int result) { return fromConstInitializer(result, this); } override Expression interpret(InterState istate) { version (LOG) { printf("VarExp.interpret() %.*s\n", toChars()); } return getVarExp(loc, istate, var); } override void dump(int indent) { assert(false); } override string toChars() { return var.toChars(); } override void toCBuffer(OutBuffer buf, HdrGenState* hgs) { buf.writestring(var.toChars()); } override void checkEscape() { VarDeclaration v = var.isVarDeclaration(); if (v) { Type tb = v.type.toBasetype(); // if reference type if (tb.ty == TY.Tarray || tb.ty == TY.Tsarray || tb.ty == TY.Tclass) { if ((v.isAuto() || v.isScope()) && !v.noauto) error("escaping reference to scope local %s", v.toChars()); else if (v.storage_class & STC.STCvariadic) error("escaping reference to variadic parameter %s", v.toChars()); } } } override void checkEscapeRef() { VarDeclaration v = var.isVarDeclaration(); if (v) { if (!v.isDataseg() && !(v.storage_class & (STCref | STCout))) error("escaping reference to local variable %s", v.toChars()); } } version (DMDV2) { override int isLvalue() { if (var.storage_class & STClazy) return 0; return 1; } } override Expression toLvalue(Scope sc, Expression e) { static if (false) { tym = tybasic(e1.ET.Tty); if (!(tyscalar(tym) || tym == TYM.TYstruct || tym == TYM.TYarray && e.Eoper == TOK.TOKaddr)) { synerr(EM_lvalue); // lvalue expected } } if (var.storage_class & STC.STClazy) error("lazy variables cannot be lvalues"); return this; } override Expression modifiableLvalue(Scope sc, Expression e) { //printf("VarExp::modifiableLvalue('%s')\n", var.toChars()); //if (type && type.toBasetype().ty == TY.Tsarray) // error("cannot change reference to static array '%s'", var.toChars()); var.checkModify(loc, sc, type); // See if this expression is a modifiable lvalue (i.e. not const) return toLvalue(sc, e); } override dt_t** toDt(dt_t** pdt) { // writef("VarExp::toDt() %d\n", op); for (; *pdt; pdt = &((*pdt).DTnext)) {} VarDeclaration v = var.isVarDeclaration(); if (v && (v.isConst() || v.isImmutable()) && type.toBasetype().ty != Tsarray && v.init) { if (v.inuse) { error("recursive reference %s", toChars()); return pdt; } v.inuse++; *pdt = v.init.toDt(); v.inuse--; return pdt; } SymbolDeclaration sd = var.isSymbolDeclaration(); if (sd && sd.dsym) { sd.dsym.toDt(pdt); return pdt; } debug writef("VarExp::toDt(), kind = %s\n", var.kind()); error("non-constant expression %s", toChars()); pdt = dtnzeros(pdt, 1); return pdt; } version(DMDV1) override elem* toElem(IRState* irs) { assert(false); } override void scanForNestedRef(Scope sc) { //printf("VarExp.scanForNestedRef(%s)\n", toChars()); VarDeclaration v = var.isVarDeclaration(); if (v) v.checkNestedReference(sc, Loc(0)); } override int inlineCost(InlineCostState* ics) { //printf("VarExp.inlineCost() %s\n", toChars()); return 1; } override Expression doInline(InlineDoState ids) { int i; //printf("VarExp.doInline(%s)\n", toChars()); for (i = 0; i < ids.from.dim; i++) { if (var == cast(Declaration)ids.from.data[i]) { VarExp ve = cast(VarExp)copy(); ve.var = cast(Declaration)ids.to.data[i]; return ve; } } return this; } }