diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index a0a2561505..ae9af636b1 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -5,19 +5,26 @@ module builtin import strings -// array is a struct used for denoting array types in V +// `array` is a struct, used for denoting all array types in V. +// `.data` is a void pointer to the backing heap memory block, +// which avoids using generics and thus without generating extra +// code for every type. pub struct array { pub: element_size int // size in bytes of one element in the array. pub mut: data voidptr offset int // in bytes (should be `usize`) - len int // length of the array. - cap int // capacity of the array. + len int // length of the array in elements. + cap int // capacity of the array in elements. + flags ArrayFlags +} + +[flag] +pub enum ArrayFlags { + noslices } -// array.data uses a void pointer, which allows implementing arrays without generics and without generating -// extra code for every type. // Internal function, used by V (`nums := []int`) fn __new_array(mylen int, cap int, elm_size int) array { cap_ := if cap < mylen { mylen } else { cap } @@ -104,6 +111,11 @@ fn (mut a array) ensure_cap(required int) { if a.data != voidptr(0) { unsafe { vmemcpy(new_data, a.data, a.len * a.element_size) } // TODO: the old data may be leaked when no GC is used (ref-counting?) + if a.flags.has(.noslices) { + unsafe { + free(a.data) + } + } } a.data = new_data a.offset = 0 diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index 60daf1ce56..39ea002ea6 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -510,7 +510,7 @@ pub fn memdup_noscan(src voidptr, sz int) voidptr { return vcalloc_noscan(1) } unsafe { - mem := vcalloc_noscan(sz) + mem := malloc_noscan(sz) return C.memcpy(mem, src, sz) } } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index f4fe75e070..3feb9352e6 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1663,8 +1663,9 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) { c.fail_if_immutable(expr.expr) } .array, .string { - // This should only happen in `builtin` - if c.file.mod.name != 'builtin' { + // should only happen in `builtin` and unsafe blocks + inside_builtin := c.file.mod.name == 'builtin' + if !inside_builtin && !c.inside_unsafe { c.error('`$typ_sym.kind` can not be modified', expr.pos) return '', expr.pos }