/* RUN_OUTPUT: --- Success --- */ // REQUIRED_ARGS: // Test array bounds checking import core.exception; extern(C) int printf(const char*, ...); template TypeTuple(T...) { alias T TypeTuple; } /******************************************/ const int[10] foos = [1,2,3,4,5,6,7,8,9,10]; const int[] food = [21,22,23,24,25,26,27,28,29,30]; const int *foop = cast(int*) foos; static int x = 2; int index() { return x++; } int tests(int i) { return foos[index()]; } int testd(int i) { return food[index()]; } int testp(int i) { return foop[i]; } const(int)[] slices(int lwr, int upr) { return foos[lwr .. upr]; } const(int)[] sliced(int lwr, int upr) { return food[lwr .. upr]; } const(int)[] slicep(int lwr, int upr) { return foop[lwr .. upr]; } void test1() { int i; i = tests(0); assert(i == 3); i = testd(0); assert(i == 24); i = testp(1); assert(i == 2); x = 10; try { i = tests(0); } catch (RangeError a) { i = 73; } assert(i == 73); x = -1; try { i = testd(0); } catch (RangeError a) { i = 37; } assert(i == 37); const(int)[] r; r = slices(3,5); assert(r[0] == foos[3]); assert(r[1] == foos[4]); r = sliced(3,5); assert(r[0] == food[3]); assert(r[1] == food[4]); r = slicep(3,5); assert(r[0] == foos[3]); assert(r[1] == foos[4]); try { i = 7; r = slices(5,3); } catch (RangeError a) { i = 53; } assert(i == 53); try { i = 7; r = slices(5,11); } catch (RangeError a) { i = 53; } assert(i == 53); try { i = 7; r = sliced(5,11); } catch (RangeError a) { i = 53; } assert(i == 53); try { i = 7; r = slicep(5,3); } catch (RangeError a) { i = 53; } assert(i == 53); // Take side effects into account x = 1; r = foos[index() .. 3]; assert(x == 2); assert(r[0] == foos[1]); assert(r[1] == foos[2]); r = foos[1 .. index()]; assert(r.length == 1); assert(x == 3); assert(r[0] == foos[1]); x = 1; r = food[index() .. 3]; assert(x == 2); assert(r[0] == food[1]); assert(r[1] == food[2]); r = food[1 .. index()]; assert(r.length == 1); assert(x == 3); assert(r[0] == food[1]); x = 1; r = foop[index() .. 3]; assert(x == 2); assert(r[0] == foop[1]); assert(r[1] == foop[2]); r = foop[1 .. index()]; assert(r.length == 1); assert(x == 3); assert(r[0] == foop[1]); } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=13976 void test13976() { int[] da = new int[](10); int[10] sa; enum size_t two = 2; enum size_t five = 5; size_t lb = 0; // upperInRange size_t ub = 9; // | lowerLessThan // | | check code { auto s = da[lb .. ub]; } // 0 0 (ub <= $ && lb <= ub ) { auto s = da[1 .. ub]; } // 0 0 (ub <= $ && 1 <= ub ) { auto s = da[lb .. 10]; } // 0 0 (10 <= $ && lb <= 10 ) { auto s = da[1 .. ub%5]; } // 0 0 (ub%5 <= $ && 1 <= ub%5) { auto s = da[lb .. ub]; } // 0 0 (ub <= $ && lb <= ub ) { auto s = da[0 .. ub]; } // 0 1 (ub <= $ ) { auto s = da[lb .. 10]; } // 0 0 (10 <= $ && lb <= 10 ) { auto s = da[0 .. ub%5]; } // 0 1 (ub%5 <= $ ) { auto s = da[0 .. 0]; } // 1 1 NULL { auto s = da[0 .. $]; } // 1 1 NULL { auto s = da[1 .. $]; } // 1 0 ( 1 <= $ ) { auto s = da[$ .. $]; } // 1 0 ( $ <= $ ) { auto s = da[0 .. $/two]; } // 0 1 ($/2 <= $ ) { auto s = da[$/two .. $]; } // 1 0 ( $/2 <= $ ) { auto s = da[$/five .. $/two]; } // 0 0 ($/2 <= $ && $/5 <= $/2) { auto s = sa[lb .. ub]; } // 0 0 (ub <= 10 && lb <= ub ) { auto s = sa[1 .. ub]; } // 0 0 (ub <= 10 && 1 <= ub ) { auto s = sa[lb .. 10]; } // 1 0 ( lb <= 10 ) { auto s = sa[1 .. ub%5]; } // 1 0 ( 1 <= ub%5) { auto s = sa[lb .. ub]; } // 0 0 (ub <= 10 && lb <= ub ) { auto s = sa[0 .. ub]; } // 0 1 (ub <= 10 ) { auto s = sa[lb .. 10]; } // 1 0 ( lb <= 10 ) { auto s = sa[0 .. ub%5]; } // 1 1 NULL { auto s = sa[0 .. 0]; } // 1 1 NULL { auto s = sa[0 .. $]; } // 1 1 NULL { auto s = sa[1 .. $]; } // 1 1 NULL { auto s = sa[$ .. $]; } // 1 1 NULL { auto s = sa[0 .. $/two]; } // 1 1 NULL { auto s = sa[$/two .. $]; } // 1 1 NULL { auto s = sa[$/five .. $/two]; } // 1 1 NULL int* p = new int[](10).ptr; { auto s = p[0 .. ub]; } // 1 1 NULL { auto s = p[lb .. ub]; } // 1 0 (lb <= ub ) { auto s = p[0 .. ub%5]; } // 1 1 NULL { auto s = p[1 .. ub%5]; } // 1 0 (1 <= ub%5) { auto s = p[0 .. 0]; } // 1 1 NULL } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=3652 void test3652() { int foo(int[4] x) { return x[0] + x[1] * x[2] - x[3]; } int[] xs = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; // simple case foo(xs[0 .. 4]); version(none) { // Need deformation of formula and detection of base point int x = 0; int y = 0; foreach (i; 0 .. 4) { x += foo(xs[i .. i + 4]); y += foo(xs[(i*4+10)/2 .. (i*8>>1)/2+9]); // lwr = (i*4 + 10)/2 = i*4/2 + 10/2 = (i*2+5) // upr = (i*8>>1)/2 + 5 = (i*4/2) + 5 = i*2 + 9 = (i*2+5) + 4 } assert(x == (0,1,2,3) + (1,2,3, 4) + (2, 3, 4, 5) + ( 3, 4, 5, 6)); assert(y == (5,6,7,8) + (7,8,9,10) + (9,10,11,12) + (11,12,13,14)); } } void test3652a() @safe { string str = "aaaabbbbccccdddd"; //printf("str.ptr = %p\n", str.ptr); void foo(ref const(char)[16] buf) { //printf("buf.ptr = %p\n", buf.ptr); assert(buf.ptr is str.ptr); } // can check length at runtime assert(str.length == 16); // compiler can check the length of string literal, so // conversion from immutable(char)[] to ref const(char)[16] is allowed; static assert(__traits(compiles, foo("aaaabbbbccccdddd"))); // OK, correctly rejected by the compiler. static assert(!__traits(compiles, foo(str[]))); // Ugly, furthermore does not work in safe code! //foo(*cast(const(char)[16]*)(str[0..16].ptr)); // New: compiler can check the length of slice, but currently it is not allowed. enum size_t m = 0; size_t calc(){ return 0; } foo(str[0 .. 16]); foo(str[m .. 16]); //foo(str[calc() .. 16]); // with CTFE // If boundaries cannot be calculated in compile time, it's rejected. size_t n; size_t calc2(){ return n; } static assert(!__traits(compiles, foo(str[n .. 16]))); static assert(!__traits(compiles, foo(str[calc2() .. 16]))); void hoo1(size_t dim)(char[dim]) { static assert(dim == 2); } void hoo2(char[2]) {} void hoo3(size_t dim)(ref char[dim]) {} void hoo4(ref char[2]) {} hoo1(str[0 .. 2]); hoo2(str[0 .. 2]); static assert(!__traits(compiles, hoo3(str[0 .. 2]))); static assert(!__traits(compiles, hoo4(str[0 .. 2]))); } void test3652b() @safe { int[] da = [1,2,3,4,5]; void bar(int[3] sa1, ref int[3] sa2) { assert(sa1 == [1,2,3] && sa1.ptr !is da.ptr); assert(sa2 == [1,2,3] && sa2.ptr is da.ptr); } bar(da[0..3], da[0..3]); static assert(!__traits(compiles, bar(da[0..4], da[0..4]))); void baz1(T)(T[3] sa1, ref T[3] sa2) { assert(sa1 == [1,2,3] && sa1.ptr !is da.ptr); assert(sa2 == [1,2,3] && sa2.ptr is da.ptr); } void baz2(T, size_t dim)(T[dim] sa1, ref T[dim] sa2, size_t result) { assert(dim == result); static if (dim == 3) { assert(sa1 == [1,2,3] && sa1.ptr !is da.ptr); assert(sa2 == [1,2,3] && sa2.ptr is da.ptr); } else { assert(sa1 == [1,2,3,4] && sa1.ptr !is da.ptr); assert(sa2 == [1,2,3,4] && sa2.ptr is da.ptr); } } baz1(da[0..3], da[0..3]); static assert(!__traits(compiles, baz1(da[0..4], da[0..4]))); baz2(da[0..3], da[0..3], 3); baz2(da[0..4], da[0..4], 4); void hoo1(size_t dim)(int[dim]) { static assert(dim == 2); } void hoo2(int[2]) {} void hoo3(size_t dim)(ref int[dim]) {} void hoo4(ref int[2]) {} hoo1(da.idup[0 .. 2]); hoo2(da.idup[0 .. 2]); static assert(!__traits(compiles, hoo3(da.idup[0 .. 2]))); static assert(!__traits(compiles, hoo4(da.idup[0 .. 2]))); } /**********************************/ // https://issues.dlang.org/show_bug.cgi?id=9654 auto foo9654a(ref char[8] str) { return str; } auto foo9654b(ref const char[8] str) { return str; } auto foo9654c(ref immutable char[8] str) { return str; } static assert(!is(typeof(foo9654a("testinfo")))); static assert( is(typeof(foo9654b("testinfo")) == const char[8])); static assert( is(typeof(foo9654c("testinfo")) == immutable char[8])); auto bar9654a(T)(ref T[8] str) { return str; static assert(is(T == immutable char)); } auto bar9654b(T)(ref const T[8] str) { return str; static assert(is(T == char)); } auto bar9654c(T)(ref immutable T[8] str) { return str; static assert(is(T == char)); } static assert( is(typeof(bar9654a("testinfo")) == immutable char[8])); static assert( is(typeof(bar9654b("testinfo")) == const char[8])); static assert( is(typeof(bar9654c("testinfo")) == immutable char[8])); auto baz9654a(T, size_t dim)(ref T[dim] str) { return str; static assert(is(T == immutable char)); } auto baz9654b(T, size_t dim)(ref const T[dim] str) { return str; static assert(is(T == char)); } auto baz9654c(T, size_t dim)(ref immutable T[dim] str) { return str; static assert(is(T == char)); } static assert( is(typeof(baz9654a("testinfo")) == immutable char[8])); static assert( is(typeof(baz9654b("testinfo")) == const char[8])); static assert( is(typeof(baz9654c("testinfo")) == immutable char[8])); /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=9712 auto func9712(T)(T[2] arg) { return arg; } static assert(is(typeof(func9712([1,2])) == int[2])); auto deduceLength9712(T,size_t n)(T[n] a) { return a; } static assert(is(typeof(deduceLength9712([1,2,3])) == int[3])); /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=9743 void test9743() { // +-Char // |+-Immutable or Const or Mutable // ||+-Value or Ref // |||+-Function or +-Template void fCIVF( immutable char[4]) {} void fCIVT()( immutable char[4]) {} void fCCVF( const char[4]) {} void fCCVT()( const char[4]) {} void fCMVF( char[4]) {} void fCMVT()( char[4]) {} void fCIRF(ref immutable char[4]) {} void fCIRT()(ref immutable char[4]) {} void fCCRF(ref const char[4]) {} void fCCRT()(ref const char[4]) {} void fCMRF(ref char[4]) {} void fCMRT()(ref char[4]) {} alias fcOK = TypeTuple!(fCIVF, fCIVT, fCCVF, fCCVT, fCMVF, fCMVT, fCIRF, fCIRT, fCCRF, fCCRT); foreach (f; fcOK) f("1234" ) ; foreach (f; fcOK) f("1234"c) ; foreach (f; fcOK) static assert(!__traits(compiles, f("1234"w) )); foreach (f; fcOK) static assert(!__traits(compiles, f("1234"d) )); alias fcNG = TypeTuple!(fCMRF, fCMRT); // cannot hold immutable data by mutable ref foreach (f; fcNG) static assert(!__traits(compiles, f("1234" ) )); foreach (f; fcNG) static assert(!__traits(compiles, f("1234"c) )); foreach (f; fcNG) static assert(!__traits(compiles, f("1234"w) )); foreach (f; fcNG) static assert(!__traits(compiles, f("1234"d) )); // +-Wchar void fWIVF( immutable wchar[4]) {} void fWIVT()( immutable wchar[4]) {} void fWCVF( const wchar[4]) {} void fWCVT()( const wchar[4]) {} void fWMVF( wchar[4]) {} void fWMVT()( wchar[4]) {} void fWIRF(ref immutable wchar[4]) {} void fWIRT()(ref immutable wchar[4]) {} void fWCRF(ref const wchar[4]) {} void fWCRT()(ref const wchar[4]) {} void fWMRF(ref wchar[4]) {} void fWMRT()(ref wchar[4]) {} alias fwOK = TypeTuple!(fWIVF, fWIVT, fWCVF, fWCVT, fWMVF, fWMVT, fWIRF, fWIRT, fWCRF, fWCRT); foreach (f; fwOK) f("1234" ) ; foreach (f; fwOK) static assert(!__traits(compiles, f("1234"c) )); foreach (f; fwOK) f("1234"w) ; foreach (f; fwOK) static assert(!__traits(compiles, f("1234"d) )); alias fwNG = TypeTuple!(fWMRF, fWMRT); // cannot hold immutable data by mutable ref foreach (f; fwNG) static assert(!__traits(compiles, f("1234" ) )); foreach (f; fwNG) static assert(!__traits(compiles, f("1234"c) )); foreach (f; fwNG) static assert(!__traits(compiles, f("1234"w) )); foreach (f; fwNG) static assert(!__traits(compiles, f("1234"d) )); // +-Dchar void fDIVF( immutable dchar[4]) {} void fDIVT()( immutable dchar[4]) {} void fDCVF( const dchar[4]) {} void fDCVT()( const dchar[4]) {} void fDMVF( dchar[4]) {} void fDMVT()( dchar[4]) {} void fDIRF(ref immutable dchar[4]) {} void fDIRT()(ref immutable dchar[4]) {} void fDCRF(ref const dchar[4]) {} void fDCRT()(ref const dchar[4]) {} void fDMRF(ref dchar[4]) {} void fDMRT()(ref dchar[4]) {} alias fdOK = TypeTuple!(fDIVF, fDIVT, fDCVF, fDCVT, fDMVF, fDMVT, fDIRF, fDIRT, fDCRF, fDCRT); foreach (f; fdOK) f("1234" ) ; foreach (f; fdOK) static assert(!__traits(compiles, f("1234"c) )); foreach (f; fdOK) static assert(!__traits(compiles, f("1234"w) )); foreach (f; fdOK) f("1234"d) ; alias fdNG = TypeTuple!(fDMRF, fDMRT); // cannot hold immutable data by mutable ref foreach (f; fdNG) static assert(!__traits(compiles, f("1234" ) )); foreach (f; fdNG) static assert(!__traits(compiles, f("1234"c) )); foreach (f; fdNG) static assert(!__traits(compiles, f("1234"w) )); foreach (f; fdNG) static assert(!__traits(compiles, f("1234"d) )); } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=9747 void foo9747A(T)(T[4]) {} void foo9747C(size_t dim)(char[dim]) {} void foo9747W(size_t dim)(wchar[dim]) {} void foo9747D(size_t dim)(dchar[dim]) {} void test9747() { foo9747A("abcd"c); foo9747A("abcd"w); foo9747A("abcd"d); foo9747C("abcd"c); foo9747W("abcd"w); foo9747D("abcd"d); } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=12876 void test12876() { void foo(int[4] b) {} void bar(size_t n)(int[n] c) { static assert(n == 4); } int[5] a; foo(a[1 .. $]); // OK bar(a[1 .. $]); // OK <- Error } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=13775 void test13775() { ubyte[4] ubytes = [1,2,3,4]; // CT-known slicing (https://issues.dlang.org/show_bug.cgi?id=3652) auto ok1 = cast(ubyte[2]) ubytes[0 .. 2]; assert(ok1 == [1, 2]); // CT-known slicing with implicit conversion of SliceExp::e1 (https://issues.dlang.org/show_bug.cgi?id=13154) enum double[] arr = [1.0, 2.0, 3.0]; auto ok2 = cast(float[2]) [1.0, 2.0, 3.0][0..2]; auto ok3 = cast(float[2]) arr[1..3]; // currently this is accepted assert(ok2 == [1f, 2f]); assert(ok3 == [2f, 3f]); // CT-known slicing with type coercing (https://issues.dlang.org/show_bug.cgi?id=13775) auto ok4 = cast( byte[2]) ubytes[0 .. 2]; // CT-known slicing + type coercing auto ok5 = cast(short[1]) ubytes[0 .. 2]; // CT-known slicing + type coercing assert(ok4 == [1, 2]); version(LittleEndian) assert(ok5 == [0x0201]); version( BigEndian) assert(ok5 == [0x0102]); } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=15889 // Array bounds check should report index and length void test15889() { int[] a = new int[2]; try { a[3] = 40; } catch (ArrayIndexError e) { assert(e.index == 3); assert(e.length == 2); } try { a[1 .. 4] = 50; } catch (ArraySliceError e) { assert(e.lower == 1); assert(e.upper == 4); assert(e.length == 2); } } /******************************************/ int main() { test1(); test13976(); test3652(); test3652a(); test3652b(); test9743(); test9747(); test13775(); test15889(); printf("Success\n"); return 0; }