Bug 23618 – Right Shift equals expressions on unsigned shorts should be unsigned right shift
Status
RESOLVED
Resolution
FIXED
Severity
blocker
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2023-01-11T03:15:08Z
Last change time
2023-01-14T14:39:45Z
Keywords
backend, pull
Assigned to
No Owner
Creator
mhh
Comments
Comment #0 by maxhaton — 2023-01-11T03:15:08Z
unittest {
const ushort tru = 1028;
ushort ee = tru;
ee <<= 5U;
ee >>= 5U;
assert(((tru << 5U) >> 5U) == ee);
}
Seems similar to regression 3583 from 2009
Comment #1 by ibuclaw — 2023-01-14T00:07:10Z
Only affects dmd.
Comment #2 by bugzilla — 2023-01-14T06:50:59Z
The issue comes up because (ee >>= 5) is done as a signed right shift, even though ee is an unsigned type.
Step by step:
https://dlang.org/spec/expression.html#assignment_operator_expressions says:
a op= b
are semantically equivalent to:
a = cast(typeof(a))(a op b)
so, (ee >>= 5) is rewritten to:
ee = cast(ushort)(ee >> b);
https://dlang.org/spec/expression.html#shift_expressions says:
the operands undergo integral promotions
ee = cast(ushort)(cast(int)ee >> b)
or:
ee = cast(ushort)((ee & 0x0000_FFFF) >> b)
then:
>> is a signed right shift
but the sign bit is 0, so it is, in effect, an unsigned right shift. The compiler generates a signed right shift, though.
Comment #3 by salihdb — 2023-01-14T07:12:26Z
The problem is also seen when the sign extension is not done.
Here is the test code:
struct TestType(T)
{
import std.traits : Unsigned;
alias U = Unsigned!T;
T t = T.min; // sample: -128 for byte
U u = U.max/2 + 1; // sample: 128 for ubyte
}
void main()
{
alias T = long; // int, short, byte
TestType!T v1, v2;
enum bits = T.sizeof * 8 - 1;
v1.t >>= bits;
assert(v1.t == -1); // okay, because signed type
v1.u >>= bits;
assert(v1.u == 1); // okay, because unsigned type
v2.t >>>= bits;
assert(v2.t == 1); /* okay, no sign extension
but -1 for byte, short, int */
v2.u >>>= bits;
assert(v2.u == 1); // okay, no sign extension
}
SDB@79
Comment #4 by dlang-bot — 2023-01-14T07:28:36Z
@WalterBright created dlang/dmd pull request #14814 "fix Issue 23618 - Right Shift equals expressions on unsigned shorts s…" fixing this issue:
- fix Issue 23618 - Right Shift equals expressions on unsigned shorts should be unsigned right shift
https://github.com/dlang/dmd/pull/14814
Comment #5 by dlang-bot — 2023-01-14T12:18:43Z
dlang/dmd pull request #14814 "fix Issue 23618 - Right Shift equals expressions on unsigned shorts s…" was merged into stable:
- 1a7eebc1a52954a56173f098ee5128bfbfe6b746 by Walter Bright:
fix Issue 23618 - Right Shift equals expressions on unsigned shorts should be unsigned right shift
https://github.com/dlang/dmd/pull/14814
Comment #6 by dlang-bot — 2023-01-14T14:39:45Z
dlang/dmd pull request #14815 "Merge stable" was merged into master:
- 579c97ab66ddc2c6a8f3db177937bb4c94353120 by Walter Bright:
fix Issue 23618 - Right Shift equals expressions on unsigned shorts should be unsigned right shift (#14814)
https://github.com/dlang/dmd/pull/14815