diff --git a/gen/nested.cpp b/gen/nested.cpp index 50009543..2199a2a0 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -50,6 +50,8 @@ static cl::opt nestedCtx("nested-ctx", ////////////////////////////////////////////////////////////////////////////////////////*/ static FuncDeclaration* getParentFunc(Dsymbol* sym) { + if (!sym) + return NULL; Dsymbol* parent = sym->parent; assert(parent); while (parent && !parent->isFuncDeclaration()) @@ -178,27 +180,54 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) LOG_SCOPE; IrFunction* irfunc = gIR->func(); + bool fromParent = true; + LLValue* val; // if this func has its own vars that are accessed by nested funcs // use its own context - if (irfunc->nestedVar) - return irfunc->nestedVar; + if (irfunc->nestedVar) { + val = irfunc->nestedVar; + fromParent = false; + } // otherwise, it may have gotten a context from the caller else if (irfunc->nestArg) - return irfunc->nestArg; + val = irfunc->nestArg; // or just have a this argument else if (irfunc->thisArg) { ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration(); if (!cd || !cd->vthis) return getNullPtr(getVoidPtrType()); - LLValue* val = DtoLoad(irfunc->thisArg); - return DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis")); + val = DtoLoad(irfunc->thisArg); + val = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis")); } else { return getNullPtr(getVoidPtrType()); } + if (nestedCtx == NCHybrid) { + // If sym is a nested function, and its parent elided the context list but the + // context we got didn't, we need to index to the first frame. + if (FuncDeclaration* fd = getParentFunc(sym->isFuncDeclaration())) { + Logger::println("For nested function, parent is %s", fd->toChars()); + FuncDeclaration* ctxfd = irfunc->decl; + Logger::println("Current function is %s", ctxfd->toChars()); + if (fromParent) { + ctxfd = getParentFunc(ctxfd); + assert(ctxfd && "Context from outer function, but no outer function?"); + } + Logger::println("Context is from %s", ctxfd->toChars()); + if (fd->ir.irFunc->elidedCtxList && !ctxfd->ir.irFunc->elidedCtxList) { + Logger::println("Adjusting to remove context frame list", ctxfd->toChars()); + val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->framesType)); + val = DtoGEPi(val, 0, 0); + val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); + } + } + } + Logger::cout() << "result = " << *val << '\n'; + Logger::cout() << "of type " << *val->getType() << '\n'; + return val; } void DtoCreateNestedContext(FuncDeclaration* fd) { diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 0a949352..a8efe2b9 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -452,6 +452,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* if (Logger::enabled()) { Logger::cout() << "arg: " << *arg << '\n'; + Logger::cout() << "of type: " << *arg->getType() << '\n'; Logger::cout() << "expects: " << *callableTy->getParamType(j) << '\n'; } #endif diff --git a/tests/mini/nested21.d b/tests/mini/nested21.d new file mode 100644 index 00000000..3a6c52b6 --- /dev/null +++ b/tests/mini/nested21.d @@ -0,0 +1,16 @@ +module nested21; + +extern(C) int printf(char*, ...); + +void main() { + int i = 42; + int foo() { return i; } + int bar() { + int j = 47; + int baz() { return j; } + return foo() + baz(); + } + auto result = bar(); + printf("%d\n", result); + assert(result == 42 + 47); +}