1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: do not allow modifying immutable vars via arrays with refs

This commit is contained in:
Alexander Medvednikov 2023-07-21 02:47:31 +03:00
parent 93b3f1ca55
commit 9cc24c5dac
4 changed files with 63 additions and 10 deletions

View File

@ -458,20 +458,42 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
// no point to show the notice, if the old error was already shown: // no point to show the notice, if the old error was already shown:
if !old_assign_error_condition { if !old_assign_error_condition {
mut_str := if node.op == .decl_assign { 'mut ' } else { '' } mut_str := if node.op == .decl_assign { 'mut ' } else { '' }
c.note('use `${mut_str}array2 ${node.op.str()} array1.clone()` instead of `${mut_str}array2 ${node.op.str()} array1` (or use `unsafe`)', c.warn('use `${mut_str}array2 ${node.op.str()} array1.clone()` instead of `${mut_str}array2 ${node.op.str()} array1` (or use `unsafe`)',
node.pos) node.pos)
} }
} }
if left_sym.kind == .array && right_sym.kind == .array && node.op == .assign { if left_sym.kind == .array && right_sym.kind == .array {
// `mut arr := [u8(1),2,3]`
// `arr = [byte(4),5,6]`
left_info := left_sym.info as ast.Array
left_elem_type := c.table.unaliased_type(left_info.elem_type)
right_info := right_sym.info as ast.Array right_info := right_sym.info as ast.Array
right_elem_type := c.table.unaliased_type(right_info.elem_type) right_elem_type := c.table.unaliased_type(right_info.elem_type)
if left_type_unwrapped.nr_muls() == right_type_unwrapped.nr_muls() if node.op in [.decl_assign, .assign] {
&& left_info.nr_dims == right_info.nr_dims && left_elem_type == right_elem_type { // Do not allow `mut arr := [&immutable_object]`
continue if mut left is ast.Ident && right_elem_type.is_ptr() {
if left.is_mut() || (left.obj is ast.Var && left.obj.is_mut) {
if mut right is ast.ArrayInit && right.exprs.len > 0 {
elem_expr := right.exprs[0]
if elem_expr is ast.PrefixExpr && elem_expr.op == .amp {
r := elem_expr.right
if r is ast.Ident {
obj := r.obj
if obj is ast.Var && !obj.is_mut {
c.warn('cannot add a referenece to an immutable object to a mutable array',
elem_expr.pos)
}
}
}
}
}
}
}
if node.op == .assign {
// `mut arr := [u8(1),2,3]`
// `arr = [byte(4),5,6]`
left_info := left_sym.info as ast.Array
left_elem_type := c.table.unaliased_type(left_info.elem_type)
if left_type_unwrapped.nr_muls() == right_type_unwrapped.nr_muls()
&& left_info.nr_dims == right_info.nr_dims && left_elem_type == right_elem_type {
continue
}
} }
} }
if left_sym.kind == .array_fixed && !c.inside_unsafe && node.op in [.assign, .decl_assign] if left_sym.kind == .array_fixed && !c.inside_unsafe && node.op in [.assign, .decl_assign]

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/array_assign_err.vv:8:8: notice: use `mut array2 := array1.clone()` instead of `mut array2 := array1` (or use `unsafe`) vlib/v/checker/tests/array_assign_err.vv:8:8: warning: use `mut array2 := array1.clone()` instead of `mut array2 := array1` (or use `unsafe`)
6 | fn main() { 6 | fn main() {
7 | a := Dumb{[1, 2, 3]} 7 | a := Dumb{[1, 2, 3]}
8 | mut b := a.v // I expect a compiler error 8 | mut b := a.v // I expect a compiler error

View File

@ -0,0 +1,14 @@
vlib/v/checker/tests/array_of_refs_mutability.vv:11:14: warning: cannot add a referenece to an immutable object to a mutable array
9 | }
10 |
11 | mut arr := [&x]
| ^
12 | arr[0].bar = 30
13 |
vlib/v/checker/tests/array_of_refs_mutability.vv:15:10: warning: cannot add a referenece to an immutable object to a mutable array
13 |
14 | mut arr2 := [&Foo{}]
15 | arr2 = [&x]
| ^
16 | arr2[0].bar = 40
17 | }

View File

@ -0,0 +1,17 @@
struct Foo {
mut:
bar int
}
fn main() {
x := Foo{
bar: 20
}
mut arr := [&x]
arr[0].bar = 30
mut arr2 := [&Foo{}]
arr2 = [&x]
arr2[0].bar = 40
}