diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index b9ba50c1f3b5..18f412ba14a3 100644 --- a/src/dmd/expressionsem.d +++ b/src/dmd/expressionsem.d @@ -5724,10 +5724,21 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor el = el.optimize(WANTvalue); if (el.op == TOK.int64) { + // Array length is known at compile-time. Upper is in bounds if it fits length. dinteger_t length = el.toInteger(); auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length)); exp.upperIsInBounds = bounds.contains(uprRange); } + else if (exp.upr.op == TOK.int64 && exp.upr.toInteger() == 0) + { + // Upper slice expression is '0'. Value is always in bounds. + exp.upperIsInBounds = true; + } + else if (exp.upr.op == TOK.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar) + { + // Upper slice expression is '$'. Value is always in bounds. + exp.upperIsInBounds = true; + } } else if (t1b.ty == Tpointer) { diff --git a/test/runnable/testbounds.d b/test/runnable/testbounds.d index 2deb8902793a..7c6cdbe9b512 100644 --- a/test/runnable/testbounds.d +++ b/test/runnable/testbounds.d @@ -200,12 +200,12 @@ void test13976() { 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]; } // 0 1 (0 <= $ ) - { auto s = da[0 .. $]; } // 0 1 ($ <= $ ) - { auto s = da[1 .. $]; } // 0 0 ($ <= $ && 1 <= $ ) - { auto s = da[$ .. $]; } // 0 0 ($ <= $ && $ <= $ ) + { 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 .. $]; } // 0 0 ($ <= $ && $/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 )