Fixed crash in DtoCreateNestedContextType().

In some cases, like the following, DtoDeclareFunction() hasn't already been called when DtoCreateNestedContextType() is invoked. This seems to have been anticipated when the function was originally written, but DtoDeclareFunction() was previously called after the ir func was already accessed in fd->ir.irFunc->nestedContextCreated.

---
void main() {
  mixin({
    string foo() {
      return "";
    }

    string bar()() {
      return foo();
    }

    return bar();
  }());
}
---
This commit is contained in:
David Nadlinger
2011-07-28 23:17:20 +02:00
parent e397b29722
commit 618051022f
+38 -34
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());
} }
@@ -365,12 +365,15 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) {
Logger::println("DtoCreateNestedContextType for %s", fd->toChars()); Logger::println("DtoCreateNestedContextType for %s", fd->toChars());
LOG_SCOPE LOG_SCOPE
#if DMDV2
DtoDeclareFunction(fd);
#endif
if (fd->ir.irFunc->nestedContextCreated) if (fd->ir.irFunc->nestedContextCreated)
return; return;
fd->ir.irFunc->nestedContextCreated = true; fd->ir.irFunc->nestedContextCreated = true;
#if DMDV2 #if DMDV2
DtoDeclareFunction(fd);
if (fd->nestedVars.empty()) { if (fd->nestedVars.empty()) {
// fill nestedVars // fill nestedVars
size_t nnest = fd->closureVars.dim; size_t nnest = fd->closureVars.dim;
@@ -381,6 +384,7 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) {
} }
} }
#endif #endif
if (nestedCtx == NCHybrid) { if (nestedCtx == NCHybrid) {
// construct nested variables array // construct nested variables array
if (!fd->nestedVars.empty()) if (!fd->nestedVars.empty())
@@ -512,16 +516,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 +543,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 +588,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 +622,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());