# HG changeset patch # User Frits van Bommel # Date 1243021081 -7200 # Node ID e57859ca8f1e1df958a955447bc5f0a625899897 # Parent cc2d8a7388c7f6b60af0c6a65ac2fe32201caebf Fix `scope(exit) foreach (ref v; arr) foo(v);` diff -r cc2d8a7388c7 -r e57859ca8f1e gen/llvmhelpers.cpp --- a/gen/llvmhelpers.cpp Fri May 22 13:17:06 2009 +0200 +++ b/gen/llvmhelpers.cpp Fri May 22 21:38:01 2009 +0200 @@ -1055,8 +1055,20 @@ { // 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; + if (addr && addr != var->ir.irLocal->value) { + // This can happen, for example, in scope(exit) blocks which + // are translated to IR multiple times. + // That *should* only happen after the first one is completely done + // though, so just set the address. + IF_LOG { + Logger::println("Replacing LLVM address of %s", var->toChars()); + LOG_SCOPE; + Logger::cout() << "Old val: " << *var->ir.irLocal->value << '\n'; + Logger::cout() << "New val: " << *addr << '\n'; + } + var->ir.irLocal->value = addr; + } + return addr; } assert(!var->ir.isSet()); diff -r cc2d8a7388c7 -r e57859ca8f1e tests/mini/compile_scope_exit_foreach.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/mini/compile_scope_exit_foreach.d Fri May 22 21:38:01 2009 +0200 @@ -0,0 +1,14 @@ +module scope_exit_foreach; + +void bar(size_t); + +long foo(ubyte[] arr) { + scope(exit) { + foreach (ref b; arr) { + bar(b); + } + } + if (arr.length == 3) + return 0; + return arr.length; +}