From the comment at https://github.com/D-Programming-Language/druntime/pull/335
---
version = bug;
bool foo(const(int)[] a, const(int)[] b)
{
version(bug) {
return a.length &&
b.ptr >= a.ptr &&
b.ptr + b.length <= a.ptr + a.length;
} else {
if (a.length && b.length)
{
auto bend = b.ptr + b.length;
auto aend = a.ptr + a.length;
return a.ptr <= b.ptr && bend <= aend;
}
return false;
}
}
bool bug1()
{
auto a1 = [1,2,3,4,5];
return foo(a1[0..4], a1[2..4]);
}
bool bug2()
{
auto a1 = [1,2,3,4,5];
auto a2 = [1,2,3,4,5];
return foo(a1[0..4], a2[2..4]);
}
static assert( bug1());
static assert(!bug2()); // Fails CTFE when version = bug; defines.
---
Comment #1 by clugdbug — 2012-10-24T10:42:30Z
This behaviour is intentional. The relevant line is:
return a.length &&
b.ptr >= a.ptr &&
b.ptr + b.length <= a.ptr + a.length;
This means:
return (a.length &&
b.ptr >= a.ptr) &&
b.ptr + b.length <= a.ptr + a.length;
If the b.ptr < a.ptr, then the first subexpression fails, and because of short-circuit evaluation, b.ptr + b.length <= a.ptr + a.length is never evaluated.
What you actually want is:
return a.length &&
(b.ptr >= a.ptr &&
b.ptr + b.length <= a.ptr + a.length);
Now in this particular case, the compiler could recognize e1 && e2 && e3 but it won't work in general, I think it makes things unpredictable.
Changing to a diagnostic bug.
I'm so disappointed, I went to a lot of trouble to give a good error message (even using the variable names you used!), and it seems it's still not clear enough. Any suggestions?
Comment #2 by clugdbug — 2012-10-24T10:57:37Z
To clarify: When I say "it won't work in general", the problem is things like:
a < b && c < d && e > f
If a and b are pointers to the same memory block, then a < b is OK, and this expression means:
a < b && isInside(c..e, d..f)
but if a and b are different pointers, then it would be:
isInside(a..c, b..d) && e > f
which is OK as long as e and f are in the same memory block.
then there is an explosion of possible cases, and many similar things _still_ aren't handled ( eg, a1 < b1 && c1 < d1 && a2 > b2 && c2 > d2, why isn't this recognized as two isInside operations?)
So the rule is simple: they have to be part of a single && or || expression.
Comment #3 by robert.schadek — 2024-12-13T18:01:58Z