Skip to content

Commit fe5b069

Browse files
authored
parser,cgen: support a @[ignore_overflow] fn tag, cleanup cgen (#25470)
1 parent e5df2d5 commit fe5b069

File tree

9 files changed

+53
-19
lines changed

9 files changed

+53
-19
lines changed

vlib/v/ast/ast.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ pub:
600600
is_unsafe bool // true, when @[unsafe] is used on a fn
601601
is_must_use bool // true, when @[must_use] is used on a fn. Calls to such functions, that ignore the return value, will cause warnings.
602602
is_markused bool // true, when an explicit `@[markused]` tag was put on a fn; `-skip-unused` will not remove that fn
603+
is_ignore_overflow bool // true, when an explicit `@[ignore_overflow]` tag was put on a fn. `-check-overflow` will not generate checks for arithmetic done in that fn.
603604
is_file_translated bool // true, when the file it resides in is `@[translated]`
604605
is_closure bool // true, for actual closures like `fn [inherited] () {}` . It is false for normal anonymous functions, and for named functions/methods too.
605606
receiver StructField // TODO: this is not a struct field
@@ -621,7 +622,7 @@ pub:
621622
body_pos token.Pos // function bodys position
622623
file string
623624
generic_names []string
624-
is_direct_arr bool // direct array access
625+
is_direct_arr bool // @[direct_array_access] was used; a[i] inside such a fn, will *not* do array index bounds checks.
625626
attrs []Attr
626627
ctdefine_idx int = -1 // the index in fn.attrs of `[if xyz]`, when such attribute exists
627628
pub mut:

vlib/v/gen/c/assign.v

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -307,13 +307,10 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
307307
scope: unsafe { nil }
308308
}
309309
mut cur_indexexpr := -1
310-
is_safe_add_assign := node.op == .plus_assign && g.pref.is_check_overflow
311-
&& g.unwrap_generic(var_type).is_int() && !g.is_builtin_overflow_mod
312-
is_safe_sub_assign := node.op == .minus_assign && g.pref.is_check_overflow
313-
&& g.unwrap_generic(var_type).is_int() && !g.is_builtin_overflow_mod
314-
is_safe_mul_assign := node.op == .mult_assign && g.pref.is_check_overflow
315-
&& g.unwrap_generic(var_type).is_int() && !g.is_builtin_overflow_mod
316-
310+
consider_int_overflow := g.do_int_overflow_checks && g.unwrap_generic(var_type).is_int()
311+
is_safe_add_assign := node.op == .plus_assign && consider_int_overflow
312+
is_safe_sub_assign := node.op == .minus_assign && consider_int_overflow
313+
is_safe_mul_assign := node.op == .mult_assign && consider_int_overflow
317314
left_sym := g.table.sym(g.unwrap_generic(var_type))
318315
is_va_list = left_sym.language == .c && left_sym.name == 'C.va_list'
319316
if mut left is ast.Ident {

vlib/v/gen/c/cgen.v

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ mut:
282282
postinclude_nodes []&ast.HashStmtNode // allows hash stmts to go after all the rest of the code generation
283283
curr_comptime_node &ast.Expr = unsafe { nil } // current `$if` expr
284284
is_builtin_overflow_mod bool
285+
do_int_overflow_checks bool // outside a `@[ignore_overflow] fn abc() {}` or a function in `builtin.overflow`
285286
}
286287

