checker: never allow taking the address of map values

pull/7424/head
Alexander Medvednikov 2020-12-20 07:55:23 +01:00
parent bbcaaa1232
commit 4fc5e83771
2 changed files with 71 additions and 68 deletions

View File

@ -3003,67 +3003,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
return c.postfix_expr(mut node)
}
ast.PrefixExpr {
right_type := c.expr(node.right)
node.right_type = right_type
// TODO: testing ref/deref strategy
if node.op == .amp && !right_type.is_ptr() {
if node.right is ast.IntegerLiteral {
c.error('cannot take the address of an int', node.pos)
}
if node.right is ast.StringLiteral || node.right is ast.StringInterLiteral {
c.error('cannot take the address of a string', node.pos)
}
if mut node.right is ast.IndexExpr {
typ_sym := c.table.get_type_symbol(node.right.left_type)
mut is_mut := false
if mut node.right.left is ast.Ident {
ident := node.right.left
// TODO: temporary, remove this
ident_obj := ident.obj
if ident_obj is ast.Var {
is_mut = ident_obj.is_mut
}
}
if !c.inside_unsafe && is_mut {
if typ_sym.kind == .map {
c.error('cannot take the address of mutable map values outside unsafe blocks',
node.right.pos)
}
if typ_sym.kind == .array {
c.error('cannot take the address of mutable array elements outside unsafe blocks',
node.right.pos)
}
}
}
return right_type.to_ptr()
} else if node.op == .amp && node.right !is ast.CastExpr {
return right_type.to_ptr()
}
if node.op == .mul {
if right_type.is_ptr() {
return right_type.deref()
}
if !right_type.is_pointer() {
s := c.table.type_to_str(right_type)
c.error('invalid indirect of `$s`', node.pos)
}
}
if node.op == .bit_not && !right_type.is_int() && !c.pref.translated {
c.error('operator ~ only defined on int types', node.pos)
}
if node.op == .not && right_type != table.bool_type_idx && !c.pref.translated {
c.error('! operator can only be used with bool types', node.pos)
}
if node.op == .arrow {
right := c.table.get_type_symbol(right_type)
if right.kind == .chan {
c.stmts(node.or_block.stmts)
return right.chan_info().elem_type
} else {
c.error('<- operator can only be used with `chan` types', node.pos)
}
}
return right_type
return c.prefix_expr(mut node)
}
ast.None {
return table.none_type
@ -4295,6 +4235,69 @@ pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) table.Type {
return typ
}
pub fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) table.Type {
right_type := c.expr(node.right)
node.right_type = right_type
// TODO: testing ref/deref strategy
if node.op == .amp && !right_type.is_ptr() {
if node.right is ast.IntegerLiteral {
c.error('cannot take the address of an int', node.pos)
}
if node.right is ast.StringLiteral || node.right is ast.StringInterLiteral {
c.error('cannot take the address of a string', node.pos)
}
if mut node.right is ast.IndexExpr {
typ_sym := c.table.get_type_symbol(node.right.left_type)
mut is_mut := false
if mut node.right.left is ast.Ident {
ident := node.right.left
// TODO: temporary, remove this
ident_obj := ident.obj
if ident_obj is ast.Var {
is_mut = ident_obj.is_mut
}
}
if typ_sym.kind == .map {
c.error('cannot take the address of map values', node.right.pos)
}
if !c.inside_unsafe {
if typ_sym.kind == .array && is_mut {
c.error('cannot take the address of mutable array elements outside unsafe blocks',
node.right.pos)
}
}
}
return right_type.to_ptr()
} else if node.op == .amp && node.right !is ast.CastExpr {
return right_type.to_ptr()
}
if node.op == .mul {
if right_type.is_ptr() {
return right_type.deref()
}
if !right_type.is_pointer() {
s := c.table.type_to_str(right_type)
c.error('invalid indirect of `$s`', node.pos)
}
}
if node.op == .bit_not && !right_type.is_int() && !c.pref.translated {
c.error('operator ~ only defined on int types', node.pos)
}
if node.op == .not && right_type != table.bool_type_idx && !c.pref.translated {
c.error('! operator can only be used with bool types', node.pos)
}
if node.op == .arrow {
right := c.table.get_type_symbol(right_type)
if right.kind == .chan {
c.stmts(node.or_block.stmts)
return right.chan_info().elem_type
} else {
c.error('<- operator can only be used with `chan` types', node.pos)
}
}
return right_type
}
fn (mut c Checker) check_index_type(typ_sym &table.TypeSymbol, index_type table.Type, pos token.Position) {
index_type_sym := c.table.get_type_symbol(index_type)
// println('index expr left=$typ_sym.name $node.pos.line_nr')

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/mut_map_get_value_address_err.vv:3:12: error: cannot take the address of mutable map values outside unsafe blocks
vlib/v/checker/tests/mut_map_get_value_address_err.vv:3:12: error: cannot take the address of map values
1 | fn main() {
2 | mut m := {'key' : 3}
3 | a := &m['key']