From 17bba712bd950294387220f87d3456f37b388161 Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Fri, 20 May 2022 17:30:16 +0200 Subject: [PATCH] checker: ban unsafe pointer/fn comparison (#14462) --- cmd/tools/vwatch.v | 2 +- .../sokol/particles/modules/particle/system.v | 4 +-- vlib/builtin/prealloc.c.v | 5 ++-- vlib/cli/command.v | 2 +- vlib/cli/help.v | 2 +- vlib/cli/man.v | 8 +++--- vlib/datatypes/bstree.v | 28 +++++++++---------- vlib/datatypes/doubly_linked_list.v | 2 +- vlib/datatypes/linked_list.v | 22 +++++++-------- vlib/net/html/dom_test.v | 2 +- vlib/os/process_windows.c.v | 4 +-- vlib/sync/channels.c.v | 4 +-- vlib/term/ui/input_windows.c.v | 4 +-- vlib/term/ui/termios_nix.c.v | 12 ++++---- vlib/v/ast/types.v | 9 ++++++ vlib/v/checker/infix.v | 7 +++++ ...checker_comparison_between_obj_and_int.out | 7 +++++ .../checker_comparison_between_obj_and_int.vv | 14 ++++++++++ vlib/v/gen/c/comptime.v | 2 +- vlib/v/gen/c/fn.v | 2 +- vlib/v/gen/c/index.v | 11 +++++--- vlib/v/gen/c/match.v | 3 +- vlib/v/gen/c/utils.v | 2 +- vlib/v/gen/js/fn.v | 4 +-- vlib/v/gen/js/js.v | 11 ++++---- vlib/v/pkgconfig/main.v | 2 +- ...ics_assign_reference_generic_struct_test.v | 2 +- vlib/v/tests/pointers_multilevel_casts_test.v | 2 +- 28 files changed, 111 insertions(+), 68 deletions(-) create mode 100644 vlib/v/checker/tests/checker_comparison_between_obj_and_int.out create mode 100644 vlib/v/checker/tests/checker_comparison_between_obj_and_int.vv diff --git a/cmd/tools/vwatch.v b/cmd/tools/vwatch.v index 26afdf113..9fbf5aa5d 100644 --- a/cmd/tools/vwatch.v +++ b/cmd/tools/vwatch.v @@ -207,7 +207,7 @@ fn change_detection_loop(ocontext &Context) { } fn (mut context Context) kill_pgroup() { - if context.child_process == 0 { + if unsafe { context.child_process == 0 } { return } if context.child_process.is_alive() { diff --git a/examples/sokol/particles/modules/particle/system.v b/examples/sokol/particles/modules/particle/system.v index c319e6177..dc19ddfc2 100644 --- a/examples/sokol/particles/modules/particle/system.v +++ b/examples/sokol/particles/modules/particle/system.v @@ -95,7 +95,7 @@ pub fn (mut s System) explode(x f32, y f32) { pub fn (mut s System) free() { for p in s.pool { - if p == 0 { + if unsafe { p == 0 } { print(ptr_str(p) + ' ouch') continue } @@ -103,7 +103,7 @@ pub fn (mut s System) free() { } s.pool.clear() for p in s.bin { - if p == 0 { + if unsafe { p == 0 } { print(ptr_str(p) + ' ouch') continue } diff --git a/vlib/builtin/prealloc.c.v b/vlib/builtin/prealloc.c.v index a8d64639d..20b421615 100644 --- a/vlib/builtin/prealloc.c.v +++ b/vlib/builtin/prealloc.c.v @@ -32,9 +32,10 @@ mut: [unsafe] fn vmemory_block_new(prev &VMemoryBlock, at_least isize) &VMemoryBlock { mut v := unsafe { &VMemoryBlock(C.calloc(1, sizeof(VMemoryBlock))) } - if prev != 0 { + if unsafe { prev != 0 } { v.id = prev.id + 1 } + v.previous = prev block_size := if at_least < prealloc_block_size { prealloc_block_size } else { at_least } v.start = unsafe { C.malloc(block_size) } @@ -79,7 +80,7 @@ fn prealloc_vcleanup() { // The second loop however should *not* allocate at all. mut nr_mallocs := i64(0) mut mb := g_memory_block - for mb != 0 { + for unsafe { mb != 0 } { nr_mallocs += mb.mallocs eprintln('> freeing mb.id: ${mb.id:3} | cap: ${mb.cap:7} | rem: ${mb.remaining:7} | start: ${voidptr(mb.start)} | current: ${voidptr(mb.current)} | diff: ${u64(mb.current) - u64(mb.start):7} bytes | mallocs: $mb.mallocs') mb = mb.previous diff --git a/vlib/cli/command.v b/vlib/cli/command.v index c5d5d7d53..30b8eda96 100644 --- a/vlib/cli/command.v +++ b/vlib/cli/command.v @@ -53,7 +53,7 @@ pub fn (cmd Command) str() string { res << ' cb execute: $cmd.execute' res << ' cb pre_execute: $cmd.pre_execute' res << ' cb post_execute: $cmd.post_execute' - if cmd.parent == 0 { + if unsafe { cmd.parent == 0 } { res << ' parent: &Command(0)' } else { res << ' parent: &Command{$cmd.parent.name ...}' diff --git a/vlib/cli/help.v b/vlib/cli/help.v index 20c176d7c..014a40ee7 100644 --- a/vlib/cli/help.v +++ b/vlib/cli/help.v @@ -49,7 +49,7 @@ pub fn print_help_for_command(help_cmd Command) ? { } print(cmd.help_message()) } else { - if help_cmd.parent != 0 { + if unsafe { help_cmd.parent != 0 } { print(help_cmd.parent.help_message()) } } diff --git a/vlib/cli/man.v b/vlib/cli/man.v index c27f23307..8ac68797f 100644 --- a/vlib/cli/man.v +++ b/vlib/cli/man.v @@ -41,7 +41,7 @@ pub fn print_manpage_for_command(man_cmd Command) ? { } print(cmd.manpage()) } else { - if man_cmd.parent != 0 { + if unsafe { man_cmd.parent != 0 } { print(man_cmd.parent.manpage()) } } @@ -55,7 +55,7 @@ pub fn (cmd Command) manpage() string { mdoc += '.Os\n.Sh NAME\n.Nm ${cmd.full_name().replace(' ', '-')}\n.Nd $cmd.description\n' mdoc += '.Sh SYNOPSIS\n' mdoc += '.Nm $cmd.root().name\n' - if cmd.parent != 0 { + if unsafe { cmd.parent != 0 } { mut parents := []Command{} if !cmd.parent.is_root() { parents.prepend(cmd.parent) @@ -96,7 +96,7 @@ pub fn (cmd Command) manpage() string { } if cmd.commands.len > 0 { mdoc += '.Nm $cmd.root().name\n' - if cmd.parent != 0 { + if unsafe { cmd.parent != 0 } { mut parents := []Command{} if !cmd.parent.is_root() { parents.prepend(cmd.parent) @@ -158,7 +158,7 @@ pub fn (cmd Command) manpage() string { if cmd.commands.len > 0 { mdoc += '.Sh SEE ALSO\n' mut cmds := []string{} - if cmd.parent != 0 { + if unsafe { cmd.parent != 0 } { cmds << cmd.parent.full_name().replace(' ', '-') } for c in cmd.commands { diff --git a/vlib/datatypes/bstree.v b/vlib/datatypes/bstree.v index 93d65e5cc..306ac66f0 100644 --- a/vlib/datatypes/bstree.v +++ b/vlib/datatypes/bstree.v @@ -76,13 +76,13 @@ pub fn (mut bst BSTree) insert(value T) bool { // insert_helper walks the tree and inserts the given node. fn (mut bst BSTree) insert_helper(mut node BSTreeNode, value T) bool { if node.value < value { - if node.right != 0 && node.right.is_init { + if unsafe { node.right != 0 } && node.right.is_init { return bst.insert_helper(mut node.right, value) } node.right = new_node(node, value) return true } else if node.value > value { - if node.left != 0 && node.left.is_init { + if unsafe { node.left != 0 } && node.left.is_init { return bst.insert_helper(mut node.left, value) } node.left = new_node(node, value) @@ -99,7 +99,7 @@ pub fn (bst &BSTree) contains(value T) bool { // contains_helper is a helper function to walk the tree, and return // the absence or presence of the `value`. fn (bst &BSTree) contains_helper(node &BSTreeNode, value T) bool { - if node == 0 || !node.is_init { + if unsafe { node == 0 } || !node.is_init { return false } if node.value < value { @@ -124,12 +124,12 @@ fn (mut bst BSTree) remove_helper(mut node BSTreeNode, value T, left bool) return false } if node.value == value { - if node.left != 0 && node.left.is_init { + if unsafe { node.left != 0 } && node.left.is_init { // In order to remove the element we need to bring up as parent the max of the // left sub-tree. mut max_node := bst.get_max_from_right(node.left) node.bind(mut max_node, true) - } else if node.right != 0 && node.right.is_init { + } else if unsafe { node.right != 0 } && node.right.is_init { // Bring up the element with the minimum value in the right sub-tree. mut min_node := bst.get_min_from_left(node.right) node.bind(mut min_node, false) @@ -153,11 +153,11 @@ fn (mut bst BSTree) remove_helper(mut node BSTreeNode, value T, left bool) // get_max_from_right returns the max element of the BST following the right branch. fn (bst &BSTree) get_max_from_right(node &BSTreeNode) &BSTreeNode { - if node == 0 { + if unsafe { node == 0 } { return new_none_node(false) } right_node := node.right - if right_node == 0 || !right_node.is_init { + if unsafe { right_node == 0 } || !right_node.is_init { return node } return bst.get_max_from_right(right_node) @@ -165,11 +165,11 @@ fn (bst &BSTree) get_max_from_right(node &BSTreeNode) &BSTreeNode { // get_min_from_left returns the min element of the BST by following the left branch. fn (bst &BSTree) get_min_from_left(node &BSTreeNode) &BSTreeNode { - if node == 0 { + if unsafe { node == 0 } { return new_none_node(false) } left_node := node.left - if left_node == 0 || !left_node.is_init { + if unsafe { left_node == 0 } || !left_node.is_init { return node } return bst.get_min_from_left(left_node) @@ -177,7 +177,7 @@ fn (bst &BSTree) get_min_from_left(node &BSTreeNode) &BSTreeNode { // is_empty checks if the BST is empty pub fn (bst &BSTree) is_empty() bool { - return bst.root == 0 + return unsafe { bst.root == 0 } } // in_order_traversal traverses the BST in order, and returns the result as an array. @@ -189,7 +189,7 @@ pub fn (bst &BSTree) in_order_traversal() []T { // in_order_traversal_helper helps traverse the BST, and accumulates the result in the `result` array. fn (bst &BSTree) in_order_traversal_helper(node &BSTreeNode, mut result []T) { - if node == 0 || !node.is_init { + if unsafe { node == 0 } || !node.is_init { return } bst.in_order_traversal_helper(node.left, mut result) @@ -207,7 +207,7 @@ pub fn (bst &BSTree) post_order_traversal() []T { // post_order_traversal_helper is a helper function that traverses the BST in post order, // accumulating the result in an array. fn (bst &BSTree) post_order_traversal_helper(node &BSTreeNode, mut result []T) { - if node == 0 || !node.is_init { + if unsafe { node == 0 } || !node.is_init { return } @@ -226,7 +226,7 @@ pub fn (bst &BSTree) pre_order_traversal() []T { // pre_order_traversal_helper is a helper function to traverse the BST // in pre order and accumulates the results in an array. fn (bst &BSTree) pre_order_traversal_helper(node &BSTreeNode, mut result []T) { - if node == 0 || !node.is_init { + if unsafe { node == 0 } || !node.is_init { return } result << node.value @@ -236,7 +236,7 @@ fn (bst &BSTree) pre_order_traversal_helper(node &BSTreeNode, mut result [ // get_node is a helper method to ge the internal rapresentation of the node with the `value`. fn (bst &BSTree) get_node(node &BSTreeNode, value T) &BSTreeNode { - if node == 0 || !node.is_init { + if unsafe { node == 0 } || !node.is_init { return new_none_node(false) } if node.value == value { diff --git a/vlib/datatypes/doubly_linked_list.v b/vlib/datatypes/doubly_linked_list.v index d489b807d..6ed3122f4 100644 --- a/vlib/datatypes/doubly_linked_list.v +++ b/vlib/datatypes/doubly_linked_list.v @@ -251,7 +251,7 @@ pub fn (mut list DoublyLinkedList) delete(idx int) { pub fn (list DoublyLinkedList) str() string { mut result_array := []T{} mut node := list.head - for node != 0 { + for unsafe { node != 0 } { result_array << node.data node = node.next } diff --git a/vlib/datatypes/linked_list.v b/vlib/datatypes/linked_list.v index 739d027d2..719a6c161 100644 --- a/vlib/datatypes/linked_list.v +++ b/vlib/datatypes/linked_list.v @@ -29,11 +29,11 @@ pub fn (list LinkedList) first() ?T { // last returns the last element of the linked list pub fn (list LinkedList) last() ?T { - if list.head == 0 { + if unsafe { list.head == 0 } { return error('Linked list is empty') } else { mut node := list.head - for node.next != 0 { + for unsafe { node.next != 0 } { node = node.next } return node.data @@ -42,12 +42,12 @@ pub fn (list LinkedList) last() ?T { // index returns the element at the given index of the linked list pub fn (list LinkedList) index(idx int) ?T { - if list.head == 0 { + if unsafe { list.head == 0 } { return error('Linked list is empty') } else { mut node := list.head mut iterations := 0 - for node.next != 0 && iterations < idx { + for unsafe { node.next != 0 } && iterations < idx { node = node.next iterations++ } @@ -64,12 +64,12 @@ pub fn (mut list LinkedList) push(item T) { new_node := &ListNode{ data: item } - if list.head == 0 { + if unsafe { list.head == 0 } { // first node case list.head = new_node } else { mut node := list.head - for node.next != 0 { + for unsafe { node.next != 0 } { node = node.next } node.next = new_node @@ -79,17 +79,17 @@ pub fn (mut list LinkedList) push(item T) { // pop removes the last element of the linked list pub fn (mut list LinkedList) pop() ?T { - if list.head == 0 { + if unsafe { list.head == 0 } { return error('Linked list is empty') } mut node := list.head mut to_return := node.data - if node.next == 0 { + if unsafe { node.next == 0 } { // first node case // set to null list.head = voidptr(0) } else { - for node.next.next != 0 { + for unsafe { node.next.next != 0 } { node = node.next } to_return = node.next.data @@ -102,7 +102,7 @@ pub fn (mut list LinkedList) pop() ?T { // shift removes the first element of the linked list pub fn (mut list LinkedList) shift() ?T { - if list.head == 0 { + if unsafe { list.head == 0 } { return error('Linked list is empty') } else { list.len -= 1 @@ -149,7 +149,7 @@ pub fn (mut list LinkedList) prepend(item T) { pub fn (list LinkedList) str() string { mut result_array := []T{} mut node := list.head - for node != 0 { + for unsafe { node != 0 } { result_array << node.data node = node.next } diff --git a/vlib/net/html/dom_test.v b/vlib/net/html/dom_test.v index d4fd292b7..3d37be0c4 100644 --- a/vlib/net/html/dom_test.v +++ b/vlib/net/html/dom_test.v @@ -32,7 +32,7 @@ fn test_access_parent() { mut dom := parse(generate_temp_html()) div_tags := dom.get_tag('div') parent := div_tags[0].parent - assert parent != 0 + assert unsafe { parent != 0 } for div_tag in div_tags { assert div_tag.parent == parent } diff --git a/vlib/os/process_windows.c.v b/vlib/os/process_windows.c.v index 1d513ea2b..c1bec1032 100644 --- a/vlib/os/process_windows.c.v +++ b/vlib/os/process_windows.c.v @@ -176,7 +176,7 @@ fn (mut p Process) win_write_string(idx int, s string) { fn (mut p Process) win_read_string(idx int, maxbytes int) (string, int) { mut wdata := &WProcess(p.wdata) - if wdata == 0 { + if unsafe { wdata == 0 } { return '', 0 } mut rhandle := &u32(0) @@ -207,7 +207,7 @@ fn (mut p Process) win_read_string(idx int, maxbytes int) (string, int) { fn (mut p Process) win_slurp(idx int) string { mut wdata := &WProcess(p.wdata) - if wdata == 0 { + if unsafe { wdata == 0 } { return '' } mut rhandle := &u32(0) diff --git a/vlib/sync/channels.c.v b/vlib/sync/channels.c.v index 73257b75e..60c5475a2 100644 --- a/vlib/sync/channels.c.v +++ b/vlib/sync/channels.c.v @@ -645,7 +645,7 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo unsafe { *subscr[i].prev = subscr[i].nxt } - if subscr[i].nxt != 0 { + if unsafe { subscr[i].nxt != 0 } { subscr[i].nxt.prev = subscr[i].prev // just in case we have missed a semaphore during restore subscr[i].nxt.sem.post() @@ -659,7 +659,7 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo unsafe { *subscr[i].prev = subscr[i].nxt } - if subscr[i].nxt != 0 { + if unsafe { subscr[i].nxt != 0 } { subscr[i].nxt.prev = subscr[i].prev subscr[i].nxt.sem.post() } diff --git a/vlib/term/ui/input_windows.c.v b/vlib/term/ui/input_windows.c.v index 6f08f2a93..751fb9410 100644 --- a/vlib/term/ui/input_windows.c.v +++ b/vlib/term/ui/input_windows.c.v @@ -21,7 +21,7 @@ mut: } fn restore_terminal_state() { - if ui.ctx_ptr != 0 { + if unsafe { ui.ctx_ptr != 0 } { if ui.ctx_ptr.cfg.use_alternate_buffer { // clear the terminal and set the cursor to the origin print('\x1b[2J\x1b[3J') @@ -84,7 +84,7 @@ pub fn init(cfg Config) &Context { for code in ctx.cfg.reset { os.signal_opt(code, fn (_ os.Signal) { mut c := ui.ctx_ptr - if c != 0 { + if unsafe { c != 0 } { c.cleanup() } exit(0) diff --git a/vlib/term/ui/termios_nix.c.v b/vlib/term/ui/termios_nix.c.v index 37c08169a..024dd8de6 100644 --- a/vlib/term/ui/termios_nix.c.v +++ b/vlib/term/ui/termios_nix.c.v @@ -44,7 +44,7 @@ fn restore_terminal_state_signal(_ os.Signal) { fn restore_terminal_state() { termios_reset() mut c := ctx_ptr - if c != 0 { + if unsafe { c != 0 } { c.paused = true load_title() } @@ -121,7 +121,7 @@ fn (mut ctx Context) termios_setup() ? { os.signal_opt(.tstp, restore_terminal_state_signal) or {} os.signal_opt(.cont, fn (_ os.Signal) { mut c := ctx_ptr - if c != 0 { + if unsafe { c != 0 } { c.termios_setup() or { panic(err) } c.window_height, c.window_width = get_terminal_size() mut event := &Event{ @@ -136,7 +136,7 @@ fn (mut ctx Context) termios_setup() ? { for code in ctx.cfg.reset { os.signal_opt(code, fn (_ os.Signal) { mut c := ctx_ptr - if c != 0 { + if unsafe { c != 0 } { c.cleanup() } exit(0) @@ -145,7 +145,7 @@ fn (mut ctx Context) termios_setup() ? { os.signal_opt(.winch, fn (_ os.Signal) { mut c := ctx_ptr - if c != 0 { + if unsafe { c != 0 } { c.window_height, c.window_width = get_terminal_size() mut event := &Event{ @@ -200,7 +200,7 @@ fn termios_reset() { C.tcsetattr(C.STDIN_FILENO, C.TCSAFLUSH, &ui.termios_at_startup) print('\x1b[?1003l\x1b[?1006l\x1b[?25h') c := ctx_ptr - if c != 0 && c.cfg.use_alternate_buffer { + if unsafe { c != 0 } && c.cfg.use_alternate_buffer { print('\x1b[?1049l') } os.flush() @@ -267,7 +267,7 @@ fn (mut ctx Context) parse_events() { ctx.shift(1) } } - if event != 0 { + if unsafe { event != 0 } { ctx.event(event) nr_iters = 0 } diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index e2c29d2b8..c7569807d 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -547,6 +547,15 @@ pub fn (t &Table) type_kind(typ Type) Kind { return t.sym(typ).kind } +pub fn (t &Table) type_is_for_pointer_arithmetic(typ Type) bool { + typ_sym := t.sym(typ) + if typ_sym.kind == .struct_ { + return false + } else { + return typ.is_any_kind_of_pointer() || typ.is_int_valptr() + } +} + pub enum Kind { placeholder void diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index 1452c5707..ff01115da 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -592,6 +592,13 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } c.error('infix expr: cannot use `$right_sym.name` (right expression) as `$left_sym.name`', left_right_pos) + } else if left_type.is_ptr() { + for_ptr_op := c.table.type_is_for_pointer_arithmetic(left_type) + if left_sym.language == .v && !c.inside_unsafe && !for_ptr_op && right_type.is_int() { + sugg := ' (you can use it inside an `unsafe` block)' + c.error('infix expr: cannot use `$right_sym.name` (right expression) as `$left_sym.name` $sugg', + left_right_pos) + } } /* if (node.left is ast.InfixExpr && diff --git a/vlib/v/checker/tests/checker_comparison_between_obj_and_int.out b/vlib/v/checker/tests/checker_comparison_between_obj_and_int.out new file mode 100644 index 000000000..aba27b5f8 --- /dev/null +++ b/vlib/v/checker/tests/checker_comparison_between_obj_and_int.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/checker_comparison_between_obj_and_int.vv:10:5: error: infix expr: cannot use `int literal` (right expression) as `Foo` (you can use it inside an `unsafe` block) + 8 | + 9 | fn insert_helper(mut node Foo) { + 10 | if node == 0 { + | ~~~~~~~~~ + 11 | } + 12 | } diff --git a/vlib/v/checker/tests/checker_comparison_between_obj_and_int.vv b/vlib/v/checker/tests/checker_comparison_between_obj_and_int.vv new file mode 100644 index 000000000..e57dfa8ac --- /dev/null +++ b/vlib/v/checker/tests/checker_comparison_between_obj_and_int.vv @@ -0,0 +1,14 @@ +struct Foo {} + +// inside a unsafe block it is valid +fn insert_helper_unsafe(mut node Foo) { + if unsafe { node == 0 } { + } +} + +fn insert_helper(mut node Foo) { + if node == 0 { + } +} + +fn main() {} diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index c7e9d5db0..47bd9c183 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -288,7 +288,7 @@ fn (mut g Gen) comptime_if(node ast.IfExpr) { } } else { // Only wrap the contents in {} if we're inside a function, not on the top level scope - should_create_scope := g.fn_decl != 0 + should_create_scope := unsafe { g.fn_decl != 0 } if should_create_scope { g.writeln('{') } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 8fa596265..0868f1d68 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -717,7 +717,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { g.checker_bug('CallExpr.receiver_type is 0 in method_call', node.pos) } mut unwrapped_rec_type := node.receiver_type - if g.cur_fn != 0 && g.cur_fn.generic_names.len > 0 { // in generic fn + if unsafe { g.cur_fn != 0 } && g.cur_fn.generic_names.len > 0 { // in generic fn unwrapped_rec_type = g.unwrap_generic(node.receiver_type) } else { // in non-generic fn sym := g.table.sym(node.receiver_type) diff --git a/vlib/v/gen/c/index.v b/vlib/v/gen/c/index.v index 8af7cca26..d70caa28f 100644 --- a/vlib/v/gen/c/index.v +++ b/vlib/v/gen/c/index.v @@ -18,7 +18,8 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { } else if sym.kind == .map { g.index_of_map(node, sym) } else if sym.kind == .string && !node.left_type.is_ptr() { - is_direct_array_access := (g.fn_decl != 0 && g.fn_decl.is_direct_arr) || node.is_direct + is_direct_array_access := (unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr) + || node.is_direct if is_direct_array_access { g.expr(node.left) g.write('.str[ ') @@ -174,7 +175,8 @@ fn (mut g Gen) index_of_array(node ast.IndexExpr, sym ast.TypeSymbol) { // `vals[i].field = x` is an exception and requires `array_get`: // `(*(Val*)array_get(vals, i)).field = x;` if g.is_assign_lhs && node.is_setter { - is_direct_array_access := (g.fn_decl != 0 && g.fn_decl.is_direct_arr) || node.is_direct + is_direct_array_access := (unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr) + || node.is_direct is_op_assign := g.assign_op != .assign && info.elem_type != ast.string_type if is_direct_array_access { g.write('(($elem_type_str*)') @@ -233,7 +235,8 @@ fn (mut g Gen) index_of_array(node ast.IndexExpr, sym ast.TypeSymbol) { } } } else { - is_direct_array_access := (g.fn_decl != 0 && g.fn_decl.is_direct_arr) || node.is_direct + is_direct_array_access := (unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr) + || node.is_direct // do not clone inside `opt_ok(opt_ok(&(string[]) {..})` before returns needs_clone := info.elem_type == ast.string_type_idx && g.is_autofree && !(g.inside_return && g.fn_decl.return_type.has_flag(.optional)) && !g.is_assign_lhs @@ -335,7 +338,7 @@ fn (mut g Gen) index_of_fixed_array(node ast.IndexExpr, sym ast.TypeSymbol) { g.expr(node.left) } g.write('[') - direct := g.fn_decl != 0 && g.fn_decl.is_direct_arr + direct := unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr if (direct || node.index is ast.IntegerLiteral) || g.pref.translated { g.expr(node.index) } else { diff --git a/vlib/v/gen/c/match.v b/vlib/v/gen/c/match.v index 1e1d29f13..a922f1acf 100644 --- a/vlib/v/gen/c/match.v +++ b/vlib/v/gen/c/match.v @@ -91,7 +91,8 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) { typ := g.table.final_sym(node.cond_type) if node.is_sum_type { g.match_expr_sumtype(node, is_expr, cond_var, tmp_var) - } else if typ.kind == .enum_ && g.loop_depth == 0 && node.branches.len > 5 && g.fn_decl != 0 { // do not optimize while in top-level + } else if typ.kind == .enum_ && g.loop_depth == 0 && node.branches.len > 5 + && unsafe { g.fn_decl != 0 } { // do not optimize while in top-level g.match_expr_switch(node, is_expr, cond_var, tmp_var, typ) } else { g.match_expr_classic(node, is_expr, cond_var, tmp_var) diff --git a/vlib/v/gen/c/utils.v b/vlib/v/gen/c/utils.v index fe2aa4a9c..79f6bc0a2 100644 --- a/vlib/v/gen/c/utils.v +++ b/vlib/v/gen/c/utils.v @@ -16,7 +16,7 @@ fn (mut g Gen) unwrap_generic(typ ast.Type) ast.Type { non-mut to make sure no one else can accidentally mutates the table. */ mut muttable := unsafe { &ast.Table(g.table) } - if t_typ := muttable.resolve_generic_to_concrete(typ, if g.cur_fn != 0 { + if t_typ := muttable.resolve_generic_to_concrete(typ, if unsafe { g.cur_fn != 0 } { g.cur_fn.generic_names } else { []string{} diff --git a/vlib/v/gen/js/fn.v b/vlib/v/gen/js/fn.v index 0fde78185..20d02cc95 100644 --- a/vlib/v/gen/js/fn.v +++ b/vlib/v/gen/js/fn.v @@ -45,7 +45,7 @@ fn (mut g JsGen) js_mname(name_ string) string { '' } } - } else if g.ns == 0 { + } else if unsafe { g.ns == 0 } { name } else if ns == g.ns.name { name.split('.').last() @@ -222,7 +222,7 @@ fn (mut g JsGen) method_call(node ast.CallExpr) { g.get_str_fn(rec_type) } mut unwrapped_rec_type := node.receiver_type - if g.fn_decl != 0 && g.fn_decl.generic_names.len > 0 { // in generic fn + if unsafe { g.fn_decl != 0 } && g.fn_decl.generic_names.len > 0 { // in generic fn unwrapped_rec_type = g.unwrap_generic(node.receiver_type) } else { // in non-generic fn sym := g.table.sym(node.receiver_type) diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 2896727c1..235752fb1 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -412,7 +412,7 @@ fn (g &JsGen) get_all_test_function_names() []string { } pub fn (mut g JsGen) enter_namespace(name string) { - if g.namespaces[name] == 0 { + if unsafe { g.namespaces[name] == 0 } { // create a new namespace ns := &Namespace{ name: name @@ -521,7 +521,7 @@ pub fn (mut g JsGen) dec_indent() { [inline] pub fn (mut g JsGen) write(s string) { - if g.ns == 0 { + if unsafe { g.ns == 0 } { verror('g.write: not in a namespace') } g.gen_indent() @@ -530,7 +530,7 @@ pub fn (mut g JsGen) write(s string) { [inline] pub fn (mut g JsGen) writeln(s string) { - if g.ns == 0 { + if unsafe { g.ns == 0 } { verror('g.writeln: not in a namespace') } g.gen_indent() @@ -2449,7 +2449,8 @@ fn (mut g JsGen) match_expr(node ast.MatchExpr) { typ := g.table.final_sym(node.cond_type) if node.is_sum_type { g.match_expr_sumtype(node, is_expr, cond_var, tmp_var) - } else if typ.kind == .enum_ && !g.inside_loop && node.branches.len > 5 && g.fn_decl != 0 { // do not optimize while in top-level + } else if typ.kind == .enum_ && !g.inside_loop && node.branches.len > 5 + && unsafe { g.fn_decl != 0 } { // do not optimize while in top-level g.match_expr_switch(node, is_expr, cond_var, tmp_var, typ) } else { g.match_expr_classic(node, is_expr, cond_var, tmp_var) @@ -3691,7 +3692,7 @@ fn (mut g JsGen) unwrap_generic(typ ast.Type) ast.Type { non-mut to make sure no one else can accidentally mutates the table. */ mut muttable := unsafe { &ast.Table(g.table) } - if t_typ := muttable.resolve_generic_to_concrete(typ, if g.fn_decl != 0 { + if t_typ := muttable.resolve_generic_to_concrete(typ, if unsafe { g.fn_decl != 0 } { g.fn_decl.generic_names } else { []string{} diff --git a/vlib/v/pkgconfig/main.v b/vlib/v/pkgconfig/main.v index cfd472428..ecde62558 100644 --- a/vlib/v/pkgconfig/main.v +++ b/vlib/v/pkgconfig/main.v @@ -93,7 +93,7 @@ pub fn (mut m Main) run() ?string { } res += pcdep.description } - if pc != 0 { + if unsafe { pc != 0 } { pc.extend(pcdep)? } else { pc = pcdep diff --git a/vlib/v/tests/generics_assign_reference_generic_struct_test.v b/vlib/v/tests/generics_assign_reference_generic_struct_test.v index 74b2c9a33..2e5513fb9 100644 --- a/vlib/v/tests/generics_assign_reference_generic_struct_test.v +++ b/vlib/v/tests/generics_assign_reference_generic_struct_test.v @@ -15,7 +15,7 @@ pub fn list_new() List { pub fn (mut l List) add(value T) { mut node := &ListNode{value, 0} - if l.head == 0 { + if unsafe { l.head == 0 } { l.head = node } else { node.next = l.head diff --git a/vlib/v/tests/pointers_multilevel_casts_test.v b/vlib/v/tests/pointers_multilevel_casts_test.v index aff9ef32f..e705f944a 100644 --- a/vlib/v/tests/pointers_multilevel_casts_test.v +++ b/vlib/v/tests/pointers_multilevel_casts_test.v @@ -56,7 +56,7 @@ fn test_struct_pointer_casts_with_field_selectors() { // &Struct cast and selecting .x assert true } - if &&Struct(pss) != 0 { + if unsafe { &&Struct(pss) != 0 } { // &&Struct assert true } -- 2.30.2