287288
@[heap]
@@ -3916,8 +3917,8 @@ fn (mut g Gen) expr(node_ ast.Expr) {
39163917
if node.auto_locked != '' {
39173918
g.writeln('sync__RwMutex_lock(&${node.auto_locked}->mtx);')
39183919
}
3919-
is_safe_inc := node.op == .inc && g.pref.is_check_overflow && !g.is_builtin_overflow_mod
3920-
is_safe_dec := node.op == .dec && g.pref.is_check_overflow && !g.is_builtin_overflow_mod
3920+
is_safe_inc := g.do_int_overflow_checks && node.op == .inc
3921+
is_safe_dec := g.do_int_overflow_checks && node.op == .dec
39213922
g.inside_map_postfix = true
39223923
if node.is_c2v_prefix {
39233924
g.write(node.op.str())

vlib/v/gen/c/fn.v

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
8383
g.is_direct_array_access = prev_is_direct_array_access
8484
}
8585

86+
// handle `@[ignore_overflow] fn abc() {}` and -check-overflow :
87+
prev_do_int_overflow_checks := g.do_int_overflow_checks
88+
g.do_int_overflow_checks = g.pref.is_check_overflow && !g.is_builtin_overflow_mod
89+
&& !node.is_ignore_overflow
90+
defer {
91+
g.do_int_overflow_checks = prev_do_int_overflow_checks
92+
}
93+
8694
// handle `@[c_extern] fn C.some_name() int` declarations:
8795
old_inside_c_extern := g.inside_c_extern
8896
defer {

vlib/v/gen/c/for.v

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
140140
mut node := unsafe { node_ }
141141
mut is_comptime := false
142142

143-
is_safe_op := g.pref.is_check_overflow && !g.is_builtin_overflow_mod
144-
145143
if (node.cond is ast.Ident && node.cond.ct_expr) || node.cond is ast.ComptimeSelector {
146144
mut unwrapped_typ := g.unwrap_generic(node.cond_type)
147145
ctyp := g.type_resolver.get_type(node.cond)
@@ -211,7 +209,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
211209
if node.is_range {
212210
// `for x in 1..10 {`
213211
i := if node.val_var == '_' { g.new_tmp_var() } else { c_name(node.val_var) }
214-
plus_plus_i := if is_safe_op {
212+
plus_plus_i := if g.do_int_overflow_checks {
215213
$if new_int ? && x64 {
216214
'${i}=builtin__overflow__add_i64(${i},1)'
217215
} $else {
@@ -250,7 +248,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
250248
g.writeln(';')
251249
}
252250
i := if node.key_var in ['', '_'] { g.new_tmp_var() } else { node.key_var }
253-
plus_plus_i := if is_safe_op {
251+
plus_plus_i := if g.do_int_overflow_checks {
254252
$if new_int ? && x64 {
255253
'${i}=builtin__overflow__add_i64(${i},1)'
256254
} $else {
@@ -326,7 +324,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
326324
cond_var = g.expr_string(node.cond)
327325
}
328326
idx := if node.key_var in ['', '_'] { g.new_tmp_var() } else { node.key_var }
329-
plus_plus_idx := if is_safe_op {
327+
plus_plus_idx := if g.do_int_overflow_checks {
330328
$if new_int ? && x64 {
331329
'${idx}=builtin__overflow__add_i64(${idx},1)'
332330
} $else {
@@ -384,7 +382,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
384382
}
385383
dot_or_ptr := g.dot_or_ptr(node.cond_type)
386384
idx := g.new_tmp_var()
387-
plus_plus_idx := if is_safe_op {
385+
plus_plus_idx := if g.do_int_overflow_checks {
388386
$if new_int ? && x64 {
389387
'${idx}=builtin__overflow__add_i64(${idx},1)'
390388
} $else {
@@ -451,7 +449,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
451449
}
452450
field_accessor := if node.cond_type.is_ptr() { '->' } else { '.' }
453451
i := if node.key_var in ['', '_'] { g.new_tmp_var() } else { node.key_var }
454-
plus_plus_i := if is_safe_op {
452+
plus_plus_i := if g.do_int_overflow_checks {
455453
$if new_int ? && x64 {
456454
'${i}=builtin__overflow__add_i64(${i},1)'
457455
} $else {
@@ -491,7 +489,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
491489
g.expr(node.cond)
492490
g.writeln(';')
493491
i := node.key_var
494-
plus_plus_i := if is_safe_op {
492+
plus_plus_i := if g.do_int_overflow_checks {
495493
$if new_int ? && x64 {
496494
'${i}=builtin__overflow__add_i64(${i},1)'
497495
} $else {

vlib/v/gen/c/infix.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1256,7 +1256,7 @@ fn (mut g Gen) gen_plain_infix_expr(node ast.InfixExpr) {
12561256
}
12571257
// do not use promoted_type for overflow detect
12581258
left_type := g.unwrap_generic(node.left_type)
1259-
checkoverflow_op := g.pref.is_check_overflow && !g.is_builtin_overflow_mod && left_type.is_int()
1259+
checkoverflow_op := g.do_int_overflow_checks && left_type.is_int()
12601260
is_safe_add := checkoverflow_op && node.op == .plus
12611261
is_safe_sub := checkoverflow_op && node.op == .minus
12621262
is_safe_mul := checkoverflow_op && node.op == .mul
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-2
2+
0
3+
1
4+
2
5+
0
6+
1
7+
hi from main
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// vtest vflags: -check-overflow
2+
3+
@[ignore_overflow]
4+
fn arithmetic_i32(x i32, y i32) {
5+
a := x + y
6+
b := x - y
7+
c := x * y
8+
println(a)
9+
println(b)
10+
println(c)
11+
}
12+
13+
fn main() {
14+
arithmetic_i32(2147483647, 2147483647)
15+
arithmetic_i32(-2147483647, -2147483647)
16+
println('hi from main')
17+
}

vlib/v/parser/fn.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
213213
mut is_c2v_variadic := false
214214
mut is_c_extern := false
215215
mut is_markused := false
216+
mut is_ignore_overflow := false
216217
mut is_weak := false
217218
mut is_expand_simple_interpolation := false
218219
mut comments := []ast.Comment{}
@@ -264,6 +265,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
264265
'markused' {
265266
is_markused = true
266267
}
268+
'ignore_overflow' {
269+
is_ignore_overflow = true
270+
}
267271
'c_extern' {
268272
is_c_extern = true
269273
}
@@ -710,6 +714,7 @@ run them via `v file.v` instead',
710714
is_unsafe: is_unsafe
711715
is_must_use: is_must_use
712716
is_markused: is_markused
717+
is_ignore_overflow: is_ignore_overflow
713718
is_weak: is_weak
714719
is_file_translated: p.is_translated
715720
//

0 commit comments

Comments
 (0)