Skip to content

Commit 59ec186

Browse files
authored
checker: add warning for fn f(x u8) {} f(999) (fix #26584) (fix #26585) (#26586)
1 parent edd4a71 commit 59ec186

9 files changed

Lines changed: 506 additions & 18 deletions

vlib/gg/color.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ pub mut:
122122
}
123123

124124
// hex takes in a 32 bit integer and splits it into 4 byte values
125-
pub fn hex(color i32) Color {
125+
pub fn hex(color u32) Color {
126126
return Color{
127127
r: u8((color >> 16) & 0xFF)
128128
g: u8((color >> 8) & 0xFF)
@@ -318,7 +318,7 @@ const string_colors = {
318318
pub fn color_from_string(s string) Color {
319319
if s.starts_with('#') {
320320
mut hex_str := '0x' + s[1..]
321-
return hex(hex_str.i32())
321+
return hex(hex_str.u32())
322322
} else {
323323
return string_colors[s]
324324
}

vlib/v/checker/check_types.v

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ fn (mut c Checker) check_expected_call_arg(got_ ast.Type, expected_ ast.Type, la
302302
expected_typ_str := c.table.type_to_str(expected.clear_flag(.variadic))
303303
return error('cannot use literal signed integer as `${expected_typ_str}`')
304304
}
305+
c.warn_if_integer_literal_overflow_for_known_type(expected, arg.expr, arg.pos)
305306

306307
idx_got := got.idx()
307308
idx_expected := expected.idx()
@@ -383,6 +384,73 @@ fn (mut c Checker) check_expected_call_arg(got_ ast.Type, expected_ ast.Type, la
383384
}
384385
}
385386

387+
fn (mut c Checker) warn_if_integer_literal_overflow_for_known_type(expected ast.Type, expr ast.Expr, pos token.Pos) {
388+
if !expected.is_int() {
389+
return
390+
}
391+
if expr !is ast.IntegerLiteral {
392+
return
393+
}
394+
int_lit := expr as ast.IntegerLiteral
395+
mut lit := int_lit.val.replace('_', '')
396+
if lit.len == 0 {
397+
return
398+
}
399+
is_negative := lit.starts_with('-')
400+
if is_negative || lit.starts_with('+') {
401+
lit = lit[1..]
402+
}
403+
if lit.len == 0 {
404+
return
405+
}
406+
literal_value := lit.u64()
407+
bits, _ := c.table.type_size(expected.idx_type())
408+
bit_size := bits * 8
409+
if bit_size == 0 {
410+
return
411+
}
412+
mut outside_type_range := false
413+
if expected.is_signed() {
414+
max_signed_i64 := if bit_size >= 64 {
415+
max_i64
416+
} else {
417+
i64((u64(1) << (bit_size - 1)) - 1)
418+
}
419+
min_signed := if bit_size >= 64 {
420+
min_i64
421+
} else {
422+
-max_signed_i64 - 1
423+
}
424+
max_signed := u64(max_signed_i64)
425+
if is_negative {
426+
min_negative_abs := if min_signed == min_i64 {
427+
u64(1) << 63
428+
} else {
429+
u64(-min_signed)
430+
}
431+
outside_type_range = literal_value > min_negative_abs
432+
} else {
433+
outside_type_range = literal_value > max_signed
434+
}
435+
} else {
436+
if is_negative {
437+
outside_type_range = true
438+
} else {
439+
max_unsigned := if bit_size >= 64 {
440+
max_u64
441+
} else {
442+
(u64(1) << bit_size) - 1
443+
}
444+
outside_type_range = literal_value > max_unsigned
445+
}
446+
}
447+
if outside_type_range {
448+
expected_type_str := c.table.type_to_str(expected.clear_flag(.variadic))
449+
c.warn('value `${int_lit.val}` is outside the range of `${expected_type_str}` in argument, this will be considered hard error soon',
450+
pos)
451+
}
452+
}
453+
386454
fn (c &Checker) get_string_names_of(got ast.Type, expected ast.Type) (string, string) {
387455
got_typ_str := c.table.type_to_str(got.clear_flag(.variadic))
388456
expected_typ_str := c.table.type_to_str(expected.clear_flag(.variadic))

vlib/v/checker/struct.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,8 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
782782
if exp_type_is_option && got_type.is_ptr() && !exp_type.is_ptr() {
783783
c.error('cannot assign a pointer to option struct field', init_field.pos)
784784
}
785+
c.warn_if_integer_literal_overflow_for_known_type(exp_type, init_field.expr,
786+
init_field.pos)
785787
if exp_type_sym.kind == .voidptr {
786788
if got_type_sym.kind == .struct && !got_type.is_ptr() {
787789
c.error('allocate `${got_type_sym.name}` on the heap for use in other functions',

vlib/v/checker/tests/number_literal_overflows_known_type_range_warn.out

Lines changed: 313 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
fn f_u8(a u8) {
2+
_ = a
3+
}
4+
5+
fn f_i8(a i8) {
6+
_ = a
7+
}
8+
9+
fn f_u16(a u16) {
10+
_ = a
11+
}
12+
13+
fn f_i16(a i16) {
14+
_ = a
15+
}
16+
17+
fn f_u32(a u32) {
18+
_ = a
19+
}
20+
21+
fn f_i32(a i32) {
22+
_ = a
23+
}
24+
25+
fn f_i64(a i64) {
26+
_ = a
27+
}
28+
29+
fn f_isize(a isize) {
30+
_ = a
31+
}
32+
33+
struct Sample {
34+
i16_over_max i16
35+
i16_under_min i16
36+
i32_over_max i32
37+
i32_under_min i32
38+
i64_over_max i64
39+
i64_under_min i64
40+
i8_over_max i8
41+
i8_under_min i8
42+
isize_over_max isize
43+
isize_under_min isize
44+
u16_over_max u16
45+
u32_over_max u32
46+
u8_over_max u8
47+
}
48+
49+
struct GenericSample[T] {
50+
field T
51+
}
52+
53+
fn main() {
54+
f_u8(256)
55+
f_i8(128)
56+
f_i8(-129)
57+
f_u16(65536)
58+
f_i16(32768)
59+
f_i16(-32769)
60+
f_u32(4294967296)
61+
f_i32(2147483648)
62+
f_i32(-2147483649)
63+
f_i64(9223372036854775808)
64+
f_i64(-9223372036854775809)
65+
f_isize(9223372036854775808)
66+
f_isize(-9223372036854775809)
67+
68+
_ := Sample{
69+
i16_over_max: 32768
70+
i16_under_min: -32769
71+
i32_over_max: 2147483648
72+
i32_under_min: -2147483649
73+
i64_over_max: 9223372036854775808
74+
i64_under_min: -9223372036854775809
75+
i8_over_max: 128
76+
i8_under_min: -129
77+
isize_over_max: 9223372036854775808
78+
isize_under_min: -9223372036854775809
79+
u16_over_max: 65536
80+
u32_over_max: 4294967296
81+
u8_over_max: 256
82+
}
83+
84+
_ := GenericSample[u8]{256}
85+
_ := GenericSample[u16]{65536}
86+
_ := GenericSample[u32]{4294967296}
87+
88+
_ := GenericSample[i8]{128}
89+
_ := GenericSample[i8]{-129}
90+
_ := GenericSample[i16]{32768}
91+
_ := GenericSample[i16]{-32769}
92+
_ := GenericSample[i32]{2147483648}
93+
_ := GenericSample[i32]{-2147483649}
94+
_ := GenericSample[i64]{9223372036854775808}
95+
_ := GenericSample[i64]{-9223372036854775809}
96+
_ := GenericSample[isize]{9223372036854775808}
97+
_ := GenericSample[isize]{-9223372036854775809}
98+
}

vlib/v/checker/tests/struct_field_unsign_type_check_err.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
vlib/v/checker/tests/struct_field_unsign_type_check_err.vv:8:3: warning: value `-1` is outside the range of `u32` in argument, this will be considered hard error soon
2+
6 | fn main() {
3+
7 | mut foo := Foo{
4+
8 | n: -1
5+
| ~~~~~
6+
9 | }
7+
10 |
18
vlib/v/checker/tests/struct_field_unsign_type_check_err.vv:3:10: error: cannot assign negative value to unsigned integer type
29
1 | struct Foo {
310
2 | mut:

vlib/v/gen/native/amd64.v

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,7 +2191,7 @@ pub fn (mut c Amd64) cg_call_fn(node ast.CallExpr) {
21912191
if is_floats[i] {
21922192
if args_size[i] == 8
21932193
&& node.expected_arg_types[int(i) + args_offset] == ast.f32_type_idx {
2194-
c.g.write32(0xc05a0ff2)
2194+
c.g.write32(i32(0xc05a0ff2))
21952195
c.g.println('cvtsd2ss xmm0, xmm0')
21962196
}
21972197
c.push_sse(.xmm0)
@@ -3000,7 +3000,7 @@ fn (mut c Amd64) cg_return_stmt(node ast.Return) {
30003000
typ := if node.types.len > 1 { c.g.return_type } else { node.types[0] }
30013001
if typ == ast.float_literal_type_idx && c.g.return_type == ast.f32_type_idx {
30023002
if c.g.pref.arch == .amd64 {
3003-
c.g.write32(0xc05a0ff2)
3003+
c.g.write32(i32(0xc05a0ff2))
30043004
c.g.println('cvtsd2ss xmm0, xmm0')
30053005
}
30063006
}
@@ -3485,7 +3485,7 @@ fn (mut c Amd64) fp_infix_expr(node ast.InfixExpr, left_type ast.Type) {
34853485
}
34863486
match node.op {
34873487
.eq, .ne {
3488-
c.g.write32(0xc1c20ff3)
3488+
c.g.write32(i32(0xc1c20ff3))
34893489
c.g.write8(if node.op == .eq { i32(0x00) } else { i32(0x04) })
34903490
inst := if node.op == .eq { 'cmpeqss' } else { 'cmpneqss' }
34913491
c.g.println('${inst} xmm0, xmm1')
@@ -3712,7 +3712,7 @@ fn (mut c Amd64) cg_infix_expr(node ast.InfixExpr) {
37123712
c.sub_reg(.rax, .rdx)
37133713
}
37143714
.mul {
3715-
c.g.write32(0xc2af0f48)
3715+
c.g.write32(i32(0xc2af0f48))
37163716
c.g.println('imul .rax, .rdx')
37173717
}
37183718
.div {
@@ -4871,11 +4871,11 @@ fn (mut c Amd64) cg_gen_cast_expr(expr ast.CastExpr) {
48714871
from_size := c.g.get_type_size(expr.expr_type)
48724872
to_size := c.g.get_type_size(expr.typ)
48734873
if from_size == 4 && to_size == 8 {
4874-
c.g.write32(0xc05a0ff3)
4874+
c.g.write32(i32(0xc05a0ff3))
48754875
c.g.println('cvtss2sd xmm0, xmm0')
48764876
}
48774877
if from_size == 8 && to_size == 4 {
4878-
c.g.write32(0xc05a0ff2)
4878+
c.g.write32(i32(0xc05a0ff2))
48794879
c.g.println('cvtsd2ss xmm0, xmm0')
48804880
}
48814881
} else if expr.typ.is_pure_float() {

vlib/v/gen/native/arm64.v

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,16 +277,16 @@ fn (mut c Arm64) adr(r Arm64Register, delta i32) {
277277

278278
fn (mut c Arm64) bl() {
279279
// g.write32(0xa9400000)
280-
c.g.write32(0x94000000)
280+
c.g.write32(i32(0x94000000))
281281
c.g.println('bl 0')
282282
}
283283

284284
fn (mut c Arm64) svc() {
285285
if c.g.pref.os == .linux {
286-
c.g.write32(0xd4001001)
286+
c.g.write32(i32(0xd4001001))
287287
c.g.println('svc 0x80')
288288
} else {
289-
c.g.write32(0xd4000001)
289+
c.g.write32(i32(0xd4000001))
290290
c.g.println('svc 0')
291291
}
292292
}
@@ -388,7 +388,7 @@ fn (mut c Arm64) cg_convert_rune_to_string(r Register, buffer i32, var Var, conf
388388
}
389389

390390
fn (mut c Arm64) cg_trap() {
391-
c.g.write32(0xcccccccc)
391+
c.g.write32(i32(0xcccccccc))
392392
c.g.println('trap')
393393
}
394394

@@ -397,7 +397,7 @@ fn (mut c Arm64) cg_leave() {
397397
}
398398

399399
fn (mut c Arm64) cg_ret() {
400-
c.g.write32(0xd65f03c0)
400+
c.g.write32(i32(0xd65f03c0))
401401
c.g.println('ret')
402402
}
403403

vlib/v/gen/native/macho.v

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,13 @@ fn (mut g Gen) macho_segment64_linkedit() {
104104
}
105105

106106
fn (mut g Gen) macho_header(ncmds i32, bintype i32) i32 {
107-
g.write32(0xfeedfacf) // MH_MAGIC_64
107+
g.write32(i32(0xfeedfacf)) // MH_MAGIC_64
108108
if g.pref.arch == .arm64 {
109109
g.write32(0x0100000c) // CPU_TYPE_ARM64
110110
g.write32(0x00000000) // CPU_SUBTYPE_ARM64_ALL
111111
} else {
112112
g.write32(0x01000007) // CPU_TYPE_X64
113-
g.write32(0x80000003) // CPU_SUBTYPE_X64
113+
g.write32(i32(0x80000003)) // CPU_SUBTYPE_X64
114114
}
115115
g.write32(mh_execute) // filetype
116116
g.write32(ncmds) // ncmds
@@ -163,7 +163,7 @@ fn (mut g Gen) macho_segment64_text() []i32 {
163163
if g.pref.arch == .amd64 {
164164
g.write32(0) // flags
165165
} else {
166-
g.write32(0x80000400) // flags
166+
g.write32(i32(0x80000400)) // flags
167167
}
168168
g.write32(0)
169169

@@ -273,11 +273,11 @@ fn (mut g Gen) write_nulls(len i32) {
273273

274274
pub fn (mut g Gen) generate_macho_object_header() {
275275
if g.pref.arch == .arm64 {
276-
g.write32(0xfeedfacf) // MH_MAGIC_64
276+
g.write32(i32(0xfeedfacf)) // MH_MAGIC_64
277277
g.write32(0x0100000c) // CPU_TYPE_ARM64
278278
g.write32(0) // CPU_SUBTYPE_ARM64_ALL
279279
} else {
280-
g.write32(0xfeedfacf) // MH_MAGIC_64
280+
g.write32(i32(0xfeedfacf)) // MH_MAGIC_64
281281
g.write32(0x01000007) // CPU_TYPE_X64
282282
g.write32(3) // CPU_SUBTYPE_X64
283283
}

0 commit comments

Comments
 (0)