checker: warn if unsafe method called outside unsafe block (#5863)
parent
90d9040e6e
commit
105a0e015e
|
@ -331,12 +331,18 @@ pub fn (a &array) clone() array {
|
||||||
if a.element_size == sizeof(array) {
|
if a.element_size == sizeof(array) {
|
||||||
for i in 0..a.len {
|
for i in 0..a.len {
|
||||||
ar := array{}
|
ar := array{}
|
||||||
C.memcpy(&ar, a.get_unsafe(i), sizeof(array))
|
unsafe {
|
||||||
|
C.memcpy(&ar, a.get_unsafe(i), sizeof(array))
|
||||||
|
}
|
||||||
ar_clone := ar.clone()
|
ar_clone := ar.clone()
|
||||||
arr.set_unsafe(i, &ar_clone)
|
unsafe {
|
||||||
|
arr.set_unsafe(i, &ar_clone)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
C.memcpy(byteptr(arr.data), a.data, a.cap * a.element_size)
|
unsafe {
|
||||||
|
C.memcpy(byteptr(arr.data), a.data, a.cap * a.element_size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
@ -681,7 +687,9 @@ pub fn compare_f32(a, b &f32) int {
|
||||||
pub fn (a array) pointers() []voidptr {
|
pub fn (a array) pointers() []voidptr {
|
||||||
mut res := []voidptr{}
|
mut res := []voidptr{}
|
||||||
for i in 0..a.len {
|
for i in 0..a.len {
|
||||||
res << a.get_unsafe(i)
|
unsafe {
|
||||||
|
res << a.get_unsafe(i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -517,7 +517,7 @@ pub fn (m map) clone() map {
|
||||||
cap: m.cap
|
cap: m.cap
|
||||||
cached_hashbits: m.cached_hashbits
|
cached_hashbits: m.cached_hashbits
|
||||||
shift: m.shift
|
shift: m.shift
|
||||||
key_values: m.key_values.clone()
|
key_values: unsafe {m.key_values.clone()}
|
||||||
metas: &u32(malloc(int(metas_size)))
|
metas: &u32(malloc(int(metas_size)))
|
||||||
extra_metas: m.extra_metas
|
extra_metas: m.extra_metas
|
||||||
len: m.len
|
len: m.len
|
||||||
|
|
|
@ -1201,11 +1201,14 @@ pub fn (u ustring) at(idx int) string {
|
||||||
return u.substr(idx, idx + 1)
|
return u.substr(idx, idx + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[unsafe_fn]
|
||||||
fn (u &ustring) free() {
|
fn (u &ustring) free() {
|
||||||
$if prealloc {
|
$if prealloc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u.runes.free()
|
unsafe {
|
||||||
|
u.runes.free()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c byte) is_digit() bool {
|
pub fn (c byte) is_digit() bool {
|
||||||
|
|
|
@ -42,17 +42,22 @@ pub fn compile(command string, pref &pref.Preferences) {
|
||||||
println('compilation took: $sw.elapsed().milliseconds() ms')
|
println('compilation took: $sw.elapsed().milliseconds() ms')
|
||||||
}
|
}
|
||||||
// running does not require the parsers anymore
|
// running does not require the parsers anymore
|
||||||
b.myfree()
|
unsafe {
|
||||||
|
b.myfree()
|
||||||
|
}
|
||||||
if pref.is_test || pref.is_run {
|
if pref.is_test || pref.is_run {
|
||||||
b.run_compiled_executable_and_exit()
|
b.run_compiled_executable_and_exit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporary, will be done by -autofree
|
// Temporary, will be done by -autofree
|
||||||
|
[unsafe_fn]
|
||||||
fn (mut b Builder) myfree() {
|
fn (mut b Builder) myfree() {
|
||||||
// for file in b.parsed_files {
|
// for file in b.parsed_files {
|
||||||
// }
|
// }
|
||||||
b.parsed_files.free()
|
unsafe {
|
||||||
|
b.parsed_files.free()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut b Builder) run_compiled_executable_and_exit() {
|
fn (mut b Builder) run_compiled_executable_and_exit() {
|
||||||
|
|
|
@ -954,6 +954,10 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if method.is_unsafe && !c.inside_unsafe {
|
||||||
|
c.warn('method `${left_type_sym.name}.$method_name` must be called from an `unsafe` block',
|
||||||
|
call_expr.pos)
|
||||||
|
}
|
||||||
// TODO: typ optimize.. this node can get processed more than once
|
// TODO: typ optimize.. this node can get processed more than once
|
||||||
if call_expr.expected_arg_types.len == 0 {
|
if call_expr.expected_arg_types.len == 0 {
|
||||||
for i in 1 .. method.args.len {
|
for i in 1 .. method.args.len {
|
||||||
|
|
|
@ -123,6 +123,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
p.top_level_statement_start()
|
p.top_level_statement_start()
|
||||||
start_pos := p.tok.position()
|
start_pos := p.tok.position()
|
||||||
is_deprecated := 'deprecated' in p.attrs
|
is_deprecated := 'deprecated' in p.attrs
|
||||||
|
is_unsafe := 'unsafe_fn' in p.attrs
|
||||||
is_pub := p.tok.kind == .key_pub
|
is_pub := p.tok.kind == .key_pub
|
||||||
if is_pub {
|
if is_pub {
|
||||||
p.next()
|
p.next()
|
||||||
|
@ -250,6 +251,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
is_generic: is_generic
|
is_generic: is_generic
|
||||||
is_pub: is_pub
|
is_pub: is_pub
|
||||||
is_deprecated: is_deprecated
|
is_deprecated: is_deprecated
|
||||||
|
is_unsafe: is_unsafe
|
||||||
ctdefine: ctdefine
|
ctdefine: ctdefine
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
attrs: p.attrs
|
attrs: p.attrs
|
||||||
|
@ -271,12 +273,13 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
args: args
|
args: args
|
||||||
return_type: return_type
|
return_type: return_type
|
||||||
is_variadic: is_variadic
|
is_variadic: is_variadic
|
||||||
language: language
|
|
||||||
is_generic: is_generic
|
is_generic: is_generic
|
||||||
is_pub: is_pub
|
is_pub: is_pub
|
||||||
is_deprecated: is_deprecated
|
is_deprecated: is_deprecated
|
||||||
|
is_unsafe: is_unsafe
|
||||||
ctdefine: ctdefine
|
ctdefine: ctdefine
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
|
language: language
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Body
|
// Body
|
||||||
|
|
|
@ -29,6 +29,7 @@ pub:
|
||||||
is_generic bool
|
is_generic bool
|
||||||
is_pub bool
|
is_pub bool
|
||||||
is_deprecated bool
|
is_deprecated bool
|
||||||
|
is_unsafe bool
|
||||||
mod string
|
mod string
|
||||||
ctdefine string // compile time define. myflag, when [if myflag] tag
|
ctdefine string // compile time define. myflag, when [if myflag] tag
|
||||||
attrs []string
|
attrs []string
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
unsafe.v:4:6: warning: pointer arithmetic is only allowed in `unsafe` blocks
|
||||||
|
2 | v := 5
|
||||||
|
3 | mut p := &v
|
||||||
|
4 | p++
|
||||||
|
| ~~
|
||||||
|
5 | p += 2
|
||||||
|
6 | _ := v
|
||||||
|
unsafe.v:5:7: warning: pointer arithmetic is only allowed in `unsafe` blocks
|
||||||
|
3 | mut p := &v
|
||||||
|
4 | p++
|
||||||
|
5 | p += 2
|
||||||
|
| ~~
|
||||||
|
6 | _ := v
|
||||||
|
7 | }
|
||||||
|
unsafe.v:11:14: warning: pointer arithmetic is only allowed in `unsafe` blocks
|
||||||
|
9 | fn test_ptr_infix() {
|
||||||
|
10 | v := 4
|
||||||
|
11 | mut q := &v - 1
|
||||||
|
| ^
|
||||||
|
12 | q = q + 3
|
||||||
|
13 | _ := q
|
||||||
|
unsafe.v:12:9: warning: pointer arithmetic is only allowed in `unsafe` blocks
|
||||||
|
10 | v := 4
|
||||||
|
11 | mut q := &v - 1
|
||||||
|
12 | q = q + 3
|
||||||
|
| ^
|
||||||
|
13 | _ := q
|
||||||
|
14 | _ := v
|
||||||
|
unsafe.v:24:7: warning: method `S1.f` must be called from an `unsafe` block
|
||||||
|
22 | fn test_funcs() {
|
||||||
|
23 | s := S1{}
|
||||||
|
24 | s.f()
|
||||||
|
| ~~~
|
||||||
|
25 | }
|
|
@ -0,0 +1,25 @@
|
||||||
|
fn test_ptr_assign() {
|
||||||
|
v := 5
|
||||||
|
mut p := &v
|
||||||
|
p++
|
||||||
|
p += 2
|
||||||
|
_ := v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_ptr_infix() {
|
||||||
|
v := 4
|
||||||
|
mut q := &v - 1
|
||||||
|
q = q + 3
|
||||||
|
_ := q
|
||||||
|
_ := v
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S1 {}
|
||||||
|
|
||||||
|
[unsafe_fn]
|
||||||
|
fn (s S1) f(){}
|
||||||
|
|
||||||
|
fn test_funcs() {
|
||||||
|
s := S1{}
|
||||||
|
s.f()
|
||||||
|
}
|
Loading…
Reference in New Issue