Mercurial > projects > ldc
view dmd2/clone.c @ 1112:829ac3f30103
Updating revisions.pl.in:
- Change the way the LLVM SVN revision is detected, using `svn info` instead
of `svnversion`. This speeds it up significantly on my machine (especially
when the LLVM SVN checkout isn't in disk cache).
- Add "last changed date" to SVN checkouts too, not just unpacked tarballs
- No longer rely on SVN revision to detect release vs trunk checkouts, treat
release checkout the same as unpacked release tarball. (Except for date
determination, which uses SVN date instead of filesystem date)
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Fri, 13 Mar 2009 16:18:01 +0100 |
parents | 356e65836fb5 |
children | 638d16625da2 |
line wrap: on
line source
// 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 "expression.h" #include "statement.h" #include "init.h" /******************************************* * We need an opAssign for the struct if * it has a destructor or a postblit. * We need to generate one if a user-specified one does not exist. */ int StructDeclaration::needOpAssign() { #define X 0 if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars()); if (hasIdentityAssign) goto Ldontneed; if (dtor || postblit) goto Lneed; /* If any of the fields need an opAssign, then we * need it too. */ for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = (Dsymbol *)fields.data[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); Type *tv = v->type->toBasetype(); while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; tv = tv->nextOf()->toBasetype(); } if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->needOpAssign()) goto Lneed; } } Ldontneed: if (X) printf("\tdontneed\n"); return 0; Lneed: if (X) printf("\tneed\n"); return 1; #undef X } /****************************************** * Build opAssign for struct. * S* opAssign(S s) { ... } */ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) { if (!needOpAssign()) return NULL; //printf("StructDeclaration::buildOpAssign() %s\n", toChars()); FuncDeclaration *fop = NULL; Argument *param = new Argument(STCnodtor, type, Id::p, NULL); Arguments *fparams = new Arguments; fparams->push(param); Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd); #if STRUCTTHISREF ((TypeFunction *)ftype)->isref = 1; #endif fop = new FuncDeclaration(0, 0, Id::assign, STCundefined, ftype); Expression *e = NULL; if (postblit) { /* Swap: * tmp = *this; *this = s; tmp.dtor(); */ //printf("\tswap copy\n"); Identifier *idtmp = Lexer::uniqueId("__tmp"); VarDeclaration *tmp; AssignExp *ec = NULL; if (dtor) { tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0)); tmp->noauto = 1; e = new DeclarationExp(0, tmp); ec = new AssignExp(0, new VarExp(0, tmp), #if STRUCTTHISREF new ThisExp(0) #else new PtrExp(0, new ThisExp(0)) #endif ); ec->op = TOKblit; e = Expression::combine(e, ec); } ec = new AssignExp(0, #if STRUCTTHISREF new ThisExp(0), #else new PtrExp(0, new ThisExp(0)), #endif new IdentifierExp(0, Id::p)); ec->op = TOKblit; e = Expression::combine(e, ec); if (dtor) { /* Instead of running the destructor on s, run it * on tmp. This avoids needing to copy tmp back in to s. */ Expression *ec = new DotVarExp(0, new VarExp(0, tmp), dtor, 0); ec = new CallExp(0, ec); e = Expression::combine(e, ec); } } else { /* Do memberwise copy */ //printf("\tmemberwise copy\n"); for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = (Dsymbol *)fields.data[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); // this.v = s.v; AssignExp *ec = new AssignExp(0, new DotVarExp(0, new ThisExp(0), v, 0), new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0)); ec->op = TOKblit; e = Expression::combine(e, ec); } } Statement *s1 = new ExpStatement(0, e); /* Add: * return this; */ e = new ThisExp(0); Statement *s2 = new ReturnStatement(0, e); fop->fbody = new CompoundStatement(0, s1, s2); members->push(fop); fop->addMember(sc, this, 1); sc = sc->push(); sc->stc = 0; sc->linkage = LINKd; fop->semantic(sc); sc->pop(); //printf("-StructDeclaration::buildOpAssign() %s\n", toChars()); return fop; } /******************************************* * Build copy constructor for struct. * Copy constructors are compiler generated only, and are only * callable from the compiler. They are not user accessible. * A copy constructor is: * void cpctpr(ref S s) * { * *this = s; * this.postBlit(); * } * This is done so: * - postBlit() never sees uninitialized data * - memcpy can be much more efficient than memberwise copy * - no fields are overlooked */ FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc) { //printf("StructDeclaration::buildCpCtor() %s\n", toChars()); FuncDeclaration *fcp = NULL; /* Copy constructor is only necessary if there is a postblit function, * otherwise the code generator will just do a bit copy. */ if (postblit) { //printf("generating cpctor\n"); Argument *param = new Argument(STCref, type, Id::p, NULL); Arguments *fparams = new Arguments; fparams->push(param); Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd); fcp = new FuncDeclaration(0, 0, Id::cpctor, STCundefined, ftype); // Build *this = p; Expression *e = new ThisExp(0); #if !STRUCTTHISREF e = new PtrExp(0, e); #endif AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p)); ea->op = TOKblit; Statement *s = new ExpStatement(0, ea); // Build postBlit(); e = new VarExp(0, postblit, 0); e = new CallExp(0, e); s = new CompoundStatement(0, s, new ExpStatement(0, e)); fcp->fbody = s; members->push(fcp); sc = sc->push(); sc->stc = 0; sc->linkage = LINKd; fcp->semantic(sc); sc->pop(); } return fcp; } /***************************************** * Create inclusive postblit for struct by aggregating * all the postblits in postblits[] with the postblits for * all the members. * Note the close similarity with AggregateDeclaration::buildDtor(), * and the ordering changes (runs forward instead of backwards). */ #if DMDV2 FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) { //printf("StructDeclaration::buildPostBlit() %s\n", toChars()); Expression *e = NULL; for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = (Dsymbol *)fields.data[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); Type *tv = v->type->toBasetype(); size_t dim = 1; while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; dim *= ((TypeSArray *)tv)->dim->toInteger(); tv = tv->nextOf()->toBasetype(); } if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->postblit) { Expression *ex; // this.v ex = new ThisExp(0); ex = new DotVarExp(0, ex, v, 0); if (dim == 1) { // this.v.dtor() ex = new DotVarExp(0, ex, sd->postblit, 0); ex = new CallExp(0, ex); } else { // Typeinfo.postblit(cast(void*)&this.v); Expression *ea = new AddrExp(0, ex); ea = new CastExp(0, ea, Type::tvoid->pointerTo()); Expression *et = v->type->getTypeInfo(sc); et = new DotIdExp(0, et, Id::postblit); ex = new CallExp(0, et, ea); } e = Expression::combine(e, ex); // combine in forward order } } } /* Build our own "postblit" which executes e */ if (e) { //printf("Building __fieldPostBlit()\n"); PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__fieldPostBlit")); dd->fbody = new ExpStatement(0, e); dtors.push(dd); members->push(dd); dd->semantic(sc); } switch (postblits.dim) { case 0: return NULL; case 1: return (FuncDeclaration *)postblits.data[0]; default: e = NULL; for (size_t i = 0; i < postblits.dim; i++) { FuncDeclaration *fd = (FuncDeclaration *)postblits.data[i]; Expression *ex = new ThisExp(0); ex = new DotVarExp(0, ex, fd, 0); ex = new CallExp(0, ex); e = Expression::combine(e, ex); } PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__aggrPostBlit")); dd->fbody = new ExpStatement(0, e); members->push(dd); dd->semantic(sc); return dd; } } #endif /***************************************** * 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 *AggregateDeclaration::buildDtor(Scope *sc) { //printf("AggregateDeclaration::buildDtor() %s\n", toChars()); Expression *e = NULL; #if DMDV2 for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = (Dsymbol *)fields.data[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); Type *tv = v->type->toBasetype(); size_t dim = 1; while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; dim *= ((TypeSArray *)tv)->dim->toInteger(); tv = tv->nextOf()->toBasetype(); } if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->dtor) { Expression *ex; // this.v ex = new ThisExp(0); ex = new DotVarExp(0, ex, v, 0); if (dim == 1) { // this.v.dtor() ex = new DotVarExp(0, ex, sd->dtor, 0); ex = new CallExp(0, ex); } else { // Typeinfo.destroy(cast(void*)&this.v); Expression *ea = new AddrExp(0, ex); ea = new CastExp(0, ea, Type::tvoid->pointerTo()); Expression *et = v->type->getTypeInfo(sc); et = new DotIdExp(0, et, Id::destroy); ex = new CallExp(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(0, 0, Lexer::idPool("__fieldDtor")); dd->fbody = new ExpStatement(0, e); dtors.shift(dd); members->push(dd); dd->semantic(sc); } #endif switch (dtors.dim) { case 0: return NULL; case 1: return (FuncDeclaration *)dtors.data[0]; default: e = NULL; for (size_t i = 0; i < dtors.dim; i++) { FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i]; Expression *ex = new ThisExp(0); ex = new DotVarExp(0, ex, fd, 0); ex = new CallExp(0, ex); e = Expression::combine(ex, e); } DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor")); dd->fbody = new ExpStatement(0, e); members->push(dd); dd->semantic(sc); return dd; } }