diff --git a/vlib/cli/command.v b/vlib/cli/command.v index 178e22df7a9ae8..099421d64ffd86 100644 --- a/vlib/cli/command.v +++ b/vlib/cli/command.v @@ -18,9 +18,9 @@ pub mut: description string man_description string version string - pre_execute FnCommandCallback - execute FnCommandCallback - post_execute FnCommandCallback + pre_execute FnCommandCallback = unsafe { nil } + execute FnCommandCallback = unsafe { nil } + post_execute FnCommandCallback = unsafe { nil } disable_help bool disable_man bool disable_version bool diff --git a/vlib/datatypes/bloom_filter.v b/vlib/datatypes/bloom_filter.v index 34ee924da1abfd..8b909d87d8f481 100644 --- a/vlib/datatypes/bloom_filter.v +++ b/vlib/datatypes/bloom_filter.v @@ -4,13 +4,22 @@ module datatypes [heap] struct BloomFilter[T] { - hash_func fn (T) u32 // hash function, input [T] , output u32 - table_size int // every entry is one-bit, packed into `table` - num_functions int // 1~16 + // TODO V bug + hash_func fn (T) u32 = unsafe { nil } // hash function, input [T] , output u32 + // hash_func fn (T) u32 = empty_cb // hash function, input [T] , output u32 + table_size int // every entry is one-bit, packed into `table` + num_functions int // 1~16 mut: table []u8 } +/* +TODO maybe allow pointing to generic fns? +fn empty_cb[T](x T) u32 { + panic('empty BloomFilter.hash_func callback') +} +*/ + const ( // Salt values(random values). These salts are XORed with the output of the hash function to give multiple unique hashes. salts = [ diff --git a/vlib/eventbus/eventbus.v b/vlib/eventbus/eventbus.v index 1b5baf951a4052..dfa6fbb6e448de 100644 --- a/vlib/eventbus/eventbus.v +++ b/vlib/eventbus/eventbus.v @@ -19,8 +19,8 @@ mut: struct EventHandler[T] { name T - handler EventHandlerFn - receiver voidptr = unsafe { nil } + handler EventHandlerFn = unsafe { nil } + receiver voidptr = unsafe { nil } once bool } diff --git a/vlib/fontstash/fontstash_structs.c.v b/vlib/fontstash/fontstash_structs.c.v index 324db5464aa4d1..5d5f1d2bfdf185 100644 --- a/vlib/fontstash/fontstash_structs.c.v +++ b/vlib/fontstash/fontstash_structs.c.v @@ -6,15 +6,15 @@ pub struct C.FONSparams { flags char userPtr voidptr // int (*renderCreate)(void* uptr, int width, int height) - renderCreate fn (uptr voidptr, width int, height int) int + renderCreate fn (uptr voidptr, width int, height int) int = unsafe { nil } // int (*renderResize)(void* uptr, int width, int height) - renderResize fn (uptr voidptr, width int, height int) int + renderResize fn (uptr voidptr, width int, height int) int = unsafe { nil } // void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data) - renderUpdate fn (uptr voidptr, rect &int, data &u8) + renderUpdate fn (uptr voidptr, rect &int, data &u8) = unsafe { nil } // void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts) - renderDraw fn (uptr voidptr, verts &f32, tcoords &f32, colors &u32, nverts int) + renderDraw fn (uptr voidptr, verts &f32, tcoords &f32, colors &u32, nverts int) = unsafe { nil } // void (*renderDelete)(void* uptr) - renderDelete fn (uptr voidptr) + renderDelete fn (uptr voidptr) = unsafe { nil } } pub struct C.FONSquad { diff --git a/vlib/regex/regex.v b/vlib/regex/regex.v index 4c3ddc04df0194..36e47740823887 100644 --- a/vlib/regex/regex.v +++ b/vlib/regex/regex.v @@ -248,7 +248,7 @@ mut: // counters for quantifier check (repetitions) rep int // validator function pointer - validator FnValidator + validator FnValidator = unsafe { nil } // groups variables group_neg bool // negation flag for the group, 0 => no negation > 0 => negataion group_rep int // repetition of the group @@ -376,7 +376,7 @@ fn (mut re RE) reset_src() { ******************************************************************************/ struct BslsStruct { ch rune // meta char - validator FnValidator // validator function pointer + validator FnValidator = unsafe { nil } // validator function pointer } const ( @@ -463,7 +463,7 @@ mut: cc_type int // type of cc token ch0 rune // first char of the interval a-b a in this case ch1 rune // second char of the interval a-b b in this case - validator FnValidator // validator function pointer + validator FnValidator = unsafe { nil } // validator function pointer } enum CharClass_parse_state { diff --git a/vlib/sokol/gfx/gfx_allocator_and_logger.c.v b/vlib/sokol/gfx/gfx_allocator_and_logger.c.v index d32c6ee40904f5..76e7f9aa00d0ec 100644 --- a/vlib/sokol/gfx/gfx_allocator_and_logger.c.v +++ b/vlib/sokol/gfx/gfx_allocator_and_logger.c.v @@ -5,14 +5,14 @@ import sokol.memory [typedef] pub struct C.sg_allocator { pub mut: - alloc memory.FnAllocatorAlloc - free memory.FnAllocatorFree + alloc memory.FnAllocatorAlloc = unsafe { nil } + free memory.FnAllocatorFree = unsafe { nil } user_data voidptr } [typedef] pub struct C.sg_logger { pub mut: - log_cb memory.FnLogCb + log_cb memory.FnLogCb = unsafe { nil } user_data voidptr } diff --git a/vlib/sokol/gfx/gfx_structs.c.v b/vlib/sokol/gfx/gfx_structs.c.v index 02fc8c7f8a1624..b578df814cba42 100644 --- a/vlib/sokol/gfx/gfx_structs.c.v +++ b/vlib/sokol/gfx/gfx_structs.c.v @@ -46,8 +46,8 @@ pub type GLContextDesc = C.sg_gl_context_desc struct C.sg_metal_context_desc { device voidptr - renderpass_descriptor_cb fn () voidptr - drawable_cb fn () voidptr + renderpass_descriptor_cb fn () voidptr = unsafe { nil } + drawable_cb fn () voidptr = unsafe { nil } } pub type MetalContextDesc = C.sg_metal_context_desc @@ -55,8 +55,8 @@ pub type MetalContextDesc = C.sg_metal_context_desc struct C.sg_d3d11_context_desc { device voidptr device_context voidptr - render_target_view_cb fn () voidptr - depth_stencil_view_cb fn () voidptr + render_target_view_cb fn () voidptr = unsafe { nil } + depth_stencil_view_cb fn () voidptr = unsafe { nil } } pub type D3D11ContextDesc = C.sg_d3d11_context_desc diff --git a/vlib/sokol/sapp/sapp_allocator_and_logger.c.v b/vlib/sokol/sapp/sapp_allocator_and_logger.c.v index 7044bfa3c61a3e..e2ef1f73ed67d5 100644 --- a/vlib/sokol/sapp/sapp_allocator_and_logger.c.v +++ b/vlib/sokol/sapp/sapp_allocator_and_logger.c.v @@ -5,14 +5,14 @@ import sokol.memory [typedef] pub struct C.sapp_allocator { pub mut: - alloc memory.FnAllocatorAlloc - free memory.FnAllocatorFree + alloc memory.FnAllocatorAlloc = unsafe { nil } + free memory.FnAllocatorFree = unsafe { nil } user_data voidptr } [typedef] pub struct C.sapp_logger { pub mut: - log_cb memory.FnLogCb + log_cb memory.FnLogCb = unsafe { nil } user_data voidptr } diff --git a/vlib/sokol/sapp/sapp_structs.c.v b/vlib/sokol/sapp/sapp_structs.c.v index 3787e310d1c28a..08da6996b222b3 100644 --- a/vlib/sokol/sapp/sapp_structs.c.v +++ b/vlib/sokol/sapp/sapp_structs.c.v @@ -37,18 +37,19 @@ pub type IconDesc = C.sapp_icon_desc [typedef] pub struct C.sapp_desc { pub: - init_cb fn () // these are the user-provided callbacks without user data - frame_cb fn () - cleanup_cb fn () - event_cb fn (&Event) //&sapp_event) - fail_cb fn (&u8) + // these are the user-provided callbacks without user data + init_cb fn () = unsafe { nil } + frame_cb fn () = unsafe { nil } + cleanup_cb fn () = unsafe { nil } + event_cb fn (&Event) = unsafe { nil } // &sapp_event + fail_cb fn (&u8) = unsafe { nil } user_data voidptr // these are the user-provided callbacks with user data - init_userdata_cb fn (voidptr) - frame_userdata_cb fn (voidptr) - cleanup_userdata_cb fn (voidptr) - event_userdata_cb fn (&Event, voidptr) - fail_userdata_cb fn (&char, voidptr) + init_userdata_cb fn (voidptr) = unsafe { nil } + frame_userdata_cb fn (voidptr) = unsafe { nil } + cleanup_userdata_cb fn (voidptr) = unsafe { nil } + event_userdata_cb fn (&Event, voidptr) = unsafe { nil } + fail_userdata_cb fn (&char, voidptr) = unsafe { nil } width int // the preferred width of the window / canvas height int // the preferred height of the window / canvas diff --git a/vlib/sokol/sfons/sfons_funcs.c.v b/vlib/sokol/sfons/sfons_funcs.c.v index 1b0f8cf47fe5dc..00510483828c34 100644 --- a/vlib/sokol/sfons/sfons_funcs.c.v +++ b/vlib/sokol/sfons/sfons_funcs.c.v @@ -6,8 +6,8 @@ import sokol.memory [typedef] pub struct C.sfons_allocator_t { pub: - alloc memory.FnAllocatorAlloc - free memory.FnAllocatorFree + alloc memory.FnAllocatorAlloc = unsafe { nil } + free memory.FnAllocatorFree = unsafe { nil } user_data voidptr } diff --git a/vlib/sokol/sgl/sgl_allocator_and_logger.c.v b/vlib/sokol/sgl/sgl_allocator_and_logger.c.v index a98819cee638d2..e745b61a890ad3 100644 --- a/vlib/sokol/sgl/sgl_allocator_and_logger.c.v +++ b/vlib/sokol/sgl/sgl_allocator_and_logger.c.v @@ -5,14 +5,14 @@ import sokol.memory [typedef] pub struct C.sgl_allocator_t { pub mut: - alloc memory.FnAllocatorAlloc - free memory.FnAllocatorFree + alloc memory.FnAllocatorAlloc = unsafe { nil } + free memory.FnAllocatorFree = unsafe { nil } user_data voidptr } [typedef] pub struct C.sgl_logger_t { pub mut: - log_cb memory.FnLogCb + log_cb memory.FnLogCb = unsafe { nil } user_data voidptr } diff --git a/vlib/sync/pool/pool.v b/vlib/sync/pool/pool.v index b4f27186553abf..9dc4bd8eac0a02 100644 --- a/vlib/sync/pool/pool.v +++ b/vlib/sync/pool/pool.v @@ -24,9 +24,15 @@ mut: pub type ThreadCB = fn (mut p PoolProcessor, idx int, task_id int) voidptr +fn empty_cb(mut p PoolProcessor, idx int, task_id int) voidptr { + unsafe { + return nil + } +} + pub struct PoolProcessorConfig { maxjobs int - callback ThreadCB + callback ThreadCB = empty_cb } // new_pool_processor returns a new PoolProcessor instance. diff --git a/vlib/toml/ast/walker/walker.v b/vlib/toml/ast/walker/walker.v index c259659da3850f..0a70410594ebc8 100644 --- a/vlib/toml/ast/walker/walker.v +++ b/vlib/toml/ast/walker/walker.v @@ -15,7 +15,7 @@ pub interface Modifier { pub type InspectorFn = fn (value &ast.Value, data voidptr) ! struct Inspector { - inspector_callback InspectorFn + inspector_callback InspectorFn = unsafe { nil } mut: data voidptr } diff --git a/vlib/v/ast/walker/walker.v b/vlib/v/ast/walker/walker.v index 92341e32187b8c..93e3aff2953460 100644 --- a/vlib/v/ast/walker/walker.v +++ b/vlib/v/ast/walker/walker.v @@ -10,8 +10,12 @@ mut: pub type InspectorFn = fn (node &ast.Node, data voidptr) bool +fn empty_callback(node &ast.Node, data voidptr) bool { + panic('empty ast.walker') +} + struct Inspector { - inspector_callback InspectorFn + inspector_callback InspectorFn = empty_callback mut: data voidptr } diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 65561da3f5797e..e09ec820babe12 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -70,6 +70,19 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { } } } + // Do not allow uninitialized `fn` fields, or force `?fn` + // (allow them in `C.` structs) + if !c.is_builtin_mod && node.language == .v { + sym := c.table.sym(field.typ) + if sym.kind == .function { + if !field.typ.has_flag(.option) && !field.has_default_expr + && field.attrs.filter(it.name == 'required').len == 0 { + error_msg := 'uninitialized `fn` struct fields are not allowed, since they can result in segfaults; use `?fn` or initialize the field with `=` (if you absolutely want to have unsafe function pointers, use `= unsafe { nil }`)' + c.note(error_msg, field.pos) + } + } + } + if field.has_default_expr { c.expected_type = field.typ field.default_expr_typ = c.expr(mut field.default_expr) diff --git a/vlib/v/checker/tests/duplicate_field_method_err.vv b/vlib/v/checker/tests/duplicate_field_method_err.vv index 2c34f781753d43..11b8e9940af8b8 100644 --- a/vlib/v/checker/tests/duplicate_field_method_err.vv +++ b/vlib/v/checker/tests/duplicate_field_method_err.vv @@ -1,5 +1,5 @@ -struct St{ - attr fn() +struct St { + attr fn () = unsafe { nil } } fn (s St) attr() {} diff --git a/vlib/v/checker/tests/fn_check_for_matching_option_result_in_fields.out b/vlib/v/checker/tests/fn_check_for_matching_option_result_in_fields.out index e16a4346aa05ff..d4a30b953c5db2 100644 --- a/vlib/v/checker/tests/fn_check_for_matching_option_result_in_fields.out +++ b/vlib/v/checker/tests/fn_check_for_matching_option_result_in_fields.out @@ -1,7 +1,13 @@ +vlib/v/checker/tests/fn_check_for_matching_option_result_in_fields.vv:2:2: notice: uninitialized `fn` struct fields are not allowed, since they can result in segfaults; use `?fn` or initialize the field with `=` (if you absolutely want to have unsafe function pointers, use `= unsafe { nil }`) + 1 | struct Abc { + 2 | f fn (voidptr) + | ~~~~~~~~~~~~~~ + 3 | } + 4 | vlib/v/checker/tests/fn_check_for_matching_option_result_in_fields.vv:7:3: error: cannot assign to field `f`: expected `fn (voidptr)`, not `fn (voidptr) ?` 5 | fn main() { 6 | a := Abc{ 7 | f: fn (data voidptr) ? {} | ~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | } - 9 | println(a) \ No newline at end of file + 9 | println(a) diff --git a/vlib/v/checker/tests/generics_struct_init_err.out b/vlib/v/checker/tests/generics_struct_init_err.out index 32e1c26f4fb389..f6b7d2048e41f8 100644 --- a/vlib/v/checker/tests/generics_struct_init_err.out +++ b/vlib/v/checker/tests/generics_struct_init_err.out @@ -1,3 +1,10 @@ +vlib/v/checker/tests/generics_struct_init_err.vv:14:2: notice: uninitialized `fn` struct fields are not allowed, since they can result in segfaults; use `?fn` or initialize the field with `=` (if you absolutely want to have unsafe function pointers, use `= unsafe { nil }`) + 12 | + 13 | struct FnHolder2[T] { + 14 | func fn (int) int + | ~~~~~~~~~~~~~~~~~ + 15 | } + 16 | vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: could not infer generic type `T` in generic struct `FnHolder2[T]` 65 | ret = holder_call_22(neg, 5) 66 | assert ret == -5 @@ -6,14 +13,14 @@ vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: could not infer ge 68 | assert ret == -6 69 | } vlib/v/checker/tests/generics_struct_init_err.vv:22:7: error: generic struct init must specify type parameter, e.g. Foo[T] - 20 | + 20 | 21 | fn holder_call_1[T](func T, a int) int { 22 | h := FnHolder1{func} | ~~~~~~~~~~~~~~~ 23 | return h.call(a) 24 | } vlib/v/checker/tests/generics_struct_init_err.vv:27:7: error: generic struct init must specify type parameter, e.g. Foo[T] - 25 | + 25 | 26 | fn holder_call_2[T](func T, a int) int { 27 | h := FnHolder2{func} | ~~~~~~~~~~~~~~~ @@ -34,14 +41,14 @@ vlib/v/checker/tests/generics_struct_init_err.vv:39:7: error: generic struct ini 40 | return h.call(a) 41 | } vlib/v/checker/tests/generics_struct_init_err.vv:44:9: error: generic struct init must specify type parameter, e.g. Foo[T] - 42 | + 42 | 43 | fn holder_call_12[T](func T, a int) int { 44 | return FnHolder1{func}.call(a) | ~~~~~~~~~~~~~~~ 45 | } 46 | vlib/v/checker/tests/generics_struct_init_err.vv:48:9: error: generic struct init must specify type parameter, e.g. Foo[T] - 46 | + 46 | 47 | fn holder_call_22[T](func T, a int) int { 48 | return FnHolder2{func}.call(a) | ~~~~~~~~~~~~~~~ diff --git a/vlib/v/checker/tests/method_call_arg_no_mut_err.vv b/vlib/v/checker/tests/method_call_arg_no_mut_err.vv index f406de5f7bcdde..458cea8364c20c 100644 --- a/vlib/v/checker/tests/method_call_arg_no_mut_err.vv +++ b/vlib/v/checker/tests/method_call_arg_no_mut_err.vv @@ -9,7 +9,7 @@ struct Alarm { struct Clock { mut: arr []Alarm - alarm_fkt Fkt + alarm_fkt Fkt = unsafe { nil } } fn fkt(mut a Alarm) { diff --git a/vlib/v/checker/tests/option_fn_err.vv b/vlib/v/checker/tests/option_fn_err.vv index 0319c83b3d4633..51469e617cd95b 100644 --- a/vlib/v/checker/tests/option_fn_err.vv +++ b/vlib/v/checker/tests/option_fn_err.vv @@ -13,7 +13,7 @@ const ( ) struct Data { - f fn (int) + f fn (int) = unsafe { nil } mut: value int = bar(0) opt ?int = bar(0) diff --git a/vlib/v/checker/tests/struct_field_init_with_nobody_anon_fn_err.vv b/vlib/v/checker/tests/struct_field_init_with_nobody_anon_fn_err.vv index fabdfce29e5bf3..9d7ac2c4d2ac27 100644 --- a/vlib/v/checker/tests/struct_field_init_with_nobody_anon_fn_err.vv +++ b/vlib/v/checker/tests/struct_field_init_with_nobody_anon_fn_err.vv @@ -1,5 +1,5 @@ struct App { - cb fn(x int) // the function signature doesn't make a difference + cb fn(x int) = unsafe { nil } // the function signature doesn't make a difference } fn main() { diff --git a/vlib/v/checker/tests/struct_field_type_err.vv b/vlib/v/checker/tests/struct_field_type_err.vv index 44850c28179726..9a022d48ca71c4 100644 --- a/vlib/v/checker/tests/struct_field_type_err.vv +++ b/vlib/v/checker/tests/struct_field_type_err.vv @@ -2,8 +2,8 @@ struct Data { mut: n int b bool - f1 fn (voidptr) - f2 fn (...voidptr) + f1 fn (voidptr) [required] + f2 fn (...voidptr) [required] data &Data } diff --git a/vlib/v/checker/tests/unknown_type_in_anon_fn.out b/vlib/v/checker/tests/unknown_type_in_anon_fn.out index 1ccfeaff44f443..6fea7a8a9083a3 100644 --- a/vlib/v/checker/tests/unknown_type_in_anon_fn.out +++ b/vlib/v/checker/tests/unknown_type_in_anon_fn.out @@ -1,7 +1,7 @@ vlib/v/checker/tests/unknown_type_in_anon_fn.vv:5:10: error: unknown type `Another` 3 | struct Struc{ 4 | mut: - 5 | f fn (s Another, i int)? + 5 | f fn (s Another, i int)? [required] | ~~~~~~~ 6 | } 7 | diff --git a/vlib/v/checker/tests/unknown_type_in_anon_fn.vv b/vlib/v/checker/tests/unknown_type_in_anon_fn.vv index 64e1a18db34d75..742675d6d791e5 100644 --- a/vlib/v/checker/tests/unknown_type_in_anon_fn.vv +++ b/vlib/v/checker/tests/unknown_type_in_anon_fn.vv @@ -2,7 +2,7 @@ module main struct Struc{ mut: - f fn (s Another, i int)? + f fn (s Another, i int)? [required] } fn main() {} diff --git a/vlib/v/parser/tests/function_prototype_in_struct.vv b/vlib/v/parser/tests/function_prototype_in_struct.vv index d637f7d37e5695..8d500cbd456776 100644 --- a/vlib/v/parser/tests/function_prototype_in_struct.vv +++ b/vlib/v/parser/tests/function_prototype_in_struct.vv @@ -1,9 +1,9 @@ module main struct Ok { - alibaba fn (Ok, ) + alibaba fn (Ok, ) = unsafe { nil } } struct OkInt { - a fn (int, ) + a fn (int, ) = unsafe { nil } } diff --git a/vlib/v/parser/tests/struct_field_required_fn_option_type.out b/vlib/v/parser/tests/struct_field_required_fn_option_type.out index a2824797eb7c60..a13920125132ce 100644 --- a/vlib/v/parser/tests/struct_field_required_fn_option_type.out +++ b/vlib/v/parser/tests/struct_field_required_fn_option_type.out @@ -4,4 +4,4 @@ vlib/v/parser/tests/struct_field_required_fn_option_type.vv:6:7: error: field `F 6 | f := Foo{} | ~~~~~ 7 | println(f) - 8 | } \ No newline at end of file + 8 | } diff --git a/vlib/v/parser/tests/struct_field_required_fn_result_type.out b/vlib/v/parser/tests/struct_field_required_fn_result_type.out index 0f2886eb03e7a1..a32f1609b208a7 100644 --- a/vlib/v/parser/tests/struct_field_required_fn_result_type.out +++ b/vlib/v/parser/tests/struct_field_required_fn_result_type.out @@ -1,5 +1,5 @@ vlib/v/parser/tests/struct_field_required_fn_result_type.vv:6:7: error: field `Foo.foo` must be initialized - 4 | + 4 | 5 | fn main() { 6 | f := Foo{} | ~~~~~ diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index f41a184caccfc3..4c38afe1c928a4 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -446,7 +446,7 @@ type ControllerHandler = fn (ctx Context, mut url urllib.URL, host string, tid i pub struct ControllerPath { pub: path string - handler ControllerHandler + handler ControllerHandler = unsafe { nil } pub mut: host string } @@ -1111,7 +1111,7 @@ fn (mut w Worker[T]) process_incomming_requests() { [params] pub struct PoolParams[T] { - handler fn () T [required] + handler fn () T [required] = unsafe { nil } nr_workers int = runtime.nr_jobs() }