mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-12 10:53:14 +01:00
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:
@@ -16,7 +16,7 @@ enum NestedCtxType {
|
||||
/// Context is void*[] of pointers to variables.
|
||||
/// Variables from higher levels are at the front.
|
||||
NCArray,
|
||||
|
||||
|
||||
/// 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
|
||||
/// a pointer to its context. (linked-list style)
|
||||
@@ -26,7 +26,7 @@ enum NestedCtxType {
|
||||
// context.
|
||||
// NOTE: This is what DMD seems to do.
|
||||
NCStruct,
|
||||
|
||||
|
||||
/// Context is a list of pointers to structs of variables, followed by the
|
||||
/// variables of the inner-most function with variables accessed by nested
|
||||
/// functions. The initial pointers point to similar structs for enclosing
|
||||
@@ -65,7 +65,7 @@ static FuncDeclaration* getParentFunc(Dsymbol* sym, bool stopOnStatic) {
|
||||
}
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
LOG_SCOPE;
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
// Locate context value
|
||||
|
||||
|
||||
Dsymbol* vdparent = vd->toParent2();
|
||||
assert(vdparent);
|
||||
|
||||
|
||||
IrFunction* irfunc = gIR->func();
|
||||
|
||||
// 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);
|
||||
assert(fd);
|
||||
}
|
||||
|
||||
|
||||
// is the nested variable in this scope?
|
||||
if (vdparent == irfunc->decl)
|
||||
{
|
||||
LLValue* val = vd->ir.getIrValue();
|
||||
return new DVarValue(astype, vd, val);
|
||||
}
|
||||
|
||||
|
||||
// get the nested context
|
||||
LLValue* ctx = 0;
|
||||
if (irfunc->decl->isMember2())
|
||||
@@ -140,13 +140,13 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
|
||||
else
|
||||
ctx = irfunc->nestArg;
|
||||
assert(ctx);
|
||||
|
||||
|
||||
DtoCreateNestedContextType(vdparent->isFuncDeclaration());
|
||||
assert(vd->ir.irLocal);
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
// Extract variable from nested context
|
||||
|
||||
|
||||
if (nestedCtx == NCArray) {
|
||||
LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType()));
|
||||
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));
|
||||
Logger::cout() << "Context: " << *val << '\n';
|
||||
Logger::cout() << "of type: " << *val->getType() << '\n';
|
||||
|
||||
|
||||
unsigned vardepth = vd->ir.irLocal->nestedDepth;
|
||||
unsigned funcdepth = irfunc->depth;
|
||||
|
||||
|
||||
Logger::cout() << "Variable: " << vd->toChars() << '\n';
|
||||
Logger::cout() << "Variable depth: " << vardepth << '\n';
|
||||
Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n';
|
||||
Logger::cout() << "Function depth: " << funcdepth << '\n';
|
||||
|
||||
|
||||
if (vardepth == funcdepth) {
|
||||
// This is not always handled above because functions without
|
||||
// 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() << "of type: " << *val->getType() << '\n';
|
||||
}
|
||||
|
||||
|
||||
return new DVarValue(astype, vd, val);
|
||||
}
|
||||
else {
|
||||
@@ -200,30 +200,30 @@ void DtoNestedInit(VarDeclaration* vd)
|
||||
{
|
||||
Logger::println("DtoNestedInit for %s", vd->toChars());
|
||||
LOG_SCOPE
|
||||
|
||||
|
||||
IrFunction* irfunc = gIR->func()->decl->ir.irFunc;
|
||||
LLValue* nestedVar = irfunc->nestedVar;
|
||||
|
||||
|
||||
if (nestedCtx == NCArray) {
|
||||
// alloca as usual if no value already
|
||||
if (!vd->ir.irLocal->value)
|
||||
vd->ir.irLocal->value = DtoAlloca(vd->type, vd->toChars());
|
||||
|
||||
|
||||
// store the address into the nested vars array
|
||||
assert(vd->ir.irLocal->nestedIndex >= 0);
|
||||
LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex);
|
||||
|
||||
|
||||
assert(isaPointer(vd->ir.irLocal->value));
|
||||
LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
|
||||
|
||||
|
||||
DtoAlignedStore(val, gep);
|
||||
}
|
||||
else if (nestedCtx == NCHybrid) {
|
||||
assert(vd->ir.irLocal->value && "Nested variable without storage?");
|
||||
|
||||
|
||||
if (!vd->isParameter() && (vd->isRef() || vd->isOut())) {
|
||||
unsigned vardepth = vd->ir.irLocal->nestedDepth;
|
||||
|
||||
|
||||
LLValue* val = NULL;
|
||||
// Retrieve frame pointer
|
||||
if (vardepth == irfunc->depth) {
|
||||
@@ -231,7 +231,7 @@ void DtoNestedInit(VarDeclaration* vd)
|
||||
} else {
|
||||
FuncDeclaration *parentfunc = getParentFunc(vd, true);
|
||||
assert(parentfunc && "No parent function for nested variable?");
|
||||
|
||||
|
||||
val = DtoGEPi(nestedVar, 0, vardepth);
|
||||
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());
|
||||
LOG_SCOPE
|
||||
|
||||
#if DMDV2
|
||||
DtoDeclareFunction(fd);
|
||||
#endif
|
||||
|
||||
if (fd->ir.irFunc->nestedContextCreated)
|
||||
return;
|
||||
fd->ir.irFunc->nestedContextCreated = true;
|
||||
|
||||
#if DMDV2
|
||||
DtoDeclareFunction(fd);
|
||||
if (fd->nestedVars.empty()) {
|
||||
// fill nestedVars
|
||||
size_t nnest = fd->closureVars.dim;
|
||||
@@ -381,6 +384,7 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nestedCtx == NCHybrid) {
|
||||
// construct nested variables array
|
||||
if (!fd->nestedVars.empty())
|
||||
@@ -512,16 +516,16 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||
}
|
||||
}
|
||||
int nelems = fd->nestedVars.size() + nparelems;
|
||||
|
||||
|
||||
// make array type for nested vars
|
||||
const LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems);
|
||||
|
||||
|
||||
// alloca it
|
||||
// FIXME align ?
|
||||
LLValue* nestedVars = DtoRawAlloca(nestedVarsTy, 0, ".nested_vars");
|
||||
|
||||
|
||||
IrFunction* irfunction = fd->ir.irFunc;
|
||||
|
||||
|
||||
// copy parent frame into beginning
|
||||
if (nparelems)
|
||||
{
|
||||
@@ -539,10 +543,10 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||
DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE),
|
||||
getABITypeAlign(getVoidPtrType()));
|
||||
}
|
||||
|
||||
|
||||
// store in IrFunction
|
||||
irfunction->nestedVar = nestedVars;
|
||||
|
||||
|
||||
// go through all nested vars and assign indices
|
||||
int idx = nparelems;
|
||||
for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
|
||||
@@ -584,7 +588,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||
#endif
|
||||
frame = DtoRawAlloca(frameType, 0, ".frame");
|
||||
|
||||
|
||||
|
||||
// copy parent frames into beginning
|
||||
if (depth != 0) {
|
||||
LLValue* src = irfunction->nestArg;
|
||||
@@ -618,15 +622,15 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||
LLValue* gep = DtoGEPi(frame, 0, depth-1);
|
||||
DtoAlignedStore(src, gep);
|
||||
}
|
||||
|
||||
|
||||
// store context in IrFunction
|
||||
irfunction->nestedVar = frame;
|
||||
|
||||
|
||||
// go through all nested vars and assign addresses where possible.
|
||||
for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
|
||||
{
|
||||
VarDeclaration* vd = *i;
|
||||
|
||||
|
||||
LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
|
||||
if (vd->isParameter()) {
|
||||
Logger::println("nested param: %s", vd->toChars());
|
||||
|
||||
Reference in New Issue
Block a user