File: gh1433.d

package info (click to toggle)
ldc 1%3A1.30.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 59,248 kB
  • sloc: cpp: 61,598; ansic: 14,545; sh: 1,014; makefile: 972; asm: 510; objc: 135; exp: 48; python: 12
file content (80 lines) | stat: -rw-r--r-- 1,765 bytes parent folder | download | duplicates (4)
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) {}
}