From 071ab6c3628b402123a7a5add8dc6b9331422c09 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sun, 6 Apr 2025 02:27:57 -0300 Subject: [PATCH] checker, cgen: fix non-voidptr to voidptr on `-cstrict` + notice about such usage (fix #24139) (#24143) --- vlib/os/file.c.v | 6 ++--- vlib/v/checker/fn.v | 5 ++++ vlib/v/checker/struct.v | 25 ++++++++++++++++--- .../v/checker/tests/struct_void_field_err.out | 21 ++++++++++++++++ vlib/v/checker/tests/struct_void_field_err.vv | 19 ++++++++++++++ .../tests/struct_voidptr_field_init_err.out | 7 ++++++ vlib/v/gen/c/cgen.v | 4 ++- 7 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 vlib/v/checker/tests/struct_void_field_err.out create mode 100644 vlib/v/checker/tests/struct_void_field_err.vv diff --git a/vlib/os/file.c.v b/vlib/os/file.c.v index b69ef6ce0..146c34fc1 100644 --- a/vlib/os/file.c.v +++ b/vlib/os/file.c.v @@ -187,7 +187,7 @@ pub fn create(path string) !File { pub fn stdin() File { return File{ fd: 0 - cfile: C.stdin + cfile: voidptr(C.stdin) is_opened: true } } @@ -196,7 +196,7 @@ pub fn stdin() File { pub fn stdout() File { return File{ fd: 1 - cfile: C.stdout + cfile: voidptr(C.stdout) is_opened: true } } @@ -205,7 +205,7 @@ pub fn stdout() File { pub fn stderr() File { return File{ fd: 2 - cfile: C.stderr + cfile: voidptr(C.stderr) is_opened: true } } diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 71cd6441b..fcd9e4675 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -863,6 +863,7 @@ fn (mut c Checker) needs_unwrap_generic_type(typ ast.Type) bool { fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.Type { is_va_arg := node.name == 'C.va_arg' is_json_decode := node.name == 'json.decode' + is_json_encode := node.name == 'json.encode' mut fn_name := node.name if node.is_static_method { // resolve static call T.name() @@ -1780,6 +1781,10 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. } } } + if is_json_encode { + // json.encode param is set voidptr, we should bound the proper type here + node.expected_arg_types = [node.args[0].typ] + } if func.generic_names.len != node.concrete_types.len { // no type arguments given in call, attempt implicit instantiation c.infer_fn_generic_types(func, mut node) diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 140d99b1f..225bcdd7f 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -133,6 +133,16 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { } } + if c.table.final_sym(field.typ).kind == .voidptr + && field.default_expr_typ !in [ast.nil_type, ast.voidptr_type, ast.byteptr_type] + && !field.default_expr_typ.is_ptr() + && (field.default_expr !is ast.IntegerLiteral + || (field.default_expr is ast.IntegerLiteral + && field.default_expr.val.int() != 0)) { + c.note('voidptr variables may only be assigned voidptr values (e.g. unsafe { voidptr(${field.default_expr.str()}) })', + field.default_expr.pos()) + } + // disallow map `mut a = b` field_sym := c.table.sym(field.typ) expr_sym := c.table.sym(field.default_expr_typ) @@ -716,10 +726,17 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini if exp_type_is_option && got_type.is_ptr() && !exp_type.is_ptr() { c.error('cannot assign a pointer to option struct field', init_field.pos) } - if exp_type_sym.kind == .voidptr && got_type_sym.kind == .struct - && !got_type.is_ptr() { - c.error('allocate `${got_type_sym.name}` on the heap for use in other functions', - init_field.pos) + if exp_type_sym.kind == .voidptr { + if got_type_sym.kind == .struct && !got_type.is_ptr() { + c.error('allocate `${got_type_sym.name}` on the heap for use in other functions', + init_field.pos) + } else if got_type !in [ast.nil_type, ast.voidptr_type, ast.byteptr_type] + && !got_type.is_ptr() && (init_field.expr !is ast.IntegerLiteral + || (init_field.expr is ast.IntegerLiteral + && init_field.expr.val.int() != 0)) { + c.note('voidptr variables may only be assigned voidptr values (e.g. unsafe { voidptr(${init_field.expr.str()}) })', + init_field.expr.pos()) + } } // disallow `mut a: b`, when b is const map if exp_type_sym.kind == .map && got_type_sym.kind == .map && !got_type.is_ptr() diff --git a/vlib/v/checker/tests/struct_void_field_err.out b/vlib/v/checker/tests/struct_void_field_err.out new file mode 100644 index 000000000..f54f1d461 --- /dev/null +++ b/vlib/v/checker/tests/struct_void_field_err.out @@ -0,0 +1,21 @@ +vlib/v/checker/tests/struct_void_field_err.vv:5:16: notice: voidptr variables may only be assigned voidptr values (e.g. unsafe { voidptr(1) }) + 3 | struct Foo { + 4 | mut: + 5 | bar voidptr = 1 + | ^ + 6 | } + 7 | +vlib/v/checker/tests/struct_void_field_err.vv:11:8: notice: voidptr variables may only be assigned voidptr values (e.g. unsafe { voidptr(n) }) + 9 | n := 1 + 10 | _ := Foo{ + 11 | bar: n + | ^ + 12 | } + 13 | _ := Foo{ +vlib/v/checker/tests/struct_void_field_err.vv:17:8: notice: voidptr variables may only be assigned voidptr values (e.g. unsafe { voidptr(1) }) + 15 | } + 16 | _ := Foo{ + 17 | bar: 1 + | ^ + 18 | } + 19 | } diff --git a/vlib/v/checker/tests/struct_void_field_err.vv b/vlib/v/checker/tests/struct_void_field_err.vv new file mode 100644 index 000000000..b49b4df96 --- /dev/null +++ b/vlib/v/checker/tests/struct_void_field_err.vv @@ -0,0 +1,19 @@ +module main + +struct Foo { +mut: + bar voidptr = 1 +} + +fn main() { + n := 1 + _ := Foo{ + bar: n + } + _ := Foo{ + bar: 0 + } + _ := Foo{ + bar: 1 + } +} diff --git a/vlib/v/checker/tests/struct_voidptr_field_init_err.out b/vlib/v/checker/tests/struct_voidptr_field_init_err.out index 872bc8b29..c0279f4f1 100644 --- a/vlib/v/checker/tests/struct_voidptr_field_init_err.out +++ b/vlib/v/checker/tests/struct_voidptr_field_init_err.out @@ -1,3 +1,10 @@ +vlib/v/checker/tests/struct_voidptr_field_init_err.vv:7:12: notice: voidptr variables may only be assigned voidptr values (e.g. unsafe { voidptr(get()) }) + 5 | fn main() { + 6 | println(Example{ + 7 | example: get() + | ~~~~~ + 8 | }) + 9 | } vlib/v/checker/tests/struct_voidptr_field_init_err.vv:7:3: error: cannot assign to field `example`: expected a pointer `voidptr`, but got `string` 5 | fn main() { 6 | println(Example{ diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 92dc01900..7789d373a 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3092,7 +3092,9 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ return } } - if exp_sym.kind == .function && !expected_type.has_option_or_result() { + if (exp_sym.kind == .function && !expected_type.has_option_or_result()) + || (g.inside_struct_init && expected_type == ast.voidptr_type + && expected_type != got_type_raw) { g.write('(voidptr)') } // no cast -- 2.39.5