]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Fix jump statements in try with finally
authorJiří Zárevúcky <zarevucky.jiri@gmail.com>
Tue, 28 Jul 2009 20:32:51 +0000 (22:32 +0200)
committerJürg Billeter <j@bitron.ch>
Tue, 28 Jul 2009 20:32:51 +0000 (22:32 +0200)
Fixes bug 579101.

codegen/valaccodebasemodule.vala
codegen/valagerrormodule.vala
vala/valacatchclause.vala
vala/valaifstatement.vala
vala/valatrystatement.vala

index ea5fd2389dce3f92cc859814bff26575d4bb06fd..ac5769dab479b97876d70c56f60555bcfd5993e5 100644 (file)
@@ -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 */
 
index 90e9552beb0ea250843746d37329fda61ee0d45f..649f6dd2d958a5a009165de3d6100ae3429e61e8 100644 (file)
@@ -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
index 8d3d4124f73a0565d29361e6281e036bd0b41fe3..4ce8ce1fe1e60b1060f3d703d2221fab4f833efb 100644 (file)
@@ -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 
         *
index 4a97f81c1896914ca1540178241c1d63d0eb22d9..b245f44c548c906380f7e08a1a3fb5246437ad71 100644 (file)
@@ -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.
index 715ab7d8dc5165e9ccebe572043db940806be8fa..6e209a8762ea202303308ce3949a62dd4467b2f7 100644 (file)
@@ -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);
        }