diff --git a/doc/docs.md b/doc/docs.md index bcec7916fd..fd91b9038e 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -1907,10 +1907,10 @@ To mark potentially memory-unsafe operations, enclose them in an `unsafe` block: ```v // allocate 2 uninitialized bytes & return a reference to them -mut p := unsafe(&byte(malloc(2))) +mut p := unsafe { &byte(malloc(2)) } p[0] = `h` // Error: pointer indexing is only allowed in `unsafe` blocks unsafe { - p[0] = `h` // OK + p[0] = `h` p[1] = `i` } p++ // Error: pointer arithmetic is only allowed in `unsafe` blocks @@ -1920,12 +1920,13 @@ unsafe { assert *p == `i` ``` -Best practice is to avoid putting memory-safe expressions inside an `unsafe` expression/block, +Best practice is to avoid putting memory-safe expressions inside an `unsafe` block, so that the reason for using `unsafe` is as clear as possible. Generally any code -you think is memory-safe should be verified by the compiler. +you think is memory-safe should not be inside an `unsafe` block, so the compiler +can verify it. If you suspect your program does violate memory-safety, you have a head start on -finding the cause: look for the `unsafe` keyword (and how it affects the +finding the cause: look at the `unsafe` blocks (and how they interact with surrounding code). * Note: This is work in progress. diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 471423dcd0..498cb3053d 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -728,7 +728,6 @@ pub: pub struct ParExpr { pub: expr Expr - is_unsafe bool // unsafe(expr) } pub struct GoStmt { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 5b95f3da04..637eb2b3a2 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2385,14 +2385,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { return table.void_type } ast.ParExpr { - if !node.is_unsafe { - return c.expr(node.expr) - } - assert !c.inside_unsafe - c.inside_unsafe = true - t := c.expr(node.expr) - c.inside_unsafe = false - return t + return c.expr(node.expr) } ast.RangeExpr { // never happens diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 51623a457b..e166dcaf7a 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -902,9 +902,6 @@ pub fn (mut f Fmt) expr(node ast.Expr) { panic('fmt: OrExpr should to linked to CallExpr') } ast.ParExpr { - if node.is_unsafe { - f.write('unsafe') - } f.write('(') f.par_level++ f.expr(node.expr) diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 22f2fd55b9..95f187d5b3 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -602,22 +602,13 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt { } } .key_unsafe { - // unsafe { - if p.peek_tok.kind == .lcbr { - p.next() - assert !p.inside_unsafe - p.inside_unsafe = true - stmts := p.parse_block() - p.inside_unsafe = false - return ast.UnsafeStmt{ - stmts: stmts - } - } - // unsafe( - pos := p.tok.position() - return ast.ExprStmt{ - expr: p.expr(0) - pos: pos + p.next() + assert !p.inside_unsafe + p.inside_unsafe = true + stmts := p.parse_block() + p.inside_unsafe = false + return ast.UnsafeStmt{ + stmts: stmts } } .hash { diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index 5b6ccfd07d..6a9084cabe 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -93,23 +93,12 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { pos := p.tok.position() assert !p.inside_unsafe p.inside_unsafe = true - if p.tok.kind == .lpar { - // unsafe( - p.check(.lpar) - node = ast.ParExpr{ - expr: p.expr(0) - is_unsafe: true - } - p.check(.rpar) - } else { - // unsafe { - // old syntax, UnsafeExpr can be removed later - node = ast.UnsafeExpr{ - stmts: p.parse_block() - pos: pos - } - } + stmts := p.parse_block() p.inside_unsafe = false + node = ast.UnsafeExpr{ + stmts: stmts + pos: pos + } } .key_lock, .key_rlock { node = p.lock_expr() diff --git a/vlib/v/tests/unsafe_test.v b/vlib/v/tests/unsafe_test.v index c18506a340..82e06e1440 100644 --- a/vlib/v/tests/unsafe_test.v +++ b/vlib/v/tests/unsafe_test.v @@ -3,9 +3,17 @@ fn test_ptr_assign() { mut p := &v[0] unsafe { (*p)++ - p++ // p now points to v[1] + } + unsafe { + p++ + } // p now points to v[1] + unsafe { (*p) += 2 - p += 2 // p now points to v[3] + } + unsafe { + p += 2 + } // p now points to v[3] + unsafe { *p = 31 } assert v[0] == 6 @@ -16,9 +24,16 @@ fn test_ptr_assign() { fn test_ptr_infix() { v := 4 - mut q := unsafe(&v - 1) - q = unsafe(q + 3) - assert q == unsafe(&v + 2) + mut q := unsafe { + &v - 1 + } + + q = unsafe { + q + 3 + } + + _ := q + _ := v } struct S1 {