diff options
author | Jiří Zárevúcky <zarevucky.jiri@gmail.com> | 2009-07-28 22:32:51 +0200 |
---|---|---|
committer | Jürg Billeter <j@bitron.ch> | 2009-07-28 22:32:51 +0200 |
commit | 068d310a4943b04747f0fc9ad7b645709405ff53 (patch) | |
tree | 5eaf9ba38bd60eba768ffccea9ff4eeec0dbb93f | |
parent | 70eec997de972da1bc20f9879da53079cf23aa09 (diff) | |
download | vala-068d310a4943b04747f0fc9ad7b645709405ff53.tar.gz |
Fix jump statements in try with finally
Fixes bug 579101.
-rw-r--r-- | codegen/valaccodebasemodule.vala | 26 | ||||
-rw-r--r-- | codegen/valagerrormodule.vala | 32 | ||||
-rw-r--r-- | vala/valacatchclause.vala | 19 | ||||
-rw-r--r-- | vala/valaifstatement.vala | 19 | ||||
-rw-r--r-- | vala/valatrystatement.vala | 20 |
5 files changed, 99 insertions, 17 deletions
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index ea5fd2389..ac5769dab 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -2316,7 +2316,7 @@ internal class Vala.CCodeBaseModule : CCodeModule { stmt.ccodenode = cfrag; } - public void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop = false) { + public virtual void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop = false) { var b = (Block) sym; var local_vars = b.get_local_variables (); @@ -2385,12 +2385,32 @@ internal class Vala.CCodeBaseModule : CCodeModule { stmt.ccodenode = cfrag; } + public virtual bool variable_accessible_in_finally (LocalVariable local) { + if (current_try == null) { + return false; + } + + var sym = current_symbol; + + while (!(sym is Method) && sym.scope.lookup (local.name) == null) { + if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) || + (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) { + + return true; + } + + sym = sym.parent_symbol; + } + + return false; + } + public override void visit_return_statement (ReturnStatement stmt) { // avoid unnecessary ref/unref pair if (stmt.return_expression != null) { var local = stmt.return_expression.symbol_reference as LocalVariable; if (current_return_type.value_owned - && local != null && local.variable_type.value_owned) { + && local != null && local.variable_type.value_owned && !variable_accessible_in_finally (local)) { /* return expression is local variable taking ownership and * current method is transferring ownership */ @@ -2423,7 +2443,7 @@ internal class Vala.CCodeBaseModule : CCodeModule { // avoid unnecessary ref/unref pair var local = stmt.return_expression.symbol_reference as LocalVariable; if (current_return_type.value_owned - && local != null && local.variable_type.value_owned) { + && local != null && local.variable_type.value_owned && !variable_accessible_in_finally (local)) { /* return expression is local variable taking ownership and * current method is transferring ownership */ diff --git a/codegen/valagerrormodule.vala b/codegen/valagerrormodule.vala index 90e9552be..649f6dd2d 100644 --- a/codegen/valagerrormodule.vala +++ b/codegen/valagerrormodule.vala @@ -27,6 +27,7 @@ using Gee; internal class Vala.GErrorModule : CCodeDelegateModule { private int current_try_id = 0; private int next_try_id = 0; + private bool is_in_catch = false; public GErrorModule (CCodeGenerator codegen, CCodeModule? next) { base (codegen, next); @@ -169,7 +170,7 @@ internal class Vala.GErrorModule : CCodeDelegateModule { CCodeStatement cerror_handler = null; - if (current_try != null) { + if (current_try != null && !is_in_catch) { // surrounding try found var cerror_block = new CCodeBlock (); @@ -257,8 +258,10 @@ internal class Vala.GErrorModule : CCodeDelegateModule { var old_try = current_try; var old_try_id = current_try_id; + var old_is_in_catch = is_in_catch; current_try = stmt; current_try_id = this_try_id; + is_in_catch = true; foreach (CatchClause clause in stmt.get_catch_clauses ()) { clause.clabel_name = "__catch%d_%s".printf (this_try_id, clause.error_type.get_lower_case_cname ()); @@ -268,25 +271,23 @@ internal class Vala.GErrorModule : CCodeDelegateModule { stmt.finally_body.accept (codegen); } + is_in_catch = false; stmt.body.accept (codegen); - - current_try = old_try; - current_try_id = old_try_id; + is_in_catch = true; foreach (CatchClause clause in stmt.get_catch_clauses ()) { clause.accept (codegen); } - if (stmt.finally_body != null) { - stmt.finally_body.accept (codegen); - } + current_try = old_try; + current_try_id = old_try_id; + is_in_catch = old_is_in_catch; var cfrag = new CCodeFragment (); cfrag.append (stmt.body.ccodenode); foreach (CatchClause clause in stmt.get_catch_clauses ()) { cfrag.append (new CCodeGotoStatement ("__finally%d".printf (this_try_id))); - cfrag.append (clause.ccodenode); } @@ -344,6 +345,21 @@ internal class Vala.GErrorModule : CCodeDelegateModule { clause.ccodenode = cfrag; } + + public override void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop = false) { + var finally_block = (Block) null; + if (sym.parent_node is TryStatement) { + finally_block = (sym.parent_node as TryStatement).finally_body; + } else if (sym.parent_node is CatchClause) { + finally_block = (sym.parent_node.parent_node as TryStatement).finally_body; + } + + if (finally_block != null) { + cfrag.append (finally_block.ccodenode); + } + + base.append_local_free (sym, cfrag, stop_at_loop); + } } // vim:sw=8 noet diff --git a/vala/valacatchclause.vala b/vala/valacatchclause.vala index 8d3d4124f..4ce8ce1fe 100644 --- a/vala/valacatchclause.vala +++ b/vala/valacatchclause.vala @@ -47,12 +47,24 @@ public class Vala.CatchClause : CodeNode { /** * Specifies the error handler body. */ - public Block body { get; set; } + public Block body { + get { return _body; } + set { + _body = value; + _body.parent_node = this; + } + } /** * Specifies the declarator for the generated error variable. */ - public LocalVariable error_variable { get; set; } + public LocalVariable error_variable { + get { return _error_variable; } + set { + _error_variable = value; + _error_variable.parent_node = this; + } + } /** * Specifies the label used for this catch clause in the C code. @@ -61,6 +73,9 @@ public class Vala.CatchClause : CodeNode { private DataType _data_type; + private Block _body; + private LocalVariable _error_variable; + /** * Creates a new catch * diff --git a/vala/valaifstatement.vala b/vala/valaifstatement.vala index 4a97f81c1..b245f44c5 100644 --- a/vala/valaifstatement.vala +++ b/vala/valaifstatement.vala @@ -42,14 +42,29 @@ public class Vala.IfStatement : CodeNode, Statement { /** * The statement to be evaluated if the condition holds. */ - public Block true_statement { get; set; } + public Block true_statement { + get { return _true_statement; } + set { + _true_statement = value; + _true_statement.parent_node = this; + } + } /** * The optional statement to be evaluated if the condition doesn't hold. */ - public Block? false_statement { get; set; } + public Block? false_statement { + get { return _false_statement; } + set { + _false_statement = value; + if (_false_statement != null) + _false_statement.parent_node = this; + } + } private Expression _condition; + private Block _true_statement; + private Block _false_statement; /** * Creates a new if statement. diff --git a/vala/valatrystatement.vala b/vala/valatrystatement.vala index 715ab7d8d..6e209a876 100644 --- a/vala/valatrystatement.vala +++ b/vala/valatrystatement.vala @@ -30,13 +30,28 @@ public class Vala.TryStatement : CodeNode, Statement { /** * Specifies the body of the try statement. */ - public Block body { get; set; } + public Block body { + get { return _body; } + set { + _body = value; + _body.parent_node = this; + } + } /** * Specifies the body of the optional finally clause. */ - public Block? finally_body { get; set; } + public Block? finally_body { + get { return _finally_body; } + set { + _finally_body = value; + if (_finally_body != null) + _finally_body.parent_node = this; + } + } + private Block _body; + private Block _finally_body; private Gee.List<CatchClause> catch_clauses = new ArrayList<CatchClause> (); /** @@ -59,6 +74,7 @@ public class Vala.TryStatement : CodeNode, Statement { * @param clause a catch clause */ public void add_catch_clause (CatchClause clause) { + clause.parent_node = this; catch_clauses.add (clause); } |