Fixes bug 579101.
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 ();
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 */
// 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 */
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);
CCodeStatement cerror_handler = null;
- if (current_try != null) {
+ if (current_try != null && !is_in_catch) {
// surrounding try found
var cerror_block = new CCodeBlock ();
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 ());
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);
}
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
/**
* 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.
private DataType _data_type;
+ private Block _body;
+ private LocalVariable _error_variable;
+
/**
* Creates a new catch
*
/**
* 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.
/**
* 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> ();
/**
* @param clause a catch clause
*/
public void add_catch_clause (CatchClause clause) {
+ clause.parent_node = this;
catch_clauses.add (clause);
}