Mercurial > projects > ddmd
view dmd/AggregateDeclaration.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 | fa9a71a9f5a8 |
children | b0d41ff5e0df |
line wrap: on
line source
module dmd.AggregateDeclaration; import dmd.common; import dmd.ScopeDsymbol; import dmd.Type; import dmd.Id; import dmd.ExpStatement; import dmd.AddrExp; import dmd.CastExp; import dmd.TypeSArray; import dmd.DotVarExp; import dmd.TypeStruct; import dmd.StructDeclaration; import dmd.Declaration; import dmd.TypeClass; import dmd.TOK; import dmd.ThisExp; import dmd.Global; import dmd.PROT; import dmd.Expression; import dmd.STC; import dmd.DotIdExp; import dmd.CallExp; import dmd.DtorDeclaration; import dmd.Lexer; import dmd.TY; import dmd.Array; import dmd.ArrayTypes; import dmd.VarDeclaration; import dmd.InvariantDeclaration; import dmd.NewDeclaration; import dmd.DeleteDeclaration; import dmd.CtorDeclaration; import dmd.FuncDeclaration; import dmd.Identifier; import dmd.Json; import dmd.Loc; import dmd.Dsymbol; import dmd.Scope; import dmd.OutBuffer; import dmd.ClassDeclaration; import dmd.BaseClass; import dmd.Util; import dmd.backend.Symbol; import dmd.backend.Classsym; import dmd.backend.Util; import dmd.backend.LIST; import dmd.backend.SC; import dmd.backend.FL; import dmd.backend.SFL; import dmd.codegen.Util; /**************************************** * Determine if scope sc has package level access to s. */ bool hasPackageAccess(Scope sc, Dsymbol s) { version (LOG) { printf("hasPackageAccess(s = '%s', sc = '%p')\n", s.toChars(), sc); } for (; s; s = s.parent) { if (s.isPackage() && !s.isModule()) break; } version (LOG) { if (s) printf("\tthis is in package '%s'\n", s.toChars()); } if (s && s == sc.module_.parent) { version (LOG) { printf("\ts is in same package as sc\n"); } return true; } version (LOG) { printf("\tno package access\n"); } return false; } /******************************************************** * Helper function for ClassDeclaration.accessCheck() * Returns: * 0 no access * 1 access */ bool accessCheckX(Dsymbol smember, Dsymbol sfunc, AggregateDeclaration dthis, AggregateDeclaration cdscope) { assert(dthis); static if (false) { writef("accessCheckX for %s.%s in function %s() in scope %s\n", dthis.toChars(), smember.toChars(), sfunc ? sfunc.toChars() : "null", cdscope ? cdscope.toChars() : "null"); } if (dthis.hasPrivateAccess(sfunc) || dthis.isFriendOf(cdscope)) { if (smember.toParent() == dthis) return true; else { ClassDeclaration cdthis = dthis.isClassDeclaration(); if (cdthis) { foreach (b; cdthis.baseclasses) { PROT access = b.base.getAccess(smember); if (access >= PROT.PROTprotected || accessCheckX(smember, sfunc, b.base, cdscope)) return true; } } } } else { if (smember.toParent() != dthis) { ClassDeclaration cdthis = dthis.isClassDeclaration(); if (cdthis) { foreach (b; cdthis.baseclasses) { if (accessCheckX(smember, sfunc, b.base, cdscope)) return true; } } } } return false; } class AggregateDeclaration : ScopeDsymbol { Type type; StorageClass storage_class; PROT protection = PROT.PROTpublic; Type handle; // 'this' type uint structsize; // size of struct uint alignsize; // size of struct for alignment purposes uint structalign; // struct member alignment in effect int hasUnions; // set if aggregate has overlapping fields VarDeclarations fields; // VarDeclaration fields uint sizeok; // set when structsize contains valid data // 0: no size // 1: size is correct // 2: cannot determine size; fwd referenced bool isdeprecated; // true if deprecated version (DMDV2) { bool isnested; // true if is nested VarDeclaration vthis; // 'this' parameter if this aggregate is nested } // Special member functions InvariantDeclaration inv; // invariant NewDeclaration aggNew; // allocator DeleteDeclaration aggDelete; // deallocator version (DMDV2) { //CtorDeclaration *ctor; Dsymbol ctor; // CtorDeclaration or TemplateDeclaration CtorDeclaration defaultCtor; // default constructor Dsymbol aliasthis; // forward unresolved lookups to aliasthis } FuncDeclarations dtors; // Array of destructors FuncDeclaration dtor; // aggregate destructor version (IN_GCC) { Array methods; // flat list of all methods for debug information } this(Loc loc, Identifier id) { register(); super(id); this.loc = loc; fields = new VarDeclarations(); /// dtors = new FuncDeclarations(); } override void semantic2(Scope sc) { //printf("AggregateDeclaration.semantic2(%s)\n", toChars()); if (scope_ && members) { error("has forward references"); return; } if (members) { sc = sc.push(this); foreach(Dsymbol s; members) s.semantic2(sc); sc.pop(); } } override void semantic3(Scope sc) { //printf("AggregateDeclaration.semantic3(%s)\n", toChars()); if (members) { sc = sc.push(this); foreach(Dsymbol s; members) s.semantic3(sc); sc.pop(); } } override void inlineScan() { //printf("AggregateDeclaration.inlineScan(%s)\n", toChars()); if (members) { foreach(Dsymbol s; members) { //printf("inline scan aggregate symbol '%s'\n", s.toChars()); s.inlineScan(); } } } override uint size(Loc loc) { //printf("AggregateDeclaration.size() = %d\n", structsize); if (!members) error(loc, "unknown size"); if (sizeok != 1) { error(loc, "no size yet for forward reference"); //*(char*)0=0; } return structsize; } /**************************** * Do byte or word alignment as necessary. * Align sizes of 0, as we may not know array sizes yet. */ static void alignmember(uint salign, uint size, uint* poffset) { //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); if (salign > 1) { assert(size != 3); int sa = size; if (sa == 0 || salign < sa) sa = salign; *poffset = (*poffset + sa - 1) & ~(sa - 1); } //printf("result = %d\n",offset); } override Type getType() { return type; } void addField(Scope sc, VarDeclaration v) { uint memsize; // size of member uint memalignsize; // size of member for alignment purposes uint xalign; // alignment boundaries //printf("AggregateDeclaration.addField('%s') %s\n", v.toChars(), toChars()); assert(!(v.storage_class & (STC.STCstatic | STC.STCextern | STC.STCparameter | STC.STCtls))); // Check for forward referenced types which will fail the size() call Type t = v.type.toBasetype(); if (v.storage_class & STC.STCref) { // References are the size of a pointer t = global.tvoidptr; } if (t.ty == TY.Tstruct /*&& isStructDeclaration()*/) { TypeStruct ts = cast(TypeStruct)t; version (DMDV2) { if (ts.sym == this) { error("cannot have field %s with same struct type", v.toChars()); } } if (ts.sym.sizeok != 1) { sizeok = 2; // cannot finish; flag as forward referenced return; } } if (t.ty == TY.Tident) { sizeok = 2; // cannot finish; flag as forward referenced return; } memsize = cast(uint)t.size(loc); /// memalignsize = t.alignsize(); xalign = t.memalign(sc.structalign); alignmember(xalign, memalignsize, &sc.offset); v.offset = sc.offset; sc.offset += memsize; if (sc.offset > structsize) structsize = sc.offset; if (sc.structalign < memalignsize) memalignsize = sc.structalign; if (alignsize < memalignsize) alignsize = memalignsize; //printf("\talignsize = %d\n", alignsize); v.storage_class |= STC.STCfield; //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v.toChars(), toChars(), v.offset, memsize); fields.push(v); } override bool isDeprecated() // is aggregate deprecated? { return isdeprecated; } /***************************************** * Create inclusive destructor for struct/class by aggregating * all the destructors in dtors[] with the destructors for * all the members. * Note the close similarity with StructDeclaration.buildPostBlit(), * and the ordering changes (runs backward instead of forwards). */ FuncDeclaration buildDtor(Scope sc) { //printf("AggregateDeclaration.buildDtor() %s\n", toChars()); Expression e = null; version (DMDV2) { foreach (size_t i, VarDeclaration v; fields) { assert(v && v.storage_class & STC.STCfield); if (v.storage_class & STC.STCref) continue; Type tv = v.type.toBasetype(); size_t dim = 1; while (tv.ty == TY.Tsarray) { TypeSArray ta = cast(TypeSArray)tv; dim *= (cast(TypeSArray)tv).dim.toInteger(); tv = tv.nextOf().toBasetype(); } if (tv.ty == TY.Tstruct) { TypeStruct ts = cast(TypeStruct)tv; StructDeclaration sd = ts.sym; if (sd.dtor) { Expression ex; // this.v ex = new ThisExp(Loc(0)); ex = new DotVarExp(Loc(0), ex, v, 0); if (dim == 1) { // this.v.dtor() ex = new DotVarExp(Loc(0), ex, sd.dtor, 0); ex = new CallExp(Loc(0), ex); } else { // Typeinfo.destroy(cast(void*)&this.v); Expression ea = new AddrExp(Loc(0), ex); ea = new CastExp(Loc(0), ea, Type.tvoid.pointerTo()); Expression et = v.type.getTypeInfo(sc); et = new DotIdExp(Loc(0), et, Id.destroy); ex = new CallExp(Loc(0), et, ea); } e = Expression.combine(ex, e); // combine in reverse order } } } /* Build our own "destructor" which executes e */ if (e) { //printf("Building __fieldDtor()\n"); DtorDeclaration dd = new DtorDeclaration(Loc(0), Loc(0), Lexer.idPool("__fieldDtor")); dd.fbody = new ExpStatement(Loc(0), e); dtors.shift(dd); members.push(dd); dd.semantic(sc); } } switch (dtors.dim) { case 0: return null; case 1: return cast(FuncDeclaration)dtors[0]; default: e = null; foreach(FuncDeclaration fd; dtors) { Expression ex = new ThisExp(Loc(0)); ex = new DotVarExp(Loc(0), ex, fd, 0); ex = new CallExp(Loc(0), ex); e = Expression.combine(ex, e); } auto dd = new DtorDeclaration(Loc(0), Loc(0), Lexer.idPool("__aggrDtor")); dd.fbody = new ExpStatement(Loc(0), e); members.push(dd); dd.semantic(sc); return dd; } } /**************************************** * Returns true if there's an extra member which is the 'this' * pointer to the enclosing context (enclosing aggregate or function) */ bool isNested() { return isnested; } override void emitComment(Scope sc) { assert(false); } override void toJsonBuffer(OutBuffer buf) { //writef("AggregateDeclaration.toJsonBuffer()\n"); buf.writestring("{\n"); JsonProperty(buf, Pname, toChars()); JsonProperty(buf, Pkind, kind()); if (comment) JsonProperty(buf, Pcomment, comment); if (loc.linnum) JsonProperty(buf, Pline, loc.linnum); ClassDeclaration cd = isClassDeclaration(); if (cd) { if (cd.baseClass) { JsonProperty(buf, "base", cd.baseClass.toChars()); } if (cd.interfaces_dim) { JsonString(buf, "interfaces"); buf.writestring(" : [\n"); size_t offset = buf.offset; for (int i = 0; i < cd.interfaces_dim; i++) { BaseClass b = cd.interfaces[i]; if (offset != buf.offset) { buf.writestring(",\n"); offset = buf.offset; } JsonString(buf, b.base.toChars()); } JsonRemoveComma(buf); buf.writestring("],\n"); } } JsonString(buf, Pmembers); buf.writestring(" : [\n"); size_t offset = buf.offset; foreach (Dsymbol s; members) { if (offset != buf.offset) { buf.writestring(",\n"); offset = buf.offset; } s.toJsonBuffer(buf); } JsonRemoveComma(buf); buf.writestring("]\n"); buf.writestring("}\n"); } override void toDocBuffer(OutBuffer buf) { assert(false); } // For access checking PROT getAccess(Dsymbol smember) // determine access to smember { assert(false); } /**************************************** * Determine if this is the same or friend of cd. */ bool isFriendOf(AggregateDeclaration cd) { version (LOG) { printf("AggregateDeclaration.isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd.toChars() : "null"); } if (this is cd) return true; // Friends if both are in the same module //if (toParent() == cd.toParent()) if (cd && getModule() == cd.getModule()) { version (LOG) { printf("\tin same module\n"); } return true; } version (LOG) { printf("\tnot friend\n"); } return false; } /********************************** * Determine if smember has access to private members of this declaration. */ bool hasPrivateAccess(Dsymbol smember) // does smember have private access to members of this class? { if (smember) { AggregateDeclaration cd = null; Dsymbol smemberparent = smember.toParent(); if (smemberparent) cd = smemberparent.isAggregateDeclaration(); version (LOG) { printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", toChars(), smember.toChars()); } if (this == cd) // smember is a member of this class { version (LOG) { printf("\tyes 1\n"); } return true; // so we get private access } // If both are members of the same module, grant access while (true) { Dsymbol sp = smember.toParent(); if (sp.isFuncDeclaration() && smember.isFuncDeclaration()) smember = sp; else break; } if (!cd && toParent() == smember.toParent()) { version (LOG) { printf("\tyes 2\n"); } return true; } if (!cd && getModule() == smember.getModule()) { version (LOG) { printf("\tyes 3\n"); } return true; } } version (LOG) { printf("\tno\n"); } return false; } /******************************* * Do access check for member of this class, this class being the * type of the 'this' pointer used to access smember. */ void accessCheck(Loc loc, Scope sc, Dsymbol smember) { bool result; FuncDeclaration f = sc.func; AggregateDeclaration cdscope = sc.getStructClassScope(); PROT access; version (LOG) { printf("AggregateDeclaration.accessCheck() for %s.%s in function %s() in scope %s\n", toChars(), smember.toChars(), f ? f.toChars() : null, cdscope ? cdscope.toChars() : null); } Dsymbol smemberparent = smember.toParent(); if (!smemberparent || !smemberparent.isAggregateDeclaration()) { version (LOG) { printf("not an aggregate member\n"); } return; // then it is accessible } // BUG: should enable this check //assert(smember.parent.isBaseOf(this, null)); if (smemberparent == this) { PROT access2 = smember.prot(); result = access2 >= PROT.PROTpublic || hasPrivateAccess(f) || isFriendOf(cdscope) || (access2 == PROT.PROTpackage && hasPackageAccess(sc, this)); version (LOG) { printf("result1 = %d\n", result); } } else if ((access = this.getAccess(smember)) >= PROT.PROTpublic) { result = true; version (LOG) { printf("result2 = %d\n", result); } } else if (access == PROT.PROTpackage && hasPackageAccess(sc, this)) { result = true; version (LOG) { printf("result3 = %d\n", result); } } else { result = accessCheckX(smember, f, this, cdscope); version (LOG) { printf("result4 = %d\n", result); } } if (!result) { error(loc, "member %s is not accessible", smember.toChars()); halt(); } } override PROT prot() { assert(false); } // Back end Symbol* stag; // tag symbol for debug data Symbol* sinit; Symbol* toInitializer() { Symbol* s; Classsym* stag; if (!sinit) { stag = fake_classsym(Id.ClassInfo); s = toSymbolX("__init", SC.SCextern, stag.Stype, "Z"); s.Sfl = FL.FLextern; s.Sflags |= SFL.SFLnodebug; slist_add(s); sinit = s; } return sinit; } override AggregateDeclaration isAggregateDeclaration() { return this; } }