cgen: fix `mut` var in `for` loop reads as address (fix #8548) (#8745)

pull/8790/head
yuyi 2021-02-16 20:24:19 +08:00 committed by GitHub
parent 01aa09d515
commit 982e35909d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 269 additions and 9 deletions

View File

@ -763,7 +763,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
left_pos := infix_expr.left.position() left_pos := infix_expr.left.position()
right_pos := infix_expr.right.position() right_pos := infix_expr.right.position()
if (left_type.is_ptr() || left.is_pointer()) && infix_expr.op in [.plus, .minus] { if (left_type.is_ptr() || left.is_pointer()) && infix_expr.op in [.plus, .minus] {
if !c.inside_unsafe { if !c.inside_unsafe && !infix_expr.left.is_mut_ident() && !infix_expr.right.is_mut_ident() {
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', left_pos) c.warn('pointer arithmetic is only allowed in `unsafe` blocks', left_pos)
} }
if left_type == table.voidptr_type { if left_type == table.voidptr_type {
@ -2600,7 +2600,11 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
right := if i < assign_stmt.right.len { assign_stmt.right[i] } else { assign_stmt.right[0] } right := if i < assign_stmt.right.len { assign_stmt.right[i] } else { assign_stmt.right[0] }
mut right_type := assign_stmt.right_types[i] mut right_type := assign_stmt.right_types[i]
if is_decl { if is_decl {
left_type = c.table.mktyp(right_type) if right.is_mut_ident() {
left_type = c.table.mktyp(right_type.deref())
} else {
left_type = c.table.mktyp(right_type)
}
if left_type == table.int_type { if left_type == table.int_type {
if right is ast.IntegerLiteral { if right is ast.IntegerLiteral {
mut is_large := right.val.len > 13 mut is_large := right.val.len > 13
@ -3007,7 +3011,11 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
} }
// The first element's type // The first element's type
if i == 0 { if i == 0 {
elem_type = c.table.mktyp(typ) if expr.is_mut_ident() {
elem_type = c.table.mktyp(typ.deref())
} else {
elem_type = c.table.mktyp(typ)
}
c.expected_type = elem_type c.expected_type = elem_type
continue continue
} }
@ -5097,7 +5105,7 @@ pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) table.Type {
typ := c.expr(node.expr) typ := c.expr(node.expr)
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
is_non_void_pointer := (typ.is_ptr() || typ.is_pointer()) && typ_sym.kind != .voidptr is_non_void_pointer := (typ.is_ptr() || typ.is_pointer()) && typ_sym.kind != .voidptr
if !c.inside_unsafe && is_non_void_pointer { if !c.inside_unsafe && is_non_void_pointer && !node.expr.is_mut_ident() {
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos) c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)
} }
if !(typ_sym.is_number() || (c.inside_unsafe && is_non_void_pointer)) { if !(typ_sym.is_number() || (c.inside_unsafe && is_non_void_pointer)) {
@ -5224,7 +5232,7 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type {
'(note, that variables may be mutable but string values are always immutable, like in Go and Java)', '(note, that variables may be mutable but string values are always immutable, like in Go and Java)',
node.pos) node.pos)
} }
if !c.inside_unsafe && (typ.is_ptr() || typ.is_pointer()) { if !c.inside_unsafe && ((typ.is_ptr() && !node.left.is_mut_ident()) || typ.is_pointer()) {
mut is_ok := false mut is_ok := false
if mut node.left is ast.Ident { if mut node.left is ast.Ident {
if node.left.obj is ast.Var { if node.left.obj is ast.Var {
@ -5403,8 +5411,14 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) table.Type {
return node.typ return node.typ
} }
// `{'age': 20}` // `{'age': 20}`
key0_type := c.table.mktyp(c.expr(node.keys[0])) mut key0_type := c.table.mktyp(c.expr(node.keys[0]))
val0_type := c.table.mktyp(c.expr(node.vals[0])) if node.keys[0].is_mut_ident() {
key0_type = key0_type.deref()
}
mut val0_type := c.table.mktyp(c.expr(node.vals[0]))
if node.vals[0].is_mut_ident() {
val0_type = val0_type.deref()
}
mut same_key_type := true mut same_key_type := true
for i, key in node.keys { for i, key in node.keys {
if i == 0 { if i == 0 {

View File

@ -26,6 +26,9 @@ fn (mut g Gen) array_init(node ast.ArrayInit) {
g.write('{') g.write('{')
if node.has_val { if node.has_val {
for i, expr in node.exprs { for i, expr in node.exprs {
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr) g.expr(expr)
if i != node.exprs.len - 1 { if i != node.exprs.len - 1 {
g.write(', ') g.write(', ')

View File

@ -1525,7 +1525,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw table.Type, expected_t
return return
} }
if got_is_ptr && !expected_is_ptr && neither_void if got_is_ptr && !expected_is_ptr && neither_void
&& exp_sym.kind !in [.interface_, .placeholder] { && exp_sym.kind !in [.interface_, .placeholder] && expr !is ast.InfixExpr {
got_deref_type := got_type.deref() got_deref_type := got_type.deref()
deref_sym := g.table.get_type_symbol(got_deref_type) deref_sym := g.table.get_type_symbol(got_deref_type)
deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx] deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx]
@ -2111,6 +2111,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
g.write('for (int $i_var=0; $i_var<$fixed_array.size; $i_var++) {') g.write('for (int $i_var=0; $i_var<$fixed_array.size; $i_var++) {')
g.expr(left) g.expr(left)
g.write('[$i_var] = ') g.write('[$i_var] = ')
if val.is_mut_ident() {
g.write('*')
}
g.expr(val) g.expr(val)
g.write('[$i_var];') g.write('[$i_var];')
g.writeln('}') g.writeln('}')
@ -2133,6 +2136,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
g.write('{0}') g.write('{0}')
} }
} else { } else {
if val.is_mut_ident() {
g.write('*')
}
g.expr(val) g.expr(val)
} }
} else { } else {
@ -2715,7 +2721,13 @@ fn (mut g Gen) expr(node ast.Expr) {
g.writeln('sync__RwMutex_lock(&$node.auto_locked->mtx);') g.writeln('sync__RwMutex_lock(&$node.auto_locked->mtx);')
} }
g.inside_map_postfix = true g.inside_map_postfix = true
g.expr(node.expr) if node.expr.is_mut_ident() {
g.write('(*')
g.expr(node.expr)
g.write(')')
} else {
g.expr(node.expr)
}
g.inside_map_postfix = false g.inside_map_postfix = false
g.write(node.op.str()) g.write(node.op.str())
if node.auto_locked != '' { if node.auto_locked != '' {
@ -3375,8 +3387,14 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
if need_par { if need_par {
g.write('(') g.write('(')
} }
if node.left_type.is_ptr() && node.left.is_mut_ident() {
g.write('*')
}
g.expr(node.left) g.expr(node.left)
g.write(' $node.op.str() ') g.write(' $node.op.str() ')
if node.right_type.is_ptr() && node.right.is_mut_ident() {
g.write('*')
}
g.expr(node.right) g.expr(node.right)
if need_par { if need_par {
g.write(')') g.write(')')
@ -3706,6 +3724,9 @@ fn (mut g Gen) map_init(node ast.MapInit) {
g.write('}), _MOV(($value_typ_str[$size]){') g.write('}), _MOV(($value_typ_str[$size]){')
} }
for expr in node.vals { for expr in node.vals {
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr) g.expr(expr)
g.write(', ') g.write(', ')
} }

View File

@ -264,9 +264,15 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
if typ == table.string_type { if typ == table.string_type {
if g.inside_vweb_tmpl { if g.inside_vweb_tmpl {
g.write('vweb__filter(') g.write('vweb__filter(')
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr) g.expr(expr)
g.write(')') g.write(')')
} else { } else {
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr) g.expr(expr)
} }
} else if node.fmts[i] == `s` || typ.has_flag(.variadic) { } else if node.fmts[i] == `s` || typ.has_flag(.variadic) {
@ -283,12 +289,21 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
} else { } else {
g.write('(u64)(') g.write('(u64)(')
} }
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr) g.expr(expr)
g.write(')') g.write(')')
} else { } else {
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr) g.expr(expr)
} }
} else { } else {
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr) g.expr(expr)
} }
if node.fmts[i] == `s` && node.fwidths[i] != 0 { if node.fmts[i] == `s` && node.fwidths[i] != 0 {

View File

@ -47,3 +47,210 @@ fn test_mut_2() {
assert b.a[0].v[3] == 8 assert b.a[0].v[3] == 8
assert b.a[0].v[4] == 5 assert b.a[0].v[4] == 5
} }
fn test_mut_3() {
mut indices := []int{len: 3}
mut results := []string{}
for i, mut v in indices {
v = i
a := v
println('$i $v $a')
results << '$i $v $a'
}
assert results[0] == '0 0 0'
assert results[1] == '1 1 1'
assert results[2] == '2 2 2'
}
struct St {
mut:
n int
}
fn f(mut x St) {
mut y := St{n: 2}
a := x
b := y
x.n = 3
y.n = 4
println('$a.n $b.n')
assert '$a.n $b.n' == '1 2'
}
fn test_mut_4() {
mut x := St{ n: 1 }
f(mut x)
}
fn test_mut_5() {
mut arr1 := []int{len:2}
mut arr2 := []int{len:2}
mut results := []string{}
for i, mut v in arr1 {
for ii, mut vv in arr2 {
v = i
a := v
println('$i $v $a')
results << '$i $v $a'
vv = ii
aa := vv
println('$ii $vv $aa')
results << "$ii $vv $aa"
}
}
assert results[0] == '0 0 0'
assert results[1] == '0 0 0'
assert results[2] == '0 0 0'
assert results[3] == '1 1 1'
assert results[4] == '1 1 1'
assert results[5] == '0 0 0'
assert results[6] == '1 1 1'
assert results[7] == '1 1 1'
}
fn test_mut_6() {
mut results := []int{}
mut arr := []int{len:3}
for _, mut v in arr {
v = v + 1
println(v)
results << v
}
assert results[0] == 1
assert results[1] == 1
assert results[2] == 1
}
fn test_mut_7() {
mut arr := []int{len:3}
mut results := []int{}
for _, mut v in arr {
v = v + 1 // v: 1
mut vv := v // vv: 1, v: 1
vv = vv + v // vv: 2, v: 1
println(v)
println(vv)
results << v
results << vv
}
assert results[0] == 1
assert results[1] == 2
assert results[2] == 1
assert results[3] == 2
assert results[4] == 1
assert results[5] == 2
}
fn test_mut_8() {
mut indices := []int{len: 1}
for i, mut v in indices {
v = i
mut b := v
println(typeof(i).name)
println(typeof(v).name)
println(typeof(b).name)
u := [v, 5, 6]
println(typeof(u).name)
println(u)
assert typeof(b).name == 'int'
assert typeof(u).name == '[]int'
assert u == [0, 5, 6]
}
}
fn test_mut_9() {
mut arr := [0,0,0]
mut results := []string{}
for _, mut v in arr {
v = v + 1 // v: 1
mut vv := v // vv: 1, v: 1
vv = vv + v // vv: 2, v: 1
foo := {'a': v, 'b': vv} // or use new syntax foo := map{'a': v, 'b': vv}, results are the same
println(v)
println(vv)
println(foo)
results << '$v'
results << '$vv'
results << '$foo'
}
assert results[0] == '1'
assert results[1] == '2'
assert results[2] == "{'a': 1, 'b': 2}"
assert results[3] == '1'
assert results[4] == '2'
assert results[5] == "{'a': 1, 'b': 2}"
assert results[6] == '1'
assert results[7] == '2'
assert results[8] == "{'a': 1, 'b': 2}"
}
fn foo1(mut arr [][]int) {
mut results := []int{}
for _, mut j in arr {
for _, mut k in j {
k = k + 1 // k: 1
mut kk := k // kk: 1, k: 1
kk = kk + k // kk: 2, k: 1
k++ // kk: 2, k: 2
kk++ // kk: 3, k: 2
println(k)
println(kk)
results << k
results << kk
}
}
assert results[0] == 2
assert results[1] == 3
assert results[2] == 2
assert results[3] == 3
}
fn test_mut_10() {
mut arr := [[0,0]]
foo1(mut arr)
}
fn foo2(mut arr [][]int) {
mut results := []int{}
for _, mut j in arr {
for _, mut k in j {
k = k + 1 // k: 1
mut kk := k // kk: 1, k: 1
kk = kk + k // kk: 2, k: 1
k-- // kk: 2, k: 2
kk-- // kk: 3, k: 2
println(k)
println(kk)
results << k
results << kk
}
}
assert results[0] == 0
assert results[1] == 1
assert results[2] == 0
assert results[3] == 1
}
fn test_mut_11() {
mut arr := [[0,0]]
foo2(mut arr)
}
fn foo3(mut arr [][]int) {
mut results := []string{}
for _, mut j in arr {
j[0] += 2
println(j) // [2, 0]
results << '$j'
}
assert results[0] == '[2, 0]'
}
fn test_mut_12() {
mut arr := [[0, 0]]
foo3(mut arr)
}