diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 8e980b0290..449865f2cd 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -4680,15 +4680,16 @@ fn (c &Checker) has_return(stmts []ast.Stmt) ?bool { pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) table.Type { typ := c.expr(node.expr) typ_sym := c.table.get_type_symbol(typ) - if !typ_sym.is_number() && typ_sym.kind !in [.byteptr, .charptr] { + is_non_void_pointer := (typ.is_ptr() || typ.is_pointer()) && typ_sym.kind != .voidptr + if !c.inside_unsafe && is_non_void_pointer { + c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos) + } + if !(typ_sym.is_number() || (c.inside_unsafe && is_non_void_pointer)) { c.error('invalid operation: $node.op.str() (non-numeric type `$typ_sym.name`)', node.pos) } else { node.auto_locked, _ = c.fail_if_immutable(node.expr) } - if !c.inside_unsafe && (typ.is_ptr() || typ_sym.is_pointer()) { - c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos) - } return typ } diff --git a/vlib/v/embed_file/embed_file.v b/vlib/v/embed_file/embed_file.v index 651b98701d..b598e90f85 100644 --- a/vlib/v/embed_file/embed_file.v +++ b/vlib/v/embed_file/embed_file.v @@ -79,7 +79,7 @@ pub fn find_index_entry_by_path(start voidptr, path string) &EmbedFileIndexEntry mut x := &EmbedFileIndexEntry(start) for !(x.path == path || isnil(x.data)) { unsafe { - x = &EmbedFileIndexEntry(u64(x) + sizeof(EmbedFileIndexEntry)) + x++ } } $if debug_embed_file_in_prod ? { diff --git a/vlib/v/tests/ptr_arithmetic_test.v b/vlib/v/tests/ptr_arithmetic_test.v index 2b2075cdef..e64016fda8 100644 --- a/vlib/v/tests/ptr_arithmetic_test.v +++ b/vlib/v/tests/ptr_arithmetic_test.v @@ -1,4 +1,4 @@ -fn test_ptr_arithmetic(){ +fn test_ptr_arithmetic() { unsafe { // Do NOT move this outside unsafe{}. // It causes too much churn in CI when new checks are implemented. @@ -18,7 +18,7 @@ fn test_ptr_arithmetic(){ } } -fn test_ptr_arithmetic_over_byteptr() { +fn test_ptr_arithmetic_over_byteptr() { // byteptr, voidptr, charptr are handled differently mut q := byteptr(10) unsafe { @@ -28,7 +28,43 @@ fn test_ptr_arithmetic_over_byteptr() { assert q == byteptr(9) s := unsafe { q - 1 } assert s == byteptr(8) - - unsafe {q++ q++ q--} + unsafe { + q++ + q++ + q-- + } assert q == byteptr(10) } + +struct Abc { +mut: + x int + y int + z int +} + +fn test_ptr_arithmetic_over_struct() { + mut a := [3]Abc{} + a[0].x = 10 + a[1].x = 100 + a[2].x = 1000 + mut pa := &a[0] + assert pa == &a[0] + unsafe { + assert pa.x == 10 + pa++ + assert u64(pa) - u64(&a[0]) == sizeof(Abc) + assert pa.x == 100 + pa++ + assert u64(pa) - u64(&a[0]) == 2 * sizeof(Abc) + assert pa.x == 1000 + pa-- + assert pa.x == 100 + pa-- + assert pa.x == 10 + pa += 2 + assert pa.x == 1000 + pa -= 2 + } + assert pa == &a[0] +}