checker: prohibit passing non-lvalue as `voidptr` (#10838)
parent
1a6a7a678a
commit
eb65ad078d
|
@ -93,6 +93,7 @@ test.bin
|
||||||
|
|
||||||
# ignore codespace env
|
# ignore codespace env
|
||||||
.venv/
|
.venv/
|
||||||
|
.direnv/
|
||||||
shell.nix
|
shell.nix
|
||||||
default.nix
|
default.nix
|
||||||
flake.nix
|
flake.nix
|
||||||
|
|
|
@ -157,6 +157,11 @@ pub fn (t Type) is_ptr() bool {
|
||||||
return (int(t) >> 16) & 0xff > 0
|
return (int(t) >> 16) & 0xff > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn (t Type) is_any_kind_of_pointer() bool {
|
||||||
|
return (int(t) >> 16) & 0xff > 0 || (u16(t) & 0xffff) in ast.pointer_type_idxs
|
||||||
|
}
|
||||||
|
|
||||||
// set nr_muls on `t` and return it
|
// set nr_muls on `t` and return it
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (t Type) set_nr_muls(nr_muls int) Type {
|
pub fn (t Type) set_nr_muls(nr_muls int) Type {
|
||||||
|
|
|
@ -2825,6 +2825,19 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
||||||
if func.is_variadic && param_typ_sym.info is ast.Array {
|
if func.is_variadic && param_typ_sym.info is ast.Array {
|
||||||
final_param_sym = c.table.get_type_symbol(param_typ_sym.array_info().elem_type)
|
final_param_sym = c.table.get_type_symbol(param_typ_sym.array_info().elem_type)
|
||||||
}
|
}
|
||||||
|
// NB: Casting to voidptr is used as an escape mechanism, so:
|
||||||
|
// 1. allow passing *explicit* voidptr (native or through cast) to functions
|
||||||
|
// expecting voidptr or ...voidptr
|
||||||
|
// ... but 2. disallow passing non-pointers - that is very rarely what the user wanted,
|
||||||
|
// it can lead to codegen errors (except for 'magic' functions like `json.encode` that,
|
||||||
|
// the compiler has special codegen support for), so it should be opt in, that is it
|
||||||
|
// shoould require an explicit voidptr(x) cast (and probably unsafe{} ?) .
|
||||||
|
if call_arg.typ != param.typ
|
||||||
|
&& (param.typ == ast.voidptr_type || final_param_sym.idx == ast.voidptr_type_idx)
|
||||||
|
&& !call_arg.typ.is_any_kind_of_pointer() && func.language == .v
|
||||||
|
&& !call_arg.expr.is_lvalue() && func.name != 'json.encode' {
|
||||||
|
c.error('expression cannot be passed as `voidptr`', call_arg.expr.position())
|
||||||
|
}
|
||||||
// Handle expected interface
|
// Handle expected interface
|
||||||
if final_param_sym.kind == .interface_ {
|
if final_param_sym.kind == .interface_ {
|
||||||
if c.type_implements(typ, param.typ, call_arg.expr.position()) {
|
if c.type_implements(typ, param.typ, call_arg.expr.position()) {
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
vlib/v/checker/tests/non_lvalue_as_voidptr.vv:5:13: error: expression cannot be passed as `voidptr`
|
||||||
|
3 | }
|
||||||
|
4 |
|
||||||
|
5 | println(add(5, 10))
|
||||||
|
| ^
|
|
@ -0,0 +1,5 @@
|
||||||
|
fn add(a voidptr, b voidptr) int {
|
||||||
|
return int(a) + int(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
println(add(5, 10))
|
|
@ -0,0 +1,5 @@
|
||||||
|
vlib/v/checker/tests/passing_expr_to_fn_expecting_voidptr.vv:3:31: error: expression cannot be passed as `voidptr`
|
||||||
|
1 | import strconv
|
||||||
|
2 |
|
||||||
|
3 | strconv.v_printf('%02.02f\n', 1.1)
|
||||||
|
| ~~~
|
|
@ -0,0 +1,3 @@
|
||||||
|
import strconv
|
||||||
|
|
||||||
|
strconv.v_printf('%02.02f\n', 1.1)
|
Loading…
Reference in New Issue