1
0
forked from aniani/vim

patch 8.2.5004: right shift on negative number does not work as documented

Problem:    Right shift on negative number does not work as documented.
Solution:   Use a uvarnumber_T type cast.
This commit is contained in:
Bram Moolenaar 2022-05-22 20:16:32 +01:00
parent a061f34191
commit 338bf58eba
7 changed files with 26 additions and 19 deletions

View File

@ -1138,9 +1138,10 @@ expr6 >> expr6 bitwise right shift *expr->>*
*E1282* *E1283*
The "<<" and ">>" operators can be used to perform bitwise left or right shift
of the left operand by the number of bits specified by the right operand. The
operands must be positive numbers. The topmost bit (sign bit) is always
cleared for ">>". If the right operand (shift amount) is more than the
maximum number of bits in a number (|v:numbersize|) the result is zero.
operands are used as positive numbers. When shifting right with ">>" the
topmost bit (somtimes called the sign bit) is cleared. If the right operand
(shift amount) is more than the maximum number of bits in a number
(|v:numbersize|) the result is zero.
expr6 and expr7 *expr6* *expr7* *E1036* *E1051*
@ -1417,6 +1418,10 @@ number number constant *expr-number*
Decimal, Hexadecimal (starting with 0x or 0X), Binary (starting with 0b or 0B)
and Octal (starting with 0, 0o or 0O).
Assuming 64 bit numbers are used (see |v:numbersize|) an unsigned number is
truncated to 0x7fffffffffffffff or 9223372036854775807. You can use -1 to get
0xffffffffffffffff.
*floating-point-format*
Floating point numbers can be written in two forms:

View File

@ -2002,6 +2002,7 @@ vim_str2nr(
}
else
{
// prevent a larg unsigned number to become negative
if (un > VARNUM_MAX)
un = VARNUM_MAX;
*nptr = (varnumber_T)un;

View File

@ -3091,12 +3091,8 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
rettv->vval.v_number =
rettv->vval.v_number << var2.vval.v_number;
else
{
rettv->vval.v_number =
rettv->vval.v_number >> var2.vval.v_number;
// clear the topmost sign bit
rettv->vval.v_number &= ~((uvarnumber_T)1 << MAX_LSHIFT_BITS);
}
(uvarnumber_T)rettv->vval.v_number >> var2.vval.v_number;
}
clear_tv(&var2);

View File

@ -958,6 +958,8 @@ func Test_bitwise_shift()
call assert_equal(0, 0 >> 4)
call assert_equal(0, 999999 >> 100)
call assert_equal(0, 999999 << 100)
call assert_equal(-1, -1 >> 0)
call assert_equal(-1, -1 << 0)
VAR a = 8
VAR b = 2
call assert_equal(2, a >> b)
@ -976,6 +978,15 @@ func Test_bitwise_shift()
for i in range(0, v:numbersize - 2)
LET val = and(val, invert(1 << i))
endfor
#" -1 has all the bits set
call assert_equal(-2, -1 << 1)
call assert_equal(-4, -1 << 2)
call assert_equal(-8, -1 << 3)
if v:numbersize == 64
call assert_equal(0x7fffffffffffffff, -1 >> 1)
call assert_equal(0x3fffffffffffffff, -1 >> 2)
call assert_equal(0x1fffffffffffffff, -1 >> 3)
endif
call assert_equal(0, val)
#" multiple operators
call assert_equal(16, 1 << 2 << 2)

View File

@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
5004,
/**/
5003,
/**/

View File

@ -4096,12 +4096,7 @@ exec_instructions(ectx_T *ectx)
case EXPR_RSHIFT: if (arg2 > MAX_LSHIFT_BITS)
res = 0;
else
{
res = arg1 >> arg2;
// clear the topmost sign bit
res &= ~((uvarnumber_T)1
<< MAX_LSHIFT_BITS);
}
res = (uvarnumber_T)arg1 >> arg2;
break;
default: break;
}

View File

@ -2719,11 +2719,8 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
else if (type == EXPR_LSHIFT)
tv1->vval.v_number = tv1->vval.v_number << tv2->vval.v_number;
else
{
tv1->vval.v_number = tv1->vval.v_number >> tv2->vval.v_number;
// clear the topmost sign bit
tv1->vval.v_number &= ~((uvarnumber_T)1 << MAX_LSHIFT_BITS);
}
tv1->vval.v_number =
(uvarnumber_T)tv1->vval.v_number >> tv2->vval.v_number;
clear_tv(tv2);
--ppconst->pp_used;
}