mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-09-20 04:10:18 +02: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:
+38
-34
@@ -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());
|
||||||
|
|||||||
Reference in New Issue
Block a user