From 83f651c29a877312bfa3a1f285e63ca841cea923 Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Sun, 6 Dec 2020 02:36:27 +1100 Subject: [PATCH] cgen: autofree - know where to stop freeing parent scops on continue/break --- vlib/v/ast/ast.v | 7 ++++--- vlib/v/gen/cgen.v | 19 ++++++++++++------- vlib/v/parser/for.v | 1 + vlib/v/parser/parser.v | 2 ++ vlib/v/tests/valgrind/1.strings_and_arrays.v | 20 +++++++++++++++----- 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index e1acd34b01..f3f81f25ea 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -286,9 +286,10 @@ pub mut: // break, continue pub struct BranchStmt { pub: - kind token.Kind - label string - pos token.Position + kind token.Kind + label string + pos token.Position + parent_pos int } pub struct CallExpr { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 3650204d44..c872b82e26 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -858,7 +858,8 @@ fn (mut g Gen) stmt(node ast.Stmt) { // continue or break if g.pref.autofree && !g.is_builtin_mod { g.writeln('// free before continue/break') - g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, false) + g.autofree_scope_vars_stop(node.pos.pos - 1, node.pos.line_nr, true, + node.parent_pos) } g.writeln('$node.kind;') } @@ -2061,8 +2062,11 @@ fn (mut g Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, ad return true } -// fn (mut g Gen) autofree_scope_vars(pos int, line_nr int) { fn (mut g Gen) autofree_scope_vars(pos int, line_nr int, free_parent_scopes bool) { + g.autofree_scope_vars_stop(pos, line_nr, free_parent_scopes, -1) +} + +fn (mut g Gen) autofree_scope_vars_stop(pos int, line_nr int, free_parent_scopes bool, stop_pos int) { if g.is_builtin_mod { // In `builtin` everything is freed manually. return @@ -2078,12 +2082,12 @@ fn (mut g Gen) autofree_scope_vars(pos int, line_nr int, free_parent_scopes bool return } g.writeln('// autofree_scope_vars(pos=$pos line_nr=$line_nr 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) + g.autofree_scope_vars2(scope, scope.start_pos, scope.end_pos, line_nr, free_parent_scopes, + stop_pos) } // fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, end_pos int) { -fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int, line_nr int, free_parent_scopes bool) { +fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int, line_nr int, free_parent_scopes bool, stop_pos int) { if isnil(scope) { return } @@ -2129,9 +2133,10 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int // } // ``` // if !isnil(scope.parent) && line_nr > 0 { - if free_parent_scopes && !isnil(scope.parent) { + if free_parent_scopes && !isnil(scope.parent) && + (stop_pos == -1 || scope.parent.start_pos >= stop_pos) { g.writeln('// af parent scope:') - g.autofree_scope_vars2(scope.parent, start_pos, end_pos, line_nr, true) + g.autofree_scope_vars2(scope.parent, start_pos, end_pos, line_nr, true, stop_pos) } } diff --git a/vlib/v/parser/for.v b/vlib/v/parser/for.v index 924faf5925..6b70ac40e6 100644 --- a/vlib/v/parser/for.v +++ b/vlib/v/parser/for.v @@ -9,6 +9,7 @@ import v.table fn (mut p Parser) for_stmt() ast.Stmt { p.check(.key_for) pos := p.tok.position() + p.branch_parent_pos = pos.pos p.open_scope() p.inside_for = true if p.tok.kind == .key_match { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index b89e0b3455..d33f41672e 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -60,6 +60,7 @@ mut: vet_errors []string cur_fn_name string in_generic_params bool // indicates if parsing between `<` and `>` of a method/function + branch_parent_pos int // used in BranchStmt (continue/break) autofree stop position } // for tests @@ -690,6 +691,7 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt { kind: tok.kind label: label pos: tok.position() + parent_pos: p.branch_parent_pos } } .key_unsafe { diff --git a/vlib/v/tests/valgrind/1.strings_and_arrays.v b/vlib/v/tests/valgrind/1.strings_and_arrays.v index 1981bd79ca..32f83224b7 100644 --- a/vlib/v/tests/valgrind/1.strings_and_arrays.v +++ b/vlib/v/tests/valgrind/1.strings_and_arrays.v @@ -258,17 +258,28 @@ fn free_before_break() { q := [1, 2, 3] break } - /* for { - qq := [1, 2, 3] + aa := [1, 2, 3] if true { // breaking should free only vars in the closest for loop's scope // `qq`, not `s` break } + // nested 1 + for { + bb := [4, 5, 6] + if true { + break + } + // nested 2 + for { + cc := [7, 8, 9] + if true { + break + } + } + } } - */ - /* mut i := 0 for { i++ @@ -280,7 +291,6 @@ fn free_before_break() { continue } } - */ } struct User {