@@ -1,4 +1,4 @@
-5220ad51eebe06754e6881d9bd5aab89dba2b065
+e2fe2687b817a201528abaa3aa882333e04db01b
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
@@ -446,13 +446,13 @@ UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2)
if (n2 == -1 && !type->isunsigned())
{
// Check for int.min / -1
- if ((dinteger_t)n1 == 0xFFFFFFFF80000000UL && type->toBasetype()->ty != Tint64)
+ if ((dinteger_t)n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64)
{
e2->error("integer overflow: int.min / -1");
new(&ue) ErrorExp();
return ue;
}
- else if ((dinteger_t)n1 == 0x8000000000000000L) // long.min / -1
+ else if ((dinteger_t)n1 == 0x8000000000000000LL) // long.min / -1
{
e2->error("integer overflow: long.min / -1");
new(&ue) ErrorExp();
@@ -986,6 +986,19 @@ MATCH implicitConvTo(Expression *e, Type *t)
visit((Expression *)e);
}
+ void visit(AndExp *e)
+ {
+ visit((Expression *)e);
+ if (result != MATCHnomatch)
+ return;
+
+ MATCH m1 = e->e1->implicitConvTo(t);
+ MATCH m2 = e->e2->implicitConvTo(t);
+
+ // Pick the worst match
+ result = (m1 < m2) ? m1 : m2;
+ }
+
void visit(OrExp *e)
{
visit((Expression *)e);
@@ -3381,74 +3394,6 @@ IntRange getIntRange(Expression *e)
{
class IntRangeVisitor : public Visitor
{
- private:
- static uinteger_t getMask(uinteger_t v)
- {
- // Ref: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- v |= v >> 32;
- return v;
- }
-
- // The algorithms for &, |, ^ are not yet the best! Sometimes they will produce
- // not the tightest bound. See
- // https://github.com/D-Programming-Language/dmd/pull/116
- // for detail.
- static IntRange unsignedBitwiseAnd(const IntRange& a, const IntRange& b)
- {
- // the DiffMasks stores the mask of bits which are variable in the range.
- uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
- uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
- // Since '&' computes the digitwise-minimum, the we could set all varying
- // digits to 0 to get a lower bound, and set all varying digits to 1 to get
- // an upper bound.
- IntRange result;
- result.imin.value = (a.imin.value & ~aDiffMask) & (b.imin.value & ~bDiffMask);
- result.imax.value = (a.imax.value | aDiffMask) & (b.imax.value | bDiffMask);
- // Sometimes the upper bound is overestimated. The upper bound will never
- // exceed the input.
- if (result.imax.value > a.imax.value)
- result.imax.value = a.imax.value;
- if (result.imax.value > b.imax.value)
- result.imax.value = b.imax.value;
- result.imin.negative = result.imax.negative = a.imin.negative && b.imin.negative;
- return result;
- }
- static IntRange unsignedBitwiseOr(const IntRange& a, const IntRange& b)
- {
- // the DiffMasks stores the mask of bits which are variable in the range.
- uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
- uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
- // The imax algorithm by Adam D. Ruppe.
- // http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=108796
- IntRange result;
- result.imin.value = (a.imin.value & ~aDiffMask) | (b.imin.value & ~bDiffMask);
- result.imax.value = a.imax.value | b.imax.value | getMask(a.imax.value & b.imax.value);
- // Sometimes the lower bound is underestimated. The lower bound will never
- // less than the input.
- if (result.imin.value < a.imin.value)
- result.imin.value = a.imin.value;
- if (result.imin.value < b.imin.value)
- result.imin.value = b.imin.value;
- result.imin.negative = result.imax.negative = a.imin.negative || b.imin.negative;
- return result;
- }
- static IntRange unsignedBitwiseXor(const IntRange& a, const IntRange& b)
- {
- // the DiffMasks stores the mask of bits which are variable in the range.
- uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
- uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
- IntRange result;
- result.imin.value = (a.imin.value ^ b.imin.value) & ~(aDiffMask | bDiffMask);
- result.imax.value = (a.imax.value ^ b.imax.value) | (aDiffMask | bDiffMask);
- result.imin.negative = result.imax.negative = a.imin.negative != b.imin.negative;
- return result;
- }
-
public:
IntRange range;
@@ -3471,14 +3416,14 @@ IntRange getIntRange(Expression *e)
{
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
- range = IntRange(ir1.imin + ir2.imin, ir1.imax + ir2.imax).cast(e->type);
+ range = (ir1 + ir2).cast(e->type);
}
void visit(MinExp *e)
{
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
- range = IntRange(ir1.imin - ir2.imax, ir1.imax - ir2.imin).cast(e->type);
+ range = (ir1 - ir2).cast(e->type);
}
void visit(DivExp *e)
@@ -3486,20 +3431,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
- // Should we ignore the possibility of div-by-0???
- if (ir2.containsZero())
- {
- visit((Expression *)e);
- return;
- }
-
- // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
- SignExtendedNumber bdy[4];
- bdy[0] = ir1.imin / ir2.imin;
- bdy[1] = ir1.imin / ir2.imax;
- bdy[2] = ir1.imax / ir2.imin;
- bdy[3] = ir1.imax / ir2.imax;
- range = IntRange::fromNumbers4(bdy).cast(e->type);
+ range = (ir1 / ir2).cast(e->type);
}
void visit(MulExp *e)
@@ -3507,107 +3439,38 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
- // [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
- SignExtendedNumber bdy[4];
- bdy[0] = ir1.imin * ir2.imin;
- bdy[1] = ir1.imin * ir2.imax;
- bdy[2] = ir1.imax * ir2.imin;
- bdy[3] = ir1.imax * ir2.imax;
- range = IntRange::fromNumbers4(bdy).cast(e->type);
+ range = (ir1 * ir2).cast(e->type);
}
void visit(ModExp *e)
{
- IntRange irNum = getIntRange(e->e1);
- IntRange irDen = getIntRange(e->e2).absNeg();
-
- /*
- due to the rules of D (C)'s % operator, we need to consider the cases
- separately in different range of signs.
-
- case 1. [500, 1700] % [7, 23] (numerator is always positive)
- = [0, 22]
- case 2. [-500, 1700] % [7, 23] (numerator can be negative)
- = [-22, 22]
- case 3. [-1700, -500] % [7, 23] (numerator is always negative)
- = [-22, 0]
-
- the number 22 is the maximum absolute value in the denomator's range. We
- don't care about divide by zero.
- */
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
// Modding on 0 is invalid anyway.
- if (!irDen.imin.negative)
+ if (!ir2.absNeg().imin.negative)
{
visit((Expression *)e);
return;
}
-
- ++ irDen.imin;
- irDen.imax = -irDen.imin;
-
- if (!irNum.imin.negative)
- irNum.imin.value = 0;
- else if (irNum.imin < irDen.imin)
- irNum.imin = irDen.imin;
-
- if (irNum.imax.negative)
- {
- irNum.imax.negative = false;
- irNum.imax.value = 0;
- }
- else if (irNum.imax > irDen.imax)
- irNum.imax = irDen.imax;
-
- range = irNum.cast(e->type);
+ range = (ir1 % ir2).cast(e->type);
}
void visit(AndExp *e)
{
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
-
- IntRange ir1neg, ir1pos, ir2neg, ir2pos;
- bool has1neg, has1pos, has2neg, has2pos;
-
- ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
- ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
-
IntRange result;
bool hasResult = false;
- if (has1pos && has2pos)
- result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2pos), hasResult);
- if (has1pos && has2neg)
- result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2neg), hasResult);
- if (has1neg && has2pos)
- result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2pos), hasResult);
- if (has1neg && has2neg)
- result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2neg), hasResult);
+ result.unionOrAssign(getIntRange(e->e1) & getIntRange(e->e2), hasResult);
+
assert(hasResult);
range = result.cast(e->type);
}
void visit(OrExp *e)
{
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
-
- IntRange ir1neg, ir1pos, ir2neg, ir2pos;
- bool has1neg, has1pos, has2neg, has2pos;
-
- ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
- ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
-
IntRange result;
bool hasResult = false;
- if (has1pos && has2pos)
- result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2pos), hasResult);
- if (has1pos && has2neg)
- result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2neg), hasResult);
- if (has1neg && has2pos)
- result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2pos), hasResult);
- if (has1neg && has2neg)
- result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2neg), hasResult);
+ result.unionOrAssign(getIntRange(e->e1) | getIntRange(e->e2), hasResult);
assert(hasResult);
range = result.cast(e->type);
@@ -3615,25 +3478,9 @@ IntRange getIntRange(Expression *e)
void visit(XorExp *e)
{
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
-
- IntRange ir1neg, ir1pos, ir2neg, ir2pos;
- bool has1neg, has1pos, has2neg, has2pos;
-
- ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
- ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
-
IntRange result;
bool hasResult = false;
- if (has1pos && has2pos)
- result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2pos), hasResult);
- if (has1pos && has2neg)
- result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2neg), hasResult);
- if (has1neg && has2pos)
- result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2pos), hasResult);
- if (has1neg && has2neg)
- result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2neg), hasResult);
+ result.unionOrAssign(getIntRange(e->e1) ^ getIntRange(e->e2), hasResult);
assert(hasResult);
range = result.cast(e->type);
@@ -3644,13 +3491,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
- if (ir2.imin.negative)
- ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
-
- SignExtendedNumber lower = ir1.imin << (ir1.imin.negative ? ir2.imax : ir2.imin);
- SignExtendedNumber upper = ir1.imax << (ir1.imax.negative ? ir2.imin : ir2.imax);
-
- range = IntRange(lower, upper).cast(e->type);
+ range = (ir1 << ir2).cast(e->type);
}
void visit(ShrExp *e)
@@ -3658,13 +3499,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1);
IntRange ir2 = getIntRange(e->e2);
- if (ir2.imin.negative)
- ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
-
- SignExtendedNumber lower = ir1.imin >> (ir1.imin.negative ? ir2.imin : ir2.imax);
- SignExtendedNumber upper = ir1.imax >> (ir1.imax.negative ? ir2.imax : ir2.imin);
-
- range = IntRange(lower, upper).cast(e->type);
+ range = (ir1 >> ir2).cast(e->type);
}
void visit(UshrExp *e)
@@ -3672,10 +3507,7 @@ IntRange getIntRange(Expression *e)
IntRange ir1 = getIntRange(e->e1).castUnsigned(e->e1->type);
IntRange ir2 = getIntRange(e->e2);
- if (ir2.imin.negative)
- ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
-
- range = IntRange(ir1.imin >> ir2.imax, ir1.imax >> ir2.imin).cast(e->type);
+ range = (ir1 >> ir2).cast(e->type);
}
void visit(AssignExp *e)
@@ -3719,7 +3551,7 @@ IntRange getIntRange(Expression *e)
void visit(NegExp *e)
{
IntRange ir = getIntRange(e->e1);
- range = IntRange(-ir.imax, -ir.imin).cast(e->type);
+ range = (-ir).cast(e->type);
}
};
@@ -1191,12 +1191,12 @@ void ScopeDsymbol::importScope(Dsymbol *s, Prot protection)
static void bitArraySet(BitArray *array, size_t idx)
{
- array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] |= 1 << (idx & (sizeof(size_t) * CHAR_BIT - 1));
+ array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] |= 1ULL << (idx & (sizeof(size_t) * CHAR_BIT - 1));
}
static bool bitArrayGet(BitArray *array, size_t idx)
{
- return (array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] & (1 << (idx & (sizeof(size_t) * CHAR_BIT - 1)))) != 0;
+ return (array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] & (1ULL << (idx & (sizeof(size_t) * CHAR_BIT - 1)))) != 0;
}
static void bitArrayLength(BitArray *array, size_t len)
@@ -54,6 +54,26 @@ SignExtendedNumber SignExtendedNumber::max()
return SignExtendedNumber(UINT64_MAX, false);
}
+SignExtendedNumber& SignExtendedNumber::operator++()
+{
+ if (value != UINT64_MAX)
+ ++value;
+ else if (negative)
+ {
+ value = 0;
+ negative = false;
+ }
+ return *this;
+}
+
+SignExtendedNumber SignExtendedNumber::operator~() const
+{
+ if (~value == 0)
+ return SignExtendedNumber(~value);
+ else
+ return SignExtendedNumber(~value, !negative);
+}
+
SignExtendedNumber SignExtendedNumber::operator-() const
{
if (value == 0)
@@ -62,11 +82,26 @@ SignExtendedNumber SignExtendedNumber::operator-() const
return SignExtendedNumber(-value, !negative);
}
-SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) const
+SignExtendedNumber SignExtendedNumber::operator&(const SignExtendedNumber& rhs) const
{
- uinteger_t sum = value + a.value;
- bool carry = sum < value && sum < a.value;
- if (negative != a.negative)
+ return SignExtendedNumber(value & rhs.value);
+}
+
+SignExtendedNumber SignExtendedNumber::operator|(const SignExtendedNumber& rhs) const
+{
+ return SignExtendedNumber(value | rhs.value);
+}
+
+SignExtendedNumber SignExtendedNumber::operator^(const SignExtendedNumber& rhs) const
+{
+ return SignExtendedNumber(value ^ rhs.value);
+}
+
+SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& rhs) const
+{
+ uinteger_t sum = value + rhs.value;
+ bool carry = sum < value && sum < rhs.value;
+ if (negative != rhs.negative)
return SignExtendedNumber(sum, !carry);
else if (negative)
return SignExtendedNumber(carry ? sum : 0, true);
@@ -74,16 +109,15 @@ SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) co
return SignExtendedNumber(carry ? UINT64_MAX : sum, false);
}
-SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& a) const
+SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& rhs) const
{
- if (a.isMinimum())
+ if (rhs.isMinimum())
return negative ? SignExtendedNumber(value, false) : max();
else
- return *this + (-a);
+ return *this + (-rhs);
}
-
-SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) const
+SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& rhs) const
{
// perform *saturated* multiplication, otherwise we may get bogus ranges
// like 0x10 * 0x10 == 0x100 == 0.
@@ -98,19 +132,19 @@ SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) co
{
if (!negative)
return *this;
- else if (a.negative)
+ else if (rhs.negative)
return max();
else
- return a.value == 0 ? a : *this;
+ return rhs.value == 0 ? rhs : *this;
}
- else if (a.value == 0)
- return a * *this; // don't duplicate the symmetric case.
+ else if (rhs.value == 0)
+ return rhs * *this; // don't duplicate the symmetric case.
SignExtendedNumber rv;
// these are != 0 now surely.
uinteger_t tAbs = copySign(value, negative);
- uinteger_t aAbs = copySign(a.value, a.negative);
- rv.negative = negative != a.negative;
+ uinteger_t aAbs = copySign(rhs.value, rhs.negative);
+ rv.negative = negative != rhs.negative;
if (UINT64_MAX / tAbs < aAbs)
rv.value = rv.negative-1;
else
@@ -118,7 +152,7 @@ SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) co
return rv;
}
-SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) const
+SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& rhs) const
{
/* special handling for zeros:
INT65_MIN / INT65_MIN = 1
@@ -126,15 +160,15 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co
+ / 0 = INT65_MAX (eh?)
- / 0 = INT65_MIN (eh?)
*/
- if (a.value == 0)
+ if (rhs.value == 0)
{
- if (a.negative)
+ if (rhs.negative)
return SignExtendedNumber(value == 0 && negative);
else
return extreme(negative);
}
- uinteger_t aAbs = copySign(a.value, a.negative);
+ uinteger_t aAbs = copySign(rhs.value, rhs.negative);
uinteger_t rvVal;
if (!isMinimum())
@@ -147,7 +181,7 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co
else
{
if (aAbs == 1)
- return extreme(!a.negative);
+ return extreme(!rhs.negative);
rvVal = 1ULL << 63;
aAbs >>= 1;
if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1;
@@ -157,18 +191,18 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co
if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16;
if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32;
}
- bool rvNeg = negative != a.negative;
+ bool rvNeg = negative != rhs.negative;
rvVal = copySign(rvVal, rvNeg);
return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg);
}
-SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) const
+SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& rhs) const
{
- if (a.value == 0)
- return !a.negative ? a : isMinimum() ? SignExtendedNumber(0) : *this;
+ if (rhs.value == 0)
+ return !rhs.negative ? rhs : isMinimum() ? SignExtendedNumber(0) : *this;
- uinteger_t aAbs = copySign(a.value, a.negative);
+ uinteger_t aAbs = copySign(rhs.value, rhs.negative);
uinteger_t rvVal;
// a % b == sgn(a) * abs(a) % abs(b).
@@ -186,25 +220,13 @@ SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) co
return SignExtendedNumber(rvVal, rvVal != 0 && negative);
}
-SignExtendedNumber& SignExtendedNumber::operator++()
-{
- if (value != UINT64_MAX)
- ++ value;
- else if (negative)
- {
- value = 0;
- negative = false;
- }
- return *this;
-}
-
-SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) const
+SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& rhs) const
{
// assume left-shift the shift-amount is always unsigned. Thus negative
// shifts will give huge result.
if (value == 0)
return *this;
- else if (a.negative)
+ else if (rhs.negative)
return extreme(negative);
uinteger_t v = copySign(value, negative);
@@ -223,21 +245,21 @@ SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) c
r |= (v >> 1);
uinteger_t allowableShift = 63 - r;
- if (a.value > allowableShift)
+ if (rhs.value > allowableShift)
return extreme(negative);
else
- return SignExtendedNumber(value << a.value, negative);
+ return SignExtendedNumber(value << rhs.value, negative);
}
-SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& a) const
+SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& rhs) const
{
- if (a.negative || a.value > 64)
+ if (rhs.negative || rhs.value > 63)
return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
else if (isMinimum())
- return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (64-a.value), true);
+ return rhs.value == 0 ? *this : SignExtendedNumber(-1ULL << (64 - rhs.value), true);
uinteger_t x = value ^ -negative;
- x >>= a.value;
+ x >>= rhs.value;
return SignExtendedNumber(x ^ -negative, negative);
}
@@ -448,6 +470,364 @@ void IntRange::splitBySign(IntRange& negRange, bool& hasNegRange,
}
}
+IntRange IntRange::operator~() const
+{
+ return IntRange(~imax, ~imin);
+}
+
+IntRange IntRange::operator-() const
+{
+ return IntRange(-imax, -imin);
+}
+
+IntRange IntRange::operator&(const IntRange& rhs) const
+{
+ // unsigned or identical sign bits
+ if ((imin.negative ^ imax.negative) != 1 && (rhs.imin.negative ^ rhs.imax.negative) != 1)
+ {
+ return IntRange(minAnd(*this, rhs), maxAnd(*this, rhs));
+ }
+
+ IntRange l = IntRange(*this);
+ IntRange r = IntRange(rhs);
+
+ // both intervals span [-1,0]
+ if ((l.imin.negative ^ l.imax.negative) == 1 && (r.imin.negative ^ r.imax.negative) == 1)
+ {
+ // cannot be larger than either l.max or r.max, set the other one to -1
+ SignExtendedNumber max = l.imax.value > r.imax.value ? l.imax : r.imax;
+
+ // only negative numbers for minimum
+ l.imax.value = -1;
+ l.imax.negative = true;
+ r.imax.value = -1;
+ r.imax.negative = true;
+
+ return IntRange(minAnd(l, r), max);
+ }
+ else
+ {
+ // only one interval spans [-1,0]
+ if ((l.imin.negative ^ l.imax.negative) == 1)
+ {
+ swap(l, r); // r spans [-1,0]
+ }
+
+ SignExtendedNumber minAndNeg = minAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ SignExtendedNumber minAndPos = minAnd(l, IntRange(SignExtendedNumber(0), r.imax));
+ SignExtendedNumber maxAndNeg = maxAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ SignExtendedNumber maxAndPos = maxAnd(l, IntRange(SignExtendedNumber(0), r.imax));
+
+ SignExtendedNumber min = minAndNeg < minAndPos ? minAndNeg : minAndPos;
+ SignExtendedNumber max = maxAndNeg > maxAndPos ? maxAndNeg : maxAndPos;
+
+ return IntRange(min, max);
+ }
+}
+
+IntRange IntRange::operator|(const IntRange& rhs) const
+{
+ // unsigned or identical sign bits:
+ if ((imin.negative ^ imax.negative) == 0 && (rhs.imin.negative ^ rhs.imax.negative) == 0)
+ {
+ return IntRange(minOr(*this, rhs), maxOr(*this, rhs));
+ }
+
+ IntRange l = IntRange(*this);
+ IntRange r = IntRange(rhs);
+
+ // both intervals span [-1,0]
+ if ((l.imin.negative ^ l.imax.negative) == 1 && (r.imin.negative ^ r.imax.negative) == 1)
+ {
+ // cannot be smaller than either l.min or r.min, set the other one to 0
+ SignExtendedNumber min = l.imin.value < r.imin.value ? l.imin : r.imin;
+
+ // only negative numbers for minimum
+ l.imin.value = 0;
+ l.imin.negative = false;
+ r.imin.value = 0;
+ r.imin.negative = false;
+
+ return IntRange(min, maxOr(l, r));
+ }
+ else
+ {
+ // only one interval spans [-1,0]
+ if ((imin.negative ^ imax.negative) == 1)
+ {
+ swap(l, r); // r spans [-1,0]
+ }
+
+ SignExtendedNumber minOrNeg = minOr(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ SignExtendedNumber minOrPos = minOr(l, IntRange(SignExtendedNumber(0), r.imax));
+ SignExtendedNumber maxOrNeg = maxOr(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ SignExtendedNumber maxOrPos = maxOr(l, IntRange(SignExtendedNumber(0), r.imax));
+
+ SignExtendedNumber min = minOrNeg < minOrPos ? minOrNeg : minOrPos;
+ SignExtendedNumber max = maxOrNeg > maxOrPos ? maxOrNeg : maxOrPos;
+
+ return IntRange(min, max);
+ }
+}
+
+IntRange IntRange::operator^(const IntRange& rhs) const
+{
+ return (*this & (~rhs)) | (~(*this) & rhs);
+}
+
+IntRange IntRange::operator+(const IntRange& rhs) const
+{
+ return IntRange(imin + rhs.imin, imax + rhs.imax);
+}
+
+IntRange IntRange::operator-(const IntRange& rhs) const
+{
+ return IntRange(imin - rhs.imax, imax - rhs.imin);
+}
+
+IntRange IntRange::operator*(const IntRange& rhs) const
+{
+ // [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
+ SignExtendedNumber bdy[4];
+ bdy[0] = imin * rhs.imin;
+ bdy[1] = imin * rhs.imax;
+ bdy[2] = imax * rhs.imin;
+ bdy[3] = imax * rhs.imax;
+ return IntRange::fromNumbers4(bdy);
+}
+
+IntRange IntRange::operator/(const IntRange& rhs) const
+{
+ // Handle divide by 0
+ if (rhs.imax.value == 0 && rhs.imin.value == 0)
+ return widest();
+
+ IntRange r = IntRange(rhs);
+
+ // Don't treat the whole range as divide by 0 if only one end of a range is 0.
+ // Issue 15289
+ if (r.imax.value == 0)
+ {
+ r.imax.value--;
+ }
+ else if(r.imin.value == 0)
+ {
+ r.imin.value++;
+ }
+
+ if (!imin.negative && !imax.negative && !r.imin.negative && !r.imax.negative)
+ {
+ return IntRange(imin / r.imax, imax / r.imin);
+ }
+ else
+ {
+ // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
+ SignExtendedNumber bdy[4];
+ bdy[0] = imin / r.imin;
+ bdy[1] = imin / r.imax;
+ bdy[2] = imax / r.imin;
+ bdy[3] = imax / r.imax;
+
+ return IntRange::fromNumbers4(bdy);
+ }
+}
+
+IntRange IntRange::operator%(const IntRange& rhs) const
+{
+ IntRange irNum = *this;
+ IntRange irDen = rhs.absNeg();
+
+ /*
+ due to the rules of D (C)'s % operator, we need to consider the cases
+ separately in different range of signs.
+
+ case 1. [500, 1700] % [7, 23] (numerator is always positive)
+ = [0, 22]
+ case 2. [-500, 1700] % [7, 23] (numerator can be negative)
+ = [-22, 22]
+ case 3. [-1700, -500] % [7, 23] (numerator is always negative)
+ = [-22, 0]
+
+ the number 22 is the maximum absolute value in the denomator's range. We
+ don't care about divide by zero.
+ */
+
+ irDen.imin = irDen.imin + SignExtendedNumber(1);
+ irDen.imax = -irDen.imin;
+
+ if (!irNum.imin.negative)
+ {
+ irNum.imin.value = 0;
+ }
+ else if (irNum.imin < irDen.imin)
+ {
+ irNum.imin = irDen.imin;
+ }
+
+ if (irNum.imax.negative)
+ {
+ irNum.imax.negative = false;
+ irNum.imax.value = 0;
+ }
+ else if (irNum.imax > irDen.imax)
+ {
+ irNum.imax = irDen.imax;
+ }
+
+ return irNum;
+}
+
+IntRange IntRange::operator<<(const IntRange& rhs) const
+{
+ IntRange r = IntRange(rhs);
+ if (r.imin.negative)
+ {
+ r = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+ }
+
+ SignExtendedNumber lower = imin << (imin.negative ? r.imax : r.imin);
+ SignExtendedNumber upper = imax << (imax.negative ? r.imin : r.imax);
+
+ return IntRange(lower, upper);
+}
+
+IntRange IntRange::operator>>(const IntRange& rhs) const
+{
+ IntRange r = IntRange(rhs);
+ if (r.imin.negative)
+ {
+ r = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+ }
+
+ SignExtendedNumber lower = imin >> (imin.negative ? r.imin : r.imax);
+ SignExtendedNumber upper = imax >> (imax.negative ? r.imax : r.imin);
+
+ return IntRange(lower, upper);
+}
+
+SignExtendedNumber IntRange::maxOr(const IntRange& lhs, const IntRange& rhs)
+{
+ uinteger_t x = 0;
+ bool sign = false;
+ uinteger_t xorvalue = lhs.imax.value ^ rhs.imax.value;
+ uinteger_t andvalue = lhs.imax.value & rhs.imax.value;
+ IntRange lhsc = IntRange(lhs);
+ IntRange rhsc = IntRange(rhs);
+
+ // Sign bit not part of the .value so we need an extra iteration
+ if (lhsc.imax.negative ^ rhsc.imax.negative)
+ {
+ sign = true;
+ if (lhsc.imax.negative)
+ {
+ if (!lhsc.imin.negative)
+ {
+ lhsc.imin.value = 0;
+ }
+ if (!rhsc.imin.negative)
+ {
+ rhsc.imin.value = 0;
+ }
+ }
+ }
+ else if (lhsc.imin.negative & rhsc.imin.negative)
+ {
+ sign = true;
+ }
+ else if (lhsc.imax.negative & rhsc.imax.negative)
+ {
+ return SignExtendedNumber(-1, false);
+ }
+
+ for (uinteger_t d = 1ULL << (8 * sizeof(uinteger_t) - 1); d; d >>= 1)
+ {
+ if (xorvalue & d)
+ {
+ x |= d;
+ if (lhsc.imax.value & d)
+ {
+ if (~lhsc.imin.value & d)
+ {
+ lhsc.imin.value = 0;
+ }
+ }
+ else
+ {
+ if (~rhsc.imin.value & d)
+ {
+ rhsc.imin.value = 0;
+ }
+ }
+ }
+ else if (lhsc.imin.value & rhsc.imin.value & d)
+ {
+ x |= d;
+ }
+ else if (andvalue & d)
+ {
+ x |= (d << 1) - 1;
+ break;
+ }
+ }
+
+ return SignExtendedNumber(x, sign);
+}
+
+SignExtendedNumber IntRange::minOr(const IntRange& lhs, const IntRange& rhs)
+{
+ return ~maxAnd(~lhs, ~rhs);
+}
+
+SignExtendedNumber IntRange::maxAnd(const IntRange& lhs, const IntRange& rhs)
+{
+ uinteger_t x = 0;
+ bool sign = false;
+ IntRange lhsc = IntRange(lhs);
+ IntRange rhsc = IntRange(rhs);
+
+ if (lhsc.imax.negative & rhsc.imax.negative)
+ {
+ sign = true;
+ }
+
+ for (uinteger_t d = 1ULL << (8 * sizeof(uinteger_t) - 1); d; d >>= 1)
+ {
+ if (lhsc.imax.value & rhsc.imax.value & d)
+ {
+ x |= d;
+ if (~lhsc.imin.value & d)
+ {
+ lhsc.imin.value = 0;
+ }
+ if (~rhsc.imin.value & d)
+ {
+ rhsc.imin.value = 0;
+ }
+ }
+ else if (~lhsc.imin.value & d && lhsc.imax.value & d)
+ {
+ lhsc.imax.value |= d - 1;
+ }
+ else if (~rhsc.imin.value & d && rhsc.imax.value & d)
+ {
+ rhsc.imax.value |= d - 1;
+ }
+ }
+
+ return SignExtendedNumber(x, sign);
+}
+
+SignExtendedNumber IntRange::minAnd(const IntRange& lhs, const IntRange& rhs)
+{
+ return ~maxOr(~lhs, ~rhs);
+}
+
+void IntRange::swap(IntRange& a, IntRange& b)
+{
+ IntRange aux = a;
+ a = b;
+ b = aux;
+}
const IntRange& IntRange::dump(const char* funcName, Expression *e) const
{
@@ -60,13 +60,23 @@ struct SignExtendedNumber
bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); }
bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); }
+ /// Increase the sign-extended number by 1 (saturated).
+ SignExtendedNumber& operator++();
+ /// Compute the saturated complement of a sign-extended number.
+ SignExtendedNumber operator~() const;
/// Compute the saturated negation of a sign-extended number.
SignExtendedNumber operator-() const;
+ /// Compute the saturated binary and of two sign-extended number.
+ SignExtendedNumber operator&(const SignExtendedNumber&) const;
+ /// Compute the saturated binary or of two sign-extended number.
+ SignExtendedNumber operator|(const SignExtendedNumber&) const;
+ /// Compute the saturated binary xor of two sign-extended number.
+ SignExtendedNumber operator^(const SignExtendedNumber&) const;
/// Compute the saturated sum of two sign-extended number.
SignExtendedNumber operator+(const SignExtendedNumber&) const;
/// Compute the saturated difference of two sign-extended number.
- SignExtendedNumber operator-(const SignExtendedNumber& a) const;
+ SignExtendedNumber operator-(const SignExtendedNumber&) const;
/// Compute the saturated product of two sign-extended number.
SignExtendedNumber operator*(const SignExtendedNumber&) const;
/// Compute the saturated quotient of two sign-extended number.
@@ -74,9 +84,6 @@ struct SignExtendedNumber
/// Compute the saturated modulus of two sign-extended number.
SignExtendedNumber operator%(const SignExtendedNumber&) const;
- /// Increase the sign-extended number by 1 (saturated).
- SignExtendedNumber& operator++();
-
/// Compute the saturated shifts of two sign-extended number.
SignExtendedNumber operator<<(const SignExtendedNumber&) const;
SignExtendedNumber operator>>(const SignExtendedNumber&) const;
@@ -146,4 +153,25 @@ struct IntRange
/// Split the range into two nonnegative- and negative-only subintervals.
void splitBySign(IntRange& negRange, bool& hasNegRange,
IntRange& nonNegRange, bool& hasNonNegRange) const;
+
+ /// Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
+ /// https://github.com/tgehr/d-compiler/blob/master/vrange.d
+ static SignExtendedNumber maxOr(const IntRange&, const IntRange&);
+ static SignExtendedNumber minOr(const IntRange&, const IntRange&);
+ static SignExtendedNumber maxAnd(const IntRange&, const IntRange&);
+ static SignExtendedNumber minAnd(const IntRange&, const IntRange&);
+ static void swap(IntRange&, IntRange&);
+
+ IntRange operator~() const;
+ IntRange operator-() const;
+ IntRange operator&(const IntRange&) const;
+ IntRange operator|(const IntRange&) const;
+ IntRange operator^(const IntRange&) const;
+ IntRange operator+(const IntRange&) const;
+ IntRange operator-(const IntRange&) const;
+ IntRange operator*(const IntRange&) const;
+ IntRange operator/(const IntRange&) const;
+ IntRange operator%(const IntRange&) const;
+ IntRange operator<<(const IntRange&) const;
+ IntRange operator>>(const IntRange&) const;
};
@@ -3832,6 +3832,7 @@ MATCH TypeVector::implicitConvTo(Type *to)
//printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
if (this == to)
return MATCHexact;
+#ifdef IN_GCC
if (to->ty == Tvector)
{
TypeVector *tv = (TypeVector *)to;
@@ -3848,6 +3849,10 @@ MATCH TypeVector::implicitConvTo(Type *to)
// Otherwise implicitly convertible only if basetypes are.
return basetype->implicitConvTo(tv->basetype);
}
+#else
+ if (ty == to->ty)
+ return MATCHconvert;
+#endif
return MATCHnomatch;
}
@@ -1,55 +1,80 @@
// PERMUTE_ARGS: -O -inline
// Test value-range propagation.
-// See Bug 3147, Bug 6000, Bug 5225.
+// https://issues.dlang.org/show_bug.cgi?id=3147
+// https://issues.dlang.org/show_bug.cgi?id=6000
+// https://issues.dlang.org/show_bug.cgi?id=5225
-void add() {
+void add()
+{
byte x, y;
short a = x + y;
}
-void leftShift() {
+void leftShift()
+{
byte x, y;
short z = x << 1;
}
-void leftShiftFail() {
- ubyte x, y;
- ushort z;
- static assert(!__traits(compiles, z = x << y));
- // 1 << 31 surely overflows the range of 'ushort'.
+void leftShiftFail()
+{
+ {
+ ubyte x, y;
+ ushort z;
+ static assert(!__traits(compiles, z = x << y));
+ // 1 << 31 surely overflows the range of 'ushort'.
+ }
+ {
+ ulong a, b;
+ int res;
+ static assert(!__traits(compiles, res = a << (b % 65U)));
+ }
}
-void rightShiftFail() {
- short x;
- byte y, z;
- static assert(!__traits(compiles, z = x >> y));
- // [this passes in 2.053.]
+void rightShiftFail()
+{
+ {
+ short x;
+ byte y, z;
+ static assert(!__traits(compiles, z = x >> y));
+ // [this passes in 2.053.]
+ }
+ {
+ ulong a, b;
+ int res;
+ static assert(!__traits(compiles, res = a >> (b % 65U)));
+ }
}
-void rightShift() {
+void rightShift()
+{
ushort x;
ubyte y = x >> 16;
}
-void unsignedRightShiftFail() {
+void unsignedRightShiftFail()
+{
int x;
ubyte y;
static assert(!__traits(compiles, y = x >>> 2));
// [this passes in 2.053.]
}
-void subtract() {
+void subtract()
+{
ubyte x, y;
short z = x - y;
}
-void multiply() {
+void multiply()
+{
byte x, y;
short z = x * y;
}
-void subMulFail() {
+void subMulFail()
+{
ubyte x, y;
ubyte z;
static assert(!__traits(compiles, z = x - y));
@@ -57,65 +82,82 @@ void subMulFail() {
// [these pass in 2.053.]
}
-void multiplyNeg1() {
+void multiplyNeg1()
+{
byte b;
b = -1 + (b * -1);
static assert(!__traits(compiles, b = -1 + b * ulong.max));
}
-void divide() {
+void divide()
+{
short w;
byte y = w / 300;
}
-void divideFail() {
+void divideFail()
+{
short w;
byte y;
static assert(!__traits(compiles, y = w / -1));
}
-void plus1Fail() {
+void plus1Fail()
+{
byte u, v;
static assert(!__traits(compiles, v = u + 1));
// [these pass in 2.053.]
}
-void modulus() {
+void modulus()
+{
int x;
byte u = x % 128;
}
-void modulus_bug6000a() {
+void modulus_bug6000a()
+{
ulong t;
uint u = t % 16;
}
-void modulus_bug6000b() {
+void modulus_bug6000b()
+{
long n = 10520;
ubyte b;
static assert(!__traits(compiles, b = n % 10));
}
-void modulus2() {
+void modulus2()
+{
short s;
byte b = byte.max;
byte c = s % b;
}
-void modulus3() {
+void modulus3()
+{
int i;
short s = short.max;
short t = i % s;
}
-void modulus4() {
+void modulus4()
+{
uint i;
ushort s;
short t;
static assert(!__traits(compiles, t = i % s));
}
-void modulusFail() {
+void modulus5()
+{
+ short a;
+ byte foo = (a - short.max - 1) % 127;
+}
+
+void modulusFail()
+{
int i;
short s;
byte b;
@@ -124,7 +166,8 @@ void modulusFail() {
// [these pass in 2.053.]
}
-void bitwise() {
+void bitwise()
+{
ubyte a, b, c;
uint d;
c = a & b;
@@ -134,56 +177,159 @@ void bitwise() {
// [these pass in 2.053.]
}
-void bitAnd() {
+void bitAnd()
+{
byte c;
int d;
c = (0x3ff_ffffU << (0&c)) & (0x4000_0000U << (0&c));
// the result of the above is always 0 :).
}
-void bitOrFail() {
- ubyte c;
- static assert(!__traits(compiles, c = c | 0x100));
- // [this passes in 2.053.]
+void bitAndTest()
+{
+ {
+ ushort a, b;
+ byte res = ((a % 7) - 6) & ((b % 7) - 6);
+ }
+ {
+ // rhs[-128..127] outside range of lhs[0..255]
+ // -> calls byte.implicitConvTo(ubyte) => MATCH.convert
+ byte a, b;
+ ubyte res;
+
+ res = cast(byte)(a + 5) & b;
+ res = cast(byte)(a - 5) & b;
+ res = cast(byte)(a / 5) & b;
+ res = cast(byte)(a * 5) & b;
+ res = cast(byte)(a % 5) & b;
+ }
+}
+
+void bitOrFail()
+{
+ {
+ ubyte c;
+ static assert(!__traits(compiles, c = c | 0x100));
+ // [this passes in 2.053.]
+ }
+ {
+ byte a, b;
+ ubyte res;
+
+ static assert(!__traits(compiles, res = (a + 5) | b)); // [-128..255]
+ static assert(!__traits(compiles, res = (a - 5) | b)); // [-133..127]
+ static assert(!__traits(compiles, res = (a / 5) | b)); // [-128..127]
+ static assert(!__traits(compiles, res = (a * 5) | b)); // [-640..639]
+ static assert(!__traits(compiles, res = (a % 5) | b)); // [-128..127]
+ }
}
-void bitAndOr() {
+void bitAndOr()
+{
ubyte c;
c = (c | 0x1000) & ~0x1000;
}
-void bitAndFail() {
- int d;
- short s;
- byte c;
- static assert(!__traits(compiles, c = d & s));
- static assert(!__traits(compiles, c = d & 256));
- // [these pass in 2.053.]
+void bitOrTest()
+{
+ {
+ // Tests condition for different signs between min & max
+ // ((imin.negative ^ imax.negative) == 1 && (rhs.imin.negative ^ rhs.imax.negative) == 1
+ ushort a, b;
+ byte res = ((a % 127) - 126) | ((b % 6) - 5);
+ }
+ {
+ // rhs[-128..127] outside range of lhs[0..255]
+ // -> calls byte.implicitConvTo(ubyte) => MATCH.convert
+ byte a, b, c;
+ ubyte res;
+
+ res = cast(byte)(a + 5) | b;
+ res = cast(byte)(a - 5) | b;
+ res = cast(byte)(a / 5) | b;
+ res = cast(byte)(a * 5) | b;
+ res = cast(byte)(a % 5) | b;
+ }
}
-void bitXor() {
- ushort s;
- ubyte c;
- c = (0xffff << (s&0)) ^ 0xff00;
+void bitAndFail()
+{
+ {
+ int d;
+ short s;
+ byte c;
+ static assert(!__traits(compiles, c = d & s));
+ static assert(!__traits(compiles, c = d & 256));
+ // [these pass in 2.053.]
+ }
+ {
+ byte a, b;
+ ubyte res;
+
+ static assert(!__traits(compiles, res = (a + 5) & b)); // [-128..132]
+ static assert(!__traits(compiles, res = (a - 5) & b)); // [-256..127]
+ static assert(!__traits(compiles, res = (a / 5) & b)); // [-128..127]
+ static assert(!__traits(compiles, res = (a * 5) & b)); // [-640..635]
+ static assert(!__traits(compiles, res = (a % 5) & b)); // [-128..127]
+ }
+}
+
+void bitXor()
+{
+ {
+ ushort s;
+ ubyte c;
+ c = (0xffff << (s & 0)) ^ 0xff00;
+ }
+ {
+ // rhs[-128..127] outside range of lhs[0..255]
+ // -> calls byte.implicitConvTo(ubyte) => MATCH.convert
+ byte a, b, c;
+ ubyte res;
+
+ res = cast(byte)(a + 5) ^ b;
+ res = cast(byte)(a - 5) ^ b;
+ res = cast(byte)(a / 5) ^ b;
+ res = cast(byte)(a * 5) ^ b;
+ res = cast(byte)(a % 5) ^ b;
+ }
}
-void bitComplement() {
+void bitXorFail()
+{
+ {
+ byte a, b;
+ ubyte res;
+
+ static assert(!__traits(compiles, res = (a + 5) ^ b)); // [-256..255]
+ static assert(!__traits(compiles, res = (a - 5) ^ b)); // [-256..255]
+ static assert(!__traits(compiles, res = (a / 5) ^ b)); // [-128..127]
+ static assert(!__traits(compiles, res = (a * 5) ^ b)); // [-640..1023]
+ static assert(!__traits(compiles, res = (a % 5) ^ b)); // [-128..127]
+ }
+}
+
+void bitComplement()
+{
int i;
ubyte b = ~(i | ~0xff);
}
-void bitComplementFail() {
+void bitComplementFail()
+{
ubyte b;
static assert(!__traits(compiles, b = ~(b | 1)));
// [this passes in 2.053.]
}
-void negation() {
+void negation()
+{
int x;
byte b = -(x & 0x7);
}
-void negationFail() {
+void negationFail()
+{
int x;
byte b;
static assert(!__traits(compiles, b = -(x & 255)));
@@ -200,7 +346,8 @@ short bug1977_comment5(byte i) {
return o;
}
-void testDchar() {
+void testDchar()
+{
dchar d;
uint i;
/+
@@ -210,13 +357,15 @@ void testDchar() {
d = i % 0x110000;
}
-void bug1977_comment11() {
+void bug1977_comment11()
+{
uint a;
byte b = a & 1;
// [this passes in 2.053.]
}
-void bug1977_comment20() {
+void bug1977_comment20()
+{
long a;
int b = a % 1000;
}
@@ -329,3 +478,32 @@ void test13001(bool unknown)
static assert(!__traits(compiles, b = i + 254));
}
}
+
+void test10310()
+{
+ int y;
+ ubyte x = ((y & 252) ^ 2) + 1;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=15289
+void test15289a()
+{
+ int [] arr = [1, 2, 3, 4];
+ uint foo = 50 / arr.length;
+}
+
+void test15289b()
+{
+ int [] arr = [1, 2, 3, 4];
+ uint foo = 50 % arr.length;
+}
+
+void testShiftRightOnNegative()
+{
+ int neg = -1;
+ uint[] arr = [1, 2, 3];
+ ubyte b;
+ // Shift with negative value returns value in range [0, ulong.max]
+ static assert(!__traits(compiles, b = arr.length >> neg));
+ static assert(!__traits(compiles, b = arr.length << neg));
+}