checker: prohibit passing non-lvalue as `voidptr` (#10838)
parent
1a6a7a678a
commit
eb65ad078d
|
@ -93,6 +93,7 @@ test.bin
|
|||
|
||||
# ignore codespace env
|
||||
.venv/
|
||||
.direnv/
|
||||
shell.nix
|
||||
default.nix
|
||||
flake.nix
|
||||
|
|
|
@ -157,6 +157,11 @@ pub fn (t Type) is_ptr() bool {
|
|||
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
|
||||
[inline]
|
||||
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 {
|
||||
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
|
||||
if final_param_sym.kind == .interface_ {
|
||||
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