1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
|
// RUN: %ldc -run %s
@safe:
int step;
int[] globalArray;
void reset(int initialStep)
{
step = initialStep;
globalArray = [ -1, -2, -3, -4 ];
}
int[] getBaseSlice()
{
assert(step++ == 0);
return globalArray;
}
ref int[] getBaseSliceRef()
{
assert(step++ == 0);
return globalArray;
}
int getLowerBound(size_t dollar)
{
assert(step++ == 1);
assert(dollar == 4);
globalArray = null;
return 1;
}
int getUpperBound(size_t dollar, size_t expectedDollar)
{
assert(step++ == 2);
assert(dollar == expectedDollar);
globalArray = [ 1, 2, 3 ];
return 3;
}
// https://github.com/ldc-developers/ldc/issues/1433
void main()
{
reset(0);
auto r = getBaseSlice()[getLowerBound($) .. getUpperBound($, 4)];
assert(r == [ -2, -3 ]); // old buffer
// LDC and GDC treat $ as lvalue and load <base>.length each time it is accessed
// DMD apparently treats it as rvalue and loads it once at the beginning (=> wrong bounds check)
version(DigitalMars)
enum expectedDollar = 4;
else
enum expectedDollar = 0;
reset(1);
r = globalArray[getLowerBound($) .. getUpperBound($, expectedDollar)];
assert(r == [ 2, 3 ]); // new buffer
reset(0);
r = getBaseSliceRef()[getLowerBound($) .. getUpperBound($, expectedDollar)];
version(DigitalMars)
assert(r == [ -2, -3 ]); // old buffer
else
assert(r == [ 2, 3 ]); // new buffer
testBoundsCheck();
}
void testBoundsCheck() @trusted // @trusted needed for catching Errors, otherwise @safe
{
import core.exception : RangeError;
reset(1);
try
{
auto r = globalArray[getLowerBound($) .. 2]; // null[1 .. 2]
assert(0); // fails for DMD
}
catch (RangeError) {}
}
|