From a822fb669c781da18310d544e67b774d949f4c4d Mon Sep 17 00:00:00 2001 From: Brad Date: Tue, 23 Dec 2025 23:03:50 -0500 Subject: [PATCH] parser,orm: fix autofree detection for is_or with block style (fix #25969) (#26089) --- vlib/orm/orm.v | 1 + vlib/v/gen/c/coutput_test.v | 6 +++ .../gen/c/testdata/autofree_sql_or_block.out | 1 + .../v/gen/c/testdata/autofree_sql_or_block.vv | 27 ++++++++++++ vlib/v/parser/assign.v | 44 ++++++++++++++----- 5 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 vlib/v/gen/c/testdata/autofree_sql_or_block.out create mode 100644 vlib/v/gen/c/testdata/autofree_sql_or_block.vv diff --git a/vlib/orm/orm.v b/vlib/orm/orm.v index 9bba34692..686151d24 100644 --- a/vlib/orm/orm.v +++ b/vlib/orm/orm.v @@ -640,6 +640,7 @@ pub fn orm_table_gen(sql_dialect SQLDialect, table Table, q string, defaults boo } fs << unique_fields + unique_fields.clear() // ownership transferred to fs to avoid double-free under -autofree str += fs.join(', ') if index_fields.len > 0 && sql_dialect == .mysql { str += ', INDEX `idx_${table.name}` (`' diff --git a/vlib/v/gen/c/coutput_test.v b/vlib/v/gen/c/coutput_test.v index 018b6e1bc..40a67932a 100644 --- a/vlib/v/gen/c/coutput_test.v +++ b/vlib/v/gen/c/coutput_test.v @@ -245,7 +245,13 @@ pub fn get_file_options(file string) FileOptions { return res } +const github_job = os.getenv('GITHUB_JOB') + fn should_skip(relpath string) bool { + if github_job == 'docker-ubuntu-musl' && relpath.ends_with('autofree_sql_or_block.vv') { + eprintln('> skipping ${relpath} on docker-ubuntu-musl, since it uses db.sqlite, and its headers are not available to the C compiler in that environment') + return true + } if user_os == 'windows' { if relpath.contains('_nix.vv') { eprintln('> skipping ${relpath} on windows') diff --git a/vlib/v/gen/c/testdata/autofree_sql_or_block.out b/vlib/v/gen/c/testdata/autofree_sql_or_block.out new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/vlib/v/gen/c/testdata/autofree_sql_or_block.out @@ -0,0 +1 @@ +0 diff --git a/vlib/v/gen/c/testdata/autofree_sql_or_block.vv b/vlib/v/gen/c/testdata/autofree_sql_or_block.vv new file mode 100644 index 000000000..d2d42ffad --- /dev/null +++ b/vlib/v/gen/c/testdata/autofree_sql_or_block.vv @@ -0,0 +1,27 @@ +// vtest vflags: -autofree +import db.sqlite + +@[table: 'tasks'] +struct Task { +pub mut: + id int @[primary] + title string @[unique] +} + +fn get_tasks(db sqlite.DB) []Task { + tasks := sql db { + select from Task + } or { + return []Task{} + } + return tasks +} + +fn main() { + mut db := sqlite.connect(':memory:') or { panic(err) } + sql db { + create table Task + }! + tasks := get_tasks(db) + println(tasks.len) +} diff --git a/vlib/v/parser/assign.v b/vlib/v/parser/assign.v index 06fc68be8..ae927e0bb 100644 --- a/vlib/v/parser/assign.v +++ b/vlib/v/parser/assign.v @@ -239,16 +239,14 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr) ast.Stmt { } else if p.prev_tok.kind == .rsbr { v.typ = ast.array_type_idx } - if p.pref.autofree { - r0 := right[0] - if r0 is ast.CallExpr { - // Set correct variable position (after the or block) - // so that autofree doesn't free it in cgen before - // it's declared. (`Or` variables are declared after the or block). - if r0.or_block.pos.pos > 0 && r0.or_block.stmts.len > 0 { - v.is_or = true - // v.pos = r0.or_block.pos. - } + if p.pref.autofree && right.len > 0 { + expr_for_or := if v.expr !is ast.EmptyExpr { + v.expr + } else { + right[0] + } + if expr_has_block_or(expr_for_or) { + v.is_or = true } } obj := ast.ScopeObject(v) @@ -316,3 +314,29 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr) ast.Stmt { attr: attr } } + +fn expr_has_block_or(expr ast.Expr) bool { + return match expr { + ast.CallExpr { + expr.or_block.kind == .block && expr.or_block.stmts.len > 0 + } + ast.SelectorExpr { + expr.or_block.kind == .block && expr.or_block.stmts.len > 0 + } + ast.PrefixExpr { + expr.or_block.kind == .block && expr.or_block.stmts.len > 0 + } + ast.SqlExpr { + expr.or_expr.kind == .block && expr.or_expr.stmts.len > 0 + } + ast.IndexExpr { + expr.or_expr.kind == .block && expr.or_expr.stmts.len > 0 + } + ast.Ident { + expr.or_expr.kind == .block && expr.or_expr.stmts.len > 0 + } + else { + false + } + } +} -- 2.39.5