all: assigning 0 to reference fields now requires unsafe blocks (fix #14911) (#19955)

This commit is contained in:
shove 2023-11-23 17:16:26 +08:00 committed by GitHub
parent 9d7fe51b6e
commit 2a6c1d9074
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 91 additions and 58 deletions

View file

@ -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 {

View file

@ -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)
}

View file

@ -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{

View file

@ -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 = '*'

View file

@ -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

View file

@ -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 {

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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) {
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)

View file

@ -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 | }

View file

@ -0,0 +1,10 @@
struct Foo {
foo &u8
}
fn main() {
_ = Foo{0}
_ = Foo{
foo: 0
}
}

View file

@ -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

View file

@ -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 { '' }

View file

@ -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)

View file

@ -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

View file

@ -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.') {

View file

@ -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