mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	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:
		| @@ -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: | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -734,6 +734,8 @@ static char *(features[]) = | ||||
|  | ||||
| static int included_patches[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     5004, | ||||
| /**/ | ||||
|     5003, | ||||
| /**/ | ||||
|   | ||||
| @@ -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; | ||||
| 		    } | ||||
|   | ||||
| @@ -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; | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user