Mercurial > projects > ddmd
diff dmd/AggregateDeclaration.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 5c9b78899f5d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AggregateDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,643 @@ +module dmd.AggregateDeclaration; + +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.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.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) + { + for (int i = 0; i < cdthis.baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)cdthis.baseclasses.data[i]; + 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) + { + for (int i = 0; i < cdthis.baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)cdthis.baseclasses.data[i]; + + if (accessCheckX(smember, sfunc, b.base, cdscope)) + return true; + } + } + } + } + + return false; +} + +class AggregateDeclaration : ScopeDsymbol +{ + Type type; + uint 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 + Array 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 + + 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) + { + super(id); + this.loc = loc; + + fields = new Array(); /// + dtors = new FuncDeclarations(); + } + + void semantic2(Scope sc) + { + //printf("AggregateDeclaration.semantic2(%s)\n", toChars()); + if (scope_ && members) + { + error("has forward references"); + return; + } + if (members) + { + sc = sc.push(this); + for (size_t i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic2(sc); + } + sc.pop(); + } + } + + void semantic3(Scope sc) + { + int i; + + //printf("AggregateDeclaration.semantic3(%s)\n", toChars()); + if (members) + { + sc = sc.push(this); + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic3(sc); + } + sc.pop(); + } + } + + void inlineScan() + { + int i; + + //printf("AggregateDeclaration.inlineScan(%s)\n", toChars()); + if (members) + { + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + //printf("inline scan aggregate symbol '%s'\n", s.toChars()); + s.inlineScan(); + } + } + } + + 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); + } + + 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 = Type.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(cast(void*)v); + } + + 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) { + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol s = cast(Dsymbol)fields.data[i]; + VarDeclaration v = s.isVarDeclaration(); + 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(cast(void*)dd); + members.push(cast(void*)dd); + dd.semantic(sc); + } +} + + switch (dtors.dim) + { + case 0: + return null; + + case 1: + return cast(FuncDeclaration)dtors.data[0]; + + default: + e = null; + for (size_t i = 0; i < dtors.dim; i++) + { + FuncDeclaration fd = cast(FuncDeclaration)dtors.data[i]; + 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); + } + DtorDeclaration dd = new DtorDeclaration(Loc(0), Loc(0), Lexer.idPool("__aggrDtor")); + dd.fbody = new ExpStatement(Loc(0), e); + members.push(cast(void*)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; + } + + void emitComment(Scope sc) + { + assert(false); + } + + 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(); + } + } + + 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; + } + + AggregateDeclaration isAggregateDeclaration() { return this; } +} \ No newline at end of file