mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 15:40:55 +03:00
Nested static functions and function literals do not inherit the parent context
This commit is contained in:
parent
cda8a12112
commit
a2fe91d5e3
2 changed files with 64 additions and 51 deletions
|
@ -1789,12 +1789,7 @@ FuncDeclaration* getParentFunc(Dsymbol* sym, bool stopOnStatic)
|
||||||
if (stopOnStatic)
|
if (stopOnStatic)
|
||||||
{
|
{
|
||||||
// Fun fact: AggregateDeclarations are not Declarations.
|
// Fun fact: AggregateDeclarations are not Declarations.
|
||||||
if (FuncDeclaration* decl = parent->isFuncDeclaration())
|
if (AggregateDeclaration* decl = parent->isAggregateDeclaration())
|
||||||
{
|
|
||||||
if (decl->isStatic())
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else if (AggregateDeclaration* decl = parent->isAggregateDeclaration())
|
|
||||||
{
|
{
|
||||||
if (!decl->isNested())
|
if (!decl->isNested())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1803,7 +1798,11 @@ FuncDeclaration* getParentFunc(Dsymbol* sym, bool stopOnStatic)
|
||||||
parent = parent->parent;
|
parent = parent->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent ? parent->isFuncDeclaration() : NULL;
|
if (!parent)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
FuncDeclaration* fd = parent->isFuncDeclaration();
|
||||||
|
return fd;//(stopOnStatic && fd->isStatic()) ? NULL : fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue* DtoIndexAggregate(LLValue* src, AggregateDeclaration* ad, VarDeclaration* vd)
|
LLValue* DtoIndexAggregate(LLValue* src, AggregateDeclaration* ad, VarDeclaration* vd)
|
||||||
|
|
|
@ -322,15 +322,28 @@ LLValue* DtoNestedContext(Loc& loc, Dsymbol* sym)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DtoCreateNestedContextType(FuncDeclaration* fd) {
|
static void DtoCreateNestedContextType(FuncDeclaration* fd)
|
||||||
|
{
|
||||||
IF_LOG Logger::println("DtoCreateNestedContextType for %s", fd->toPrettyChars());
|
IF_LOG Logger::println("DtoCreateNestedContextType for %s", fd->toPrettyChars());
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
|
|
||||||
DtoDeclareFunction(fd);
|
DtoDeclareFunction(fd);
|
||||||
|
|
||||||
if (getIrFunc(fd)->nestedContextCreated)
|
IrFunction& irFunc = *getIrFunc(fd);
|
||||||
|
|
||||||
|
if (irFunc.nestedContextCreated)
|
||||||
return;
|
return;
|
||||||
getIrFunc(fd)->nestedContextCreated = true;
|
irFunc.nestedContextCreated = true;
|
||||||
|
|
||||||
|
// Static functions and function (not delegate) literals don't allow
|
||||||
|
// access to a parent context, even if they are nested.
|
||||||
|
const bool certainlyNewRoot = fd->isStatic() ||
|
||||||
|
(fd->isFuncLiteralDeclaration() &&
|
||||||
|
static_cast<FuncLiteralDeclaration*>(fd)->tok == TOKfunction);
|
||||||
|
FuncDeclaration* parentFunc = (certainlyNewRoot ? NULL : getParentFunc(fd, true));
|
||||||
|
// Make sure the parent has already been analyzed.
|
||||||
|
if (parentFunc)
|
||||||
|
DtoCreateNestedContextType(parentFunc);
|
||||||
|
|
||||||
// construct nested variables array
|
// construct nested variables array
|
||||||
if (fd->closureVars.dim > 0)
|
if (fd->closureVars.dim > 0)
|
||||||
|
@ -339,42 +352,34 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) {
|
||||||
// start with adding all enclosing parent frames until a static parent is reached
|
// start with adding all enclosing parent frames until a static parent is reached
|
||||||
|
|
||||||
LLStructType* innerFrameType = NULL;
|
LLStructType* innerFrameType = NULL;
|
||||||
unsigned depth = -1;
|
int depth = 0;
|
||||||
|
|
||||||
// Static functions and function (not delegate) literals don't allow
|
if (parentFunc)
|
||||||
// access to a parent context, even if they are nested.
|
{
|
||||||
const bool certainlyNewRoot = fd->isStatic() ||
|
IrFunction& parentIrFunc = *getIrFunc(parentFunc);
|
||||||
(fd->isFuncLiteralDeclaration() &&
|
innerFrameType = parentIrFunc.frameType;
|
||||||
static_cast<FuncLiteralDeclaration*>(fd)->tok == TOKfunction);
|
|
||||||
if (!certainlyNewRoot) {
|
|
||||||
if (FuncDeclaration* parfd = getParentFunc(fd, true)) {
|
|
||||||
// Make sure the parent has already been analyzed.
|
|
||||||
DtoCreateNestedContextType(parfd);
|
|
||||||
|
|
||||||
innerFrameType = getIrFunc(parfd)->frameType;
|
|
||||||
if (innerFrameType)
|
if (innerFrameType)
|
||||||
depth = getIrFunc(parfd)->depth;
|
depth = parentIrFunc.depth + 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
getIrFunc(fd)->depth = ++depth;
|
irFunc.depth = depth;
|
||||||
|
|
||||||
IF_LOG Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n';
|
IF_LOG Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n';
|
||||||
|
|
||||||
typedef std::vector<LLType*> TypeVec;
|
typedef std::vector<LLType*> TypeVec;
|
||||||
TypeVec types;
|
TypeVec types;
|
||||||
if (depth != 0) {
|
if (depth != 0)
|
||||||
|
{
|
||||||
assert(innerFrameType);
|
assert(innerFrameType);
|
||||||
// Add frame pointer types for all but last frame
|
// Add frame pointer types for all but last frame
|
||||||
if (depth > 1) {
|
for (unsigned i = 0; i < (depth - 1); ++i)
|
||||||
for (unsigned i = 0; i < (depth - 1); ++i) {
|
|
||||||
types.push_back(innerFrameType->getElementType(i));
|
types.push_back(innerFrameType->getElementType(i));
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add frame pointer type for last frame
|
// Add frame pointer type for last frame
|
||||||
types.push_back(LLPointerType::getUnqual(innerFrameType));
|
types.push_back(LLPointerType::getUnqual(innerFrameType));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Logger::enabled() && depth != 0) {
|
if (Logger::enabled() && depth != 0)
|
||||||
|
{
|
||||||
Logger::println("Frame types: ");
|
Logger::println("Frame types: ");
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
for (TypeVec::iterator i = types.begin(); i != types.end(); ++i)
|
for (TypeVec::iterator i = types.begin(); i != types.end(); ++i)
|
||||||
|
@ -385,13 +390,15 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) {
|
||||||
// TODO: optimize ordering for minimal space usage?
|
// TODO: optimize ordering for minimal space usage?
|
||||||
for (VarDeclarations::iterator I = fd->closureVars.begin(),
|
for (VarDeclarations::iterator I = fd->closureVars.begin(),
|
||||||
E = fd->closureVars.end();
|
E = fd->closureVars.end();
|
||||||
I != E; ++I) {
|
I != E; ++I)
|
||||||
|
{
|
||||||
VarDeclaration* vd = *I;
|
VarDeclaration* vd = *I;
|
||||||
IrLocal *irLocal = getIrLocal(vd, true);
|
IrLocal& irLocal = *getIrLocal(vd, true);
|
||||||
irLocal->nestedIndex = types.size();
|
irLocal.nestedIndex = types.size();
|
||||||
irLocal->nestedDepth = depth;
|
irLocal.nestedDepth = depth;
|
||||||
|
|
||||||
if (vd->isParameter() && getIrParameter(vd)->arg) {
|
if (vd->isParameter() && getIrParameter(vd)->arg)
|
||||||
|
{
|
||||||
// Parameters that are part of the LLVM signature will have
|
// Parameters that are part of the LLVM signature will have
|
||||||
// storage associated with them (to handle byref etc.), so
|
// storage associated with them (to handle byref etc.), so
|
||||||
// handle those cases specially by storing a pointer instead
|
// handle those cases specially by storing a pointer instead
|
||||||
|
@ -401,20 +408,22 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) {
|
||||||
const bool lazy = vd->storage_class & STClazy;
|
const bool lazy = vd->storage_class & STClazy;
|
||||||
const bool byref = irparam->arg->byref;
|
const bool byref = irparam->arg->byref;
|
||||||
const bool isVthisPtr = irparam->isVthis && !byref;
|
const bool isVthisPtr = irparam->isVthis && !byref;
|
||||||
if (!(refout || (byref && !lazy)) || isVthisPtr) {
|
if (!(refout || (byref && !lazy)) || isVthisPtr)
|
||||||
|
{
|
||||||
// This will be copied to the nesting frame.
|
// This will be copied to the nesting frame.
|
||||||
if (lazy)
|
if (lazy)
|
||||||
types.push_back(irparam->value->getType()->getContainedType(0));
|
types.push_back(irparam->value->getType()->getContainedType(0));
|
||||||
else
|
else
|
||||||
types.push_back(DtoMemType(vd->type));
|
types.push_back(DtoMemType(vd->type));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
types.push_back(irparam->value->getType());
|
types.push_back(irparam->value->getType());
|
||||||
}
|
}
|
||||||
} else if (isSpecialRefVar(vd)) {
|
else if (isSpecialRefVar(vd))
|
||||||
types.push_back(DtoType(vd->type->pointerTo()));
|
types.push_back(DtoType(vd->type->pointerTo()));
|
||||||
} else {
|
else
|
||||||
types.push_back(DtoMemType(vd->type));
|
types.push_back(DtoMemType(vd->type));
|
||||||
}
|
|
||||||
IF_LOG Logger::cout() << "Nested var '" << vd->toChars()
|
IF_LOG Logger::cout() << "Nested var '" << vd->toChars()
|
||||||
<< "' of type " << *types.back() << "\n";
|
<< "' of type " << *types.back() << "\n";
|
||||||
}
|
}
|
||||||
|
@ -425,12 +434,17 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) {
|
||||||
IF_LOG Logger::cout() << "frameType = " << *frameType << '\n';
|
IF_LOG Logger::cout() << "frameType = " << *frameType << '\n';
|
||||||
|
|
||||||
// Store type in IrFunction
|
// Store type in IrFunction
|
||||||
getIrFunc(fd)->frameType = frameType;
|
irFunc.frameType = frameType;
|
||||||
} else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) {
|
}
|
||||||
|
else // no captured variables
|
||||||
|
{
|
||||||
|
if (parentFunc)
|
||||||
|
{
|
||||||
// Propagate context arg properties if the context arg is passed on unmodified.
|
// Propagate context arg properties if the context arg is passed on unmodified.
|
||||||
DtoCreateNestedContextType(parFunc);
|
IrFunction& parentIrFunc = *getIrFunc(parentFunc);
|
||||||
getIrFunc(fd)->frameType = getIrFunc(parFunc)->frameType;
|
irFunc.frameType = parentIrFunc.frameType;
|
||||||
getIrFunc(fd)->depth = getIrFunc(parFunc)->depth;
|
irFunc.depth = parentIrFunc.depth;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue