diff --git a/src/e2ir.c b/src/e2ir.c index b57bda9d43f0..9b28a7523ac0 100644 --- a/src/e2ir.c +++ b/src/e2ir.c @@ -4412,71 +4412,72 @@ elem *toElem(Expression *e, IRState *irs) if (se->lwr) { elem *einit = resolveLengthVar(se->lengthVar, &e, t1); - unsigned sz = t1->nextOf()->size(); elem *elwr = toElem(se->lwr, irs); elem *eupr = toElem(se->upr, irs); - elem *elwr2 = el_same(&elwr); + elem *eupr2 = eupr; + //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", se->upperIsInBounds, se->lowerIsLessThanUpper); if (irs->arrayBoundsCheck()) { // Checks (unsigned compares): // upr <= array.length // lwr <= upr - elem *c1; - elem *c2; - elem *eupr2; - - if (t1->ty == Tpointer) + elem *c1 = NULL; + if (!se->upperIsInBounds) { - // Just do lwr <= upr check - eupr2 = el_same(&eupr); - eupr2->Ety = TYsize_t; // make sure unsigned comparison - c1 = el_bin(OPle, TYint, elwr2, eupr2); - c1 = el_combine(eupr, c1); - } - else - { - elem *elength; + eupr2->Ety = TYsize_t; // make sure unsigned comparison + elem *elen; if (t1->ty == Tsarray) { TypeSArray *tsa = (TypeSArray *)t1; - dinteger_t length = tsa->dim->toInteger(); - - elength = el_long(TYsize_t, length); + elen = el_long(TYsize_t, tsa->dim->toInteger()); } else if (t1->ty == Tarray) { if (se->lengthVar && !(se->lengthVar->storage_class & STCconst)) - elength = el_var(toSymbol(se->lengthVar)); + elen = el_var(toSymbol(se->lengthVar)); else { - elength = e; - e = el_same(&elength); - elength = el_una(I64 ? OP128_64 : OP64_32, TYsize_t, elength); + elen = e; + e = el_same(&elen); + elen = el_una(I64 ? OP128_64 : OP64_32, TYsize_t, elen); } } + c1 = el_bin(OPle, TYint, eupr, elen); + + if (!se->lowerIsLessThanUpper) + { + c1 = el_bin(OPandand, TYint, + c1, el_bin(OPle, TYint, elwr2, eupr2)); + elwr2 = el_copytree(elwr2); + eupr2 = el_copytree(eupr2); + } + } + else if (!se->lowerIsLessThanUpper) + { eupr2 = el_same(&eupr); - c1 = el_bin(OPle, TYint, eupr, elength); - eupr2->Ety = TYsize_t; // make sure unsigned comparison - c2 = el_bin(OPle, TYint, elwr2, eupr2); - c1 = el_bin(OPandand, TYint, c1, c2); // (c1 && c2) + eupr2->Ety = TYsize_t; // make sure unsigned comparison + + c1 = el_bin(OPle, TYint, elwr2, eupr); + elwr2 = el_copytree(elwr2); } - // Construct: (c1 || ModuleArray(line)) - Symbol *sassert = irs->blx->module->toModuleArray(); - elem *ea = el_bin(OPcall, TYvoid, el_var(sassert), el_long(TYint, se->loc.linnum)); - elem *eb = el_bin(OPoror, TYvoid, c1, ea); - elwr = el_combine(elwr, eb); + if (c1) + { + // Construct: (c1 || ModuleArray(line)) + Symbol *sassert = irs->blx->module->toModuleArray(); + elem *ea = el_bin(OPcall, TYvoid, el_var(sassert), el_long(TYint, se->loc.linnum)); + elem *eb = el_bin(OPoror, TYvoid, c1, ea); - elwr2 = el_copytree(elwr2); - eupr = el_copytree(eupr2); + elwr = el_combine(elwr, eb); + } } // Create an array reference where: @@ -4486,18 +4487,18 @@ elem *toElem(Expression *e, IRState *irs) e = array_toPtr(se->e1->type, e); - elem *eptr = el_same(&e); - eptr = el_bin(OPadd, TYnptr, eptr, el_bin(OPmul, TYsize_t, elwr2, el_long(TYsize_t, sz))); + elem *eofs = el_bin(OPmul, TYsize_t, elwr2, el_long(TYsize_t, sz)); + elem *eptr = el_bin(OPadd, TYnptr, el_same(&e), eofs); if (tb->ty == Tarray) { - elem *elength = el_bin(OPmin, TYsize_t, eupr, el_copytree(elwr2)); - e = el_combine(e, el_pair(TYdarray, elength, eptr)); + elem *elen = el_bin(OPmin, TYsize_t, eupr2, el_copytree(elwr2)); + e = el_combine(e, el_pair(TYdarray, elen, eptr)); } else { assert(tb->ty == Tsarray); - e = el_una(OPind, totym(se->type), eptr); + e = el_una(OPind, totym(se->type), el_combine(e, eptr)); if (tybasic(e->Ety) == TYstruct) e->ET = Type_toCtype(se->type); } @@ -4581,7 +4582,7 @@ elem *toElem(Expression *e, IRState *irs) elem *einit = resolveLengthVar(ie->lengthVar, &n1, t1); elem *n2 = toElem(ie->e2, irs); - if (irs->arrayBoundsCheck() && !ie->skipboundscheck) + if (irs->arrayBoundsCheck() && !ie->indexIsInBounds) { elem *elength; diff --git a/src/expression.c b/src/expression.c index 0a8ec8a426a4..0a097daf68b0 100644 --- a/src/expression.c +++ b/src/expression.c @@ -9737,6 +9737,8 @@ SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) this->upr = upr; this->lwr = lwr; lengthVar = NULL; + upperIsInBounds = false; + lowerIsLessThanUpper = false; } Expression *SliceExp::syntaxCopy() @@ -9977,6 +9979,38 @@ Expression *SliceExp::semantic(Scope *sc) if (type->equals(t1b)) type = e1->type; + if (lwr && upr) + { + lwr = lwr->optimize(WANTvalue); + upr = upr->optimize(WANTvalue); + + IntRange lwrRange = getIntRange(lwr); + IntRange uprRange = getIntRange(upr); + + if (t1b->ty == Tsarray || t1b->ty == Tarray) + { + Expression *el = new ArrayLengthExp(loc, e1); + el = el->semantic(sc); + el = el->optimize(WANTvalue); + if (el->op == TOKint64) + { + dinteger_t length = el->toInteger(); + IntRange bounds(SignExtendedNumber(0), SignExtendedNumber(length)); + this->upperIsInBounds = bounds.contains(uprRange); + } + } + else if (t1b->ty == Tpointer) + { + this->upperIsInBounds = true; + } + else + assert(0); + + this->lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin); + + //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", upperIsInBounds, lowerIsLessThanUpper); + } + return this; } @@ -10390,7 +10424,7 @@ IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) //printf("IndexExp::IndexExp('%s')\n", toChars()); lengthVar = NULL; modifiable = false; // assume it is an rvalue - skipboundscheck = 0; + indexIsInBounds = false; } Expression *IndexExp::syntaxCopy() @@ -10573,7 +10607,10 @@ Expression *IndexExp::semantic(Scope *sc) e2 = e2->optimize(WANTvalue); dinteger_t length = el->toInteger(); if (length) - skipboundscheck = IntRange(SignExtendedNumber(0), SignExtendedNumber(length-1)).contains(getIntRange(e2)); + { + IntRange bounds(SignExtendedNumber(0), SignExtendedNumber(length - 1)); + indexIsInBounds = bounds.contains(getIntRange(e2)); + } } } diff --git a/src/expression.h b/src/expression.h index cee56fd8b13f..173547886f25 100644 --- a/src/expression.h +++ b/src/expression.h @@ -1008,6 +1008,8 @@ class SliceExp : public UnaExp Expression *upr; // NULL if implicit 0 Expression *lwr; // NULL if implicit [length - 1] VarDeclaration *lengthVar; + bool upperIsInBounds; // true if upr <= e1.length + bool lowerIsLessThanUpper; // true if lwr <= upr SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); Expression *syntaxCopy(); @@ -1110,7 +1112,7 @@ class IndexExp : public BinExp public: VarDeclaration *lengthVar; bool modifiable; - bool skipboundscheck; + bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1 IndexExp(Loc loc, Expression *e1, Expression *e2); Expression *syntaxCopy(); diff --git a/test/runnable/testbounds.d b/test/runnable/testbounds.d index 3ae9013daff8..de031b90b291 100644 --- a/test/runnable/testbounds.d +++ b/test/runnable/testbounds.d @@ -176,11 +176,49 @@ void test1() assert(r[0] == foop[1]); } +/******************************************/ +// 13976 + +void test13976() +{ + int[] da = new int[](10); + int[10] sa; + size_t l = 0; // upperInRange + size_t u = 9; // | lowerLessThan + // | | check code + { auto s = da[l .. u]; } // 0 0 (u <= 10 && l <= u ) + { auto s = da[1 .. u]; } // 0 0 (u <= 10 && l <= u ) + { auto s = da[l .. 10]; } // 0 0 (u <= 10 && l <= u ) + { auto s = da[1 .. u%5]; } // 0 0 (u <= 10 && l <= u%5) + + { auto s = da[l .. u]; } // 0 0 (u <= 10 && l <= u) + { auto s = da[0 .. u]; } // 0 1 (u <= 10 ) + { auto s = da[l .. 10]; } // 0 0 (u <= 10 && l <= u) + { auto s = da[0 .. u%5]; } // 0 1 (u%5 <= 10 ) + + { auto s = sa[l .. u]; } // 0 0 (u <= 10 && l <= u ) + { auto s = sa[1 .. u]; } // 0 0 (u <= 10 && l <= u ) + { auto s = sa[l .. 10]; } // 1 0 ( l <= u ) + { auto s = sa[1 .. u%5]; } // 1 0 ( l <= u%5) + + { auto s = sa[l .. u]; } // 0 0 (u <= 10 && l <= u ) + { auto s = sa[0 .. u]; } // 0 1 (u <= 10 ) + { auto s = sa[l .. 10]; } // 1 0 ( l <= 10) + { auto s = sa[0 .. u%5]; } // 1 1 NULL + + int* p = new int[](10).ptr; + { auto s = p[0 .. u]; } // 1 1 NULL + { auto s = p[l .. u]; } // 1 0 (l <= u) + { auto s = p[0 .. u%5]; } // 1 1 NULL + { auto s = p[1 .. u%5]; } // 1 0 (l <= u%5) +} + /******************************************/ int main() { test1(); + test13976(); printf("Success\n"); return 0;