codegen: Fix floating reference regression with Variants
[vala-gnome.git] / codegen / valaccodeassignmentmodule.vala
blobc8f24383ee9673caf41c23cb40da89ad7f1cdbde
1 /* valaccodeassignmentmodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 /**
28 * The link between an assignment and generated code.
30 public class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
31 TargetValue emit_simple_assignment (Assignment assignment) {
32 Variable variable = (Variable) assignment.left.symbol_reference;
34 if (requires_destroy (assignment.left.value_type)) {
35 /* unref old value */
36 ccode.add_expression (destroy_value (assignment.left.target_value));
39 if (assignment.operator == AssignmentOperator.SIMPLE) {
40 store_value (assignment.left.target_value, assignment.right.target_value, assignment.source_reference);
41 } else {
42 CCodeAssignmentOperator cop;
43 if (assignment.operator == AssignmentOperator.BITWISE_OR) {
44 cop = CCodeAssignmentOperator.BITWISE_OR;
45 } else if (assignment.operator == AssignmentOperator.BITWISE_AND) {
46 cop = CCodeAssignmentOperator.BITWISE_AND;
47 } else if (assignment.operator == AssignmentOperator.BITWISE_XOR) {
48 cop = CCodeAssignmentOperator.BITWISE_XOR;
49 } else if (assignment.operator == AssignmentOperator.ADD) {
50 cop = CCodeAssignmentOperator.ADD;
51 } else if (assignment.operator == AssignmentOperator.SUB) {
52 cop = CCodeAssignmentOperator.SUB;
53 } else if (assignment.operator == AssignmentOperator.MUL) {
54 cop = CCodeAssignmentOperator.MUL;
55 } else if (assignment.operator == AssignmentOperator.DIV) {
56 cop = CCodeAssignmentOperator.DIV;
57 } else if (assignment.operator == AssignmentOperator.PERCENT) {
58 cop = CCodeAssignmentOperator.PERCENT;
59 } else if (assignment.operator == AssignmentOperator.SHIFT_LEFT) {
60 cop = CCodeAssignmentOperator.SHIFT_LEFT;
61 } else if (assignment.operator == AssignmentOperator.SHIFT_RIGHT) {
62 cop = CCodeAssignmentOperator.SHIFT_RIGHT;
63 } else {
64 assert_not_reached ();
67 CCodeExpression codenode = new CCodeAssignment (get_cvalue (assignment.left), get_cvalue (assignment.right), cop);
68 ccode.add_expression (codenode);
71 if (assignment.left.value_type is ArrayType && (((ArrayType) assignment.left.value_type).inline_allocated)) {
72 return load_variable (variable, assignment.left.target_value);
73 } else {
74 return store_temp_value (assignment.left.target_value, assignment);
78 public override void visit_assignment (Assignment assignment) {
79 if (assignment.left.error || assignment.right.error) {
80 assignment.error = true;
81 return;
84 if (assignment.left.symbol_reference is Property) {
85 var ma = assignment.left as MemberAccess;
86 var prop = (Property) assignment.left.symbol_reference;
88 store_property (prop, ma.inner, assignment.right.target_value);
89 assignment.target_value = assignment.right.target_value;
90 } else if (assignment.left.symbol_reference is Variable && is_simple_struct_creation ((Variable) assignment.left.symbol_reference, assignment.right)) {
91 // delegate to visit_object_creation_expression
92 } else {
93 assignment.target_value = emit_simple_assignment (assignment);
97 public override void store_value (TargetValue lvalue, TargetValue value, SourceReference? source_reference = null) {
98 var array_type = lvalue.value_type as ArrayType;
100 if (array_type != null && array_type.fixed_length) {
101 cfile.add_include ("string.h");
103 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
104 // simple assignments do not work in C
105 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
106 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
107 var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call);
109 var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
110 ccopy.add_argument (get_cvalue_ (lvalue));
111 ccopy.add_argument (get_cvalue_ (value));
112 ccopy.add_argument (size);
113 ccode.add_expression (ccopy);
115 return;
118 var cexpr = get_cvalue_ (value);
119 if (get_ctype (lvalue) != null) {
120 cexpr = new CCodeCastExpression (cexpr, get_ctype (lvalue));
123 ccode.add_assignment (get_cvalue_ (lvalue), cexpr);
125 if (array_type != null && ((GLibValue) lvalue).array_length_cvalues != null) {
126 var glib_value = (GLibValue) value;
127 if (glib_value.array_length_cvalues != null) {
128 for (int dim = 1; dim <= array_type.rank; dim++) {
129 ccode.add_assignment (get_array_length_cvalue (lvalue, dim), get_array_length_cvalue (value, dim));
131 } else if (glib_value.array_null_terminated) {
132 requires_array_length = true;
133 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
134 len_call.add_argument (get_cvalue_ (value));
136 ccode.add_assignment (get_array_length_cvalue (lvalue, 1), len_call);
137 } else {
138 for (int dim = 1; dim <= array_type.rank; dim++) {
139 ccode.add_assignment (get_array_length_cvalue (lvalue, dim), new CCodeConstant ("-1"));
143 if (array_type.rank == 1 && get_array_size_cvalue (lvalue) != null) {
144 ccode.add_assignment (get_array_size_cvalue (lvalue), get_array_length_cvalue (lvalue, 1));
148 var delegate_type = lvalue.value_type as DelegateType;
149 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
150 var lvalue_target = get_delegate_target_cvalue (lvalue);
151 var rvalue_target = get_delegate_target_cvalue (value);
152 if (lvalue_target != null) {
153 if (rvalue_target != null) {
154 ccode.add_assignment (lvalue_target, rvalue_target);
155 } else {
156 Report.error (source_reference, "Assigning delegate without required target in scope");
157 ccode.add_assignment (lvalue_target, new CCodeInvalidExpression ());
159 var lvalue_destroy_notify = get_delegate_target_destroy_notify_cvalue (lvalue);
160 var rvalue_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
161 if (lvalue_destroy_notify != null) {
162 if (rvalue_destroy_notify != null) {
163 ccode.add_assignment (lvalue_destroy_notify, rvalue_destroy_notify);
164 } else {
165 ccode.add_assignment (lvalue_destroy_notify, new CCodeConstant ("NULL"));
172 public override void store_local (LocalVariable local, TargetValue value, bool initializer, SourceReference? source_reference = null) {
173 if (!initializer && requires_destroy (local.variable_type)) {
174 /* unref old value */
175 ccode.add_expression (destroy_local (local));
178 store_value (get_local_cvalue (local), value, source_reference);
181 public override void store_parameter (Parameter param, TargetValue _value, bool capturing_parameter = false, SourceReference? source_reference = null) {
182 var value = _value;
184 bool capturing_parameter_in_coroutine = capturing_parameter && is_in_coroutine ();
186 var param_type = param.variable_type.copy ();
187 if (param.captured || is_in_coroutine ()) {
188 if (!param_type.value_owned && !no_implicit_copy (param_type)) {
189 // parameter value has been implicitly copied into a heap data structure
190 // treat parameter as owned
191 param_type.value_owned = true;
193 var old_coroutine = is_in_coroutine ();
194 if (old_coroutine) {
195 current_method.coroutine = false;
198 if (requires_copy (param_type) && !capturing_parameter_in_coroutine) {
199 // do not copy value when capturing parameter in coroutine
200 // as the value was already copied on coroutine initialization
201 value = copy_value (value, param);
204 if (old_coroutine) {
205 current_method.coroutine = true;
210 if (requires_destroy (param_type)) {
211 /* unref old value */
212 ccode.add_expression (destroy_parameter (param));
215 store_value (get_parameter_cvalue (param), value, source_reference);
218 public override void store_field (Field field, TargetValue? instance, TargetValue value, SourceReference? source_reference = null) {
219 var lvalue = get_field_cvalue (field, instance);
220 var type = lvalue.value_type;
221 if (lvalue.actual_value_type != null) {
222 type = lvalue.actual_value_type;
224 if (get_ccode_delegate_target (field) && requires_destroy (type)) {
225 /* unref old value */
226 ccode.add_expression (destroy_field (field, instance));
229 store_value (lvalue, value, source_reference);