diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index c7d3db52da..03ece901ff 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -99,7 +99,7 @@ fn new_dense_array(key_bytes int, value_bytes int) DenseArray { cap: cap len: 0 deletes: 0 - all_deleted: 0 + all_deleted: unsafe { nil } keys: unsafe { malloc(__at_least_one(u64(cap) * u64(key_bytes))) } values: unsafe { malloc(__at_least_one(u64(cap) * u64(value_bytes))) } } @@ -679,9 +679,9 @@ fn (d &DenseArray) clone() DenseArray { cap: d.cap len: d.len deletes: d.deletes - all_deleted: 0 - values: 0 - keys: 0 + all_deleted: unsafe { nil } + values: unsafe { nil } + keys: unsafe { nil } } unsafe { if d.deletes != 0 { diff --git a/vlib/builtin/map_d_gcboehm_opt.v b/vlib/builtin/map_d_gcboehm_opt.v index 54569b059b..90829b4267 100644 --- a/vlib/builtin/map_d_gcboehm_opt.v +++ b/vlib/builtin/map_d_gcboehm_opt.v @@ -23,7 +23,7 @@ fn new_dense_array_noscan(key_bytes int, key_noscan bool, value_bytes int, value cap: cap len: 0 deletes: 0 - all_deleted: 0 + all_deleted: unsafe { nil } keys: __malloc_at_least_one(u64(cap) * u64(key_bytes), key_noscan) values: __malloc_at_least_one(u64(cap) * u64(value_bytes), value_noscan) } diff --git a/vlib/gg/gg.c.v b/vlib/gg/gg.c.v index eecb238093..7a426eec0b 100644 --- a/vlib/gg/gg.c.v +++ b/vlib/gg/gg.c.v @@ -445,7 +445,7 @@ pub fn new_context(cfg Config) &Context { width: cfg.width height: cfg.height config: cfg - ft: 0 + ft: unsafe { nil } ui_mode: cfg.ui_mode native_rendering: cfg.native_rendering window: sapp.Desc{ diff --git a/vlib/net/urllib/urllib.v b/vlib/net/urllib/urllib.v index fe813db1c5..a8104e02c3 100644 --- a/vlib/net/urllib/urllib.v +++ b/vlib/net/urllib/urllib.v @@ -470,7 +470,7 @@ fn parse_url(rawurl string, via_request bool) !URL { return error(error_msg('parse_url: empty URL', rawurl)) } mut url := URL{ - user: 0 + user: unsafe { nil } } if rawurl == '*' { url.path = '*' diff --git a/vlib/os/os_windows.c.v b/vlib/os/os_windows.c.v index 3223096d33..9a2538d195 100644 --- a/vlib/os/os_windows.c.v +++ b/vlib/os/os_windows.c.v @@ -328,10 +328,10 @@ pub fn raw_execute(cmd string) Result { } proc_info := ProcessInformation{} start_info := StartupInfo{ - lp_reserved2: 0 - lp_reserved: 0 - lp_desktop: 0 - lp_title: 0 + lp_reserved2: unsafe { nil } + lp_reserved: unsafe { nil } + lp_desktop: unsafe { nil } + lp_title: unsafe { nil } cb: sizeof(C.PROCESS_INFORMATION) h_std_input: child_stdin h_std_output: child_stdout_write diff --git a/vlib/os/process_windows.c.v b/vlib/os/process_windows.c.v index 1d71a7db3e..6df038cfe5 100644 --- a/vlib/os/process_windows.c.v +++ b/vlib/os/process_windows.c.v @@ -68,18 +68,18 @@ fn (mut p Process) win_spawn_process() int { } p.filename = abs_path(p.filename) // expand the path to an absolute one, in case we later change the working folder mut wdata := &WProcess{ - child_stdin: 0 - child_stdout_read: 0 - child_stdout_write: 0 - child_stderr_read: 0 - child_stderr_write: 0 + child_stdin: unsafe { nil } + child_stdout_read: unsafe { nil } + child_stdout_write: unsafe { nil } + child_stderr_read: unsafe { nil } + child_stderr_write: unsafe { nil } } p.wdata = voidptr(wdata) mut start_info := StartupInfo{ - lp_reserved2: 0 - lp_reserved: 0 - lp_desktop: 0 - lp_title: 0 + lp_reserved2: unsafe { nil } + lp_reserved: unsafe { nil } + lp_desktop: unsafe { nil } + lp_title: unsafe { nil } cb: sizeof(C.PROCESS_INFORMATION) } if p.use_stdio_ctl { diff --git a/vlib/sync/channels.c.v b/vlib/sync/channels.c.v index 66d04ba62b..f056932572 100644 --- a/vlib/sync/channels.c.v +++ b/vlib/sync/channels.c.v @@ -82,8 +82,8 @@ fn new_channel_st(n u32, st u32) &Channel { read_avail: 0 ringbuf: rbuf statusbuf: sbuf - write_subscriber: 0 - read_subscriber: 0 + write_subscriber: unsafe { nil } + read_subscriber: unsafe { nil } } ch.writesem.init(wsem) ch.readsem.init(rsem) @@ -105,8 +105,8 @@ fn new_channel_st_noscan(n u32, st u32) &Channel { read_avail: 0 ringbuf: rbuf statusbuf: sbuf - write_subscriber: 0 - read_subscriber: 0 + write_subscriber: unsafe { nil } + read_subscriber: unsafe { nil } } ch.writesem.init(wsem) ch.readsem.init(rsem) diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index d9b40cfef3..d3354e9867 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -96,9 +96,9 @@ pub fn (t &Table) panic(message string) { pub fn new_table() &Table { mut t := &Table{ global_scope: &Scope{ - parent: 0 + parent: unsafe { nil } } - cur_fn: 0 + cur_fn: unsafe { nil } } t.register_builtin_type_symbols() t.is_fmt = true diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 324ecb801f..8af22768e8 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -335,7 +335,7 @@ pub fn (mut c Checker) check_files(ast_files []&ast.File) { file: the_main_file.path return_type: ast.void_type scope: &ast.Scope{ - parent: 0 + parent: nil } } has_main_fn = true @@ -2021,7 +2021,7 @@ fn (mut c Checker) stmt(mut node ast.Stmt) { if mut id.info is ast.IdentVar { if id.comptime && id.name in ast.valid_comptime_not_user_defined { node.defer_vars[i] = ast.Ident{ - scope: 0 + scope: unsafe { nil } name: '' } continue diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 8b3808b906..6afbd52082 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -691,10 +691,19 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', init_field.pos) } } else { - if exp_type.is_ptr() && !got_type.is_any_kind_of_pointer() - && init_field.expr.str() != '0' && !exp_type.has_flag(.option) { - c.error('reference field must be initialized with reference', - init_field.pos) + is_unsafe_0 := init_field.expr is ast.UnsafeExpr + && (init_field.expr as ast.UnsafeExpr).expr.str() == '0' + if exp_type.is_ptr() && !is_unsafe_0 && !got_type.is_any_kind_of_pointer() + && !exp_type.has_flag(.option) { + if init_field.expr.str() == '0' { + if !c.inside_unsafe && type_sym.language == .v { + c.note('assigning `0` to a reference field is only allowed in `unsafe` blocks', + init_field.pos) + } + } else { + c.error('reference field must be initialized with reference', + init_field.pos) + } } else if exp_type.is_pointer() && !got_type.is_any_kind_of_pointer() && !got_type.is_int() { got_typ_str := c.table.type_to_str(got_type) diff --git a/vlib/v/checker/tests/struct_ref_fields_init_0_err.out b/vlib/v/checker/tests/struct_ref_fields_init_0_err.out new file mode 100644 index 0000000000..1ec694bac1 --- /dev/null +++ b/vlib/v/checker/tests/struct_ref_fields_init_0_err.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/struct_ref_fields_init_0_err.vv:6:10: notice: assigning `0` to a reference field is only allowed in `unsafe` blocks + 4 | + 5 | fn main() { + 6 | _ = Foo{0} + | ^ + 7 | _ = Foo{ + 8 | foo: 0 +vlib/v/checker/tests/struct_ref_fields_init_0_err.vv:8:3: notice: assigning `0` to a reference field is only allowed in `unsafe` blocks + 6 | _ = Foo{0} + 7 | _ = Foo{ + 8 | foo: 0 + | ~~~~~~ + 9 | } + 10 | } diff --git a/vlib/v/checker/tests/struct_ref_fields_init_0_err.vv b/vlib/v/checker/tests/struct_ref_fields_init_0_err.vv new file mode 100644 index 0000000000..e3e20f93fa --- /dev/null +++ b/vlib/v/checker/tests/struct_ref_fields_init_0_err.vv @@ -0,0 +1,10 @@ +struct Foo { + foo &u8 +} + +fn main() { + _ = Foo{0} + _ = Foo{ + foo: 0 + } +} diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 54f9f0eeb7..277e26bda6 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -215,7 +215,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { mut gen_or := false mut blank_assign := false mut ident := ast.Ident{ - scope: 0 + scope: unsafe { nil } } left_sym := g.table.sym(g.unwrap_generic(var_type)) if mut left is ast.Ident { @@ -781,7 +781,7 @@ fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Typ for i, lx in node.left { mut is_auto_heap := false mut ident := ast.Ident{ - scope: 0 + scope: unsafe { nil } } if lx is ast.Ident { ident = lx diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 7661992548..a9efbadc74 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -279,7 +279,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref_ &pref.Preferences) (string } mut reflection_strings := map[string]int{} mut global_g := Gen{ - file: 0 + file: unsafe { nil } out: strings.new_builder(512000) cheaders: strings.new_builder(15000) includes: strings.new_builder(100) @@ -308,7 +308,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref_ &pref.Preferences) (string sql_buf: strings.new_builder(100) table: table pref: pref_ - fn_decl: 0 + fn_decl: unsafe { nil } is_autofree: pref_.autofree indent: -1 module_built: module_built @@ -662,7 +662,7 @@ fn cgen_process_one_file_cb(mut p pool.PoolProcessor, idx int, wid int) &Gen { cleanup: strings.new_builder(100) table: global_g.table pref: global_g.pref - fn_decl: 0 + fn_decl: unsafe { nil } indent: -1 module_built: global_g.module_built timers: util.new_timers( @@ -3994,7 +3994,7 @@ fn (mut g Gen) lock_expr(node ast.LockExpr) { g.cur_lock = unsafe { node } // is ok because it is discarded at end of fn defer { g.cur_lock = ast.LockExpr{ - scope: 0 + scope: unsafe { nil } } } tmp_result := if node.is_expr { g.new_tmp_var() } else { '' } diff --git a/vlib/v/gen/c/orm.v b/vlib/v/gen/c/orm.v index 45493eaf23..a0ae8cd68a 100644 --- a/vlib/v/gen/c/orm.v +++ b/vlib/v/gen/c/orm.v @@ -1025,7 +1025,7 @@ fn (mut g Gen) write_orm_select(node ast.SqlExpr, connection_var_name string, re expr: right_where_expr expr_type: (right_where_expr.info as ast.IdentVar).typ typ: (right_where_expr.info as ast.IdentVar).typ - scope: 0 + scope: unsafe { nil } } mut sql_expr_select_array := ast.SqlExpr{ typ: field.typ.set_flag(.result) diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 34fea757b7..a80edc3a2e 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -102,7 +102,7 @@ fn (mut p Parser) hash() ast.HashStmt { fn (mut p Parser) comptime_call() ast.ComptimeCall { err_node := ast.ComptimeCall{ - scope: 0 + scope: unsafe { nil } } start_pos := p.tok.pos() p.check(.dollar) @@ -130,7 +130,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { p.check(.string) p.check(.rpar) return ast.ComptimeCall{ - scope: 0 + scope: unsafe { nil } method_name: method_name args_var: s is_env: method_name == 'env' @@ -149,14 +149,14 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { p.check(.rpar) if has_args { return ast.ComptimeCall{ - scope: 0 + scope: unsafe { nil } method_name: method_name args_var: type_index pos: start_pos.extend(p.prev_tok.pos()) } } return ast.ComptimeCall{ - scope: 0 + scope: unsafe { nil } method_name: method_name pos: start_pos.extend(p.prev_tok.pos()) } @@ -197,7 +197,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { p.register_auto_import('v.preludes.embed_file.zlib') } return ast.ComptimeCall{ - scope: 0 + scope: unsafe { nil } is_embed: true embed_file: ast.EmbeddedFile{ compression_type: embed_compression_type @@ -233,7 +233,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { if !os.exists(path) { if p.pref.is_fmt { return ast.ComptimeCall{ - scope: 0 + scope: unsafe { nil } is_vweb: true method_name: method_name args_var: literal_string_param @@ -274,7 +274,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { mut file := parse_comptime(tmpl_path, v_code, p.table, p.pref, p.scope) file.path = tmpl_path return ast.ComptimeCall{ - scope: 0 + scope: unsafe { nil } is_vweb: true vweb_tmpl: file method_name: method_name diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 53ec7c36b1..a6758ea864 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -289,7 +289,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { if p.tok.kind == .lpar { is_method = true p.fn_receiver(mut params, mut rec) or { return ast.FnDecl{ - scope: 0 + scope: unsafe { nil } } } // rec.language was initialized with language variable. @@ -321,7 +321,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { p.error_with_pos('function names cannot contain uppercase letters, use snake_case instead', name_pos) return ast.FnDecl{ - scope: 0 + scope: unsafe { nil } } } if is_method { @@ -336,7 +336,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { if is_duplicate { p.error_with_pos('duplicate method `${name}`', name_pos) return ast.FnDecl{ - scope: 0 + scope: unsafe { nil } } } } @@ -344,7 +344,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { if name in p.imported_symbols { p.error_with_pos('cannot redefine imported function `${name}`', name_pos) return ast.FnDecl{ - scope: 0 + scope: unsafe { nil } } } } @@ -374,7 +374,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { } else { p.error_with_pos('expecting method name', p.tok.pos()) return ast.FnDecl{ - scope: 0 + scope: unsafe { nil } } } // [T] @@ -386,7 +386,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { fn_generic_names := generic_names.clone() generic_names = p.types_to_names(sym.info.generic_types, p.tok.pos(), 'sym.info.generic_types') or { return ast.FnDecl{ - scope: 0 + scope: unsafe { nil } } } for gname in fn_generic_names { @@ -407,7 +407,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { if p.scope.known_var(param.name) { p.error_with_pos('redefinition of parameter `${param.name}`', param.pos) return ast.FnDecl{ - scope: 0 + scope: unsafe { nil } } } is_stack_obj := !param.typ.has_flag(.shared_f) && (param.is_mut || param.typ.is_ptr()) @@ -483,7 +483,7 @@ run them via `v file.v` instead', p.error_with_pos('cannot define new methods on non-local type ${type_sym.name}', rec.type_pos) return ast.FnDecl{ - scope: 0 + scope: unsafe { nil } } } type_sym_method_idx = type_sym.register_method(ast.Fn{ @@ -585,7 +585,7 @@ run them via `v file.v` instead', if !no_body && are_params_type_only { p.error_with_pos('functions with type only params can not have bodies', body_start_pos) return ast.FnDecl{ - scope: 0 + scope: unsafe { nil } } } // if no_body && !name.starts_with('C.') { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 5797467764..56be983ac8 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -262,7 +262,7 @@ pub fn parse_vet_file(path string, table_ &ast.Table, pref_ &pref.Preferences) ( eprintln('> ${@MOD}.${@FN} path: ${path}') } global_scope := &ast.Scope{ - parent: 0 + parent: unsafe { nil } } mut p := Parser{ scanner: scanner.new_scanner_file(path, .parse_comments, pref_) or { panic(err) } @@ -1194,7 +1194,7 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt { p.check(.lcbr) p.scope = &ast.Scope{ - parent: 0 // you shouldn't be able to reference other variables in assembly blocks + parent: unsafe { nil } // you shouldn't be able to reference other variables in assembly blocks detached_from_parent: true start_pos: p.tok.pos objects: ast.all_registers(mut p.table, arch) // @@ -4295,7 +4295,7 @@ fn (mut p Parser) assoc() ast.Assoc { mut v := p.scope.find_var(var_name) or { p.error('unknown variable `${var_name}`') return ast.Assoc{ - scope: 0 + scope: unsafe { nil } } } v.is_used = true