From 3ad384e92a42021f316498e8d04c3c0779f18e59 Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Tue, 3 Jun 2025 12:56:12 +0530 Subject: [PATCH] checker: cycle through all `ast.ParExpr` first in `prefix_expr` (fix #24584) (#24588) --- vlib/v/checker/checker.v | 70 ++++++++++--------- .../tests/mut_map_get_value_address_err.out | 2 +- vlib/v/checker/tests/prefix_err.out | 8 +++ vlib/v/checker/tests/prefix_err.vv | 3 + 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 6eb77b698..6cadcabd8 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -4771,8 +4771,8 @@ fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type { expr = expr.expr } if node.op == .amp { - if node.right is ast.Nil { - c.error('invalid operation: cannot take address of nil', node.right.pos()) + if expr is ast.Nil { + c.error('invalid operation: cannot take address of nil', expr.pos()) } if mut node.right is ast.PrefixExpr { if node.right.op == .amp { @@ -4782,76 +4782,78 @@ fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type { if expr.op == .amp { c.error('cannot take the address of this expression', expr.pos) } - } else if mut node.right is ast.SelectorExpr { - if node.right.expr.is_literal() { - c.error('cannot take the address of a literal value', node.pos.extend(node.right.pos)) - } else if node.right.expr is ast.StructInit { + } else if mut expr is ast.SelectorExpr { + if expr.expr.is_literal() { + c.error('cannot take the address of a literal value', node.pos.extend(expr.pos)) + } else if expr.expr is ast.StructInit { c.error('should not create object instance on the heap to simply access a member', - node.pos.extend(node.right.pos)) + node.pos.extend(expr.pos)) } right_sym := c.table.sym(right_type) - expr_sym := c.table.sym(node.right.expr_type) + expr_sym := c.table.sym(expr.expr_type) if expr_sym.kind == .struct && (expr_sym.info as ast.Struct).is_minify - && (node.right.typ == ast.bool_type_idx || (right_sym.kind == .enum + && (expr.typ == ast.bool_type_idx || (right_sym.kind == .enum && !(right_sym.info as ast.Enum).is_flag && !(right_sym.info as ast.Enum).uses_exprs)) { - c.error('cannot take the address of field in struct `${c.table.type_to_str(node.right.expr_type)}`, which is tagged as `@[minify]`', - node.pos.extend(node.right.pos)) + c.error('cannot take the address of field in struct `${c.table.type_to_str(expr.expr_type)}`, which is tagged as `@[minify]`', + node.pos.extend(expr.pos)) } - if node.right.typ.has_flag(.option) { - c.error('cannot take the address of an Option field', node.pos.extend(node.right.pos)) + if expr.typ.has_flag(.option) { + c.error('cannot take the address of an Option field', node.pos.extend(expr.pos)) } } } // TODO: testing ref/deref strategy right_is_ptr := right_type.is_ptr() - if node.op == .amp && (!right_is_ptr || (right_is_ptr && node.right is ast.CallExpr)) { + if node.op == .amp && (!right_is_ptr || (right_is_ptr && expr is ast.CallExpr)) { if expr in [ast.BoolLiteral, ast.CallExpr, ast.CharLiteral, ast.FloatLiteral, ast.IntegerLiteral, ast.InfixExpr, ast.StringLiteral, ast.StringInterLiteral] { c.error('cannot take the address of ${expr}', node.pos) } - if mut node.right is ast.Ident { - if node.right.kind == .constant && !c.inside_unsafe && c.pref.experimental { - c.warn('cannot take the address of const outside `unsafe`', node.right.pos) + if mut expr is ast.Ident { + if expr.kind == .constant && !c.inside_unsafe && c.pref.experimental { + c.warn('cannot take the address of const outside `unsafe`', expr.pos) } } - if node.right is ast.SelectorExpr { + if expr is ast.SelectorExpr { typ_sym := c.table.sym(right_type) if typ_sym.kind == .map && !c.inside_unsafe { c.error('cannot take the address of map values outside `unsafe`', node.pos) } } - if mut node.right is ast.IndexExpr { - typ_sym := c.table.sym(node.right.left_type) + if mut expr is ast.IndexExpr { + typ_sym := c.table.sym(expr.left_type) mut is_mut := false - if mut node.right.left is ast.Ident { - ident := node.right.left + if mut expr.left is ast.Ident { + ident := expr.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) + expr.pos) + } + + if typ_sym.kind == .map { + c.error('cannot take the address of map values outside `unsafe`', + expr.pos) } } } if !c.inside_fn_arg && !c.inside_unsafe { - c.mark_as_referenced(mut &node.right, false) + c.mark_as_referenced(mut &expr, false) } return right_type.ref() - } else if node.op == .amp && node.right !is ast.CastExpr { + } else if node.op == .amp && expr !is ast.CastExpr { if !c.inside_fn_arg && !c.inside_unsafe { - c.mark_as_referenced(mut &node.right, false) + c.mark_as_referenced(mut &expr, false) } - if node.right.is_auto_deref_var() { + if expr.is_auto_deref_var() { return right_type } else { return right_type.ref() @@ -4861,7 +4863,7 @@ fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type { if node.op == .mul { if right_type.has_flag(.option) { c.error('type `?${right_sym.name}` is an Option, it must be unwrapped first; use `*var?` to do it', - node.right.pos()) + expr.pos()) } if right_type.is_ptr() { return right_type.deref() @@ -4874,11 +4876,11 @@ fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type { if right_type.is_voidptr() { c.error('cannot dereference to void', node.pos) } - if mut node.right is ast.Ident { - if var := node.right.scope.find_var('${node.right.name}') { + if mut expr is ast.Ident { + if var := expr.scope.find_var('${expr.name}') { if var.expr is ast.UnsafeExpr { if var.expr.expr is ast.Nil { - c.error('cannot deference a `nil` pointer', node.right.pos) + c.error('cannot deference a `nil` pointer', expr.pos) } } } diff --git a/vlib/v/checker/tests/mut_map_get_value_address_err.out b/vlib/v/checker/tests/mut_map_get_value_address_err.out index 03623134e..79be06325 100644 --- a/vlib/v/checker/tests/mut_map_get_value_address_err.out +++ b/vlib/v/checker/tests/mut_map_get_value_address_err.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/mut_map_get_value_address_err.vv:5:9: error: cannot take the address of map values +vlib/v/checker/tests/mut_map_get_value_address_err.vv:5:9: error: cannot take the address of map values outside `unsafe` 3 | 'key': 3 4 | } 5 | a := &m['key'] diff --git a/vlib/v/checker/tests/prefix_err.out b/vlib/v/checker/tests/prefix_err.out index 89a88e072..86246df73 100644 --- a/vlib/v/checker/tests/prefix_err.out +++ b/vlib/v/checker/tests/prefix_err.out @@ -88,8 +88,16 @@ vlib/v/checker/tests/prefix_err.vv:21:5: error: operator `~` can only be used wi 21 | _ = ~true | ^ 22 | _ = !4 + 23 | vlib/v/checker/tests/prefix_err.vv:22:5: error: operator `!` can only be used with bool types, but the value after `!` is of type `int literal` instead 20 | 21 | _ = ~true 22 | _ = !4 | ^ + 23 | + 24 | mut arr := [12, 4] +vlib/v/checker/tests/prefix_err.vv:25:11: error: cannot take the address of mutable array elements outside unsafe blocks + 23 | + 24 | mut arr := [12, 4] + 25 | _ := (&arr[1]) + | ~~~ diff --git a/vlib/v/checker/tests/prefix_err.vv b/vlib/v/checker/tests/prefix_err.vv index d5eed4d33..b45d5256a 100644 --- a/vlib/v/checker/tests/prefix_err.vv +++ b/vlib/v/checker/tests/prefix_err.vv @@ -20,3 +20,6 @@ a <- 4 _ = ~true _ = !4 + +mut arr := [12, 4] +_ := (&arr[1]) -- 2.39.5