Fix check if nested function can access outer function frame

The previous check wouldn't check intermediate aggregates for static-ness,
that was one problem. The other was the assertion that the outer function
can be reached as long as there are no static functions inbetween, which
isn't always the case, as issue #1864 clearly shows, which is resolved by
this.
This commit is contained in:
Martin 2016-11-18 00:00:37 +01:00
parent 734398a225
commit 0de021fe32
5 changed files with 31 additions and 37 deletions

View file

@ -852,7 +852,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
// data from the template function itself, but it would still mess up our // data from the template function itself, but it would still mess up our
// nested context creation code. // nested context creation code.
FuncDeclaration *parent = fd; FuncDeclaration *parent = fd;
while ((parent = getParentFunc(parent, true))) { while ((parent = getParentFunc(parent))) {
if (parent->semanticRun != PASSsemantic3done || parent->semantic3Errors) { if (parent->semanticRun != PASSsemantic3done || parent->semantic3Errors) {
IF_LOG Logger::println( IF_LOG Logger::println(
"Ignoring nested function with unanalyzed parent."); "Ignoring nested function with unanalyzed parent.");

View file

@ -1733,29 +1733,26 @@ llvm::GlobalVariable *getOrCreateGlobal(const Loc &loc, llvm::Module &module,
nullptr, tlsModel); nullptr, tlsModel);
} }
FuncDeclaration *getParentFunc(Dsymbol *sym, bool stopOnStatic) { FuncDeclaration *getParentFunc(Dsymbol *sym) {
if (!sym) { if (!sym) {
return nullptr; return nullptr;
} }
// check if symbol is itself a static function/aggregate // Static functions and function (not delegate) literals don't allow
if (stopOnStatic) { // access to a parent context, even if they are nested.
// Static functions and function (not delegate) literals don't allow if (FuncDeclaration *fd = sym->isFuncDeclaration()) {
// access to a parent context, even if they are nested. bool certainlyNewRoot =
if (FuncDeclaration *fd = sym->isFuncDeclaration()) { fd->isStatic() ||
bool certainlyNewRoot = (fd->isFuncLiteralDeclaration() &&
fd->isStatic() || static_cast<FuncLiteralDeclaration *>(fd)->tok == TOKfunction);
(fd->isFuncLiteralDeclaration() && if (certainlyNewRoot) {
static_cast<FuncLiteralDeclaration *>(fd)->tok == TOKfunction); return nullptr;
if (certainlyNewRoot) {
return nullptr;
}
} }
// Fun fact: AggregateDeclarations are not Declarations. }
else if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) { // Fun fact: AggregateDeclarations are not Declarations.
if (!ad->isNested()) { else if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) {
return nullptr; if (!ad->isNested()) {
} return nullptr;
} }
} }
@ -1764,11 +1761,9 @@ FuncDeclaration *getParentFunc(Dsymbol *sym, bool stopOnStatic) {
return fd; return fd;
} }
if (stopOnStatic) { if (AggregateDeclaration *ad = parent->isAggregateDeclaration()) {
if (AggregateDeclaration *ad = parent->isAggregateDeclaration()) { if (!ad->isNested()) {
if (!ad->isNested()) { return nullptr;
return nullptr;
}
} }
} }
} }

View file

@ -260,7 +260,7 @@ llvm::GlobalVariable *getOrCreateGlobal(const Loc &loc, llvm::Module &module,
llvm::StringRef name, llvm::StringRef name,
bool isThreadLocal = false); bool isThreadLocal = false);
FuncDeclaration *getParentFunc(Dsymbol *sym, bool stopOnStatic); FuncDeclaration *getParentFunc(Dsymbol *sym);
void Declaration_codegen(Dsymbol *decl); void Declaration_codegen(Dsymbol *decl);
void Declaration_codegen(Dsymbol *decl, IRState *irs); void Declaration_codegen(Dsymbol *decl, IRState *irs);

View file

@ -42,14 +42,13 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
// Check whether we can access the needed frame // Check whether we can access the needed frame
FuncDeclaration *fd = irfunc->decl; FuncDeclaration *fd = irfunc->decl;
while (fd != vdparent) { while (fd && fd != vdparent) {
if (fd->isStatic()) { fd = getParentFunc(fd);
error(loc, "function %s cannot access frame of function %s", }
irfunc->decl->toPrettyChars(), vdparent->toPrettyChars()); if (!fd) {
return new DLValue(astype, llvm::UndefValue::get(DtoPtrToType(astype))); error(loc, "function %s cannot access frame of function %s",
} irfunc->decl->toPrettyChars(), vdparent->toPrettyChars());
fd = getParentFunc(fd, false); return new DLValue(astype, llvm::UndefValue::get(DtoPtrToType(astype)));
assert(fd);
} }
// is the nested variable in this scope? // is the nested variable in this scope?
@ -261,7 +260,7 @@ LLValue *DtoNestedContext(Loc &loc, Dsymbol *sym) {
} else if (FuncDeclaration *symfd = sym->isFuncDeclaration()) { } else if (FuncDeclaration *symfd = sym->isFuncDeclaration()) {
// If sym is a nested function, and its parent context is different // If sym is a nested function, and its parent context is different
// than the one we got, adjust it. // than the one we got, adjust it.
frameToPass = getParentFunc(symfd, true); frameToPass = getParentFunc(symfd);
} }
if (frameToPass) { if (frameToPass) {
@ -269,7 +268,7 @@ LLValue *DtoNestedContext(Loc &loc, Dsymbol *sym) {
FuncDeclaration *ctxfd = irFunc.decl; FuncDeclaration *ctxfd = irFunc.decl;
IF_LOG Logger::println("Current function is %s", ctxfd->toChars()); IF_LOG Logger::println("Current function is %s", ctxfd->toChars());
if (fromParent) { if (fromParent) {
ctxfd = getParentFunc(ctxfd, true); ctxfd = getParentFunc(ctxfd);
assert(ctxfd && "Context from outer function, but no outer function?"); assert(ctxfd && "Context from outer function, but no outer function?");
} }
IF_LOG Logger::println("Context is from %s", ctxfd->toChars()); IF_LOG Logger::println("Context is from %s", ctxfd->toChars());
@ -319,7 +318,7 @@ static void DtoCreateNestedContextType(FuncDeclaration *fd) {
} }
irFunc.nestedContextCreated = true; irFunc.nestedContextCreated = true;
FuncDeclaration *parentFunc = getParentFunc(fd, true); FuncDeclaration *parentFunc = getParentFunc(fd);
// Make sure the parent has already been analyzed. // Make sure the parent has already been analyzed.
if (parentFunc) { if (parentFunc) {
DtoCreateNestedContextType(parentFunc); DtoCreateNestedContextType(parentFunc);

@ -1 +1 @@
Subproject commit 56c5a640ec6fa34d69b42ef2bea726c3f5991d71 Subproject commit a6d0fc716643ceee52a7a63d70d7c860e12e5f6d