checker: disallow `mut_ptr = &immutable_var` (#13814)
parent
9bbb52e9cc
commit
a4ab3c1f14
|
@ -794,7 +794,21 @@ pub mut:
|
|||
name string
|
||||
kind IdentKind
|
||||
info IdentInfo
|
||||
is_mut bool
|
||||
is_mut bool // if mut *token* is before name. Use `is_mut()` to lookup mut variable
|
||||
}
|
||||
|
||||
pub fn (i &Ident) is_mut() bool {
|
||||
match i.obj {
|
||||
Var {
|
||||
return i.obj.is_mut
|
||||
}
|
||||
ConstField {
|
||||
return false
|
||||
}
|
||||
AsmRegister, GlobalField {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (i &Ident) var_info() IdentVar {
|
||||
|
|
|
@ -559,15 +559,10 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||
if right_node.right.obj is ast.Var {
|
||||
v := right_node.right.obj
|
||||
right_type0 = v.typ
|
||||
if !v.is_mut && assigned_var.is_mut && !c.inside_unsafe {
|
||||
c.error('`$right_node.right.name` is immutable, cannot have a mutable reference to it',
|
||||
right_node.pos)
|
||||
}
|
||||
} else if right_node.right.obj is ast.ConstField {
|
||||
if assigned_var.is_mut && !c.inside_unsafe {
|
||||
c.error('`$right_node.right.name` is immutable, cannot have a mutable reference to it',
|
||||
right_node.pos)
|
||||
}
|
||||
}
|
||||
if !c.inside_unsafe && assigned_var.is_mut() && !right_node.right.is_mut() {
|
||||
c.error('`$right_node.right.name` is immutable, cannot have a mutable reference to it',
|
||||
right_node.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
vlib/v/checker/tests/modify_const_with_ref.vv:11:11: error: `constant` is immutable, cannot have a mutable reference to it
|
||||
9 | mut unused_var := Foo{}
|
||||
10 | unused_var = Foo{}
|
||||
11 | mut c := &constant
|
||||
| ^
|
||||
12 | c.value = 200
|
||||
13 | }
|
||||
vlib/v/checker/tests/modify_const_with_ref.vv:9:6: error: unused variable: `unused_var`
|
||||
7 |
|
||||
8 | fn main() {
|
||||
9 | mut unused_var := Foo{}
|
||||
| ~~~~~~~~~~
|
||||
10 | unused_var = Foo{}
|
||||
11 | mut c := &constant
|
|
@ -1,13 +0,0 @@
|
|||
struct Foo {
|
||||
mut:
|
||||
value int
|
||||
}
|
||||
|
||||
const constant = Foo{ 100 }
|
||||
|
||||
fn main() {
|
||||
mut unused_var := Foo{}
|
||||
unused_var = Foo{}
|
||||
mut c := &constant
|
||||
c.value = 200
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
vlib/v/checker/tests/mut_assign_ref.vv:10:12: error: `f` is immutable, cannot have a mutable reference to it
|
||||
8 | fn main() {
|
||||
9 | f := Foo{}
|
||||
10 | mut pf := &f
|
||||
| ^
|
||||
11 | pf = &f
|
||||
12 | p := &f
|
||||
vlib/v/checker/tests/mut_assign_ref.vv:11:7: error: `f` is immutable, cannot have a mutable reference to it
|
||||
9 | f := Foo{}
|
||||
10 | mut pf := &f
|
||||
11 | pf = &f
|
||||
| ^
|
||||
12 | p := &f
|
||||
13 | _ = p
|
||||
vlib/v/checker/tests/mut_assign_ref.vv:15:11: error: `constant` is immutable, cannot have a mutable reference to it
|
||||
13 | _ = p
|
||||
14 |
|
||||
15 | mut c := &constant
|
||||
| ^
|
||||
16 | c.value = 200
|
||||
17 | c = &constant
|
||||
vlib/v/checker/tests/mut_assign_ref.vv:17:6: error: `constant` is immutable, cannot have a mutable reference to it
|
||||
15 | mut c := &constant
|
||||
16 | c.value = 200
|
||||
17 | c = &constant
|
||||
| ^
|
||||
18 | ic := &constant // ok
|
||||
19 | _=ic
|
|
@ -0,0 +1,24 @@
|
|||
struct Foo {
|
||||
mut:
|
||||
value int
|
||||
}
|
||||
|
||||
const constant = Foo{ 100 }
|
||||
|
||||
fn main() {
|
||||
f := Foo{}
|
||||
mut pf := &f
|
||||
pf = &f
|
||||
p := &f
|
||||
_ = p
|
||||
|
||||
mut c := &constant
|
||||
c.value = 200
|
||||
c = &constant
|
||||
ic := &constant // ok
|
||||
_=ic
|
||||
|
||||
mut mf := f
|
||||
pf = &mf // ok
|
||||
_ = pf
|
||||
}
|
|
@ -19,7 +19,7 @@ fn test_voidptr_casted_as_an_interface_reference() {
|
|||
dump(pi)
|
||||
assert f(pi) == '&IAbc(0x0)'
|
||||
//
|
||||
i := IAbc(Abc{})
|
||||
mut i := IAbc(Abc{})
|
||||
pi = &i
|
||||
dump(pi)
|
||||
assert f(pi).contains('x: 123')
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
fn test_reference_array_init() {
|
||||
mut b := &[5, 6, 7]
|
||||
{
|
||||
a := [1, 2, 3]
|
||||
mut a := [1, 2, 3]
|
||||
// TODO: this should probably produce a notice at least,
|
||||
// (without unsafe{&a}), since it takes the address of something
|
||||
// on the stack, that will very soon be out of scope, even
|
||||
// though it is still in the same function:
|
||||
b = &a
|
||||
}
|
||||
println(b)
|
||||
|
|
Loading…
Reference in New Issue