[vala] Fix jump statements in try with finally



commit 068d310a4943b04747f0fc9ad7b645709405ff53
Author: JiÅ?í Zárevúcky <zarevucky jiri gmail com>
Date:   Tue Jul 28 22:32:51 2009 +0200

    Fix jump statements in try with finally
    
    Fixes bug 579101.

 codegen/valaccodebasemodule.vala |   26 +++++++++++++++++++++++---
 codegen/valagerrormodule.vala    |   32 ++++++++++++++++++++++++--------
 vala/valacatchclause.vala        |   19 +++++++++++++++++--
 vala/valaifstatement.vala        |   19 +++++++++++++++++--
 vala/valatrystatement.vala       |   20 ++++++++++++++++++--
 5 files changed, 99 insertions(+), 17 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index ea5fd23..ac5769d 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 90e9552..649f6dd 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 8d3d412..4ce8ce1 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 4a97f81..b245f44 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 715ab7d..6e209a8 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);
 	}
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]