checker: disallow confusing smaller unsigned type == signed
Otherwise C will evaluate `byte(-1) == -1` as false. Also disallow unsigned == negative literal. Fixes #13955.pull/13967/head
parent
6425000ce4
commit
3be4e19bf9
|
|
@ -1937,7 +1937,7 @@ pub fn (name string) match_glob(pattern string) bool {
|
|||
mut is_inverted := false
|
||||
mut inner_match := false
|
||||
mut inner_idx := bstart + 1
|
||||
mut inner_c := 0
|
||||
mut inner_c := byte(0)
|
||||
if inner_idx < plen {
|
||||
inner_c = pattern[inner_idx]
|
||||
if inner_c == `^` {
|
||||
|
|
|
|||
|
|
@ -442,6 +442,8 @@ pub const (
|
|||
i64_type_idx, isize_type_idx]
|
||||
unsigned_integer_type_idxs = [byte_type_idx, u8_type_idx, u16_type_idx, u32_type_idx,
|
||||
u64_type_idx, usize_type_idx]
|
||||
// C will promote any type smaller than int to int in an expression
|
||||
int_promoted_type_idxs = [char_type_idx, i8_type_idx, i16_type_idx, byte_type_idx, u8_type_idx, u16_type_idx]
|
||||
float_type_idxs = [f32_type_idx, f64_type_idx, float_literal_type_idx]
|
||||
number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx,
|
||||
byte_type_idx, char_type_idx, u16_type_idx, u32_type_idx, u64_type_idx, isize_type_idx,
|
||||
|
|
|
|||
|
|
@ -623,6 +623,30 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||
if is_mismatch {
|
||||
c.error('possible type mismatch of compared values of `$node.op` operation',
|
||||
left_right_pos)
|
||||
} else if left_type in ast.integer_type_idxs && right_type in ast.integer_type_idxs {
|
||||
is_left_type_signed := left_type in ast.signed_integer_type_idxs
|
||||
is_right_type_signed := right_type in ast.signed_integer_type_idxs
|
||||
if !is_left_type_signed && mut node.right is ast.IntegerLiteral {
|
||||
if node.right.val.int() < 0 {
|
||||
lt := c.table.sym(left_type).name
|
||||
c.error('`$lt` cannot be compared with negative value',
|
||||
node.right.pos)
|
||||
}
|
||||
} else if !is_right_type_signed && mut node.left is ast.IntegerLiteral {
|
||||
if node.left.val.int() < 0 {
|
||||
rt := c.table.sym(right_type).name
|
||||
c.error('negative value cannot be compared with `$rt`',
|
||||
node.left.pos)
|
||||
}
|
||||
} else if is_left_type_signed != is_right_type_signed {
|
||||
// prevent e.g. `u16(-1) == int(-1)` which is false in C
|
||||
if (is_right_type_signed && left_type in ast.int_promoted_type_idxs) ||
|
||||
(is_left_type_signed && right_type in ast.int_promoted_type_idxs) {
|
||||
lt := c.table.sym(left_type).name
|
||||
rt := c.table.sym(right_type).name
|
||||
c.error('`$lt` cannot be compared with `$rt`', node.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.key_in, .not_in {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,35 @@ vlib/v/checker/tests/infix_unsigned_and_signed_int_err.vv:2:14: error: unsigned
|
|||
4 | }
|
||||
vlib/v/checker/tests/infix_unsigned_and_signed_int_err.vv:6:5: error: unsigned integer cannot be compared with negative value
|
||||
4 | }
|
||||
5 |
|
||||
5 |
|
||||
6 | if -1 > u32(1) {
|
||||
| ~~
|
||||
7 | println('unexpected')
|
||||
8 | }
|
||||
vlib/v/checker/tests/infix_unsigned_and_signed_int_err.vv:10:18: error: `byte` cannot be compared with negative value
|
||||
8 | }
|
||||
9 | // unsigned == literal
|
||||
10 | _ = byte(-1) == -1 // false!
|
||||
| ~~
|
||||
11 | _ = -1 == u16(-1) // false!
|
||||
12 |
|
||||
vlib/v/checker/tests/infix_unsigned_and_signed_int_err.vv:11:6: error: negative value cannot be compared with `u16`
|
||||
9 | // unsigned == literal
|
||||
10 | _ = byte(-1) == -1 // false!
|
||||
11 | _ = -1 == u16(-1) // false!
|
||||
| ~~
|
||||
12 |
|
||||
13 | // unsigned == signed
|
||||
vlib/v/checker/tests/infix_unsigned_and_signed_int_err.vv:14:14: error: `u16` cannot be compared with `int`
|
||||
12 |
|
||||
13 | // unsigned == signed
|
||||
14 | _ = u16(-1) == int(-1)
|
||||
| ~~
|
||||
15 | _ = int(-1) != byte(-1)
|
||||
16 | }
|
||||
vlib/v/checker/tests/infix_unsigned_and_signed_int_err.vv:15:14: error: `int` cannot be compared with `byte`
|
||||
13 | // unsigned == signed
|
||||
14 | _ = u16(-1) == int(-1)
|
||||
15 | _ = int(-1) != byte(-1)
|
||||
| ~~
|
||||
16 | }
|
||||
|
|
|
|||
|
|
@ -6,4 +6,11 @@ fn main() {
|
|||
if -1 > u32(1) {
|
||||
println('unexpected')
|
||||
}
|
||||
// unsigned == literal
|
||||
_ = byte(-1) == -1 // false!
|
||||
_ = -1 == u16(-1) // false!
|
||||
|
||||
// unsigned == signed
|
||||
_ = u16(-1) == int(-1)
|
||||
_ = int(-1) != byte(-1)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue