This is currently a blocker for phobos pull request# 743, which make stride, strideBack, and decode work with arbitrary ranges of code units, which is needed for the D lexer for Phobos that I'm working on.
This is the reduced code:
import std.traits;
void main()
{
auto tmp = "hello";
size_t i = 0;
decode(tmp, i);
}
template isRange(R)
{
enum bool isRange = is(typeof(
{
R r = void;
auto w = r.front;
}));
}
@property dchar front(A)(A a)
{
size_t i = 0;
return decode(a, i);
}
dchar decode(S)(auto ref S str, ref size_t index)
{
return decodeImpl(str, index);
}
private dchar decodeImpl(S)(auto ref S str, ref size_t index)
{
enum canIndex = isRange!S;
assert(0);
}
It compiles just fine normally, but when you compile with -release and -inline together, it fails to compile, giving this error:
decodeImpl(S)
Internal error: e2ir.c 720
I think that the problem stems from the fact that isRange depends on decode, which in turn depends on isRange, and something about the inlining process screws it up. Moving the line with isRange from decodeImpl into decode makes the problem going away as does removing front from inside of isRange. And using decode inside of isRange makes it go away as well. So, it seems that the number of levels of indirection has to be at at least a certain level before the failure occurs.
The code in pull request# 743 passes its unit tests just fine as long as you don't compile with both -release and -inline, so clearly the code can work, but something about -release and -inline screws it up.
Comment #1 by issues.dlang — 2012-08-08T12:53:49Z
Okay. I was finally able to find a workaround by moving the test inside of decodeImpl to outside of it, which is leaking its implementation details and forcing a bool with the result of the test to be passed to an overload of decodeImpl which doesn't need the test at all, but it does make it so that the code works, and it doesn't affect the public API at all. So, I'm changing this bug to major rather than blocker.
Comment #2 by github-bugzilla — 2012-08-19T18:51:50Z
I just hit this bug aswell, but your work-around does not seem to help. With current head from github:
module test;
import std.utf;
dchar foo(string s)
{
size_t pos;
return decode(s, pos);
}
I get ICE with -inline:
>m:\s\d\rainers\windows\bin\dmd -c test.d
>m:\s\d\rainers\windows\bin\dmd -c -inline test.d
Statement::doInline()
goto __returnLabel;
Assertion failure: '0' on line 470 in file 'inline.c'
abnormal program termination
>m:\s\d\rainers\windows\bin\dmd -c -inline -release test.d
decodeImpl(bool canIndex,S) if (is(S : const(char[])) || isInputRange!(S) && is(Unqual!(ElementEncod
ingType!(S)) == char))
Internal error: e2ir.c 720
Comment #4 by issues.dlang — 2012-08-21T00:47:26Z
Well, it helps in that the situation is improved enough that dmd's tests passed (which wasn't the case before), but clearly, it doesn't fully get around the problem. Bleh.
I guess that I'll have to take another whack at the workaround. It would be _really_ nice if someone could fix this bug though.
Comment #5 by r.sagitario — 2012-08-21T15:05:28Z
It seems that dmd is unable to generate code for the expression
return str[index] < codeUnitLimit!S ? str[index++] : decodeImpl!true(str, index);
This workaround compiled for me:
if(str[index] < codeUnitLimit!S)
return str[index++];
return decodeImpl!true(str, index);
Comment #6 by github-bugzilla — 2012-08-22T02:27:37Z