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()
right_pos := infix_expr.right.position()
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)
}
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] }
mut right_type := assign_stmt.right_types[i]
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 right is ast.IntegerLiteral {
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
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
continue
}
@ -5097,7 +5105,7 @@ pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) table.Type {
typ := c.expr(node.expr)
typ_sym := c.table.get_type_symbol(typ)
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)
}
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)',
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
if mut node.left is ast.Ident {
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
}
// `{'age': 20}`
key0_type := c.table.mktyp(c.expr(node.keys[0]))
val0_type := c.table.mktyp(c.expr(node.vals[0]))
mut key0_type := c.table.mktyp(c.expr(node.keys[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
for i, key in node.keys {
if i == 0 {

View File

@ -26,6 +26,9 @@ fn (mut g Gen) array_init(node ast.ArrayInit) {
g.write('{')
if node.has_val {
for i, expr in node.exprs {
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr)
if i != node.exprs.len - 1 {
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
}
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()
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]
@ -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.expr(left)
g.write('[$i_var] = ')
if val.is_mut_ident() {
g.write('*')
}
g.expr(val)
g.write('[$i_var];')
g.writeln('}')
@ -2133,6 +2136,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
g.write('{0}')
}
} else {
if val.is_mut_ident() {
g.write('*')
}
g.expr(val)
}
} else {
@ -2715,7 +2721,13 @@ fn (mut g Gen) expr(node ast.Expr) {
g.writeln('sync__RwMutex_lock(&$node.auto_locked->mtx);')
}
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.write(node.op.str())
if node.auto_locked != '' {
@ -3375,8 +3387,14 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
if need_par {
g.write('(')
}
if node.left_type.is_ptr() && node.left.is_mut_ident() {
g.write('*')
}
g.expr(node.left)
g.write(' $node.op.str() ')
if node.right_type.is_ptr() && node.right.is_mut_ident() {
g.write('*')
}
g.expr(node.right)
if need_par {
g.write(')')
@ -3706,6 +3724,9 @@ fn (mut g Gen) map_init(node ast.MapInit) {
g.write('}), _MOV(($value_typ_str[$size]){')
}
for expr in node.vals {
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr)
g.write(', ')
}

View File

@ -264,9 +264,15 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
if typ == table.string_type {
if g.inside_vweb_tmpl {
g.write('vweb__filter(')
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr)
g.write(')')
} else {
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr)
}
} 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 {
g.write('(u64)(')
}
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr)
g.write(')')
} else {
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr)
}
} else {
if expr.is_mut_ident() {
g.write('*')
}
g.expr(expr)
}
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[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)
}