From a5839aa4af8ee70992238f8d4795f260138ff325 Mon Sep 17 00:00:00 2001 From: Jose Mendoza <56417208+StunxFS@users.noreply.github.com> Date: Fri, 8 Nov 2024 03:15:28 -0400 Subject: [PATCH] checker: skip redundant message for int overflows, while casting integer literals (fix #22761) (#22788) --- vlib/v/checker/checker.v | 80 ++++++++++--------- vlib/v/checker/str.v | 3 + .../tests/cast_integer_with_overflow_err.out | 7 -- 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index e3034529c..d079301b1 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -61,42 +61,43 @@ pub mut: error_details []string should_abort bool // when too many errors/warnings/notices are accumulated, .should_abort becomes true. It is checked in statement/expression loops, so the checker can return early, instead of wasting time. - expected_type ast.Type - expected_or_type ast.Type // fn() or { 'this type' } eg. string. expected or block type - expected_expr_type ast.Type // if/match is_expr: expected_type - mod string // current module name - const_var &ast.ConstField = unsafe { nil } // the current constant, when checking const declarations - const_deps []string - const_names []string - global_names []string - locked_names []string // vars that are currently locked - rlocked_names []string // vars that are currently read-locked - in_for_count int // if checker is currently in a for loop - returns bool - scope_returns bool - is_builtin_mod bool // true inside the 'builtin', 'os' or 'strconv' modules; TODO: remove the need for special casing this - is_just_builtin_mod bool // true only inside 'builtin' - is_generated bool // true for `@[generated] module xyz` .v files - inside_unsafe bool // true inside `unsafe {}` blocks - inside_const bool // true inside `const ( ... )` blocks - inside_anon_fn bool // true inside `fn() { ... }()` - inside_lambda bool // true inside `|...| ...` - inside_ref_lit bool // true inside `a := &something` - inside_defer bool // true inside `defer {}` blocks - inside_return bool // true inside `return ...` blocks - inside_fn_arg bool // `a`, `b` in `a.f(b)` - inside_ct_attr bool // true inside `[if expr]` - inside_x_is_type bool // true inside the Type expression of `if x is Type {` - inside_generic_struct_init bool - cur_struct_generic_types []ast.Type - cur_struct_concrete_types []ast.Type - skip_flags bool // should `#flag` and `#include` be skipped - fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc - smartcast_mut_pos token.Pos // match mut foo, if mut foo is Foo - smartcast_cond_pos token.Pos // match cond - ct_cond_stack []ast.Expr - ct_user_defines map[string]ComptimeBranchSkipState - ct_system_defines map[string]ComptimeBranchSkipState + expected_type ast.Type + expected_or_type ast.Type // fn() or { 'this type' } eg. string. expected or block type + expected_expr_type ast.Type // if/match is_expr: expected_type + mod string // current module name + const_var &ast.ConstField = unsafe { nil } // the current constant, when checking const declarations + const_deps []string + const_names []string + global_names []string + locked_names []string // vars that are currently locked + rlocked_names []string // vars that are currently read-locked + in_for_count int // if checker is currently in a for loop + returns bool + scope_returns bool + is_builtin_mod bool // true inside the 'builtin', 'os' or 'strconv' modules; TODO: remove the need for special casing this + is_just_builtin_mod bool // true only inside 'builtin' + is_generated bool // true for `@[generated] module xyz` .v files + inside_unsafe bool // true inside `unsafe {}` blocks + inside_const bool // true inside `const ( ... )` blocks + inside_anon_fn bool // true inside `fn() { ... }()` + inside_lambda bool // true inside `|...| ...` + inside_ref_lit bool // true inside `a := &something` + inside_defer bool // true inside `defer {}` blocks + inside_return bool // true inside `return ...` blocks + inside_fn_arg bool // `a`, `b` in `a.f(b)` + inside_ct_attr bool // true inside `[if expr]` + inside_x_is_type bool // true inside the Type expression of `if x is Type {` + inside_generic_struct_init bool + inside_integer_literal_cast bool // true inside `int(123)` + cur_struct_generic_types []ast.Type + cur_struct_concrete_types []ast.Type + skip_flags bool // should `#flag` and `#include` be skipped + fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc + smartcast_mut_pos token.Pos // match mut foo, if mut foo is Foo + smartcast_cond_pos token.Pos // match cond + ct_cond_stack []ast.Expr + ct_user_defines map[string]ComptimeBranchSkipState + ct_system_defines map[string]ComptimeBranchSkipState mut: stmt_level int // the nesting level inside each stmts list; // .stmt_level is used to check for `evaluated but not used` ExprStmts like `1 << 1` @@ -185,6 +186,7 @@ fn (mut c Checker) reset_checker_state_at_start_of_new_file() { c.inside_fn_arg = false c.inside_ct_attr = false c.inside_x_is_type = false + c.inside_integer_literal_cast = false c.skip_flags = false c.fn_level = 0 c.expr_level = 0 @@ -3206,7 +3208,12 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { // Given: `Outside( Inside(xyz) )`, // node.expr_type: `Inside` // node.typ: `Outside` + mut to_type := c.unwrap_generic(node.typ) + + old_inside_integer_literal_cast := c.inside_integer_literal_cast + c.inside_integer_literal_cast = to_type.is_int() && node.expr is ast.IntegerLiteral node.expr_type = c.expr(mut node.expr) // type to be casted + c.inside_integer_literal_cast = old_inside_integer_literal_cast if mut node.expr is ast.ComptimeSelector { node.expr_type = c.comptime.get_comptime_selector_type(node.expr, node.expr_type) @@ -3217,7 +3224,6 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { from_sym := c.table.sym(from_type) final_from_sym := c.table.final_sym(from_type) - mut to_type := c.unwrap_generic(node.typ) mut to_sym := c.table.sym(to_type) // type to be used as cast mut final_to_sym := c.table.final_sym(to_type) final_to_type := if mut to_sym.info is ast.Alias { diff --git a/vlib/v/checker/str.v b/vlib/v/checker/str.v index c4d781cc3..4bb5edd7c 100644 --- a/vlib/v/checker/str.v +++ b/vlib/v/checker/str.v @@ -229,5 +229,8 @@ fn (mut c Checker) check_num_literal(lohi LoHiLimit, is_neg bool, lit string) ! } fn (mut c Checker) num_lit_overflow_error(node &ast.IntegerLiteral) { + if c.inside_integer_literal_cast { + return + } c.error('integer literal ${node.val} overflows int', node.pos) } diff --git a/vlib/v/checker/tests/cast_integer_with_overflow_err.out b/vlib/v/checker/tests/cast_integer_with_overflow_err.out index 482a31124..eeb4db1a4 100644 --- a/vlib/v/checker/tests/cast_integer_with_overflow_err.out +++ b/vlib/v/checker/tests/cast_integer_with_overflow_err.out @@ -18,13 +18,6 @@ vlib/v/checker/tests/cast_integer_with_overflow_err.vv:6:7: error: value `300000 | ~~~~~~~~~~~~~~~~~~~~ 7 | _ = c 8 | d := u64(300_000_000_000_000_000_000) -vlib/v/checker/tests/cast_integer_with_overflow_err.vv:8:17: error: integer literal 300000000000000000000 overflows int - 6 | c := u32(300_000_000_000) - 7 | _ = c - 8 | d := u64(300_000_000_000_000_000_000) - | ~~~~~~~~~~~~~~~~~~~~~ - 9 | _ = d - 10 | } vlib/v/checker/tests/cast_integer_with_overflow_err.vv:8:7: error: value `300000000000000000000` overflows `u64` 6 | c := u32(300_000_000_000) 7 | _ = c -- 2.39.5