parent
9c9533dad9
commit
f269cbdc94
11
doc/docs.md
11
doc/docs.md
|
@ -1907,10 +1907,10 @@ To mark potentially memory-unsafe operations, enclose them in an `unsafe` block:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
// allocate 2 uninitialized bytes & return a reference to them
|
// 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
|
p[0] = `h` // Error: pointer indexing is only allowed in `unsafe` blocks
|
||||||
unsafe {
|
unsafe {
|
||||||
p[0] = `h` // OK
|
p[0] = `h`
|
||||||
p[1] = `i`
|
p[1] = `i`
|
||||||
}
|
}
|
||||||
p++ // Error: pointer arithmetic is only allowed in `unsafe` blocks
|
p++ // Error: pointer arithmetic is only allowed in `unsafe` blocks
|
||||||
|
@ -1920,12 +1920,13 @@ unsafe {
|
||||||
assert *p == `i`
|
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
|
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
|
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).
|
surrounding code).
|
||||||
|
|
||||||
* Note: This is work in progress.
|
* Note: This is work in progress.
|
||||||
|
|
|
@ -728,7 +728,6 @@ pub:
|
||||||
pub struct ParExpr {
|
pub struct ParExpr {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
expr Expr
|
||||||
is_unsafe bool // unsafe(expr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GoStmt {
|
pub struct GoStmt {
|
||||||
|
|
|
@ -2385,14 +2385,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||||
return table.void_type
|
return table.void_type
|
||||||
}
|
}
|
||||||
ast.ParExpr {
|
ast.ParExpr {
|
||||||
if !node.is_unsafe {
|
return c.expr(node.expr)
|
||||||
return c.expr(node.expr)
|
|
||||||
}
|
|
||||||
assert !c.inside_unsafe
|
|
||||||
c.inside_unsafe = true
|
|
||||||
t := c.expr(node.expr)
|
|
||||||
c.inside_unsafe = false
|
|
||||||
return t
|
|
||||||
}
|
}
|
||||||
ast.RangeExpr {
|
ast.RangeExpr {
|
||||||
// never happens
|
// never happens
|
||||||
|
|
|
@ -902,9 +902,6 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
||||||
panic('fmt: OrExpr should to linked to CallExpr')
|
panic('fmt: OrExpr should to linked to CallExpr')
|
||||||
}
|
}
|
||||||
ast.ParExpr {
|
ast.ParExpr {
|
||||||
if node.is_unsafe {
|
|
||||||
f.write('unsafe')
|
|
||||||
}
|
|
||||||
f.write('(')
|
f.write('(')
|
||||||
f.par_level++
|
f.par_level++
|
||||||
f.expr(node.expr)
|
f.expr(node.expr)
|
||||||
|
|
|
@ -602,22 +602,13 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.key_unsafe {
|
.key_unsafe {
|
||||||
// unsafe {
|
p.next()
|
||||||
if p.peek_tok.kind == .lcbr {
|
assert !p.inside_unsafe
|
||||||
p.next()
|
p.inside_unsafe = true
|
||||||
assert !p.inside_unsafe
|
stmts := p.parse_block()
|
||||||
p.inside_unsafe = true
|
p.inside_unsafe = false
|
||||||
stmts := p.parse_block()
|
return ast.UnsafeStmt{
|
||||||
p.inside_unsafe = false
|
stmts: stmts
|
||||||
return ast.UnsafeStmt{
|
|
||||||
stmts: stmts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// unsafe(
|
|
||||||
pos := p.tok.position()
|
|
||||||
return ast.ExprStmt{
|
|
||||||
expr: p.expr(0)
|
|
||||||
pos: pos
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.hash {
|
.hash {
|
||||||
|
|
|
@ -93,23 +93,12 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||||
pos := p.tok.position()
|
pos := p.tok.position()
|
||||||
assert !p.inside_unsafe
|
assert !p.inside_unsafe
|
||||||
p.inside_unsafe = true
|
p.inside_unsafe = true
|
||||||
if p.tok.kind == .lpar {
|
stmts := p.parse_block()
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.inside_unsafe = false
|
p.inside_unsafe = false
|
||||||
|
node = ast.UnsafeExpr{
|
||||||
|
stmts: stmts
|
||||||
|
pos: pos
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.key_lock, .key_rlock {
|
.key_lock, .key_rlock {
|
||||||
node = p.lock_expr()
|
node = p.lock_expr()
|
||||||
|
|
|
@ -3,9 +3,17 @@ fn test_ptr_assign() {
|
||||||
mut p := &v[0]
|
mut p := &v[0]
|
||||||
unsafe {
|
unsafe {
|
||||||
(*p)++
|
(*p)++
|
||||||
p++ // p now points to v[1]
|
}
|
||||||
|
unsafe {
|
||||||
|
p++
|
||||||
|
} // p now points to v[1]
|
||||||
|
unsafe {
|
||||||
(*p) += 2
|
(*p) += 2
|
||||||
p += 2 // p now points to v[3]
|
}
|
||||||
|
unsafe {
|
||||||
|
p += 2
|
||||||
|
} // p now points to v[3]
|
||||||
|
unsafe {
|
||||||
*p = 31
|
*p = 31
|
||||||
}
|
}
|
||||||
assert v[0] == 6
|
assert v[0] == 6
|
||||||
|
@ -16,9 +24,16 @@ fn test_ptr_assign() {
|
||||||
|
|
||||||
fn test_ptr_infix() {
|
fn test_ptr_infix() {
|
||||||
v := 4
|
v := 4
|
||||||
mut q := unsafe(&v - 1)
|
mut q := unsafe {
|
||||||
q = unsafe(q + 3)
|
&v - 1
|
||||||
assert q == unsafe(&v + 2)
|
}
|
||||||
|
|
||||||
|
q = unsafe {
|
||||||
|
q + 3
|
||||||
|
}
|
||||||
|
|
||||||
|
_ := q
|
||||||
|
_ := v
|
||||||
}
|
}
|
||||||
|
|
||||||
struct S1 {
|
struct S1 {
|
||||||
|
|
Loading…
Reference in New Issue