diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 1dd46870..93fc9568 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -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 diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 99d2a014..d9c82e9b 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -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); diff --git a/gen/statements.cpp b/gen/statements.cpp index 4954e61f..dcd1485b 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -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 diff --git a/tests/mini/compile_rawvardeclinfinally.d b/tests/mini/compile_rawvardeclinfinally.d index 7d248002..73bc58f1 100644 --- a/tests/mini/compile_rawvardeclinfinally.d +++ b/tests/mini/compile_rawvardeclinfinally.d @@ -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(); + } +} diff --git a/tests/mini/foreach10.d b/tests/mini/foreach10.d new file mode 100644 index 00000000..1551847a --- /dev/null +++ b/tests/mini/foreach10.d @@ -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; + } +} diff --git a/tests/mini/foreach11.d b/tests/mini/foreach11.d new file mode 100644 index 00000000..95eec7da --- /dev/null +++ b/tests/mini/foreach11.d @@ -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; + } +}