From cc47f0d0127bca7c6c61c8e4513e36e80c58737c Mon Sep 17 00:00:00 2001 From: Rico Tzschichholz Date: Fri, 17 May 2019 08:56:12 +0200 Subject: [PATCH] codegen: When freeing local variables don't stop at "switch" on "continue" So distinguish between BreakStatement and ContinueStatement to make the correct decision in append_local_free(). Fixes https://gitlab.gnome.org/GNOME/vala/issues/799 --- codegen/valaccodebasemodule.vala | 11 +++++++--- codegen/valaccodecontrolflowmodule.vala | 4 ++-- codegen/valagasyncmodule.vala | 2 +- codegen/valagerrormodule.vala | 8 +++---- tests/Makefile.am | 1 + tests/control-flow/for-switch-continue.vala | 24 +++++++++++++++++++++ 6 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 tests/control-flow/for-switch-continue.vala diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 48d706e37..57ee13c65 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -3648,17 +3648,22 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { } } - public void append_local_free (Symbol sym, bool stop_at_loop = false, CodeNode? stop_at = null) { + public void append_local_free (Symbol sym, Statement? jump_stmt = null, CodeNode? stop_at = null) { var b = (Block) sym; append_scope_free (sym, stop_at); - if (stop_at_loop) { + if (jump_stmt is BreakStatement) { if (b.parent_node is Loop || b.parent_node is ForeachStatement || b.parent_node is SwitchStatement) { return; } + } else if (jump_stmt is ContinueStatement) { + if (b.parent_node is Loop || + b.parent_node is ForeachStatement) { + return; + } } if (stop_at != null && b.parent_node == stop_at) { @@ -3666,7 +3671,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { } if (sym.parent_symbol is Block) { - append_local_free (sym.parent_symbol, stop_at_loop, stop_at); + append_local_free (sym.parent_symbol, jump_stmt, stop_at); } else if (sym.parent_symbol is Method) { append_param_free ((Method) sym.parent_symbol); } else if (sym.parent_symbol is PropertyAccessor) { diff --git a/codegen/valaccodecontrolflowmodule.vala b/codegen/valaccodecontrolflowmodule.vala index 91268e7d1..a549f0621 100644 --- a/codegen/valaccodecontrolflowmodule.vala +++ b/codegen/valaccodecontrolflowmodule.vala @@ -345,13 +345,13 @@ public abstract class Vala.CCodeControlFlowModule : CCodeMethodModule { } public override void visit_break_statement (BreakStatement stmt) { - append_local_free (current_symbol, true); + append_local_free (current_symbol, stmt); ccode.add_break (); } public override void visit_continue_statement (ContinueStatement stmt) { - append_local_free (current_symbol, true); + append_local_free (current_symbol, stmt); ccode.add_continue (); } diff --git a/codegen/valagasyncmodule.vala b/codegen/valagasyncmodule.vala index 6c706e8cf..214d86af2 100644 --- a/codegen/valagasyncmodule.vala +++ b/codegen/valagasyncmodule.vala @@ -866,7 +866,7 @@ public class Vala.GAsyncModule : GtkModule { set_error.add_argument (error_expr); ccode.add_expression (set_error); - append_local_free (current_symbol, false); + append_local_free (current_symbol); if (context.require_glib_version (2, 36)) { // We already returned the error above, we must not return anything else here. diff --git a/codegen/valagerrormodule.vala b/codegen/valagerrormodule.vala index fc82fb46a..1c01cc940 100644 --- a/codegen/valagerrormodule.vala +++ b/codegen/valagerrormodule.vala @@ -100,7 +100,7 @@ public class Vala.GErrorModule : CCodeDelegateModule { ccode.add_expression (cpropagate); // free local variables - append_local_free (current_symbol, false); + append_local_free (current_symbol); if (current_method is CreationMethod && current_method.parent_symbol is Class) { var cl = (Class) current_method.parent_symbol; @@ -115,7 +115,7 @@ public class Vala.GErrorModule : CCodeDelegateModule { void uncaught_error_statement (CCodeExpression inner_error, bool unexpected = false) { // free local variables - append_local_free (current_symbol, false); + append_local_free (current_symbol); var ccritical = new CCodeFunctionCall (new CCodeIdentifier ("g_critical")); ccritical.add_argument (new CCodeConstant (unexpected ? "\"file %s: line %d: unexpected error: %s (%s, %d)\"" : "\"file %s: line %d: uncaught error: %s (%s, %d)\"")); @@ -183,9 +183,9 @@ public class Vala.GErrorModule : CCodeDelegateModule { // free local variables if (is_in_catch) { - append_local_free (current_symbol, false, current_catch); + append_local_free (current_symbol, null, current_catch); } else { - append_local_free (current_symbol, false, current_try); + append_local_free (current_symbol, null, current_try); } var error_types = new ArrayList (); diff --git a/tests/Makefile.am b/tests/Makefile.am index 7df354c66..332f4b589 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -133,6 +133,7 @@ TESTS = \ control-flow/expressions-conditional.vala \ control-flow/finally-return.test \ control-flow/for.vala \ + control-flow/for-switch-continue.vala \ control-flow/foreach.vala \ control-flow/missing-break.test \ control-flow/missing-return.test \ diff --git a/tests/control-flow/for-switch-continue.vala b/tests/control-flow/for-switch-continue.vala new file mode 100644 index 000000000..da58b1ad0 --- /dev/null +++ b/tests/control-flow/for-switch-continue.vala @@ -0,0 +1,24 @@ +bool success = false; + +class Foo : Object { + ~Foo () { + success = true; + } +} + +void bar () { + assert (!success); + for (int i = 0; i < 1; i++) { + Foo? foo = null; + switch (i) { + case 0: + foo = new Foo (); + continue; + } + } + assert (success); +} + +void main() { + bar (); +} -- 2.47.2