From dd859eae55cf4e69346851fe285b9af104c8ffb7 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Tue, 6 May 2025 06:48:55 -0300 Subject: [PATCH] cgen: fix interface `unsafe {nil}` comparison and initialization (fix #24374) (#24411) --- vlib/v/gen/c/auto_eq_methods.v | 6 ++++++ vlib/v/gen/c/cgen.v | 3 +++ .../fn_returning_voidptr_casted_as_interface_test.v | 2 +- vlib/v/tests/interfaces/interface_nil_cmp_test.v | 13 +++++++++++++ ...uct_init_with_interface_pointer_and_embed_test.v | 2 +- 5 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 vlib/v/tests/interfaces/interface_nil_cmp_test.v diff --git a/vlib/v/gen/c/auto_eq_methods.v b/vlib/v/gen/c/auto_eq_methods.v index 84b8308c5f..42189c0252 100644 --- a/vlib/v/gen/c/auto_eq_methods.v +++ b/vlib/v/gen/c/auto_eq_methods.v @@ -258,7 +258,13 @@ fn (mut g Gen) gen_struct_equality_fn(left_type ast.Type) string { && (!field.typ.has_flag(.option) || !field.typ.is_ptr()) { ptr := if field.typ.is_ptr() { '*'.repeat(field.typ.nr_muls()) } else { '' } eq_fn := g.gen_interface_equality_fn(field.typ) + if ptr != '' { + fn_builder.write_string('((${left_arg} == (void*)0 && ${right_arg} == (void*)0) || (${left_arg} != (void*)0 && ${right_arg} != (void*)0 && ') + } fn_builder.write_string('${eq_fn}_interface_eq(${ptr}${left_arg}, ${ptr}${right_arg})') + if ptr != '' { + fn_builder.write_string('))') + } } else if field.typ.has_flag(.option) { fn_builder.write_string('!memcmp(&${left_arg}.data, &${right_arg}.data, sizeof(${g.base_type(field.typ)}))') } else { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index e560659401..5c9d79b053 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2786,6 +2786,9 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Ty g.write('&(${exp_styp.trim_right('*')}){._${got_styp.trim_right('*')}=') rparen_n = 0 mutable_idx = got.idx() + } else if expr is ast.UnsafeExpr && expr.expr is ast.Nil { + g.write('(void*)0') + return } else { g.write('HEAP(${exp_styp}, ${fname}(') rparen_n++ diff --git a/vlib/v/tests/interfaces/interface_edge_cases/fn_returning_voidptr_casted_as_interface_test.v b/vlib/v/tests/interfaces/interface_edge_cases/fn_returning_voidptr_casted_as_interface_test.v index f4c7792e8e..380ac356a9 100644 --- a/vlib/v/tests/interfaces/interface_edge_cases/fn_returning_voidptr_casted_as_interface_test.v +++ b/vlib/v/tests/interfaces/interface_edge_cases/fn_returning_voidptr_casted_as_interface_test.v @@ -23,5 +23,5 @@ fn test_fn_returning_voidptr_casted_as_interface_works() { // TODO: understand the root reason why msvc and // `-cc clang-11 -cflags -fsanitize=memory` produce // something like `&IAbc(e42aff650)` here - assert f(pi).contains('&IAbc(') + assert f(pi) == '&nil' } diff --git a/vlib/v/tests/interfaces/interface_nil_cmp_test.v b/vlib/v/tests/interfaces/interface_nil_cmp_test.v new file mode 100644 index 0000000000..3932320f79 --- /dev/null +++ b/vlib/v/tests/interfaces/interface_nil_cmp_test.v @@ -0,0 +1,13 @@ +interface Cfg { + id string +} + +struct XX { + cfg &Cfg = unsafe { nil } +} + +fn test_main() { + xx := XX{} + assert xx.cfg == unsafe { nil } + assert unsafe { nil } == xx.cfg +} diff --git a/vlib/v/tests/structs/struct_init_with_interface_pointer_and_embed_test.v b/vlib/v/tests/structs/struct_init_with_interface_pointer_and_embed_test.v index 5416510977..52fa639d0b 100644 --- a/vlib/v/tests/structs/struct_init_with_interface_pointer_and_embed_test.v +++ b/vlib/v/tests/structs/struct_init_with_interface_pointer_and_embed_test.v @@ -24,6 +24,6 @@ fn test_struct_with_both_an_embed_and_a_pointer_to_interface_value_fields__initi assert si.contains('Embed: Embed{') assert si.contains('foo: 0') assert si.contains('id: 0') - assert si.contains('parent: &Node(0x0)') + assert si.contains('parent: &nil') assert si.contains('}') }