summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--codegen/valaccodebasemodule.vala26
-rw-r--r--codegen/valagerrormodule.vala32
-rw-r--r--vala/valacatchclause.vala19
-rw-r--r--vala/valaifstatement.vala19
-rw-r--r--vala/valatrystatement.vala20
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);
}