mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
19
tests/mini/foreach10.d
Normal 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
18
tests/mini/foreach11.d
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user