cgen: check for null when calling function pointers in structs
parent
e2822356c2
commit
7f26e6d457
|
@ -802,6 +802,25 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) fn_call(node ast.CallExpr) {
|
fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||||
|
mut nullcheck := false
|
||||||
|
if node.is_field && !node.return_type.has_flag(.optional) {
|
||||||
|
nullcheck = true
|
||||||
|
g.write('/* null check */ (')
|
||||||
|
// fn_name := c_name(node.name)
|
||||||
|
if node.left_type != 0 {
|
||||||
|
left_sym := g.table.get_type_symbol(node.left_type)
|
||||||
|
if left_sym.kind == .interface_ {
|
||||||
|
g.write('(*')
|
||||||
|
}
|
||||||
|
g.expr(node.left)
|
||||||
|
if node.left_type.is_ptr() {
|
||||||
|
g.write('->')
|
||||||
|
} else {
|
||||||
|
g.write('.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.write('$node.name)? ')
|
||||||
|
}
|
||||||
// call struct field with fn type
|
// call struct field with fn type
|
||||||
// TODO: test node.left instead
|
// TODO: test node.left instead
|
||||||
// left & left_type will be `x` and `x type` in `x.fieldfn()`
|
// left & left_type will be `x` and `x type` in `x.fieldfn()`
|
||||||
|
@ -969,6 +988,13 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.write(')')
|
g.write(')')
|
||||||
|
if nullcheck && node.left_type != 0 {
|
||||||
|
g.write(': 0')
|
||||||
|
left_sym := g.table.get_type_symbol(node.left_type)
|
||||||
|
if left_sym.kind == .interface_ {
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
}
|
||||||
if tmp_cnt_save >= 0 {
|
if tmp_cnt_save >= 0 {
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
g.keep_alive_call_postgen(node, tmp_cnt_save)
|
g.keep_alive_call_postgen(node, tmp_cnt_save)
|
||||||
|
|
|
@ -27,3 +27,28 @@ fn test_struct_fn_field_can_be_used_directly() {
|
||||||
eprintln(res)
|
eprintln(res)
|
||||||
assert res == [byte(0x88), 0x01, 0x02, 0x02, 0x99]
|
assert res == [byte(0x88), 0x01, 0x02, 0x02, 0x99]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// null check test
|
||||||
|
|
||||||
|
struct NullCall {
|
||||||
|
mut:
|
||||||
|
nullcall fn ()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hello() {
|
||||||
|
println('hello world')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn null_function() fn () {
|
||||||
|
return NullCall{}.nullcall
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_struct_fn_field_can_be_null() {
|
||||||
|
mut a := NullCall{hello}
|
||||||
|
a.nullcall()
|
||||||
|
a.nullcall = null_function()
|
||||||
|
a.nullcall() // not segfault
|
||||||
|
unsafe {
|
||||||
|
a.nullcall() // do segfault
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue