diff --git a/vlib/os/process_windows.c.v b/vlib/os/process_windows.c.v index 8b7193b992a150..4894feb5e6f4ad 100644 --- a/vlib/os/process_windows.c.v +++ b/vlib/os/process_windows.c.v @@ -14,7 +14,7 @@ type FN_NTSuspendResume = fn (voidptr) u64 fn ntdll_fn(name &char) FN_NTSuspendResume { ntdll := C.GetModuleHandleA(c'NTDLL') if ntdll == 0 { - return FN_NTSuspendResume(0) + return unsafe { FN_NTSuspendResume(0) } } the_fn := FN_NTSuspendResume(C.GetProcAddress(ntdll, voidptr(name))) return the_fn diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 4a8f7fa212de8f..2925cd7035130e 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3591,6 +3591,25 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { || c.file.is_translated) && !c.check_matching_function_symbols(final_from_sym, final_to_sym) { c.error('casting a function value from one function signature, to another function signature, should be done inside `unsafe{}` blocks', node.pos) + } else if final_to_sym.kind == .function && final_from_sym.kind != .function { + if to_type.has_flag(.option) && node.expr !is ast.None { + c.error('casting number to Option function is not allowed, only compatible function or `none`', + node.pos) + } else if !(c.inside_unsafe || c.file.is_translated) { + if node.expr is ast.IntegerLiteral { + c.warn('casting number to function value should be done inside `unsafe{}` blocks', + node.pos) + } else if node.expr is ast.Nil { + c.warn('casting `nil` to function value should be done inside `unsafe{}` blocks', + node.pos) + } else if node.expr is ast.None { + if from_type.has_flag(.option) { + c.warn('cannot pass `none` to a non Option function type', node.pos) + } + } else if final_from_sym.kind != .voidptr { + c.error('invalid casting value to function', node.pos) + } + } } if to_type.is_ptr() && to_sym.kind == .alias && from_sym.kind == .map { c.error('cannot cast to alias pointer `${c.table.type_to_str(to_type)}` because `${c.table.type_to_str(from_type)}` is a value', diff --git a/vlib/v/checker/tests/cast_fn_err.out b/vlib/v/checker/tests/cast_fn_err.out new file mode 100644 index 00000000000000..2e690ffd58629b --- /dev/null +++ b/vlib/v/checker/tests/cast_fn_err.out @@ -0,0 +1,69 @@ +vlib/v/checker/tests/cast_fn_err.vv:24:7: warning: casting `nil` to function value should be done inside `unsafe{}` blocks + 22 | // wrong ones + 23 | _ := FnType(foo) + 24 | _ := FnType(nil) + | ~~~~~~~~~~~ + 25 | _ := FnType(0) + 26 | _ := FnType('foo') +vlib/v/checker/tests/cast_fn_err.vv:25:7: warning: casting number to function value should be done inside `unsafe{}` blocks + 23 | _ := FnType(foo) + 24 | _ := FnType(nil) + 25 | _ := FnType(0) + | ~~~~~~~~~ + 26 | _ := FnType('foo') + 27 | _ := FnType(none) +vlib/v/checker/tests/cast_fn_err.vv:23:7: error: casting a function value from one function signature, to another function signature, should be done inside `unsafe{}` blocks + 21 | + 22 | // wrong ones + 23 | _ := FnType(foo) + | ~~~~~~~~~~~ + 24 | _ := FnType(nil) + 25 | _ := FnType(0) +vlib/v/checker/tests/cast_fn_err.vv:24:14: error: `nil` is only allowed in `unsafe` code + 22 | // wrong ones + 23 | _ := FnType(foo) + 24 | _ := FnType(nil) + | ~~~ + 25 | _ := FnType(0) + 26 | _ := FnType('foo') +vlib/v/checker/tests/cast_fn_err.vv:26:7: error: invalid casting value to function + 24 | _ := FnType(nil) + 25 | _ := FnType(0) + 26 | _ := FnType('foo') + | ~~~~~~~~~~~~~ + 27 | _ := FnType(none) + 28 | _ := ?FnType(0) +vlib/v/checker/tests/cast_fn_err.vv:27:7: error: cannot cast `none` to `fn () bool` + 25 | _ := FnType(0) + 26 | _ := FnType('foo') + 27 | _ := FnType(none) + | ~~~~~~~~~~~~ + 28 | _ := ?FnType(0) + 29 | _ := ?FnType(nil) +vlib/v/checker/tests/cast_fn_err.vv:28:8: error: casting number to Option function is not allowed, only compatible function or `none` + 26 | _ := FnType('foo') + 27 | _ := FnType(none) + 28 | _ := ?FnType(0) + | ~~~~~~~~~ + 29 | _ := ?FnType(nil) + 30 | _ := ?FnType(foo) +vlib/v/checker/tests/cast_fn_err.vv:29:15: error: `nil` is only allowed in `unsafe` code + 27 | _ := FnType(none) + 28 | _ := ?FnType(0) + 29 | _ := ?FnType(nil) + | ~~~ + 30 | _ := ?FnType(foo) + 31 | } +vlib/v/checker/tests/cast_fn_err.vv:29:8: error: casting number to Option function is not allowed, only compatible function or `none` + 27 | _ := FnType(none) + 28 | _ := ?FnType(0) + 29 | _ := ?FnType(nil) + | ~~~~~~~~~~~ + 30 | _ := ?FnType(foo) + 31 | } +vlib/v/checker/tests/cast_fn_err.vv:30:8: error: casting a function value from one function signature, to another function signature, should be done inside `unsafe{}` blocks + 28 | _ := ?FnType(0) + 29 | _ := ?FnType(nil) + 30 | _ := ?FnType(foo) + | ~~~~~~~~~~~ + 31 | } diff --git a/vlib/v/checker/tests/cast_fn_err.vv b/vlib/v/checker/tests/cast_fn_err.vv new file mode 100644 index 00000000000000..7188a82313d23d --- /dev/null +++ b/vlib/v/checker/tests/cast_fn_err.vv @@ -0,0 +1,31 @@ +type FnType = fn () bool + +fn foo() int { + return 0 +} + +fn bar() bool { + return true +} + +fn main() { + // acceptable ones + _ := unsafe { FnType(nil) } + _ := unsafe { FnType(0) } + _ := unsafe { FnType(foo) } + _ := unsafe { FnType(bar) } + _ := FnType(bar) + _ := ?FnType(none) + _ := ?FnType(bar) + _ := unsafe { ?FnType(foo) } + + // wrong ones + _ := FnType(foo) + _ := FnType(nil) + _ := FnType(0) + _ := FnType('foo') + _ := FnType(none) + _ := ?FnType(0) + _ := ?FnType(nil) + _ := ?FnType(foo) +} diff --git a/vlib/v/checker/tests/mut_arg_different_muls_err.vv b/vlib/v/checker/tests/mut_arg_different_muls_err.vv index b4af7c30301be4..d04f29ecf1dcd4 100644 --- a/vlib/v/checker/tests/mut_arg_different_muls_err.vv +++ b/vlib/v/checker/tests/mut_arg_different_muls_err.vv @@ -16,7 +16,7 @@ pub: fn window_resized(mut w &Window) { window_width, window_height := 200, 100 - if w.resize_fn != WindowResizeFn(0) { + if w.resize_fn != unsafe { WindowResizeFn(0) } { println('fn present ${window_width} ${window_height}') w.resize_fn(w, window_width, window_height) }