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

checker: add error for inc/dec for non lvalue (#17091)

This commit is contained in:
Makhnev Petr 2023-01-24 12:03:37 +04:00 committed by GitHub
parent 5cd074a49e
commit 91799a1742
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 68 additions and 25 deletions

View File

@ -3565,31 +3565,6 @@ pub fn (mut c Checker) is_comptime_var(node ast.Expr) bool {
&& (node as ast.Ident).info is ast.IdentVar && (node as ast.Ident).kind == .variable && ((node as ast.Ident).obj as ast.Var).is_comptime_field
}
fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
typ := c.unwrap_generic(c.expr(node.expr))
typ_sym := c.table.sym(typ)
is_non_void_pointer := (typ.is_ptr() || typ.is_pointer()) && typ_sym.kind != .voidptr
if !c.inside_unsafe && is_non_void_pointer && !node.expr.is_auto_deref_var() {
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)
}
if !(typ_sym.is_number() || ((c.inside_unsafe || c.pref.translated) && is_non_void_pointer)) {
if c.inside_comptime_for_field {
if c.is_comptime_var(node.expr) {
return c.comptime_fields_default_type
} else if node.expr is ast.ComptimeSelector {
return c.comptime_fields_default_type
}
}
typ_str := c.table.type_to_str(typ)
c.error('invalid operation: ${node.op.str()} (non-numeric type `${typ_str}`)',
node.pos)
} else {
node.auto_locked, _ = c.fail_if_immutable(node.expr)
}
return typ
}
fn (mut c Checker) mark_as_referenced(mut node ast.Expr, as_interface bool) {
match mut node {
ast.Ident {

41
vlib/v/checker/postfix.v Normal file
View File

@ -0,0 +1,41 @@
module checker
import v.ast
fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
typ := c.unwrap_generic(c.expr(node.expr))
typ_sym := c.table.sym(typ)
is_non_void_pointer := (typ.is_ptr() || typ.is_pointer()) && typ_sym.kind != .voidptr
if node.op in [.inc, .dec] && !node.expr.is_lvalue() {
op_kind, bin_op_alt := if node.op == .inc {
'increment', '+'
} else {
'decrement', '-'
}
c.add_error_detail('try rewrite this as `${node.expr} ${bin_op_alt} 1`')
c.error('cannot ${op_kind} `${node.expr}` because it is non lvalue expression',
node.expr.pos())
}
if !c.inside_unsafe && is_non_void_pointer && !node.expr.is_auto_deref_var() {
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)
}
if !(typ_sym.is_number() || ((c.inside_unsafe || c.pref.translated) && is_non_void_pointer)) {
if c.inside_comptime_for_field {
if c.is_comptime_var(node.expr) {
return c.comptime_fields_default_type
} else if node.expr is ast.ComptimeSelector {
return c.comptime_fields_default_type
}
}
typ_str := c.table.type_to_str(typ)
c.error('invalid operation: ${node.op.str()} (non-numeric type `${typ_str}`)',
node.pos)
} else {
node.auto_locked, _ = c.fail_if_immutable(node.expr)
}
return typ
}

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/inc_dec_fun_call.vv:5:1: error: cannot decrement `foo()` because it is non lvalue expression
3 | }
4 |
5 | foo()--
| ~~~~~
Details: try rewrite this as `foo() - 1`

View File

@ -0,0 +1,5 @@
fn foo() int {
return 100
}
foo()--

View File

@ -0,0 +1,4 @@
vlib/v/checker/tests/inc_num_literal.vv:1:1: error: cannot increment `100` because it is non lvalue expression
1 | 100++
| ~~~
Details: try rewrite this as `100 + 1`

View File

@ -0,0 +1 @@
100++

View File

View File

@ -0,0 +1,6 @@
mut mp := map[string]int{}
mut val := 100
(val)++
val++
mp["100"]++

View File

@ -0,0 +1,4 @@
vlib/v/checker/tests/inc_paren_expr.vv:1:1: error: cannot increment `(100 * 10)` because it is non lvalue expression
1 | (100 * 10)++
| ~~~~~~~~~~
Details: try rewrite this as `(100 * 10) + 1`

View File

@ -0,0 +1 @@
(100 * 10)++