From 2afb9b30e97cedf6a9dcec75935e725115a4ce0e Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sat, 21 Nov 2020 19:07:47 +0100 Subject: [PATCH] autofree: minor fixes; skip in consts --- vlib/stbi/stbi.v | 2 +- vlib/v/checker/checker.v | 87 ++++++++++++++++++++++------------------ vlib/v/gen/cgen.v | 14 +++++++ vlib/v/gen/fn.v | 5 ++- 4 files changed, 66 insertions(+), 42 deletions(-) diff --git a/vlib/stbi/stbi.v b/vlib/stbi/stbi.v index 763bd1aa06..bb6a542a01 100644 --- a/vlib/stbi/stbi.v +++ b/vlib/stbi/stbi.v @@ -57,7 +57,7 @@ pub fn load_from_memory(buf byteptr, bufsize int) ?Image { } -pub fn (img Image) free() { +pub fn (img &Image) free() { C.stbi_image_free(img.data) } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 405ea7456a..afe127b7a0 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -53,6 +53,7 @@ pub mut: mod string // current module name is_builtin_mod bool // are we in `builtin`? inside_unsafe bool + inside_const bool skip_flags bool // should `#flag` and `#include` be skipped cur_generic_type table.Type mut: @@ -1028,7 +1029,7 @@ pub fn (mut c Checker) call_expr(mut call_expr ast.CallExpr) table.Type { // autofree: mark args that have to be freed (after saving them in tmp exprs) free_tmp_arg_vars := c.pref.autofree && c.pref.experimental && !c.is_builtin_mod && call_expr.args.len > 0 && !call_expr.args[0].typ.has_flag(.optional) - if free_tmp_arg_vars { + if free_tmp_arg_vars && !c.inside_const { for i, arg in call_expr.args { if arg.typ != table.string_type { continue @@ -1896,6 +1897,48 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) { } } +pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) { + mut field_names := []string{} + mut field_order := []int{} + for i, field in node.fields { + // TODO Check const name once the syntax is decided + if field.name in c.const_names { + c.error('duplicate const `$field.name`', field.pos) + } + c.const_names << field.name + field_names << field.name + field_order << i + } + mut needs_order := false + mut done_fields := []int{} + for i, field in node.fields { + c.const_decl = field.name + c.const_deps << field.name + typ := c.expr(field.expr) + node.fields[i].typ = c.table.mktyp(typ) + for cd in c.const_deps { + for j, f in node.fields { + if j != i && cd in field_names && cd == f.name && j !in done_fields { + needs_order = true + x := field_order[j] + field_order[j] = field_order[i] + field_order[i] = x + break + } + } + } + done_fields << i + c.const_deps = [] + } + if needs_order { + mut ordered_fields := []ast.ConstField{} + for order in field_order { + ordered_fields << node.fields[order] + } + node.fields = ordered_fields + } +} + pub fn (mut c Checker) enum_decl(decl ast.EnumDecl) { c.check_valid_pascal_case(decl.name, 'enum name', decl.pos) mut seen := []int{} @@ -2421,45 +2464,9 @@ fn (mut c Checker) stmt(node ast.Stmt) { c.stmts(node.stmts) } ast.ConstDecl { - mut field_names := []string{} - mut field_order := []int{} - for i, field in node.fields { - // TODO Check const name once the syntax is decided - if field.name in c.const_names { - c.error('duplicate const `$field.name`', field.pos) - } - c.const_names << field.name - field_names << field.name - field_order << i - } - mut needs_order := false - mut done_fields := []int{} - for i, field in node.fields { - c.const_decl = field.name - c.const_deps << field.name - typ := c.expr(field.expr) - node.fields[i].typ = c.table.mktyp(typ) - for cd in c.const_deps { - for j, f in node.fields { - if j != i && cd in field_names && cd == f.name && j !in done_fields { - needs_order = true - x := field_order[j] - field_order[j] = field_order[i] - field_order[i] = x - break - } - } - } - done_fields << i - c.const_deps = [] - } - if needs_order { - mut ordered_fields := []ast.ConstField{} - for order in field_order { - ordered_fields << node.fields[order] - } - node.fields = ordered_fields - } + c.inside_const = true + c.const_decl(mut node) + c.inside_const = false } ast.DeferStmt { c.stmts(node.stmts) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 15d249193e..78f730e58a 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -2069,8 +2069,16 @@ fn (mut g Gen) autofree_scope_vars(pos int, line_nr int, free_parent_scopes bool // In `builtin` everything is freed manually. return } + if pos == -1 { + // TODO why can pos be -1? + return + } // eprintln('> free_scope_vars($pos)') scope := g.file.scope.innermost(pos) + if scope.start_pos == 0 { + // TODO why can scope.pos be 0? (only outside fns?) + return + } g.writeln('// autofree_scope_vars(pos=$pos scope.pos=$scope.start_pos scope.end_pos=$scope.end_pos)') // g.autofree_scope_vars2(scope, scope.end_pos) g.autofree_scope_vars2(scope, scope.start_pos, scope.end_pos, line_nr, free_parent_scopes) @@ -3460,9 +3468,15 @@ fn (mut g Gen) if_expr(node ast.IfExpr) { // For if expressions with multiple statements or another if expression inside, it's much // easier to use a temp var, than do C tricks with commas, introduce special vars etc // (as it used to be done). + // Always use this in -autofree, since ?: can have tmp expressions that have to be freed. needs_tmp_var := node.is_expr && (g.pref.autofree || (g.pref.experimental && (node.branches[0].stmts.len > 1 || node.branches[0].stmts[0] is ast.IfExpr))) + /* + needs_tmp_var := node.is_expr && + (g.pref.autofree || g.pref.experimental) && + (node.branches[0].stmts.len > 1 || node.branches[0].stmts[0] is ast.IfExpr) + */ tmp := if needs_tmp_var { g.new_tmp_var() } else { '' } mut cur_line := '' if needs_tmp_var { diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index 09a0ab720d..dd9a35b52e 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -647,6 +647,9 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) { if g.is_js_call { return } + if g.inside_const { + return + } free_tmp_arg_vars = false // set the flag to true only if we have at least one arg to free g.tmp_count2++ mut scope := g.file.scope.innermost(node.pos.pos) @@ -778,7 +781,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) { break } use_tmp_var_autofree := g.autofree && g.pref.experimental && arg.typ == table.string_type && - arg.is_tmp_autofree + arg.is_tmp_autofree && !g.inside_const // g.write('/* af=$arg.is_tmp_autofree */') mut is_interface := false // some c fn definitions dont have args (cfns.v) or are not updated in checker