diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index ac2f6df0407ff2..27308b32ac4c17 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1312,6 +1312,7 @@ pub mut: is_volatile bool // for disabling variable access optimisations (needed for hardware drivers) is_simple bool // `x+=2` in `for x:=1; ; x+=2` has_cross_var bool + attr Attr } // `expr as Ident` diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index 9b17a7f40795d0..ee874193581e4a 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -8,6 +8,11 @@ import v.ast fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { prev_inside_assign := c.inside_assign c.inside_assign = true + if node.attr.name != '' { + c.assign_stmt_attr = node.attr.name + } else { + c.assign_stmt_attr = '' + } c.expected_type = ast.none_type // TODO: a hack to make `x := if ... work` defer { c.expected_type = ast.void_type diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 2b06d5118af413..40f983ae9a44fa 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -135,6 +135,7 @@ mut: orm_table_fields map[string][]ast.StructField // known table structs // v_current_commit_hash string // same as old C.V_CURRENT_COMMIT_HASH + assign_stmt_attr string // for `x := [1,2,3] @[freed]` } pub fn new_checker(table &ast.Table, pref_ &pref.Preferences) &Checker { diff --git a/vlib/v/checker/errors.v b/vlib/v/checker/errors.v index e3305c15ca625d..c5b9bf9daba1db 100644 --- a/vlib/v/checker/errors.v +++ b/vlib/v/checker/errors.v @@ -33,6 +33,10 @@ fn (mut c Checker) warn(s string, pos token.Pos) { } fn (mut c Checker) warn_alloc(s string, pos token.Pos) { + if c.assign_stmt_attr == 'freed' { + return + } + if !c.is_builtin_mod && c.mod !in ['strings', 'math', 'math.bits', 'builtin', 'strconv'] { c.warn('allocation (${s})', pos) } diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 8c48b6a0f50fd8..e553382e4eab1f 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -879,6 +879,9 @@ pub fn (mut f Fmt) assign_stmt(node ast.AssignStmt) { f.write(', ') } } + if node.attr.name != '' { + f.write(' @[${node.attr.name}]') + } f.comments(node.end_comments, has_nl: false, same_line: true, level: .keep) if !f.single_line_if { f.writeln('') diff --git a/vlib/v/fmt/tests/stmt_attr_keep.vv b/vlib/v/fmt/tests/stmt_attr_keep.vv new file mode 100644 index 00000000000000..68c93bdab47be3 --- /dev/null +++ b/vlib/v/fmt/tests/stmt_attr_keep.vv @@ -0,0 +1,7 @@ +fn foo() { + x := [1, 2, 3] @[freed] + unsafe { + x.free() + } + println('x is freed') +} diff --git a/vlib/v/parser/assign.v b/vlib/v/parser/assign.v index d5f52fc5e3b504..81c747cbefcafa 100644 --- a/vlib/v/parser/assign.v +++ b/vlib/v/parser/assign.v @@ -285,6 +285,14 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr) ast.Stmt { } } } + mut attr := ast.Attr{} + // This assign stmt has an attribute e.g. `x := [1,2,3] @[freed]` + if p.tok.kind == .at && p.tok.line_nr == p.prev_tok.line_nr { + p.check(.at) + p.check(.lsbr) + attr = p.parse_attr(true) + p.check(.rsbr) + } pos.update_last_line(p.prev_tok.line_nr) p.expr_mod = '' return ast.AssignStmt{ @@ -297,5 +305,6 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr) ast.Stmt { is_simple: p.inside_for && p.tok.kind == .lcbr is_static: is_static is_volatile: is_volatile + attr: attr } }