mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-07 03:16:05 +03:00
DMD Issue 6859 - Segfault when abstract method uses with contract.
This commit is contained in:
parent
edc4a5f003
commit
b41688a0b8
6 changed files with 66 additions and 21 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
51
dmd2/func.c
51
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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue