Another nested context crash fix.

The test case that would previously crash:

a.d
---
module a;

@property bool empty(T)(in T[] a) {
  return !a.length;
}

void find(alias pred,R1)(R1 haystack) {
  simpleMindedFind!pred(haystack);
}

void simpleMindedFind(alias pred, R1)(R1 haystack) {
  bool haystackTooShort() {
    return haystack.empty;
  }
}
---

b.d
---
module b;

import c;

void getTimeZone() {
  indexOf();
}
---

c.d
---
module c;

import a;

void indexOf()() {
  find!({})("");
}
---
This commit is contained in:
David Nadlinger 2011-08-17 02:31:46 +02:00
parent 11f19eec5a
commit 3f448afa37

View file

@ -16,7 +16,7 @@ enum NestedCtxType {
/// Context is void*[] of pointers to variables. /// Context is void*[] of pointers to variables.
/// Variables from higher levels are at the front. /// Variables from higher levels are at the front.
NCArray, NCArray,
/// Context is a struct containing variables belonging to the parent function. /// Context is a struct containing variables belonging to the parent function.
/// If the parent function itself has a parent function, one of the members is /// If the parent function itself has a parent function, one of the members is
/// a pointer to its context. (linked-list style) /// a pointer to its context. (linked-list style)
@ -26,7 +26,7 @@ enum NestedCtxType {
// context. // context.
// NOTE: This is what DMD seems to do. // NOTE: This is what DMD seems to do.
NCStruct, NCStruct,
/// Context is a list of pointers to structs of variables, followed by the /// Context is a list of pointers to structs of variables, followed by the
/// variables of the inner-most function with variables accessed by nested /// variables of the inner-most function with variables accessed by nested
/// functions. The initial pointers point to similar structs for enclosing /// functions. The initial pointers point to similar structs for enclosing
@ -65,7 +65,7 @@ static FuncDeclaration* getParentFunc(Dsymbol* sym, bool stopOnStatic) {
} }
parent = parent->parent; parent = parent->parent;
} }
return (parent ? parent->isFuncDeclaration() : NULL); return (parent ? parent->isFuncDeclaration() : NULL);
} }
@ -93,13 +93,13 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
{ {
Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars()); Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars());
LOG_SCOPE; LOG_SCOPE;
//////////////////////////////////// ////////////////////////////////////
// Locate context value // Locate context value
Dsymbol* vdparent = vd->toParent2(); Dsymbol* vdparent = vd->toParent2();
assert(vdparent); assert(vdparent);
IrFunction* irfunc = gIR->func(); IrFunction* irfunc = gIR->func();
// Check whether we can access the needed frame // Check whether we can access the needed frame
@ -112,14 +112,14 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
fd = getParentFunc(fd, false); fd = getParentFunc(fd, false);
assert(fd); assert(fd);
} }
// is the nested variable in this scope? // is the nested variable in this scope?
if (vdparent == irfunc->decl) if (vdparent == irfunc->decl)
{ {
LLValue* val = vd->ir.getIrValue(); LLValue* val = vd->ir.getIrValue();
return new DVarValue(astype, vd, val); return new DVarValue(astype, vd, val);
} }
// get the nested context // get the nested context
LLValue* ctx = 0; LLValue* ctx = 0;
if (irfunc->decl->isMember2()) if (irfunc->decl->isMember2())
@ -140,13 +140,13 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
else else
ctx = irfunc->nestArg; ctx = irfunc->nestArg;
assert(ctx); assert(ctx);
DtoCreateNestedContextType(vdparent->isFuncDeclaration()); DtoCreateNestedContextType(vdparent->isFuncDeclaration());
assert(vd->ir.irLocal); assert(vd->ir.irLocal);
//////////////////////////////////// ////////////////////////////////////
// Extract variable from nested context // Extract variable from nested context
if (nestedCtx == NCArray) { if (nestedCtx == NCArray) {
LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType())); LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType()));
val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex); val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex);
@ -159,15 +159,15 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType));
Logger::cout() << "Context: " << *val << '\n'; Logger::cout() << "Context: " << *val << '\n';
Logger::cout() << "of type: " << *val->getType() << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n';
unsigned vardepth = vd->ir.irLocal->nestedDepth; unsigned vardepth = vd->ir.irLocal->nestedDepth;
unsigned funcdepth = irfunc->depth; unsigned funcdepth = irfunc->depth;
Logger::cout() << "Variable: " << vd->toChars() << '\n'; Logger::cout() << "Variable: " << vd->toChars() << '\n';
Logger::cout() << "Variable depth: " << vardepth << '\n'; Logger::cout() << "Variable depth: " << vardepth << '\n';
Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n';
Logger::cout() << "Function depth: " << funcdepth << '\n'; Logger::cout() << "Function depth: " << funcdepth << '\n';
if (vardepth == funcdepth) { if (vardepth == funcdepth) {
// This is not always handled above because functions without // This is not always handled above because functions without
// variables accessed by nested functions don't create new frames. // variables accessed by nested functions don't create new frames.
@ -188,7 +188,7 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
Logger::cout() << "Was byref, now: " << *val << '\n'; Logger::cout() << "Was byref, now: " << *val << '\n';
Logger::cout() << "of type: " << *val->getType() << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n';
} }
return new DVarValue(astype, vd, val); return new DVarValue(astype, vd, val);
} }
else { else {
@ -200,30 +200,30 @@ void DtoNestedInit(VarDeclaration* vd)
{ {
Logger::println("DtoNestedInit for %s", vd->toChars()); Logger::println("DtoNestedInit for %s", vd->toChars());
LOG_SCOPE LOG_SCOPE
IrFunction* irfunc = gIR->func()->decl->ir.irFunc; IrFunction* irfunc = gIR->func()->decl->ir.irFunc;
LLValue* nestedVar = irfunc->nestedVar; LLValue* nestedVar = irfunc->nestedVar;
if (nestedCtx == NCArray) { if (nestedCtx == NCArray) {
// alloca as usual if no value already // alloca as usual if no value already
if (!vd->ir.irLocal->value) if (!vd->ir.irLocal->value)
vd->ir.irLocal->value = DtoAlloca(vd->type, vd->toChars()); vd->ir.irLocal->value = DtoAlloca(vd->type, vd->toChars());
// store the address into the nested vars array // store the address into the nested vars array
assert(vd->ir.irLocal->nestedIndex >= 0); assert(vd->ir.irLocal->nestedIndex >= 0);
LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex); LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex);
assert(isaPointer(vd->ir.irLocal->value)); assert(isaPointer(vd->ir.irLocal->value));
LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
DtoAlignedStore(val, gep); DtoAlignedStore(val, gep);
} }
else if (nestedCtx == NCHybrid) { else if (nestedCtx == NCHybrid) {
assert(vd->ir.irLocal->value && "Nested variable without storage?"); assert(vd->ir.irLocal->value && "Nested variable without storage?");
if (!vd->isParameter() && (vd->isRef() || vd->isOut())) { if (!vd->isParameter() && (vd->isRef() || vd->isOut())) {
unsigned vardepth = vd->ir.irLocal->nestedDepth; unsigned vardepth = vd->ir.irLocal->nestedDepth;
LLValue* val = NULL; LLValue* val = NULL;
// Retrieve frame pointer // Retrieve frame pointer
if (vardepth == irfunc->depth) { if (vardepth == irfunc->depth) {
@ -231,7 +231,7 @@ void DtoNestedInit(VarDeclaration* vd)
} else { } else {
FuncDeclaration *parentfunc = getParentFunc(vd, true); FuncDeclaration *parentfunc = getParentFunc(vd, true);
assert(parentfunc && "No parent function for nested variable?"); assert(parentfunc && "No parent function for nested variable?");
val = DtoGEPi(nestedVar, 0, vardepth); val = DtoGEPi(nestedVar, 0, vardepth);
val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str()); val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str());
} }
@ -392,6 +392,9 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) {
unsigned depth = -1; unsigned depth = -1;
if (!fd->isStatic()) { if (!fd->isStatic()) {
if (FuncDeclaration* parfd = getParentFunc(fd, true)) { if (FuncDeclaration* parfd = getParentFunc(fd, true)) {
// Make sure parfd->ir.irFunc has already been set.
DtoDeclareFunction(parfd);
innerFrameType = parfd->ir.irFunc->frameType; innerFrameType = parfd->ir.irFunc->frameType;
if (innerFrameType) if (innerFrameType)
depth = parfd->ir.irFunc->depth; depth = parfd->ir.irFunc->depth;
@ -512,16 +515,16 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
} }
} }
int nelems = fd->nestedVars.size() + nparelems; int nelems = fd->nestedVars.size() + nparelems;
// make array type for nested vars // make array type for nested vars
const LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems); const LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems);
// alloca it // alloca it
// FIXME align ? // FIXME align ?
LLValue* nestedVars = DtoRawAlloca(nestedVarsTy, 0, ".nested_vars"); LLValue* nestedVars = DtoRawAlloca(nestedVarsTy, 0, ".nested_vars");
IrFunction* irfunction = fd->ir.irFunc; IrFunction* irfunction = fd->ir.irFunc;
// copy parent frame into beginning // copy parent frame into beginning
if (nparelems) if (nparelems)
{ {
@ -539,10 +542,10 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE), DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE),
getABITypeAlign(getVoidPtrType())); getABITypeAlign(getVoidPtrType()));
} }
// store in IrFunction // store in IrFunction
irfunction->nestedVar = nestedVars; irfunction->nestedVar = nestedVars;
// go through all nested vars and assign indices // go through all nested vars and assign indices
int idx = nparelems; int idx = nparelems;
for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
@ -584,7 +587,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
#endif #endif
frame = DtoRawAlloca(frameType, 0, ".frame"); frame = DtoRawAlloca(frameType, 0, ".frame");
// copy parent frames into beginning // copy parent frames into beginning
if (depth != 0) { if (depth != 0) {
LLValue* src = irfunction->nestArg; LLValue* src = irfunction->nestArg;
@ -618,15 +621,15 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
LLValue* gep = DtoGEPi(frame, 0, depth-1); LLValue* gep = DtoGEPi(frame, 0, depth-1);
DtoAlignedStore(src, gep); DtoAlignedStore(src, gep);
} }
// store context in IrFunction // store context in IrFunction
irfunction->nestedVar = frame; irfunction->nestedVar = frame;
// go through all nested vars and assign addresses where possible. // go through all nested vars and assign addresses where possible.
for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
{ {
VarDeclaration* vd = *i; VarDeclaration* vd = *i;
LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
if (vd->isParameter()) { if (vd->isParameter()) {
Logger::println("nested param: %s", vd->toChars()); Logger::println("nested param: %s", vd->toChars());