mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 07:30:43 +03:00
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:
parent
11f19eec5a
commit
3f448afa37
1 changed files with 36 additions and 33 deletions
|
@ -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());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue