if (expr.lvalue) {
expr.target_value = get_field_cvalue (field, expr.inner != null ? expr.inner.target_value : null);
} else {
- expr.target_value = load_field (field, expr.inner != null ? expr.inner.target_value : null);
+ expr.target_value = load_field (field, expr.inner != null ? expr.inner.target_value : null, expr);
}
} else if (expr.symbol_reference is EnumValue) {
var ev = (EnumValue) expr.symbol_reference;
if (expr.lvalue) {
expr.target_value = get_local_cvalue (local);
} else {
- expr.target_value = load_local (local);
+ expr.target_value = load_local (local, expr);
}
}
} else if (expr.symbol_reference is Parameter) {
if (expr.lvalue) {
expr.target_value = get_parameter_cvalue (param);
} else {
- expr.target_value = load_parameter (param);
+ expr.target_value = load_parameter (param, expr);
}
}
}
return result;
}
- public override TargetValue load_variable (Variable variable, TargetValue value) {
+ public override TargetValue load_variable (Variable variable, TargetValue value, Expression? expr = null) {
var result = (GLibValue) value;
var array_type = result.value_type as ArrayType;
var delegate_type = result.value_type as DelegateType;
// no need to an extra copy of variables that are stack allocated simple types
use_temp = false;
}
+ // our implementation of postfix-expressions require temporary variables
+ if (expr is MemberAccess && ((MemberAccess) expr).tainted_access) {
+ use_temp = true;
+ }
+
var local = variable as LocalVariable;
if (local != null && local.name[0] == '.') {
// already a temporary variable generated internally
}
/* Returns unowned access to the given local variable */
- public override TargetValue load_local (LocalVariable local) {
- return load_variable (local, get_local_cvalue (local));
+ public override TargetValue load_local (LocalVariable local, Expression? expr = null) {
+ return load_variable (local, get_local_cvalue (local), expr);
}
/* Returns unowned access to the given parameter */
- public override TargetValue load_parameter (Parameter param) {
- return load_variable (param, get_parameter_cvalue (param));
+ public override TargetValue load_parameter (Parameter param, Expression? expr = null) {
+ return load_variable (param, get_parameter_cvalue (param), expr);
}
/* Convenience method returning access to "this" */
}
/* Returns unowned access to the given field */
- public override TargetValue load_field (Field field, TargetValue? instance) {
- return load_variable (field, get_field_cvalue (field, instance));
+ public override TargetValue load_field (Field field, TargetValue? instance, Expression? expr = null) {
+ return load_variable (field, get_field_cvalue (field, instance), expr);
}
}
public virtual void emit (CodeContext context) {
}
- public abstract TargetValue load_local (LocalVariable local);
+ public abstract TargetValue load_local (LocalVariable local, Expression? expr = null);
public abstract void store_local (LocalVariable local, TargetValue value, bool initializer, SourceReference? source_reference = null);
- public abstract TargetValue load_parameter (Parameter param);
+ public abstract TargetValue load_parameter (Parameter param, Expression? expr = null);
public abstract void store_parameter (Parameter param, TargetValue value, bool capturing_parameter = false, SourceReference? source_reference = null);
- public abstract TargetValue load_field (Field field, TargetValue? instance);
+ public abstract TargetValue load_field (Field field, TargetValue? instance, Expression? expr = null);
public abstract void store_field (Field field, TargetValue? instance, TargetValue value, SourceReference? source_reference = null);
}
*/
public bool prototype_access { get; set; }
+ /**
+ * Requires indirect access due to possible side-effects of parent expression.
+ */
+ public bool tainted_access { get; set; }
+
/**
* Specifies whether the member is used for object creation.
*/
value_type.check (context);
}
+ // Provide some extra information for the code generator
+ if (!tainted_access) {
+ tainted_access = is_tainted ();
+ }
+
return !error;
}
collection.add (param);
}
}
+
+ bool is_tainted () {
+ unowned CodeNode node = this;
+ if (node.parent_node is MemberAccess) {
+ return false;
+ }
+
+ while (node.parent_node is Expression) {
+ node = node.parent_node;
+ if (node is Assignment || node is MethodCall) {
+ break;
+ }
+ }
+
+ bool found = false;
+ var traverse = new TraverseVisitor ((n) => {
+ if (n is PostfixExpression) {
+ found = true;
+ return TraverseStatus.STOP;
+ } else if (n is UnaryExpression) {
+ unowned UnaryExpression e = (UnaryExpression) n;
+ if (e.operator == UnaryOperator.INCREMENT || e.operator == UnaryOperator.DECREMENT) {
+ found = true;
+ return TraverseStatus.STOP;
+ }
+ }
+ return TraverseStatus.CONTINUE;
+ });
+ node.accept (traverse);
+
+ return found;
+ }
}