[vala] Fix side-effects in assignments
- From: Jürg Billeter <juergbi src gnome org>
- To: svn-commits-list gnome org
- Subject: [vala] Fix side-effects in assignments
- Date: Mon, 30 Mar 2009 06:13:11 -0400 (EDT)
commit b677fffd9ef9597df389b8636a02ef02209df378
Author: Jürg Billeter <j bitron ch>
Date: Mon Mar 30 12:10:34 2009 +0200
Fix side-effects in assignments
Do not evaluate the left-hand side of an assignment multiple times
if it could have side-effects. Based on patch by Levi Bard,
fixes bug 543483.
---
gobject/valaccodeassignmentmodule.vala | 43 ++++++++++++++++---------------
gobject/valaccodebasemodule.vala | 34 +++++++++++++++++++++---
tests/Makefile.am | 1 +
tests/control-flow/sideeffects.test | 21 +++++++++++++++
4 files changed, 73 insertions(+), 26 deletions(-)
diff --git a/gobject/valaccodeassignmentmodule.vala b/gobject/valaccodeassignmentmodule.vala
index c1d0832..332bb4f 100644
--- a/gobject/valaccodeassignmentmodule.vala
+++ b/gobject/valaccodeassignmentmodule.vala
@@ -94,6 +94,8 @@ internal class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
CCodeExpression emit_simple_assignment (Assignment assignment) {
CCodeExpression rhs = (CCodeExpression) assignment.right.ccodenode;
+ CCodeExpression lhs = (CCodeExpression) get_ccodenode (assignment.left);
+ CCodeCommaExpression outer_ccomma = null;
bool unref_old = requires_destroy (assignment.left.value_type);
bool array = false;
@@ -105,16 +107,28 @@ internal class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
var delegate_type = (DelegateType) assignment.left.value_type;
instance_delegate = delegate_type.delegate_symbol.has_target;
}
-
+
if (unref_old || array || instance_delegate) {
var ccomma = new CCodeCommaExpression ();
-
+
+ if (!is_pure_ccode_expression (lhs)) {
+ /* Assign lhs to temp var to avoid repeating side effect */
+ outer_ccomma = new CCodeCommaExpression ();
+
+ var lhs_value_type = assignment.left.value_type.copy ();
+ string lhs_temp_name = "_tmp%d".printf (next_temp_var_id++);
+ var lhs_temp = new LocalVariable (lhs_value_type, "*" + lhs_temp_name);
+ temp_vars.insert (0, lhs_temp);
+ outer_ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (lhs_temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, lhs)));
+ lhs = new CCodeParenthesizedExpression (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (lhs_temp_name)));
+ }
+
var temp_decl = get_temp_variable (assignment.left.value_type);
temp_vars.insert (0, temp_decl);
ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_decl.name), rhs));
if (unref_old) {
/* unref old value */
- ccomma.append_expression (get_unref_expression ((CCodeExpression) get_ccodenode (assignment.left), assignment.left.value_type, assignment.left));
+ ccomma.append_expression (get_unref_expression (lhs, assignment.left.value_type, assignment.left));
}
if (array) {
@@ -166,25 +180,12 @@ internal class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
} else if (assignment.operator == AssignmentOperator.SHIFT_RIGHT) {
cop = CCodeAssignmentOperator.SHIFT_RIGHT;
}
-
- CCodeExpression codenode = new CCodeAssignment ((CCodeExpression) get_ccodenode (assignment.left), rhs, cop);
-
- if (unref_old && get_ccodenode (assignment.left) is CCodeElementAccess) {
- // ensure that index expression in element access doesn't get evaluated more than once
- // except when it's a simple expression
- var cea = (CCodeElementAccess) get_ccodenode (assignment.left);
- if (!(cea.index is CCodeConstant || cea.index is CCodeIdentifier)) {
- var index_temp_decl = get_temp_variable (int_type);
- temp_vars.insert (0, index_temp_decl);
-
- var ccomma = new CCodeCommaExpression ();
- ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (index_temp_decl.name), cea.index));
- ccomma.append_expression (codenode);
- cea.index = get_variable_cexpression (index_temp_decl.name);
-
- codenode = ccomma;
- }
+ CCodeExpression codenode = new CCodeAssignment (lhs, rhs, cop);
+
+ if (outer_ccomma != null) {
+ outer_ccomma.append_expression (codenode);
+ codenode = outer_ccomma;
}
return codenode;
diff --git a/gobject/valaccodebasemodule.vala b/gobject/valaccodebasemodule.vala
index ee3983e..9bfa75c 100644
--- a/gobject/valaccodebasemodule.vala
+++ b/gobject/valaccodebasemodule.vala
@@ -1073,13 +1073,32 @@ internal class Vala.CCodeBaseModule : CCodeModule {
} else if (cexpr is CCodeBinaryExpression) {
var cbinary = (CCodeBinaryExpression) cexpr;
return is_pure_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
+ } else if (cexpr is CCodeUnaryExpression) {
+ var cunary = (CCodeUnaryExpression) cexpr;
+ switch (cunary.operator) {
+ case CCodeUnaryOperator.PREFIX_INCREMENT:
+ case CCodeUnaryOperator.PREFIX_DECREMENT:
+ case CCodeUnaryOperator.POSTFIX_INCREMENT:
+ case CCodeUnaryOperator.POSTFIX_DECREMENT:
+ return false;
+ default:
+ return is_pure_ccode_expression (cunary.inner);
+ }
} else if (cexpr is CCodeMemberAccess) {
var cma = (CCodeMemberAccess) cexpr;
return is_pure_ccode_expression (cma.inner);
+ } else if (cexpr is CCodeElementAccess) {
+ var cea = (CCodeElementAccess) cexpr;
+ return is_pure_ccode_expression (cea.container) && is_pure_ccode_expression (cea.index);
+ } else if (cexpr is CCodeCastExpression) {
+ var ccast = (CCodeCastExpression) cexpr;
+ return is_pure_ccode_expression (ccast.inner);
+ } else if (cexpr is CCodeParenthesizedExpression) {
+ var cparenthesized = (CCodeParenthesizedExpression) cexpr;
+ return is_pure_ccode_expression (cparenthesized.inner);
}
- var cparenthesized = (cexpr as CCodeParenthesizedExpression);
- return (null != cparenthesized && is_pure_ccode_expression (cparenthesized.inner));
+ return false;
}
public override void visit_formal_parameter (FormalParameter p) {
@@ -2013,7 +2032,12 @@ internal class Vala.CCodeBaseModule : CCodeModule {
var st = local.variable_type.data_type as Struct;
- if (local.variable_type.is_reference_type_or_type_parameter ()) {
+ if (local.name.has_prefix ("*")) {
+ // do not dereference unintialized variable
+ // initialization is not needed for these special
+ // pointer temp variables
+ // used to avoid side-effects in assignments
+ } else if (local.variable_type.is_reference_type_or_type_parameter ()) {
vardecl.initializer = new CCodeConstant ("NULL");
} else if (st != null && !st.is_simple_type ()) {
// 0-initialize struct with struct initializer { 0 }
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a7bf6aa..6e113ee 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -26,6 +26,7 @@ TESTS = \
control-flow/expressions-conditional.test \
control-flow/for.test \
control-flow/switch.test \
+ control-flow/sideeffects.test \
enums/enums.test \
structs/structs.test \
delegates/delegates.test \
diff --git a/tests/control-flow/sideeffects.test b/tests/control-flow/sideeffects.test
new file mode 100644
index 0000000..a334d33
--- /dev/null
+++ b/tests/control-flow/sideeffects.test
@@ -0,0 +1,21 @@
+
+Program: test
+
+class Maman.Foo : Object {
+ public int i = 1;
+
+ public weak Foo sideeffect () {
+ --i;
+ return this;
+ }
+ public string data;
+}
+
+class Maman.Bar : Object {
+ static int main (string[] args) {
+ var foo = new Foo ();
+ foo.sideeffect ().data = "foo";
+ assert (foo.i == 0);
+ return 0;
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]