Commit 9d7d33ac by Iain Buclaw

Merge dmd upstream e2fe2687b

Backports VRP fixes from the D front-end implementation to the C++ port,
and fixes errors reported by ubsan build where the conversion from D
didn't include adjusting integer suffixes from 'UL' to 'ULL'.

Fixes https://gcc.gnu.org/PR88366

Reviewed-on: https://github.com/dlang/dmd/pull/9046

From-SVN: r266925
parent 5d62bfc3
5220ad51eebe06754e6881d9bd5aab89dba2b065 e2fe2687b817a201528abaa3aa882333e04db01b
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository. merge done from the dlang/dmd repository.
...@@ -446,13 +446,13 @@ UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2) ...@@ -446,13 +446,13 @@ UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2)
if (n2 == -1 && !type->isunsigned()) if (n2 == -1 && !type->isunsigned())
{ {
// Check for int.min / -1 // 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"); e2->error("integer overflow: int.min / -1");
new(&ue) ErrorExp(); new(&ue) ErrorExp();
return ue; 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"); e2->error("integer overflow: long.min / -1");
new(&ue) ErrorExp(); new(&ue) ErrorExp();
......
...@@ -1191,12 +1191,12 @@ void ScopeDsymbol::importScope(Dsymbol *s, Prot protection) ...@@ -1191,12 +1191,12 @@ void ScopeDsymbol::importScope(Dsymbol *s, Prot protection)
static void bitArraySet(BitArray *array, size_t idx) 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) 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) static void bitArrayLength(BitArray *array, size_t len)
......
...@@ -60,13 +60,23 @@ struct SignExtendedNumber ...@@ -60,13 +60,23 @@ struct SignExtendedNumber
bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); } bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); }
bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); } 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. /// Compute the saturated negation of a sign-extended number.
SignExtendedNumber operator-() const; 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. /// Compute the saturated sum of two sign-extended number.
SignExtendedNumber operator+(const SignExtendedNumber&) const; SignExtendedNumber operator+(const SignExtendedNumber&) const;
/// Compute the saturated difference of two sign-extended number. /// 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. /// Compute the saturated product of two sign-extended number.
SignExtendedNumber operator*(const SignExtendedNumber&) const; SignExtendedNumber operator*(const SignExtendedNumber&) const;
/// Compute the saturated quotient of two sign-extended number. /// Compute the saturated quotient of two sign-extended number.
...@@ -74,9 +84,6 @@ struct SignExtendedNumber ...@@ -74,9 +84,6 @@ struct SignExtendedNumber
/// Compute the saturated modulus of two sign-extended number. /// Compute the saturated modulus of two sign-extended number.
SignExtendedNumber operator%(const SignExtendedNumber&) const; SignExtendedNumber operator%(const SignExtendedNumber&) const;
/// Increase the sign-extended number by 1 (saturated).
SignExtendedNumber& operator++();
/// Compute the saturated shifts of two sign-extended number. /// Compute the saturated shifts of two sign-extended number.
SignExtendedNumber operator<<(const SignExtendedNumber&) const; SignExtendedNumber operator<<(const SignExtendedNumber&) const;
SignExtendedNumber operator>>(const SignExtendedNumber&) const; SignExtendedNumber operator>>(const SignExtendedNumber&) const;
...@@ -146,4 +153,25 @@ struct IntRange ...@@ -146,4 +153,25 @@ struct IntRange
/// Split the range into two nonnegative- and negative-only subintervals. /// Split the range into two nonnegative- and negative-only subintervals.
void splitBySign(IntRange& negRange, bool& hasNegRange, void splitBySign(IntRange& negRange, bool& hasNegRange,
IntRange& nonNegRange, bool& hasNonNegRange) const; 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) ...@@ -3832,6 +3832,7 @@ MATCH TypeVector::implicitConvTo(Type *to)
//printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars()); //printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
if (this == to) if (this == to)
return MATCHexact; return MATCHexact;
#ifdef IN_GCC
if (to->ty == Tvector) if (to->ty == Tvector)
{ {
TypeVector *tv = (TypeVector *)to; TypeVector *tv = (TypeVector *)to;
...@@ -3848,6 +3849,10 @@ MATCH TypeVector::implicitConvTo(Type *to) ...@@ -3848,6 +3849,10 @@ MATCH TypeVector::implicitConvTo(Type *to)
// Otherwise implicitly convertible only if basetypes are. // Otherwise implicitly convertible only if basetypes are.
return basetype->implicitConvTo(tv->basetype); return basetype->implicitConvTo(tv->basetype);
} }
#else
if (ty == to->ty)
return MATCHconvert;
#endif
return MATCHnomatch; return MATCHnomatch;
} }
......
// PERMUTE_ARGS: -O -inline // PERMUTE_ARGS: -O -inline
// Test value-range propagation. // 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; byte x, y;
short a = x + y; short a = x + y;
} }
void leftShift() { void leftShift()
{
byte x, y; byte x, y;
short z = x << 1; short z = x << 1;
} }
void leftShiftFail() { void leftShiftFail()
{
{
ubyte x, y; ubyte x, y;
ushort z; ushort z;
static assert(!__traits(compiles, z = x << y)); static assert(!__traits(compiles, z = x << y));
// 1 << 31 surely overflows the range of 'ushort'. // 1 << 31 surely overflows the range of 'ushort'.
}
{
ulong a, b;
int res;
static assert(!__traits(compiles, res = a << (b % 65U)));
}
} }
void rightShiftFail() { void rightShiftFail()
{
{
short x; short x;
byte y, z; byte y, z;
static assert(!__traits(compiles, z = x >> y)); static assert(!__traits(compiles, z = x >> y));
// [this passes in 2.053.] // [this passes in 2.053.]
}
{
ulong a, b;
int res;
static assert(!__traits(compiles, res = a >> (b % 65U)));
}
} }
void rightShift() { void rightShift()
{
ushort x; ushort x;
ubyte y = x >> 16; ubyte y = x >> 16;
} }
void unsignedRightShiftFail() { void unsignedRightShiftFail()
{
int x; int x;
ubyte y; ubyte y;
static assert(!__traits(compiles, y = x >>> 2)); static assert(!__traits(compiles, y = x >>> 2));
// [this passes in 2.053.] // [this passes in 2.053.]
} }
void subtract() { void subtract()
{
ubyte x, y; ubyte x, y;
short z = x - y; short z = x - y;
} }
void multiply() { void multiply()
{
byte x, y; byte x, y;
short z = x * y; short z = x * y;
} }
void subMulFail() { void subMulFail()
{
ubyte x, y; ubyte x, y;
ubyte z; ubyte z;
static assert(!__traits(compiles, z = x - y)); static assert(!__traits(compiles, z = x - y));
...@@ -57,65 +82,82 @@ void subMulFail() { ...@@ -57,65 +82,82 @@ void subMulFail() {
// [these pass in 2.053.] // [these pass in 2.053.]
} }
void multiplyNeg1() { void multiplyNeg1()
{
byte b; byte b;
b = -1 + (b * -1); b = -1 + (b * -1);
static assert(!__traits(compiles, b = -1 + b * ulong.max)); static assert(!__traits(compiles, b = -1 + b * ulong.max));
} }
void divide() { void divide()
{
short w; short w;
byte y = w / 300; byte y = w / 300;
} }
void divideFail() { void divideFail()
{
short w; short w;
byte y; byte y;
static assert(!__traits(compiles, y = w / -1)); static assert(!__traits(compiles, y = w / -1));
} }
void plus1Fail() { void plus1Fail()
{
byte u, v; byte u, v;
static assert(!__traits(compiles, v = u + 1)); static assert(!__traits(compiles, v = u + 1));
// [these pass in 2.053.] // [these pass in 2.053.]
} }
void modulus() { void modulus()
{
int x; int x;
byte u = x % 128; byte u = x % 128;
} }
void modulus_bug6000a() { void modulus_bug6000a()
{
ulong t; ulong t;
uint u = t % 16; uint u = t % 16;
} }
void modulus_bug6000b() { void modulus_bug6000b()
{
long n = 10520; long n = 10520;
ubyte b; ubyte b;
static assert(!__traits(compiles, b = n % 10)); static assert(!__traits(compiles, b = n % 10));
} }
void modulus2() { void modulus2()
{
short s; short s;
byte b = byte.max; byte b = byte.max;
byte c = s % b; byte c = s % b;
} }
void modulus3() { void modulus3()
{
int i; int i;
short s = short.max; short s = short.max;
short t = i % s; short t = i % s;
} }
void modulus4() { void modulus4()
{
uint i; uint i;
ushort s; ushort s;
short t; short t;
static assert(!__traits(compiles, t = i % s)); static assert(!__traits(compiles, t = i % s));
} }
void modulusFail() { void modulus5()
{
short a;
byte foo = (a - short.max - 1) % 127;
}
void modulusFail()
{
int i; int i;
short s; short s;
byte b; byte b;
...@@ -124,7 +166,8 @@ void modulusFail() { ...@@ -124,7 +166,8 @@ void modulusFail() {
// [these pass in 2.053.] // [these pass in 2.053.]
} }
void bitwise() { void bitwise()
{
ubyte a, b, c; ubyte a, b, c;
uint d; uint d;
c = a & b; c = a & b;
...@@ -134,56 +177,159 @@ void bitwise() { ...@@ -134,56 +177,159 @@ void bitwise() {
// [these pass in 2.053.] // [these pass in 2.053.]
} }
void bitAnd() { void bitAnd()
{
byte c; byte c;
int d; int d;
c = (0x3ff_ffffU << (0&c)) & (0x4000_0000U << (0&c)); c = (0x3ff_ffffU << (0&c)) & (0x4000_0000U << (0&c));
// the result of the above is always 0 :). // the result of the above is always 0 :).
} }
void bitOrFail() { 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; ubyte c;
static assert(!__traits(compiles, c = c | 0x100)); static assert(!__traits(compiles, c = c | 0x100));
// [this passes in 2.053.] // [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; ubyte c;
c = (c | 0x1000) & ~0x1000; c = (c | 0x1000) & ~0x1000;
} }
void bitAndFail() { 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 bitAndFail()
{
{
int d; int d;
short s; short s;
byte c; byte c;
static assert(!__traits(compiles, c = d & s)); static assert(!__traits(compiles, c = d & s));
static assert(!__traits(compiles, c = d & 256)); static assert(!__traits(compiles, c = d & 256));
// [these pass in 2.053.] // [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() { void bitXor()
{
{
ushort s; ushort s;
ubyte c; ubyte c;
c = (0xffff << (s&0)) ^ 0xff00; 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 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() { void bitComplement()
{
int i; int i;
ubyte b = ~(i | ~0xff); ubyte b = ~(i | ~0xff);
} }
void bitComplementFail() { void bitComplementFail()
{
ubyte b; ubyte b;
static assert(!__traits(compiles, b = ~(b | 1))); static assert(!__traits(compiles, b = ~(b | 1)));
// [this passes in 2.053.] // [this passes in 2.053.]
} }
void negation() { void negation()
{
int x; int x;
byte b = -(x & 0x7); byte b = -(x & 0x7);
} }
void negationFail() { void negationFail()
{
int x; int x;
byte b; byte b;
static assert(!__traits(compiles, b = -(x & 255))); static assert(!__traits(compiles, b = -(x & 255)));
...@@ -200,7 +346,8 @@ short bug1977_comment5(byte i) { ...@@ -200,7 +346,8 @@ short bug1977_comment5(byte i) {
return o; return o;
} }
void testDchar() { void testDchar()
{
dchar d; dchar d;
uint i; uint i;
/+ /+
...@@ -210,13 +357,15 @@ void testDchar() { ...@@ -210,13 +357,15 @@ void testDchar() {
d = i % 0x110000; d = i % 0x110000;
} }
void bug1977_comment11() { void bug1977_comment11()
{
uint a; uint a;
byte b = a & 1; byte b = a & 1;
// [this passes in 2.053.] // [this passes in 2.053.]
} }
void bug1977_comment20() { void bug1977_comment20()
{
long a; long a;
int b = a % 1000; int b = a % 1000;
} }
...@@ -329,3 +478,32 @@ void test13001(bool unknown) ...@@ -329,3 +478,32 @@ void test13001(bool unknown)
static assert(!__traits(compiles, b = i + 254)); 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));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment