Fix nested references to 'ref' foreach variables.

These "walk around" the array being iterated over, so they're a bit trickier
than other variables to get right.
This commit is contained in:
Frits van Bommel
2009-04-01 00:01:44 +02:00
parent aa8aad611c
commit 3f49ddb6d5
6 changed files with 68 additions and 17 deletions

View File

@@ -1075,7 +1075,7 @@ DValue* DtoDeclarationExp(Dsymbol* declaration)
}
// does pretty much the same as DtoDeclarationExp, except it doesn't initialize, and only handles var declarations
LLValue* DtoRawVarDeclaration(VarDeclaration* var)
LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr)
{
// we don't handle globals with this one
assert(!var->isDataseg());
@@ -1083,10 +1083,6 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var)
// we don't handle aliases either
assert(!var->aliassym);
// if this already has storage, it must've been handled already
if (var->ir.irLocal && var->ir.irLocal->value)
return var->ir.irLocal->value;
// referenced by nested function?
#if DMDV2
if (var->nestedrefs.dim)
@@ -1095,10 +1091,10 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var)
#endif
{
assert(var->ir.irLocal);
assert(!var->ir.irLocal->value);
// alloca
var->ir.irLocal->value = DtoAlloca(DtoType(var->type), var->toChars());
if(!var->ir.irLocal->value)
var->ir.irLocal->value = addr ? addr : DtoAlloca(DtoType(var->type), var->toChars());
else
assert(!addr || addr == var->ir.irLocal->value);
// store the address into the nested vars array
assert(var->ir.irLocal->nestedIndex >= 0);
@@ -1110,9 +1106,15 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var)
// normal local variable
else
{
// if this already has storage, it must've been handled already
if (var->ir.irLocal && var->ir.irLocal->value) {
assert(!addr || addr == var->ir.irLocal->value);
return var->ir.irLocal->value;
}
assert(!var->ir.isSet());
var->ir.irLocal = new IrLocal(var);
var->ir.irLocal->value = DtoAlloca(DtoType(var->type), var->toChars());
var->ir.irLocal->value = addr ? addr : DtoAlloca(DtoType(var->type), var->toChars());
}
// add debug info

View File

@@ -101,7 +101,7 @@ void DtoConstInitGlobal(VarDeclaration* vd);
// declaration inside a declarationexp
DValue* DtoDeclarationExp(Dsymbol* declaration);
LLValue* DtoRawVarDeclaration(VarDeclaration* var);
LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr = 0);
// initializer helpers
LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init);

View File

@@ -1030,11 +1030,12 @@ void ForeachStatement::toIR(IRState* p)
// value
Logger::println("value = %s", value->toPrettyChars());
DtoRawVarDeclaration(value);
const LLType* valtype = DtoType(value->type);
LLValue* valvar = NULL;
if (!value->isRef() && !value->isOut())
if (!value->isRef() && !value->isOut()) {
// Create a local variable to serve as the value.
DtoRawVarDeclaration(value);
valvar = value->ir.irLocal->value;
}
// what to iterate
DValue* aggrval = aggr->toElem(p);
@@ -1093,13 +1094,17 @@ void ForeachStatement::toIR(IRState* p)
// get value for this iteration
LLConstant* zero = llvm::ConstantInt::get(keytype,0,false);
LLValue* loadedKey = p->ir->CreateLoad(keyvar,"tmp");
value->ir.irLocal->value = DtoGEP1(val,loadedKey);
LLValue* gep = DtoGEP1(val,loadedKey);
if (!value->isRef() && !value->isOut()) {
// Copy value to local variable, and use it as the value variable.
DVarValue dst(value->type, valvar);
DVarValue src(value->type, value->ir.irLocal->value);
DVarValue src(value->type, gep);
DtoAssign(loc, &dst, &src);
value->ir.irLocal->value = valvar;
} else {
// Use the GEP as the address of the value variable.
DtoRawVarDeclaration(value, gep);
}
// emit body

View File

@@ -1 +1,8 @@
void foo() { void delegate()[] bar; try {} finally { foreach (dg; bar) dg(); } }
void foo() {
void delegate()[] bar;
try {
} finally {
foreach (dg; bar)
dg();
}
}

19
tests/mini/foreach10.d Normal file
View File

@@ -0,0 +1,19 @@
module foreach10;
extern(C) int printf(char*, ...);
void main() {
char* last = null;
printf("The addresses should increment:\n");
foreach (ref c; "bar") {
auto a = {
printf("%x '%c'\n", c, c);
return &c;
};
auto nw = a();
printf("ptr = %p\n", nw);
if (last != null)
assert(nw == last+1);
last = nw;
}
}

18
tests/mini/foreach11.d Normal file
View File

@@ -0,0 +1,18 @@
module foreach11;
extern(C) int printf(char*, ...);
void main() {
char* last = null;
printf("The addresses should remain constant:\n");
foreach (c; "bar") {
auto a = {
printf("%x '%c'\n", c, c);
printf("ptr = %p\n", &c);
if (last)
assert(last == &c);
};
a();
last = &c;
}
}