Mercurial > projects > ldc
diff dmd2/struct.c @ 758:f04dde6e882c
Added initial D2 support, D2 frontend and changes to codegen to make things compile.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:38:48 +0100 |
parents | |
children | 356e65836fb5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd2/struct.c Tue Nov 11 01:38:48 2008 +0100 @@ -0,0 +1,508 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <assert.h> + +#include "root.h" +#include "aggregate.h" +#include "scope.h" +#include "mtype.h" +#include "declaration.h" +#include "module.h" +#include "id.h" +#include "statement.h" + +/********************************* AggregateDeclaration ****************************/ + +AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) + : ScopeDsymbol(id) +{ + this->loc = loc; + + storage_class = 0; + protection = PROTpublic; + type = NULL; + handle = NULL; + structsize = 0; // size of struct + alignsize = 0; // size of struct for alignment purposes + structalign = 0; // struct member alignment in effect + hasUnions = 0; + sizeok = 0; // size not determined yet + isdeprecated = 0; + inv = NULL; + aggNew = NULL; + aggDelete = NULL; + + stag = NULL; + sinit = NULL; + scope = NULL; + dtor = NULL; + + ctor = NULL; + defaultCtor = NULL; +} + +enum PROT AggregateDeclaration::prot() +{ + return protection; +} + +void AggregateDeclaration::semantic2(Scope *sc) +{ + //printf("AggregateDeclaration::semantic2(%s)\n", toChars()); + if (scope) + { error("has forward references"); + return; + } + if (members) + { + sc = sc->push(this); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic2(sc); + } + sc->pop(); + } +} + +void AggregateDeclaration::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 = (Dsymbol *)members->data[i]; + s->semantic3(sc); + } + sc->pop(); + } +} + +void AggregateDeclaration::inlineScan() +{ int i; + + //printf("AggregateDeclaration::inlineScan(%s)\n", toChars()); + if (members) + { + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf("inline scan aggregate symbol '%s'\n", s->toChars()); + s->inlineScan(); + } + } +} + +unsigned AggregateDeclaration::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; +} + +Type *AggregateDeclaration::getType() +{ + return type; +} + +int AggregateDeclaration::isDeprecated() +{ + return isdeprecated; +} + +/**************************** + * Do byte or word alignment as necessary. + * Align sizes of 0, as we may not know array sizes yet. + */ + +void AggregateDeclaration::alignmember(unsigned salign, unsigned size, unsigned *poffset) +{ + //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); + if (salign > 1) + { int sa; + + switch (size) + { case 1: + break; + case 2: + case_2: + *poffset = (*poffset + 1) & ~1; // align to word + break; + case 3: + case 4: + if (salign == 2) + goto case_2; + *poffset = (*poffset + 3) & ~3; // align to dword + break; + default: + *poffset = (*poffset + salign - 1) & ~(salign - 1); + break; + } + } + //printf("result = %d\n",offset); +} + + +void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v) +{ + unsigned memsize; // size of member + unsigned memalignsize; // size of member for alignment purposes + unsigned xalign; // alignment boundaries + + //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars()); + assert(!(v->storage_class & (STCstatic | STCextern | STCparameter | STCtls))); + + // Check for forward referenced types which will fail the size() call + Type *t = v->type->toBasetype(); + if (t->ty == Tstruct /*&& isStructDeclaration()*/) + { TypeStruct *ts = (TypeStruct *)t; + + 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 == Tident) + { + sizeok = 2; // cannot finish; flag as forward referenced + return; + } + + memsize = v->type->size(loc); + memalignsize = v->type->alignsize(); + xalign = v->type->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 |= STCfield; + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize); + fields.push(v); +} + + +/********************************* StructDeclaration ****************************/ + +StructDeclaration::StructDeclaration(Loc loc, Identifier *id) + : AggregateDeclaration(loc, id) +{ + zeroInit = 0; // assume false until we do semantic processing + hasIdentityAssign = 0; + cpctor = NULL; + postblit = NULL; + + // For forward references + type = new TypeStruct(this); +} + +Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s) +{ + StructDeclaration *sd; + + if (s) + sd = (StructDeclaration *)s; + else + sd = new StructDeclaration(loc, ident); + ScopeDsymbol::syntaxCopy(sd); + return sd; +} + +void StructDeclaration::semantic(Scope *sc) +{ int i; + Scope *sc2; + + //printf("+StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); + + //static int count; if (++count == 20) *(char*)0=0; + + assert(type); + if (!members) // if forward reference + return; + + if (symtab) + { if (!scope) + return; // semantic() already completed + } + else + symtab = new DsymbolTable(); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } + + parent = sc->parent; + handle = type->pointerTo(); + structalign = sc->structalign; + protection = sc->protection; + storage_class |= sc->stc; + if (sc->stc & STCdeprecated) + isdeprecated = 1; + assert(!isAnonymous()); + if (sc->stc & STCabstract) + error("structs, unions cannot be abstract"); + if (storage_class & STCinvariant) + type = type->invariantOf(); + else if (storage_class & STCconst) + type = type->constOf(); + + if (sizeok == 0) // if not already done the addMember step + { + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); + s->addMember(sc, this, 1); + } + } + + sizeok = 0; + sc2 = sc->push(this); + sc2->stc &= storage_class & (STCconst | STCinvariant); + sc2->parent = this; + if (isUnionDeclaration()) + sc2->inunion = 1; + sc2->protection = PROTpublic; + sc2->explicitProtection = 0; + + int members_dim = members->dim; + for (i = 0; i < members_dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc2); + if (isUnionDeclaration()) + sc2->offset = 0; +#if 0 + if (sizeok == 2) + { //printf("forward reference\n"); + break; + } +#endif + } + + /* The TypeInfo_Struct is expecting an opEquals and opCmp with + * a parameter that is a pointer to the struct. But if there + * isn't one, but is an opEquals or opCmp with a value, write + * another that is a shell around the value: + * int opCmp(struct *p) { return opCmp(*p); } + */ + + TypeFunction *tfeqptr; + { + Arguments *arguments = new Arguments; + Argument *arg = new Argument(STCin, handle, Id::p, NULL); + + arguments->push(arg); + tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); + tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); + } + + TypeFunction *tfeq; + { + Arguments *arguments = new Arguments; + Argument *arg = new Argument(STCin, type, NULL, NULL); + + arguments->push(arg); + tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); + tfeq = (TypeFunction *)tfeq->semantic(0, sc); + } + + Identifier *id = Id::eq; + for (int i = 0; i < 2; i++) + { + Dsymbol *s = search_function(this, id); + FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; + if (fdx) + { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr); + if (!fd) + { fd = fdx->overloadExactMatch(tfeq); + if (fd) + { // Create the thunk, fdptr + FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); + Expression *e = new IdentifierExp(loc, Id::p); + e = new PtrExp(loc, e); + Expressions *args = new Expressions(); + args->push(e); + e = new IdentifierExp(loc, id); + e = new CallExp(loc, e, args); + fdptr->fbody = new ReturnStatement(loc, e); + ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); + assert(s); + s->members->push(fdptr); + fdptr->addMember(sc, s, 1); + fdptr->semantic(sc2); + } + } + } + + id = Id::cmp; + } + + dtor = buildDtor(sc2); + postblit = buildPostBlit(sc2); + cpctor = buildCpCtor(sc2); + buildOpAssign(sc2); + + sc2->pop(); + + if (sizeok == 2) + { // semantic() failed because of forward references. + // Unwind what we did, and defer it for later + fields.setDim(0); + structsize = 0; + alignsize = 0; + structalign = 0; + + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + //printf("\tdeferring %s\n", toChars()); + return; + } + + // 0 sized struct's are set to 1 byte + if (structsize == 0) + { + structsize = 1; + alignsize = 1; + } + + // Round struct size up to next alignsize boundary. + // This will ensure that arrays of structs will get their internals + // aligned properly. + structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + + sizeok = 1; + Module::dprogress++; + + //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); + + // Determine if struct is all zeros or not + zeroInit = 1; + for (i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *vd = s->isVarDeclaration(); + if (vd && !vd->isDataseg()) + { + if (vd->init) + { + // Should examine init to see if it is really all 0's + zeroInit = 0; + break; + } + else + { + if (!vd->type->isZeroInit()) + { + zeroInit = 0; + break; + } + } + } + } + + /* Look for special member functions. + */ + ctor = (CtorDeclaration *)search(0, Id::ctor, 0); + inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0); + aggNew = (NewDeclaration *)search(0, Id::classNew, 0); + aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); + + if (sc->func) + { + semantic2(sc); + semantic3(sc); + } +} + +void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + buf->printf("%s ", kind()); + if (!isAnonymous()) + buf->writestring(toChars()); + if (!members) + { + buf->writeByte(';'); + buf->writenl(); + return; + } + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + buf->writenl(); +} + + +const char *StructDeclaration::kind() +{ + return "struct"; +} + +/********************************* UnionDeclaration ****************************/ + +UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id) + : StructDeclaration(loc, id) +{ +} + +Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s) +{ + UnionDeclaration *ud; + + if (s) + ud = (UnionDeclaration *)s; + else + ud = new UnionDeclaration(loc, ident); + StructDeclaration::syntaxCopy(ud); + return ud; +} + + +const char *UnionDeclaration::kind() +{ + return "union"; +} + +