diff --git a/dmd2/declaration.c b/dmd2/declaration.c index 757e43bb..528f440c 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -1708,7 +1708,7 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) // The current function FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - if (fdv && fdthis && fdv != fdthis/* && fdthis->ident != Id::ensure*/) + if (fdv && fdthis && fdv != fdthis && fdthis->ident != Id::ensure && fdthis->ident != Id::require) { /* __ensure is always called directly, * so it never becomes closure. diff --git a/dmd2/declaration.h b/dmd2/declaration.h index ffeca869..c29af9ba 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -713,6 +713,9 @@ struct FuncDeclaration : Declaration FuncDeclaration *fdrequire; // function that does the in contract FuncDeclaration *fdensure; // function that does the out contract + Expressions *fdrequireParams; + Expressions *fdensureParams; + Identifier *outId; // identifier for out statement VarDeclaration *vresult; // variable corresponding to outId LabelDsymbol *returnLabel; // where the return goes @@ -832,8 +835,8 @@ struct FuncDeclaration : Declaration void toDocBuffer(OutBuffer *buf); FuncDeclaration *isUnique(); int needsClosure(); - Statement *mergeFrequire(Statement *); - Statement *mergeFensure(Statement *); + Statement *mergeFrequire(Statement *, Expressions *params = 0); + Statement *mergeFensure(Statement *, Expressions *params = 0); Parameters *getParameters(int *pvarargs); // LDC: give argument types to runtime functions diff --git a/dmd2/func.c b/dmd2/func.c index 1100a95d..2ea7121d 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -46,6 +46,8 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla frequire = NULL; fdrequire = NULL; fdensure = NULL; + fdrequireParams = NULL; + fdensureParams = NULL; outId = NULL; vresult = NULL; returnLabel = NULL; @@ -758,6 +760,9 @@ void FuncDeclaration::semantic(Scope *sc) if (isVirtual() && semanticRun != PASSsemanticdone) { + Parameters *arguments = ((TypeFunction*)type)->parameters; + fdrequireParams = new Expressions(); + /* Rewrite contracts as nested functions, then call them. * Doing it as nested functions means that overriding functions * can call them. @@ -769,12 +774,12 @@ void FuncDeclaration::semantic(Scope *sc) * __require(); */ Loc loc = frequire->loc; - TypeFunction *tf = new TypeFunction(NULL, Type::tvoid, 0, LINKd); + TypeFunction *tf = new TypeFunction(arguments->copy(), Type::tvoid, 0, LINKd); FuncDeclaration *fd = new FuncDeclaration(loc, loc, Id::require, STCundefined, tf); fd->fbody = frequire; Statement *s1 = new ExpStatement(loc, fd); - Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), (Expressions *)NULL); + Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), fdrequireParams); Statement *s2 = new ExpStatement(loc, e); frequire = new CompoundStatement(loc, s1, s2); fdrequire = fd; @@ -783,6 +788,13 @@ void FuncDeclaration::semantic(Scope *sc) if (!outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid) outId = Id::result; // provide a default + fdensureParams = new Expressions(); + Expression *eresult = NULL; + if (outId) { + eresult = new IdentifierExp(loc, outId); + fdensureParams->push(eresult); + } + if (fensure) { /* out (result) { ... } * becomes: @@ -790,21 +802,18 @@ void FuncDeclaration::semantic(Scope *sc) * __ensure(result); */ Loc loc = fensure->loc; - Parameters *arguments = new Parameters(); Parameter *a = NULL; + arguments = arguments->copy(); if (outId) { a = new Parameter(STCref | STCconst, f->nextOf(), outId, NULL); - arguments->push(a); + arguments->insert(0, a); } TypeFunction *tf = new TypeFunction(arguments, Type::tvoid, 0, LINKd); FuncDeclaration *fd = new FuncDeclaration(loc, loc, Id::ensure, STCundefined, tf); fd->fbody = fensure; Statement *s1 = new ExpStatement(loc, fd); - Expression *eresult = NULL; - if (outId) - eresult = new IdentifierExp(loc, outId); - Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), eresult); + Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), fdensureParams); Statement *s2 = new ExpStatement(loc, e); fensure = new CompoundStatement(loc, s1, s2); fdensure = fd; @@ -1098,6 +1107,10 @@ void FuncDeclaration::semantic3(Scope *sc) parameters->push(v); localsymtab->insert(v); v->parent = this; + if (fdrequireParams) + fdrequireParams->push(new VarExp(loc, v)); + if (fdensureParams) + fdensureParams->push(new VarExp(loc, v)); } } @@ -1935,8 +1948,11 @@ void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) * 'in's are OR'd together, i.e. only one of them needs to pass. */ -Statement *FuncDeclaration::mergeFrequire(Statement *sf) +Statement *FuncDeclaration::mergeFrequire(Statement *sf, Expressions *params) { + if (!params) + params = fdrequireParams; + /* Implementing this is done by having the overriding function call * nested functions (the fdrequire functions) nested inside the overridden * function. This requires that the stack layout of the calling function's @@ -1969,7 +1985,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf) sc->pop(); } - sf = fdv->mergeFrequire(sf); + sf = fdv->mergeFrequire(sf, params); if (sf && fdv->fdrequire) { //printf("fdv->frequire: %s\n", fdv->frequire->toChars()); @@ -1977,8 +1993,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf) * try { __require(); } * catch { frequire; } */ - Expression *eresult = NULL; - Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, 0), eresult); + Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, 0), params); Statement *s2 = new ExpStatement(loc, e); Catch *c = new Catch(loc, NULL, NULL, sf); @@ -1997,8 +2012,11 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf) * 'out's are AND'd together, i.e. all of them need to pass. */ -Statement *FuncDeclaration::mergeFensure(Statement *sf) +Statement *FuncDeclaration::mergeFensure(Statement *sf, Expressions *params) { + if (!params) + params = fdensureParams; + /* Same comments as for mergeFrequire(), except that we take care * of generating a consistent reference to the 'result' local by * explicitly passing 'result' to the nested function as a reference @@ -2024,15 +2042,12 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf) sc->pop(); } - sf = fdv->mergeFensure(sf); + sf = fdv->mergeFensure(sf, params); if (fdv->fdensure) { //printf("fdv->fensure: %s\n", fdv->fensure->toChars()); // Make the call: __ensure(result) - Expression *eresult = NULL; - if (outId) - eresult = new IdentifierExp(loc, outId); - Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure, 0), eresult); + Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure, 0), params); Statement *s2 = new ExpStatement(loc, e); if (sf) diff --git a/gen/functions.cpp b/gen/functions.cpp index a5024c69..fc17abeb 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -9,6 +9,7 @@ #include "template.h" #include "module.h" #include "statement.h" +#include "id.h" #include "gen/irstate.h" #include "gen/tollvm.h" @@ -252,6 +253,15 @@ llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl) Type *dthis=0, *dnest=0; +#if DMDV2 + if (fdecl->ident == Id::ensure || fdecl->ident == Id::require) { + FuncDeclaration *p = fdecl->parent->isFuncDeclaration(); + assert(p); + AggregateDeclaration *ad = p->isMember2(); + assert(ad); + dnest = Type::tvoid->pointerTo(); + } else +#endif if (fdecl->needThis()) { if (AggregateDeclaration* ad = fdecl->isMember2()) { Logger::println("isMember = this is: %s", ad->type->toChars()); diff --git a/gen/tocall.cpp b/gen/tocall.cpp index b6390e34..2fa85d6a 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -2,6 +2,7 @@ #include "mtype.h" #include "declaration.h" +#include "id.h" #include "gen/tollvm.h" #include "gen/llvmhelpers.h" @@ -388,6 +389,14 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // then comes a context argument... if(thiscall || delegatecall || nestedcall) { +#if DMDV2 + if (dfnval && (dfnval->func->ident == Id::ensure || dfnval->func->ident == Id::require)) { + LLValue* thisarg = DtoBitCast(DtoLoad(gIR->func()->thisArg), getVoidPtrType()); + ++argiter; + args.push_back(thisarg); + } + else +#endif // ... which can be a 'this' argument if (thiscall && dfnval && dfnval->vthis) { diff --git a/gen/toir.cpp b/gen/toir.cpp index bcc51f50..7ad69806 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1381,6 +1381,14 @@ DValue* ThisExp::toElem(IRState* p) if (VarDeclaration* vd = var->isVarDeclaration()) { LLValue* v; Dsymbol* vdparent = vd->toParent2(); +#if DMDV2 + Identifier *ident = p->func()->decl->ident; + if (ident == Id::ensure || ident == Id::require) { + Logger::println("contract this exp"); + v = p->func()->nestArg; + v = DtoBitCast(v, DtoType(type)->getPointerTo()); + } else +#endif if (vdparent != p->func()->decl) { Logger::println("nested this exp"); #if STRUCTTHISREF