mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-10 04:45:56 +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
|
// The current function
|
||||||
FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
|
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,
|
/* __ensure is always called directly,
|
||||||
* so it never becomes closure.
|
* so it never becomes closure.
|
||||||
|
|
|
@ -713,6 +713,9 @@ struct FuncDeclaration : Declaration
|
||||||
FuncDeclaration *fdrequire; // function that does the in contract
|
FuncDeclaration *fdrequire; // function that does the in contract
|
||||||
FuncDeclaration *fdensure; // function that does the out contract
|
FuncDeclaration *fdensure; // function that does the out contract
|
||||||
|
|
||||||
|
Expressions *fdrequireParams;
|
||||||
|
Expressions *fdensureParams;
|
||||||
|
|
||||||
Identifier *outId; // identifier for out statement
|
Identifier *outId; // identifier for out statement
|
||||||
VarDeclaration *vresult; // variable corresponding to outId
|
VarDeclaration *vresult; // variable corresponding to outId
|
||||||
LabelDsymbol *returnLabel; // where the return goes
|
LabelDsymbol *returnLabel; // where the return goes
|
||||||
|
@ -832,8 +835,8 @@ struct FuncDeclaration : Declaration
|
||||||
void toDocBuffer(OutBuffer *buf);
|
void toDocBuffer(OutBuffer *buf);
|
||||||
FuncDeclaration *isUnique();
|
FuncDeclaration *isUnique();
|
||||||
int needsClosure();
|
int needsClosure();
|
||||||
Statement *mergeFrequire(Statement *);
|
Statement *mergeFrequire(Statement *, Expressions *params = 0);
|
||||||
Statement *mergeFensure(Statement *);
|
Statement *mergeFensure(Statement *, Expressions *params = 0);
|
||||||
Parameters *getParameters(int *pvarargs);
|
Parameters *getParameters(int *pvarargs);
|
||||||
|
|
||||||
// LDC: give argument types to runtime functions
|
// 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;
|
frequire = NULL;
|
||||||
fdrequire = NULL;
|
fdrequire = NULL;
|
||||||
fdensure = NULL;
|
fdensure = NULL;
|
||||||
|
fdrequireParams = NULL;
|
||||||
|
fdensureParams = NULL;
|
||||||
outId = NULL;
|
outId = NULL;
|
||||||
vresult = NULL;
|
vresult = NULL;
|
||||||
returnLabel = NULL;
|
returnLabel = NULL;
|
||||||
|
@ -758,6 +760,9 @@ void FuncDeclaration::semantic(Scope *sc)
|
||||||
|
|
||||||
if (isVirtual() && semanticRun != PASSsemanticdone)
|
if (isVirtual() && semanticRun != PASSsemanticdone)
|
||||||
{
|
{
|
||||||
|
Parameters *arguments = ((TypeFunction*)type)->parameters;
|
||||||
|
fdrequireParams = new Expressions();
|
||||||
|
|
||||||
/* Rewrite contracts as nested functions, then call them.
|
/* Rewrite contracts as nested functions, then call them.
|
||||||
* Doing it as nested functions means that overriding functions
|
* Doing it as nested functions means that overriding functions
|
||||||
* can call them.
|
* can call them.
|
||||||
|
@ -769,12 +774,12 @@ void FuncDeclaration::semantic(Scope *sc)
|
||||||
* __require();
|
* __require();
|
||||||
*/
|
*/
|
||||||
Loc loc = frequire->loc;
|
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,
|
FuncDeclaration *fd = new FuncDeclaration(loc, loc,
|
||||||
Id::require, STCundefined, tf);
|
Id::require, STCundefined, tf);
|
||||||
fd->fbody = frequire;
|
fd->fbody = frequire;
|
||||||
Statement *s1 = new ExpStatement(loc, fd);
|
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);
|
Statement *s2 = new ExpStatement(loc, e);
|
||||||
frequire = new CompoundStatement(loc, s1, s2);
|
frequire = new CompoundStatement(loc, s1, s2);
|
||||||
fdrequire = fd;
|
fdrequire = fd;
|
||||||
|
@ -783,6 +788,13 @@ void FuncDeclaration::semantic(Scope *sc)
|
||||||
if (!outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid)
|
if (!outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid)
|
||||||
outId = Id::result; // provide a default
|
outId = Id::result; // provide a default
|
||||||
|
|
||||||
|
fdensureParams = new Expressions();
|
||||||
|
Expression *eresult = NULL;
|
||||||
|
if (outId) {
|
||||||
|
eresult = new IdentifierExp(loc, outId);
|
||||||
|
fdensureParams->push(eresult);
|
||||||
|
}
|
||||||
|
|
||||||
if (fensure)
|
if (fensure)
|
||||||
{ /* out (result) { ... }
|
{ /* out (result) { ... }
|
||||||
* becomes:
|
* becomes:
|
||||||
|
@ -790,21 +802,18 @@ void FuncDeclaration::semantic(Scope *sc)
|
||||||
* __ensure(result);
|
* __ensure(result);
|
||||||
*/
|
*/
|
||||||
Loc loc = fensure->loc;
|
Loc loc = fensure->loc;
|
||||||
Parameters *arguments = new Parameters();
|
|
||||||
Parameter *a = NULL;
|
Parameter *a = NULL;
|
||||||
|
arguments = arguments->copy();
|
||||||
if (outId)
|
if (outId)
|
||||||
{ a = new Parameter(STCref | STCconst, f->nextOf(), outId, NULL);
|
{ 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);
|
TypeFunction *tf = new TypeFunction(arguments, Type::tvoid, 0, LINKd);
|
||||||
FuncDeclaration *fd = new FuncDeclaration(loc, loc,
|
FuncDeclaration *fd = new FuncDeclaration(loc, loc,
|
||||||
Id::ensure, STCundefined, tf);
|
Id::ensure, STCundefined, tf);
|
||||||
fd->fbody = fensure;
|
fd->fbody = fensure;
|
||||||
Statement *s1 = new ExpStatement(loc, fd);
|
Statement *s1 = new ExpStatement(loc, fd);
|
||||||
Expression *eresult = NULL;
|
Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), fdensureParams);
|
||||||
if (outId)
|
|
||||||
eresult = new IdentifierExp(loc, outId);
|
|
||||||
Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), eresult);
|
|
||||||
Statement *s2 = new ExpStatement(loc, e);
|
Statement *s2 = new ExpStatement(loc, e);
|
||||||
fensure = new CompoundStatement(loc, s1, s2);
|
fensure = new CompoundStatement(loc, s1, s2);
|
||||||
fdensure = fd;
|
fdensure = fd;
|
||||||
|
@ -1098,6 +1107,10 @@ void FuncDeclaration::semantic3(Scope *sc)
|
||||||
parameters->push(v);
|
parameters->push(v);
|
||||||
localsymtab->insert(v);
|
localsymtab->insert(v);
|
||||||
v->parent = this;
|
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.
|
* '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
|
/* Implementing this is done by having the overriding function call
|
||||||
* nested functions (the fdrequire functions) nested inside the overridden
|
* nested functions (the fdrequire functions) nested inside the overridden
|
||||||
* function. This requires that the stack layout of the calling function's
|
* function. This requires that the stack layout of the calling function's
|
||||||
|
@ -1969,7 +1985,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf)
|
||||||
sc->pop();
|
sc->pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
sf = fdv->mergeFrequire(sf);
|
sf = fdv->mergeFrequire(sf, params);
|
||||||
if (sf && fdv->fdrequire)
|
if (sf && fdv->fdrequire)
|
||||||
{
|
{
|
||||||
//printf("fdv->frequire: %s\n", fdv->frequire->toChars());
|
//printf("fdv->frequire: %s\n", fdv->frequire->toChars());
|
||||||
|
@ -1977,8 +1993,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf)
|
||||||
* try { __require(); }
|
* try { __require(); }
|
||||||
* catch { frequire; }
|
* catch { frequire; }
|
||||||
*/
|
*/
|
||||||
Expression *eresult = NULL;
|
Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, 0), params);
|
||||||
Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, 0), eresult);
|
|
||||||
Statement *s2 = new ExpStatement(loc, e);
|
Statement *s2 = new ExpStatement(loc, e);
|
||||||
|
|
||||||
Catch *c = new Catch(loc, NULL, NULL, sf);
|
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.
|
* '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
|
/* Same comments as for mergeFrequire(), except that we take care
|
||||||
* of generating a consistent reference to the 'result' local by
|
* of generating a consistent reference to the 'result' local by
|
||||||
* explicitly passing 'result' to the nested function as a reference
|
* explicitly passing 'result' to the nested function as a reference
|
||||||
|
@ -2024,15 +2042,12 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf)
|
||||||
sc->pop();
|
sc->pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
sf = fdv->mergeFensure(sf);
|
sf = fdv->mergeFensure(sf, params);
|
||||||
if (fdv->fdensure)
|
if (fdv->fdensure)
|
||||||
{
|
{
|
||||||
//printf("fdv->fensure: %s\n", fdv->fensure->toChars());
|
//printf("fdv->fensure: %s\n", fdv->fensure->toChars());
|
||||||
// Make the call: __ensure(result)
|
// Make the call: __ensure(result)
|
||||||
Expression *eresult = NULL;
|
Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure, 0), params);
|
||||||
if (outId)
|
|
||||||
eresult = new IdentifierExp(loc, outId);
|
|
||||||
Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure, 0), eresult);
|
|
||||||
Statement *s2 = new ExpStatement(loc, e);
|
Statement *s2 = new ExpStatement(loc, e);
|
||||||
|
|
||||||
if (sf)
|
if (sf)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "statement.h"
|
#include "statement.h"
|
||||||
|
#include "id.h"
|
||||||
|
|
||||||
#include "gen/irstate.h"
|
#include "gen/irstate.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
|
@ -252,6 +253,15 @@ llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl)
|
||||||
|
|
||||||
Type *dthis=0, *dnest=0;
|
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 (fdecl->needThis()) {
|
||||||
if (AggregateDeclaration* ad = fdecl->isMember2()) {
|
if (AggregateDeclaration* ad = fdecl->isMember2()) {
|
||||||
Logger::println("isMember = this is: %s", ad->type->toChars());
|
Logger::println("isMember = this is: %s", ad->type->toChars());
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "mtype.h"
|
#include "mtype.h"
|
||||||
#include "declaration.h"
|
#include "declaration.h"
|
||||||
|
#include "id.h"
|
||||||
|
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "gen/llvmhelpers.h"
|
#include "gen/llvmhelpers.h"
|
||||||
|
@ -388,6 +389,14 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||||
// then comes a context argument...
|
// then comes a context argument...
|
||||||
if(thiscall || delegatecall || nestedcall)
|
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
|
// ... which can be a 'this' argument
|
||||||
if (thiscall && dfnval && dfnval->vthis)
|
if (thiscall && dfnval && dfnval->vthis)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1381,6 +1381,14 @@ DValue* ThisExp::toElem(IRState* p)
|
||||||
if (VarDeclaration* vd = var->isVarDeclaration()) {
|
if (VarDeclaration* vd = var->isVarDeclaration()) {
|
||||||
LLValue* v;
|
LLValue* v;
|
||||||
Dsymbol* vdparent = vd->toParent2();
|
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) {
|
if (vdparent != p->func()->decl) {
|
||||||
Logger::println("nested this exp");
|
Logger::println("nested this exp");
|
||||||
#if STRUCTTHISREF
|
#if STRUCTTHISREF
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue