1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: more precise error handling of large binary literals like 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000 (#16775)

This commit is contained in:
Delyan Angelov 2022-12-27 15:13:15 +02:00 committed by GitHub
parent 508bfbf892
commit a8f6f9ed60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 8 deletions

View File

@ -333,3 +333,20 @@ fn test_parse() {
assert u64(1) == '1'.parse_uint(10, 8) or { 0 }
assert u64(1) == '1'.parse_uint(16, 8) or { 0 }
}
fn test_interpolate_binary_literals() {
assert ' 1 ${i64(0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000)}' == ' 1 -9223372036854775808'
assert ' 2 ${i64(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111)}' == ' 2 -1'
assert ' 3 ${i64(0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111)}' == ' 3 9223372036854775807'
assert ' 4 ${u64(0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000)}' == ' 4 9223372036854775808'
assert ' 5 ${u64(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111)}' == ' 5 18446744073709551615'
assert ' 6 ${u64(0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111)}' == ' 6 9223372036854775807'
assert ' 7 ${u32(0b111_1111_1111_1111_1111)}' == ' 7 524287'
}
fn test_interpolate_literal_limits() {
assert ' 8 ${u32(2147483648)}' == ' 8 2147483648'
assert ' 9 ${u64(0xFF_FF_FF_FF_FF_FF_FF_FF)}' == ' 9 18446744073709551615'
assert '10 ${u32(0o377777_77777)}' == '10 4294967295'
assert '11 ${i64(-2147483647)}' == '11 -2147483647'
}

View File

@ -165,27 +165,56 @@ fn (mut c Checker) string_lit(mut node ast.StringLiteral) ast.Type {
return ast.string_type
}
struct LoHiLimit {
lower string
higher string
}
const iencoding_map = {
`B`: LoHiLimit{'1000000000000000000000000000000000000000000000000000000000000000', '1111111111111111111111111111111111111111111111111111111111111111'}
`O`: LoHiLimit{'1000000000000000000000', '1777777777777777777777'}
`_`: LoHiLimit{'9223372036854775808', '18446744073709551615'}
`X`: LoHiLimit{'8000000000000000', 'FFFFFFFFFFFFFFFF'}
}
fn (mut c Checker) int_lit(mut node ast.IntegerLiteral) ast.Type {
if node.val.len < 17 {
// can not be a too large number, no need for more expensive checks
return ast.int_literal_type
}
lit := node.val.replace('_', '').all_after('-')
lit := node.val.replace('_', '').all_after('-').to_upper()
is_neg := node.val.starts_with('-')
limit := if is_neg { '9223372036854775808' } else { '18446744073709551615' }
message := 'integer literal ${node.val} overflows int'
if lit.len > 2 && lit[0] == `0` && lit[1] in [`B`, `X`, `O`] {
if lohi := checker.iencoding_map[lit[1]] {
c.check_num_literal(lohi, is_neg, lit[2..]) or { c.num_lit_overflow_error(node) }
}
} else {
lohi := checker.iencoding_map[`_`]
c.check_num_literal(lohi, is_neg, lit) or { c.num_lit_overflow_error(node) }
}
return ast.int_literal_type
}
[direct_array_access]
fn (mut c Checker) check_num_literal(lohi LoHiLimit, is_neg bool, lit string) ! {
limit := if is_neg { lohi.lower } else { lohi.higher }
if lit.len < limit.len {
return
}
if lit.len > limit.len {
c.error(message, node.pos)
} else if lit.len == limit.len {
return error('length overflow')
}
if lit.len == limit.len {
for i, digit in lit {
if digit > limit[i] {
c.error(message, node.pos)
return error('value overflow at i: ${i}')
} else if digit < limit[i] {
break
}
}
}
return ast.int_literal_type
}
fn (mut c Checker) num_lit_overflow_error(node &ast.IntegerLiteral) {
c.error('integer literal ${node.val} overflows int', node.pos)
}