change run to use meson/ninja and then exec. - remove libvala code from application...
[roobuilder] / src / codegen / valaccodebasemodule.vala
1 /* valaccodebasemodule.vala
2  *
3  * Copyright (C) 2006-2012  Jürg Billeter
4  * Copyright (C) 2006-2008  Raffaele Sandrini
5  *
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.
10
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.
15
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
19  *
20  * Author:
21  *      Jürg Billeter <j@bitron.ch>
22  *      Raffaele Sandrini <raffaele@sandrini.ch>
23  */
24
25
26 /**
27  * Code visitor generating C Code.
28  */
29 public abstract class Vala.CCodeBaseModule : CodeGenerator {
30         public class EmitContext {
31                 public Symbol? current_symbol;
32                 public ArrayList<Symbol> symbol_stack = new ArrayList<Symbol> ();
33                 public TryStatement current_try;
34                 public int current_try_id;
35                 public int next_try_id;
36                 public CatchClause current_catch;
37                 public CCodeFunction ccode;
38                 public ArrayList<CCodeFunction> ccode_stack = new ArrayList<CCodeFunction> ();
39                 public ArrayList<TargetValue> temp_ref_values = new ArrayList<TargetValue> ();
40                 public int next_temp_var_id;
41                 public int current_inner_error_id;
42                 public bool current_method_inner_error;
43                 public bool current_method_return;
44                 public int next_coroutine_state = 1;
45                 public Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
46                 public Map<string,int> closure_variable_count_map = new HashMap<string,int> (str_hash, str_equal);
47                 public Map<LocalVariable,int> closure_variable_clash_map = new HashMap<LocalVariable,int> ();
48                 public bool is_in_method_precondition;
49
50                 public EmitContext (Symbol? symbol = null) {
51                         current_symbol = symbol;
52                 }
53
54                 public void push_symbol (Symbol symbol) {
55                         symbol_stack.add (current_symbol);
56                         current_symbol = symbol;
57                 }
58
59                 public void pop_symbol () {
60                         current_symbol = symbol_stack.remove_at (symbol_stack.size - 1);
61                 }
62         }
63
64         public CodeContext context { get; set; }
65
66         public Symbol root_symbol;
67
68         public EmitContext emit_context = new EmitContext ();
69
70         List<EmitContext> emit_context_stack = new ArrayList<EmitContext> ();
71
72         public CCodeLineDirective? current_line = null;
73
74         List<CCodeLineDirective> line_directive_stack = new ArrayList<CCodeLineDirective> ();
75
76         public Symbol current_symbol { get { return emit_context.current_symbol; } }
77
78         public TryStatement current_try {
79                 get { return emit_context.current_try; }
80                 set { emit_context.current_try = value; }
81         }
82
83         public int current_try_id {
84                 get { return emit_context.current_try_id; }
85                 set { emit_context.current_try_id = value; }
86         }
87
88         public int next_try_id {
89                 get { return emit_context.next_try_id; }
90                 set { emit_context.next_try_id = value; }
91         }
92
93         public CatchClause current_catch {
94                 get { return emit_context.current_catch; }
95                 set { emit_context.current_catch = value; }
96         }
97
98         public int current_inner_error_id {
99                 get { return emit_context.current_inner_error_id; }
100                 set { emit_context.current_inner_error_id = value; }
101         }
102
103         public bool is_in_method_precondition {
104                 get { return emit_context.is_in_method_precondition; }
105                 set { emit_context.is_in_method_precondition = value; }
106         }
107
108         public TypeSymbol? current_type_symbol {
109                 get {
110                         var sym = current_symbol;
111                         while (sym != null) {
112                                 if (sym is TypeSymbol) {
113                                         return (TypeSymbol) sym;
114                                 }
115                                 sym = sym.parent_symbol;
116                         }
117                         return null;
118                 }
119         }
120
121         public Class? current_class {
122                 get { return current_type_symbol as Class; }
123         }
124
125         public Method? current_method {
126                 get {
127                         var sym = current_symbol;
128                         while (sym is Block) {
129                                 sym = sym.parent_symbol;
130                         }
131                         return sym as Method;
132                 }
133         }
134
135         public PropertyAccessor? current_property_accessor {
136                 get {
137                         var sym = current_symbol;
138                         while (sym is Block) {
139                                 sym = sym.parent_symbol;
140                         }
141                         return sym as PropertyAccessor;
142                 }
143         }
144
145         public Constructor? current_constructor {
146                 get {
147                         var sym = current_symbol;
148                         while (sym is Block) {
149                                 sym = sym.parent_symbol;
150                         }
151                         return sym as Constructor;
152                 }
153         }
154
155         public Destructor? current_destructor {
156                 get {
157                         var sym = current_symbol;
158                         while (sym is Block) {
159                                 sym = sym.parent_symbol;
160                         }
161                         return sym as Destructor;
162                 }
163         }
164
165         public DataType? current_return_type {
166                 get {
167                         var m = current_method;
168                         if (m != null) {
169                                 return m.return_type;
170                         }
171
172                         var acc = current_property_accessor;
173                         if (acc != null) {
174                                 if (acc.readable) {
175                                         return acc.value_type;
176                                 } else {
177                                         return void_type;
178                                 }
179                         }
180
181                         if (is_in_constructor () || is_in_destructor ()) {
182                                 return void_type;
183                         }
184
185                         return null;
186                 }
187         }
188
189         public bool is_in_coroutine () {
190                 return current_method != null && current_method.coroutine;
191         }
192
193         public bool is_in_constructor () {
194                 if (current_method != null) {
195                         // make sure to not return true in lambda expression inside constructor
196                         return false;
197                 }
198                 var sym = current_symbol;
199                 while (sym != null) {
200                         if (sym is Constructor) {
201                                 return true;
202                         }
203                         sym = sym.parent_symbol;
204                 }
205                 return false;
206         }
207
208         public bool is_in_destructor () {
209                 if (current_method != null) {
210                         // make sure to not return true in lambda expression inside constructor
211                         return false;
212                 }
213                 var sym = current_symbol;
214                 while (sym != null) {
215                         if (sym is Destructor) {
216                                 return true;
217                         }
218                         sym = sym.parent_symbol;
219                 }
220                 return false;
221         }
222
223         public Block? current_closure_block {
224                 get {
225                         return next_closure_block (current_symbol);
226                 }
227         }
228
229         public unowned Block? next_closure_block (Symbol sym) {
230                 while (true) {
231                         unowned Method method = sym as Method;
232                         if (method != null && !method.closure) {
233                                 // parent blocks are not captured by this method
234                                 break;
235                         }
236
237                         unowned Block block = sym as Block;
238                         if (method == null && block == null) {
239                                 // no closure block
240                                 break;
241                         }
242
243                         if (block != null && block.captured) {
244                                 // closure block found
245                                 return block;
246                         }
247                         sym = sym.parent_symbol;
248                 }
249                 return null;
250         }
251
252         public CCodeFile header_file;
253         public CCodeFile internal_header_file;
254         public CCodeFile cfile;
255
256         public EmitContext class_init_context;
257         public EmitContext base_init_context;
258         public EmitContext class_finalize_context;
259         public EmitContext base_finalize_context;
260         public EmitContext instance_init_context;
261         public EmitContext instance_finalize_context;
262
263         public CCodeStruct param_spec_struct;
264         public CCodeStruct closure_struct;
265         public CCodeEnum prop_enum;
266         public CCodeEnum signal_enum;
267
268         public CCodeFunction ccode { get { return emit_context.ccode; } }
269
270         /* temporary variables that own their content */
271         public ArrayList<TargetValue> temp_ref_values { get { return emit_context.temp_ref_values; } }
272         /* cache to check whether a certain marshaller has been created yet */
273         public Set<string> user_marshal_set;
274         /* (constant) hash table with all predefined marshallers */
275         public Set<string> predefined_marshal_set;
276         /* (constant) hash table with all reserved identifiers in the generated code */
277         public static Set<string> reserved_identifiers;
278
279         public int next_temp_var_id {
280                 get { return emit_context.next_temp_var_id; }
281                 set { emit_context.next_temp_var_id = value; }
282         }
283
284         public int next_regex_id = 0;
285         public bool in_creation_method { get { return current_method is CreationMethod; } }
286
287         public bool current_method_inner_error {
288                 get { return emit_context.current_method_inner_error; }
289                 set { emit_context.current_method_inner_error = value; }
290         }
291
292         public bool current_method_return {
293                 get { return emit_context.current_method_return; }
294                 set { emit_context.current_method_return = value; }
295         }
296
297         int next_block_id = 0;
298         Map<Block,int> block_map = new HashMap<Block,int> ();
299
300         /* count of emitted inner_error variables in methods */
301         Map<weak Method,int> method_inner_error_var_count = new HashMap<weak Method,int> ();
302
303         public DataType void_type = new VoidType ();
304         public DataType bool_type;
305         public DataType char_type;
306         public DataType uchar_type;
307         public DataType? unichar_type;
308         public DataType short_type;
309         public DataType ushort_type;
310         public DataType int_type;
311         public DataType uint_type;
312         public DataType long_type;
313         public DataType ulong_type;
314         public DataType int8_type;
315         public DataType uint8_type;
316         public DataType int16_type;
317         public DataType uint16_type;
318         public DataType int32_type;
319         public DataType uint32_type;
320         public DataType int64_type;
321         public DataType uint64_type;
322         public DataType size_t_type;
323         public DataType ssize_t_type;
324         public DataType string_type;
325         public DataType regex_type;
326         public DataType float_type;
327         public DataType double_type;
328         public DataType pointer_type;
329         public TypeSymbol gtype_type;
330         public TypeSymbol gobject_type;
331         public ErrorType gerror_type;
332         public Class glist_type;
333         public Class gslist_type;
334         public Class gnode_type;
335         public Class gqueue_type;
336         public Class gvaluearray_type;
337         public TypeSymbol gstringbuilder_type;
338         public Class garray_type;
339         public TypeSymbol gbytearray_type;
340         public TypeSymbol genericarray_type;
341         public Class gsequence_type;
342         public Class gsequence_iter_type;
343         public TypeSymbol gthreadpool_type;
344         public DataType gquark_type;
345         public Struct gvalue_type;
346         public Class gvariant_type;
347         public Struct mutex_type;
348         public Struct gmutex_type;
349         public Struct grecmutex_type;
350         public Struct grwlock_type;
351         public Struct gcond_type;
352         public Class gsource_type;
353         public TypeSymbol type_module_type;
354         public TypeSymbol dbus_proxy_type;
355         public Class gtk_widget_type;
356         public DataType delegate_target_type;
357         public DelegateType delegate_target_destroy_type;
358         Delegate destroy_notify;
359         Class gerror;
360
361         public bool in_plugin = false;
362         public string module_init_param_name;
363
364         public bool requires_assert;
365         public bool requires_array_free;
366         public bool requires_array_move;
367         public bool requires_array_length;
368         public bool requires_array_n_elements;
369         public bool requires_clear_mutex;
370         public bool requires_memdup2;
371         public bool requires_vala_extern;
372
373         public Set<string> wrappers;
374         Set<Symbol> generated_external_symbols;
375
376         public Map<string,string> variable_name_map { get { return emit_context.variable_name_map; } }
377
378         public static int ccode_attribute_cache_index = CodeNode.get_attribute_cache_index ();
379
380         protected CCodeBaseModule () {
381                 if (Vala.get_build_version () != Vala.BUILD_VERSION) {
382                         Report.error (null, "Integrity check failed (libvala %s doesn't match ccodegen %s)".printf (Vala.get_build_version (), Vala.BUILD_VERSION));
383                 }
384
385                 predefined_marshal_set = new HashSet<string> (str_hash, str_equal);
386                 predefined_marshal_set.add ("VOID:VOID");
387                 predefined_marshal_set.add ("VOID:BOOLEAN");
388                 predefined_marshal_set.add ("VOID:CHAR");
389                 predefined_marshal_set.add ("VOID:UCHAR");
390                 predefined_marshal_set.add ("VOID:INT");
391                 predefined_marshal_set.add ("VOID:UINT");
392                 predefined_marshal_set.add ("VOID:LONG");
393                 predefined_marshal_set.add ("VOID:ULONG");
394                 predefined_marshal_set.add ("VOID:ENUM");
395                 predefined_marshal_set.add ("VOID:FLAGS");
396                 predefined_marshal_set.add ("VOID:FLOAT");
397                 predefined_marshal_set.add ("VOID:DOUBLE");
398                 predefined_marshal_set.add ("VOID:STRING");
399                 predefined_marshal_set.add ("VOID:POINTER");
400                 predefined_marshal_set.add ("VOID:OBJECT");
401                 predefined_marshal_set.add ("STRING:OBJECT,POINTER");
402                 predefined_marshal_set.add ("VOID:UINT,POINTER");
403                 predefined_marshal_set.add ("BOOLEAN:FLAGS");
404                 predefined_marshal_set.add ("VOID:BOXED");
405                 predefined_marshal_set.add ("VOID:VARIANT");
406                 predefined_marshal_set.add ("BOOLEAN:BOXED,BOXED");
407
408                 reserved_identifiers = new HashSet<string> (str_hash, str_equal);
409
410                 // C99 keywords
411                 reserved_identifiers.add ("_Bool");
412                 reserved_identifiers.add ("_Complex");
413                 reserved_identifiers.add ("_Imaginary");
414                 reserved_identifiers.add ("asm");
415                 reserved_identifiers.add ("auto");
416                 reserved_identifiers.add ("break");
417                 reserved_identifiers.add ("case");
418                 reserved_identifiers.add ("char");
419                 reserved_identifiers.add ("const");
420                 reserved_identifiers.add ("continue");
421                 reserved_identifiers.add ("default");
422                 reserved_identifiers.add ("do");
423                 reserved_identifiers.add ("double");
424                 reserved_identifiers.add ("else");
425                 reserved_identifiers.add ("enum");
426                 reserved_identifiers.add ("extern");
427                 reserved_identifiers.add ("float");
428                 reserved_identifiers.add ("for");
429                 reserved_identifiers.add ("goto");
430                 reserved_identifiers.add ("if");
431                 reserved_identifiers.add ("inline");
432                 reserved_identifiers.add ("int");
433                 reserved_identifiers.add ("long");
434                 reserved_identifiers.add ("register");
435                 reserved_identifiers.add ("restrict");
436                 reserved_identifiers.add ("return");
437                 reserved_identifiers.add ("short");
438                 reserved_identifiers.add ("signed");
439                 reserved_identifiers.add ("sizeof");
440                 reserved_identifiers.add ("static");
441                 reserved_identifiers.add ("struct");
442                 reserved_identifiers.add ("switch");
443                 reserved_identifiers.add ("typedef");
444                 reserved_identifiers.add ("union");
445                 reserved_identifiers.add ("unsigned");
446                 reserved_identifiers.add ("void");
447                 reserved_identifiers.add ("volatile");
448                 reserved_identifiers.add ("while");
449
450                 // C11 keywords
451                 reserved_identifiers.add ("_Alignas");
452                 reserved_identifiers.add ("_Alignof");
453                 reserved_identifiers.add ("_Atomic");
454                 reserved_identifiers.add ("_Generic");
455                 reserved_identifiers.add ("_Noreturn");
456                 reserved_identifiers.add ("_Static_assert");
457                 reserved_identifiers.add ("_Thread_local");
458
459                 // MSVC keywords
460                 reserved_identifiers.add ("cdecl");
461
462                 // reserved for Vala/GObject naming conventions
463                 reserved_identifiers.add ("error");
464                 reserved_identifiers.add ("result");
465                 reserved_identifiers.add ("self");
466         }
467
468         public override void emit (CodeContext context) {
469                 this.context = context;
470
471                 ccode_init (context.profile);
472
473                 root_symbol = context.root;
474
475                 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
476                 char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
477                 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
478                 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
479                 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
480                 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
481                 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
482                 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
483                 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
484                 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
485                 uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8"));
486                 int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16"));
487                 uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16"));
488                 int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32"));
489                 uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32"));
490                 int64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int64"));
491                 uint64_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint64"));
492                 size_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("size_t"));
493                 ssize_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ssize_t"));
494                 float_type = new FloatingType ((Struct) root_symbol.scope.lookup ("float"));
495                 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
496                 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
497                 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
498                 if (unichar_struct != null) {
499                         unichar_type = new IntegerType (unichar_struct);
500                 }
501
502                 if (context.profile == Profile.GOBJECT) {
503                         var glib_ns = root_symbol.scope.lookup ("GLib");
504
505                         gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
506                         gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
507                         gerror_type = new ErrorType (null, null);
508                         glist_type = (Class) glib_ns.scope.lookup ("List");
509                         gslist_type = (Class) glib_ns.scope.lookup ("SList");
510                         gnode_type = (Class) glib_ns.scope.lookup ("Node");
511                         gqueue_type = (Class) glib_ns.scope.lookup ("Queue");
512                         gvaluearray_type = (Class) glib_ns.scope.lookup ("ValueArray");
513                         gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
514                         garray_type = (Class) glib_ns.scope.lookup ("Array");
515                         gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
516                         genericarray_type = (TypeSymbol) glib_ns.scope.lookup ("GenericArray");
517                         gsequence_type = (Class) glib_ns.scope.lookup ("Sequence");
518                         gsequence_iter_type = (Class) glib_ns.scope.lookup ("SequenceIter");
519                         gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
520
521                         gerror = (Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Error");
522                         gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
523                         gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
524                         gvariant_type = (Class) glib_ns.scope.lookup ("Variant");
525                         gsource_type = (Class) glib_ns.scope.lookup ("Source");
526
527                         gmutex_type = (Struct) glib_ns.scope.lookup ("Mutex");
528                         grecmutex_type = (Struct) glib_ns.scope.lookup ("RecMutex");
529                         grwlock_type = (Struct) glib_ns.scope.lookup ("RWLock");
530                         gcond_type = (Struct) glib_ns.scope.lookup ("Cond");
531
532                         mutex_type = grecmutex_type;
533
534                         type_module_type = (TypeSymbol) glib_ns.scope.lookup ("TypeModule");
535
536                         regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
537
538                         if (context.module_init_method != null) {
539                                 foreach (Parameter parameter in context.module_init_method.get_parameters ()) {
540                                         if (parameter.variable_type.type_symbol.is_subtype_of (type_module_type)) {
541                                                 in_plugin = true;
542                                                 module_init_param_name = parameter.name;
543                                                 break;
544
545                                         }
546                                 }
547                         }
548
549                         dbus_proxy_type = (TypeSymbol) glib_ns.scope.lookup ("DBusProxy");
550
551                         pointer_type = new StructValueType ((Struct) glib_ns.scope.lookup ("pointer"));
552
553                         delegate_target_type = pointer_type;
554                         destroy_notify = (Delegate) glib_ns.scope.lookup ("DestroyNotify");
555                         delegate_target_destroy_type = new DelegateType (destroy_notify);
556                 } else {
557                         pointer_type = new PointerType (new VoidType ());
558
559                         delegate_target_type = pointer_type;
560                         destroy_notify = new Delegate ("ValaDestroyNotify", new VoidType ());
561                         destroy_notify.add_parameter (new Parameter ("data", new PointerType (new VoidType ())));
562                         destroy_notify.has_target = false;
563                         destroy_notify.owner = root_symbol.scope;
564                         delegate_target_destroy_type = new DelegateType (destroy_notify);
565                 }
566
567                 var gtk_ns = root_symbol.scope.lookup ("Gtk");
568                 if (gtk_ns != null) {
569                         gtk_widget_type = (Class) gtk_ns.scope.lookup ("Widget");
570                 }
571
572                 header_file = new CCodeFile (CCodeFileType.PUBLIC_HEADER);
573                 internal_header_file = new CCodeFile (CCodeFileType.INTERNAL_HEADER);
574
575                 /* we're only interested in non-pkg source files */
576                 var source_files = context.get_source_files ();
577                 foreach (SourceFile file in source_files) {
578                         if (file.file_type == SourceFileType.SOURCE ||
579                             (context.header_filename != null && file.file_type == SourceFileType.FAST)) {
580                                 file.accept (this);
581                         }
582                 }
583
584                 // generate symbols file for public API
585                 if (context.symbols_filename != null) {
586                         var stream = FileStream.open (context.symbols_filename, "w");
587                         if (stream == null) {
588                                 Report.error (null, "unable to open `%s' for writing", context.symbols_filename);
589                                 this.context = null;
590                                 return;
591                         }
592
593                         foreach (string symbol in header_file.get_symbols ()) {
594                                 stream.puts (symbol);
595                                 stream.putc ('\n');
596                         }
597
598                         stream = null;
599                 }
600
601                 // generate C header file for public API
602                 if (context.header_filename != null) {
603                         bool ret;
604                         if (context.profile == Profile.GOBJECT) {
605                                 header_file.add_include ("glib.h");
606                                 ret = header_file.store (context.header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
607                         } else {
608                                 ret = header_file.store (context.header_filename, null, context.version_header, false, "#ifdef  __cplusplus\nextern \"C\" {\n#endif", "#ifdef  __cplusplus\n}\n#endif");
609                         }
610                         if (!ret) {
611                                 Report.error (null, "unable to open `%s' for writing", context.header_filename);
612                         }
613                 }
614
615                 // generate C header file for internal API
616                 if (context.internal_header_filename != null) {
617                         bool ret;
618                         if (context.profile == Profile.GOBJECT) {
619                                 internal_header_file.add_include ("glib.h");
620                                 ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false, "G_BEGIN_DECLS", "G_END_DECLS");
621                         } else {
622                                 ret = internal_header_file.store (context.internal_header_filename, null, context.version_header, false, "#ifdef  __cplusplus\nextern \"C\" {\n#endif", "#ifdef  __cplusplus\n}\n#endif");
623                         }
624                         if (!ret) {
625                                 Report.error (null, "unable to open `%s' for writing", context.internal_header_filename);
626                         }
627                 }
628
629                 this.context = null;
630         }
631
632         public void push_context (EmitContext emit_context) {
633                 if (this.emit_context != null) {
634                         emit_context_stack.add (this.emit_context);
635                 }
636
637                 this.emit_context = emit_context;
638                 if (ccode != null) {
639                         ccode.current_line = current_line;
640                 }
641         }
642
643         public void pop_context () {
644                 if (emit_context_stack.size > 0) {
645                         this.emit_context = emit_context_stack.remove_at (emit_context_stack.size - 1);
646                         if (ccode != null) {
647                                 ccode.current_line = current_line;
648                         }
649                 } else {
650                         this.emit_context = null;
651                 }
652         }
653
654         public void push_line (SourceReference? source_reference) {
655                 line_directive_stack.add (current_line);
656                 if (source_reference != null) {
657                         current_line = new CCodeLineDirective (source_reference.file.get_relative_filename (), source_reference.begin.line);
658                         if (ccode != null) {
659                                 ccode.current_line = current_line;
660                         }
661                 }
662         }
663
664         public void pop_line () {
665                 current_line = line_directive_stack.remove_at (line_directive_stack.size - 1);
666                 if (ccode != null) {
667                         ccode.current_line = current_line;
668                 }
669         }
670
671         public void push_function (CCodeFunction func) {
672                 emit_context.ccode_stack.add (ccode);
673                 emit_context.ccode = func;
674                 ccode.current_line = current_line;
675         }
676
677         public void pop_function () {
678                 emit_context.ccode = emit_context.ccode_stack.remove_at (emit_context.ccode_stack.size - 1);
679                 if (ccode != null) {
680                         ccode.current_line = current_line;
681                 }
682         }
683
684         public bool add_symbol_declaration (CCodeFile decl_space, Symbol sym, string name) {
685                 bool in_generated_header = context.header_filename != null
686                                            && (decl_space.file_type != CCodeFileType.PUBLIC_HEADER && !sym.is_internal_symbol () && !(sym is Class && ((Class) sym).is_opaque));
687                 if (decl_space.add_declaration (name)) {
688                         return true;
689                 }
690                 if (sym.source_reference != null) {
691                         sym.source_reference.file.used = true;
692                 }
693                 if (sym.anonymous) {
694                         return in_generated_header;
695                 }
696                 // constants with initializer-list are special
697                 if (sym is Constant && ((Constant) sym).value is InitializerList) {
698                         return false;
699                 }
700                 // sealed classes are special
701                 if (!sym.external_package && sym is Class && ((Class) sym).is_sealed) {
702                         return false;
703                 }
704                 if (sym.external_package || in_generated_header
705                     || (sym.is_extern && get_ccode_header_filenames (sym).length > 0)) {
706                         // add feature test macros
707                         foreach (unowned string feature_test_macro in get_ccode_feature_test_macros (sym).split (",")) {
708                                 decl_space.add_feature_test_macro (feature_test_macro);
709                         }
710                         // add appropriate include file
711                         foreach (unowned string header_filename in get_ccode_header_filenames (sym).split (",")) {
712                                 decl_space.add_include (header_filename,
713                                         !sym.is_extern && (!sym.external_package || (sym.external_package && sym.from_commandline)));
714                         }
715                         // declaration complete
716                         return true;
717                 } else {
718                         // require declaration
719                         return false;
720                 }
721         }
722
723         public virtual void append_vala_array_free () {
724         }
725
726         public virtual void append_vala_array_move () {
727         }
728
729         public virtual void append_vala_array_length () {
730         }
731
732         public virtual void append_params_array (Method m) {
733         }
734
735         public void append_vala_clear_mutex (string typename, string funcprefix) {
736                 // memset
737                 cfile.add_include ("string.h");
738
739                 var fun = new CCodeFunction ("_vala_clear_" + typename);
740                 fun.modifiers = CCodeModifiers.STATIC;
741                 fun.add_parameter (new CCodeParameter ("mutex", typename + " *"));
742
743                 push_function (fun);
744
745                 ccode.add_declaration (typename, new CCodeVariableDeclarator.zero ("zero_mutex", new CCodeConstant ("{ 0 }")));
746
747                 var cmp = new CCodeFunctionCall (new CCodeIdentifier ("memcmp"));
748                 cmp.add_argument (new CCodeIdentifier ("mutex"));
749                 cmp.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("zero_mutex")));
750                 cmp.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
751                 ccode.open_if (cmp);
752
753                 var mutex_clear = new CCodeFunctionCall (new CCodeIdentifier (funcprefix + "_clear"));
754                 mutex_clear.add_argument (new CCodeIdentifier ("mutex"));
755                 ccode.add_expression (mutex_clear);
756
757                 var mset = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
758                 mset.add_argument (new CCodeIdentifier ("mutex"));
759                 mset.add_argument (new CCodeConstant ("0"));
760                 mset.add_argument (new CCodeIdentifier ("sizeof (" + typename + ")"));
761                 ccode.add_expression (mset);
762
763                 ccode.close ();
764
765                 pop_function ();
766
767                 cfile.add_function_declaration (fun);
768                 cfile.add_function (fun);
769         }
770
771         void append_vala_memdup2 () {
772                 // g_malloc
773                 cfile.add_include ("glib.h");
774                 // memcpy
775                 cfile.add_include ("string.h");
776
777                 var fun = new CCodeFunction ("_vala_memdup2", "gpointer");
778                 fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
779                 fun.add_parameter (new CCodeParameter ("mem", "gconstpointer"));
780                 fun.add_parameter (new CCodeParameter ("byte_size", "gsize"));
781
782                 push_function (fun);
783
784                 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("new_mem"));
785
786                 ccode.open_if (new CCodeIdentifier ("mem && byte_size != 0"));
787
788                 var malloc = new CCodeFunctionCall (new CCodeIdentifier ("g_malloc"));
789                 malloc.add_argument (new CCodeIdentifier ("byte_size"));
790                 ccode.add_assignment (new CCodeIdentifier ("new_mem"), malloc);
791                 var mcpy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
792                 mcpy.add_argument (new CCodeIdentifier ("new_mem"));
793                 mcpy.add_argument (new CCodeIdentifier ("mem"));
794                 mcpy.add_argument (new CCodeIdentifier ("byte_size"));
795                 ccode.add_expression (mcpy);
796
797                 ccode.add_else ();
798
799                 ccode.add_assignment (new CCodeIdentifier ("new_mem"), new CCodeConstant ("NULL"));
800
801                 ccode.close ();
802
803                 ccode.add_return (new CCodeIdentifier ("new_mem"));
804
805                 pop_function ();
806
807                 cfile.add_function_declaration (fun);
808                 cfile.add_function (fun);
809         }
810
811         /**
812          * Define a macro hint for exporting a symbol in a portable way.
813          */
814         void append_vala_extern_define (CCodeFile decl_space) {
815                 var extern_define = new CCodeIfSection ("!defined(VALA_EXTERN)");
816
817                 CCodeIfSection if_section;
818                 if_section = new CCodeIfSection ("defined(_MSC_VER)");
819                 extern_define.append (if_section);
820                 if_section.append (new CCodeDefine ("VALA_EXTERN", "__declspec(dllexport) extern"));
821                 if_section = if_section.append_else ("__GNUC__ >= 4");
822                 if_section.append (new CCodeDefine ("VALA_EXTERN", "__attribute__((visibility(\"default\"))) extern"));
823                 if_section = if_section.append_else ();
824                 if_section.append (new CCodeDefine ("VALA_EXTERN", "extern"));
825
826                 decl_space.add_define (extern_define);
827         }
828
829         public override void visit_source_file (SourceFile source_file) {
830                 cfile = new CCodeFile (CCodeFileType.SOURCE, source_file);
831
832                 user_marshal_set = new HashSet<string> (str_hash, str_equal);
833
834                 next_regex_id = 0;
835
836                 requires_assert = false;
837                 requires_array_free = false;
838                 requires_array_move = false;
839                 requires_array_length = false;
840                 requires_array_n_elements = false;
841                 requires_clear_mutex = false;
842                 requires_vala_extern = false;
843
844                 wrappers = new HashSet<string> (str_hash, str_equal);
845                 generated_external_symbols = new HashSet<Symbol> ();
846
847                 source_file.accept_children (this);
848
849                 if (context.report.get_errors () > 0) {
850                         return;
851                 }
852
853                 /* For fast-vapi, we only wanted the header declarations
854                  * to be emitted, so bail out here without writing the
855                  * C code output.
856                  */
857                 if (source_file.file_type == SourceFileType.FAST) {
858                         return;
859                 }
860
861                 if (requires_assert) {
862                         cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("_vala_assert(expr, msg)", new CCodeConstant ("if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);")));
863                         cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("_vala_return_if_fail(expr, msg)", new CCodeConstant ("if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }")));
864                         cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("_vala_return_val_if_fail(expr, msg, val)", new CCodeConstant ("if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }")));
865                         cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("_vala_warn_if_fail(expr, msg)", new CCodeConstant ("if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);")));
866                 }
867                 if (requires_array_free) {
868                         append_vala_array_free ();
869                 }
870                 if (requires_array_move) {
871                         append_vala_array_move ();
872                 }
873                 if (requires_array_length) {
874                         append_vala_array_length ();
875                 }
876                 if (requires_array_n_elements) {
877                         cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("VALA_N_ELEMENTS(arr)", new CCodeConstant ("(sizeof (arr) / sizeof ((arr)[0]))")));
878                 }
879                 if (requires_clear_mutex) {
880                         append_vala_clear_mutex ("GMutex", "g_mutex");
881                         append_vala_clear_mutex ("GRecMutex", "g_rec_mutex");
882                         append_vala_clear_mutex ("GRWLock", "g_rw_lock");
883                         append_vala_clear_mutex ("GCond", "g_cond");
884                 }
885                 if (requires_memdup2) {
886                         append_vala_memdup2 ();
887                 }
888                 if (requires_vala_extern) {
889                         if (context.header_filename != null) {
890                                 if (!header_file.add_declaration ("VALA_EXTERN")) {
891                                         append_vala_extern_define (header_file);
892                                 }
893                                 cfile.add_include (source_file.get_cinclude_filename (), true);
894                                 internal_header_file.add_include (source_file.get_cinclude_filename (), true);
895                         } else {
896                                 if (!cfile.add_declaration ("VALA_EXTERN")) {
897                                         append_vala_extern_define (cfile);
898                                         append_vala_extern_define (internal_header_file);
899                                 }
900                         }
901                 }
902
903                 var comments = source_file.get_comments();
904                 if (comments != null) {
905                         foreach (Comment comment in comments) {
906                                 var ccomment = new CCodeComment (comment.content);
907                                 cfile.add_comment (ccomment);
908                         }
909                 }
910
911                 if (!cfile.store (source_file.get_csource_filename (), source_file.filename, context.version_header, context.debug)) {
912                         Report.error (null, "unable to open `%s' for writing", source_file.get_csource_filename ());
913                 }
914
915                 cfile = null;
916         }
917
918         public virtual bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
919                 if (add_symbol_declaration (decl_space, en, get_ccode_name (en))) {
920                         return false;
921                 }
922
923                 var cenum = new CCodeEnum (get_ccode_name (en));
924
925                 if (en.version.deprecated) {
926                         if (context.profile == Profile.GOBJECT) {
927                                 decl_space.add_include ("glib.h");
928                         }
929                         cenum.modifiers |= CCodeModifiers.DEPRECATED;
930                 }
931
932                 var current_cfile = cfile;
933                 cfile = decl_space;
934
935                 int flag_shift = 0;
936                 foreach (EnumValue ev in en.get_values ()) {
937                         CCodeEnumValue c_ev;
938                         if (ev.value == null) {
939                                 c_ev = new CCodeEnumValue (get_ccode_name (ev));
940                                 if (en.is_flags) {
941                                         c_ev.value = new CCodeConstant ("1 << %d".printf (flag_shift));
942                                         flag_shift += 1;
943                                 }
944                         } else {
945                                 ev.value.emit (this);
946                                 c_ev = new CCodeEnumValue (get_ccode_name (ev), get_cvalue (ev.value));
947                         }
948                         c_ev.modifiers |= (ev.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
949                         cenum.add_value (c_ev);
950                 }
951
952                 cfile = current_cfile;
953
954                 decl_space.add_type_declaration (cenum);
955                 decl_space.add_type_declaration (new CCodeNewline ());
956
957                 if (context.profile != Profile.GOBJECT || !get_ccode_has_type_id (en)) {
958                         return true;
959                 }
960
961                 decl_space.add_include ("glib-object.h");
962                 decl_space.add_type_declaration (new CCodeNewline ());
963
964                 var fun_name = get_ccode_type_function (en);
965
966                 var macro = "(%s ())".printf (fun_name);
967                 decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (en), macro));
968
969                 var regfun = new CCodeFunction (fun_name, "GType");
970                 regfun.modifiers = CCodeModifiers.CONST;
971
972                 if (en.is_private_symbol ()) {
973                         // avoid C warning as this function is not always used
974                         regfun.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.UNUSED;
975                 } else if (context.hide_internal && en.is_internal_symbol ()) {
976                         regfun.modifiers |= CCodeModifiers.INTERNAL;
977                 } else {
978                         regfun.modifiers |= CCodeModifiers.EXTERN;
979                         requires_vala_extern = true;
980                 }
981
982                 decl_space.add_function_declaration (regfun);
983
984                 return true;
985         }
986
987         public override void visit_enum (Enum en) {
988                 push_line (en.source_reference);
989
990                 if (en.comment != null) {
991                         cfile.add_type_member_definition (new CCodeComment (en.comment.content));
992                 }
993
994                 generate_enum_declaration (en, cfile);
995
996                 if (!en.is_internal_symbol ()) {
997                         generate_enum_declaration (en, header_file);
998                 }
999                 if (!en.is_private_symbol ()) {
1000                         generate_enum_declaration (en, internal_header_file);
1001                 }
1002
1003                 en.accept_children (this);
1004
1005                 pop_line ();
1006         }
1007
1008         public void visit_member (Symbol m) {
1009                 /* stuff meant for all lockable members */
1010                 if (m is Lockable && ((Lockable) m).lock_used) {
1011                         CCodeExpression l = new CCodeIdentifier ("self");
1012                         var init_context = class_init_context;
1013                         var finalize_context = class_finalize_context;
1014
1015                         if (m.is_instance_member ()) {
1016                                 l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (get_ccode_name (m)));
1017                                 init_context = instance_init_context;
1018                                 finalize_context = instance_finalize_context;
1019                         } else if (m.is_class_member ()) {
1020                                 var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function ((Class) m.parent_symbol)));
1021                                 get_class_private_call.add_argument (new CCodeIdentifier ("klass"));
1022                                 l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (get_ccode_name (m)));
1023                         } else {
1024                                 l = new CCodeIdentifier (get_symbol_lock_name ("%s_%s".printf (get_ccode_lower_case_name (m.parent_symbol), get_ccode_name (m))));
1025                         }
1026
1027                         push_context (init_context);
1028                         var initf = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.default_construction_method)));
1029                         initf.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
1030                         ccode.add_expression (initf);
1031                         pop_context ();
1032
1033                         if (finalize_context != null) {
1034                                 push_context (finalize_context);
1035                                 var fc = new CCodeFunctionCall (new CCodeIdentifier ("g_rec_mutex_clear"));
1036                                 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
1037                                 ccode.add_expression (fc);
1038                                 pop_context ();
1039                         }
1040                 }
1041         }
1042
1043         static void constant_array_ranks_sizes (InitializerList initializer_list, int[] sizes, int rank = 0) {
1044                 sizes[rank] = int.max (sizes[rank], initializer_list.size);
1045                 rank++;
1046                 foreach (var expr in initializer_list.get_initializers()) {
1047                         if (expr is InitializerList && ((InitializerList) expr).target_type is ArrayType) {
1048                                 constant_array_ranks_sizes ((InitializerList) expr, sizes, rank);
1049                         }
1050                 }
1051         }
1052
1053         CCodeDeclaratorSuffix? get_constant_declarator_suffix (Constant c) {
1054                 unowned ArrayType? array = c.type_reference as ArrayType;
1055                 unowned InitializerList? initializer_list = c.value as InitializerList;
1056                 if (array == null || initializer_list == null) {
1057                         if (c.type_reference.compatible (string_type)) {
1058                                 return new CCodeDeclaratorSuffix.with_array ();
1059                         }
1060                         return null;
1061                 }
1062
1063                 var lengths = new ArrayList<CCodeExpression> ();
1064                 int[] sizes = new int[array.rank];
1065                 constant_array_ranks_sizes (initializer_list, sizes);
1066                 for (int i = 0; i < array.rank; i++) {
1067                         lengths.add (new CCodeConstant ("%d".printf (sizes[i])));
1068                 }
1069                 return new CCodeDeclaratorSuffix.with_multi_array (lengths);
1070         }
1071
1072         public void generate_constant_declaration (Constant c, CCodeFile decl_space, bool definition = false) {
1073                 if (c.parent_symbol is Block) {
1074                         // local constant
1075                         return;
1076                 }
1077
1078                 if (add_symbol_declaration (decl_space, c, get_ccode_name (c))) {
1079                         return;
1080                 }
1081
1082                 if (!c.external && c.value != null) {
1083                         generate_type_declaration (c.type_reference, decl_space);
1084
1085                         c.value.emit (this);
1086
1087                         var initializer_list = c.value as InitializerList;
1088                         if (initializer_list != null) {
1089                                 var cdecl = new CCodeDeclaration (get_ccode_const_name (c.type_reference));
1090                                 var cinitializer = get_cvalue (c.value);
1091                                 if (!definition) {
1092                                         // never output value in header
1093                                         // special case needed as this method combines declaration and definition
1094                                         cinitializer = null;
1095                                 }
1096
1097                                 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_name (c), cinitializer, get_constant_declarator_suffix (c)));
1098                                 if (c.is_private_symbol ()) {
1099                                         cdecl.modifiers = CCodeModifiers.STATIC;
1100                                 } else {
1101                                         cdecl.modifiers = CCodeModifiers.EXTERN;
1102                                         requires_vala_extern = true;
1103                                 }
1104
1105                                 decl_space.add_constant_declaration (cdecl);
1106                         } else {
1107                                 if (c.value is StringLiteral && ((StringLiteral) c.value).translate) {
1108                                         // translated string constant
1109                                         var m = (Method) root_symbol.scope.lookup ("GLib").scope.lookup ("_");
1110                                         add_symbol_declaration (decl_space, m, get_ccode_name (m));
1111                                 }
1112
1113                                 var cdefine = new CCodeDefine.with_expression (get_ccode_name (c), get_cvalue (c.value));
1114                                 decl_space.add_define (cdefine);
1115                         }
1116                 }
1117         }
1118
1119         public override void visit_constant (Constant c) {
1120                 push_line (c.source_reference);
1121
1122                 if (c.parent_symbol is Block) {
1123                         // local constant
1124
1125                         generate_type_declaration (c.type_reference, cfile);
1126
1127                         c.value.emit (this);
1128
1129                         string type_name;
1130                         if (c.type_reference.compatible (string_type)) {
1131                                 type_name = "const char";
1132                         } else {
1133                                 type_name = get_ccode_const_name (c.type_reference);
1134                         }
1135
1136                         var cinitializer = get_cvalue (c.value);
1137
1138                         ccode.add_declaration (type_name, new CCodeVariableDeclarator (get_ccode_name (c), cinitializer, get_constant_declarator_suffix (c)), CCodeModifiers.STATIC);
1139                 } else {
1140                         generate_constant_declaration (c, cfile, true);
1141
1142                         if (!c.is_internal_symbol ()) {
1143                                 generate_constant_declaration (c, header_file);
1144                         }
1145                         if (!c.is_private_symbol ()) {
1146                                 generate_constant_declaration (c, internal_header_file);
1147                         }
1148                 }
1149
1150                 pop_line ();
1151         }
1152
1153         public void append_field (CCodeStruct ccode_struct, Field f, CCodeFile decl_space) {
1154                 generate_type_declaration (f.variable_type, decl_space);
1155
1156                 CCodeModifiers modifiers = (f.is_volatile ? CCodeModifiers.VOLATILE : 0) | (f.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
1157                 ccode_struct.add_field (get_ccode_name (f.variable_type), get_ccode_name (f), modifiers, get_ccode_declarator_suffix (f.variable_type));
1158
1159                 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1160                         // create fields to store array dimensions
1161                         var array_type = (ArrayType) f.variable_type;
1162                         if (!array_type.fixed_length) {
1163                                 var length_ctype = get_ccode_array_length_type (f);
1164                                 for (int dim = 1; dim <= array_type.rank; dim++) {
1165                                         string length_cname = get_variable_array_length_cname (f, dim);
1166                                         ccode_struct.add_field (length_ctype, length_cname);
1167                                 }
1168                                 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1169                                         ccode_struct.add_field (length_ctype, get_array_size_cname (get_ccode_name (f)));
1170                                 }
1171                         }
1172                 } else if (get_ccode_delegate_target (f)) {
1173                         var delegate_type = (DelegateType) f.variable_type;
1174                         if (delegate_type.delegate_symbol.has_target) {
1175                                 // create field to store delegate target
1176                                 ccode_struct.add_field (get_ccode_name (delegate_target_type), get_ccode_delegate_target_name (f));
1177                                 if (delegate_type.is_disposable ()) {
1178                                         ccode_struct.add_field (get_ccode_name (delegate_target_destroy_type), get_ccode_delegate_target_destroy_notify_name (f));
1179                                 }
1180                         }
1181                 }
1182         }
1183
1184         public void generate_field_declaration (Field f, CCodeFile decl_space) {
1185                 if (add_symbol_declaration (decl_space, f, get_ccode_name (f))) {
1186                         return;
1187                 }
1188
1189                 generate_type_declaration (f.variable_type, decl_space);
1190
1191                 var cdecl = new CCodeDeclaration (get_ccode_name (f.variable_type));
1192                 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type)));
1193                 if (f.is_private_symbol ()) {
1194                         cdecl.modifiers = CCodeModifiers.STATIC;
1195                 } else {
1196                         cdecl.modifiers = CCodeModifiers.EXTERN;
1197                         requires_vala_extern = true;
1198                 }
1199                 if (f.version.deprecated) {
1200                         cdecl.modifiers |= CCodeModifiers.DEPRECATED;
1201                 }
1202                 if (f.is_volatile) {
1203                         cdecl.modifiers |= CCodeModifiers.VOLATILE;
1204                 }
1205                 decl_space.add_type_member_declaration (cdecl);
1206
1207                 if (f.lock_used) {
1208                         // Declare mutex for static member
1209                         var flock = new CCodeDeclaration (get_ccode_name (mutex_type));
1210                         var flock_decl = new CCodeVariableDeclarator (get_symbol_lock_name ("%s_%s".printf (get_ccode_lower_case_name (f.parent_symbol), get_ccode_name (f))), new CCodeConstant ("{0}"));
1211                         flock.add_declarator (flock_decl);
1212
1213                         if (f.is_private_symbol ()) {
1214                                 flock.modifiers = CCodeModifiers.STATIC;
1215                         } else {
1216                                 flock.modifiers = CCodeModifiers.EXTERN;
1217                                 requires_vala_extern = true;
1218                         }
1219                         decl_space.add_type_member_declaration (flock);
1220                 }
1221
1222                 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1223                         var array_type = (ArrayType) f.variable_type;
1224
1225                         if (!array_type.fixed_length) {
1226                                 var length_ctype = get_ccode_array_length_type (f);
1227
1228                                 for (int dim = 1; dim <= array_type.rank; dim++) {
1229                                         cdecl = new CCodeDeclaration (length_ctype);
1230                                         cdecl.add_declarator (new CCodeVariableDeclarator (get_variable_array_length_cname (f, dim)));
1231                                         if (f.is_private_symbol ()) {
1232                                                 cdecl.modifiers = CCodeModifiers.STATIC;
1233                                         } else {
1234                                                 cdecl.modifiers = CCodeModifiers.EXTERN;
1235                                                 requires_vala_extern = true;
1236                                         }
1237                                         decl_space.add_type_member_declaration (cdecl);
1238                                 }
1239                         }
1240                 } else if (get_ccode_delegate_target (f)) {
1241                         var delegate_type = (DelegateType) f.variable_type;
1242                         if (delegate_type.delegate_symbol.has_target) {
1243                                 // create field to store delegate target
1244
1245                                 cdecl = new CCodeDeclaration (get_ccode_name (delegate_target_type));
1246                                 cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f)));
1247                                 if (f.is_private_symbol ()) {
1248                                         cdecl.modifiers = CCodeModifiers.STATIC;
1249                                 } else {
1250                                         cdecl.modifiers = CCodeModifiers.EXTERN;
1251                                         requires_vala_extern = true;
1252                                 }
1253                                 decl_space.add_type_member_declaration (cdecl);
1254
1255                                 if (delegate_type.is_disposable ()) {
1256                                         cdecl = new CCodeDeclaration (get_ccode_name (delegate_target_destroy_type));
1257                                         cdecl.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_destroy_notify_name (f)));
1258                                         if (f.is_private_symbol ()) {
1259                                                 cdecl.modifiers = CCodeModifiers.STATIC;
1260                                         } else {
1261                                                 cdecl.modifiers = CCodeModifiers.EXTERN;
1262                                                 requires_vala_extern = true;
1263                                         }
1264                                         decl_space.add_type_member_declaration (cdecl);
1265                                 }
1266                         }
1267                 }
1268         }
1269
1270         public override void visit_field (Field f) {
1271                 push_line (f.source_reference);
1272                 visit_member (f);
1273
1274                 var cl = f.parent_symbol as Class;
1275                 bool is_gtypeinstance = (cl != null && !cl.is_compact);
1276
1277                 CCodeExpression lhs = null;
1278
1279                 if (f.binding == MemberBinding.INSTANCE)  {
1280                         if (is_gtypeinstance && f.access == SymbolAccessibility.PRIVATE) {
1281                                 lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), get_ccode_name (f));
1282                         } else {
1283                                 lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_ccode_name (f));
1284                         }
1285
1286                         if (f.initializer != null) {
1287                                 push_context (instance_init_context);
1288
1289                                 f.initializer.emit (this);
1290
1291                                 var rhs = get_cvalue (f.initializer);
1292                                 if (!is_simple_struct_creation (f, f.initializer)) {
1293                                         // otherwise handled in visit_object_creation_expression
1294
1295                                         ccode.add_assignment (lhs, rhs);
1296
1297                                         if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1298                                                 var array_type = (ArrayType) f.variable_type;
1299                                                 var field_value = get_field_cvalue (f, load_this_parameter ((TypeSymbol) f.parent_symbol));
1300
1301                                                 var glib_value = (GLibValue) f.initializer.target_value;
1302                                                 if (glib_value.array_length_cvalues != null) {
1303                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
1304                                                                 var array_len_lhs = get_array_length_cvalue (field_value, dim);
1305                                                                 ccode.add_assignment (array_len_lhs, get_array_length_cvalue (glib_value, dim));
1306                                                         }
1307                                                 } else if (glib_value.array_null_terminated) {
1308                                                         requires_array_length = true;
1309                                                         var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1310                                                         len_call.add_argument (get_cvalue_ (glib_value));
1311
1312                                                         ccode.add_assignment (get_array_length_cvalue (field_value, 1), len_call);
1313                                                 } else {
1314                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
1315                                                                 ccode.add_assignment (get_array_length_cvalue (field_value, dim), new CCodeConstant ("-1"));
1316                                                         }
1317                                                 }
1318
1319                                                 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1320                                                         var lhs_array_size = get_array_size_cvalue (field_value);
1321                                                         var rhs_array_len = get_array_length_cvalue (field_value, 1);
1322                                                         ccode.add_assignment (lhs_array_size, rhs_array_len);
1323                                                 }
1324                                         } else if (get_ccode_delegate_target (f)) {
1325                                                 var delegate_type = (DelegateType) f.variable_type;
1326                                                 if (delegate_type.delegate_symbol.has_target) {
1327                                                         var field_value = get_field_cvalue (f, load_this_parameter ((TypeSymbol) f.parent_symbol));
1328                                                         var target_cvalue = get_delegate_target_cvalue (f.initializer.target_value);
1329                                                         if (target_cvalue != null) {
1330                                                                 ccode.add_assignment (get_delegate_target_cvalue (field_value), target_cvalue);
1331                                                         } else {
1332                                                                 ccode.add_assignment (get_delegate_target_cvalue (field_value), new CCodeIdentifier ("self"));
1333                                                         }
1334                                                         if (delegate_type.is_disposable ()) {
1335                                                                 var destroy_cvalue = get_delegate_target_destroy_notify_cvalue (f.initializer.target_value);
1336                                                                 if (destroy_cvalue != null) {
1337                                                                         ccode.add_assignment (get_delegate_target_destroy_notify_cvalue (field_value), destroy_cvalue);
1338                                                                 } else {
1339                                                                         ccode.add_assignment (get_delegate_target_destroy_notify_cvalue (field_value), new CCodeConstant ("NULL"));
1340                                                                 }
1341                                                         }
1342                                                 }
1343                                         }
1344                                 }
1345
1346                                 foreach (var value in temp_ref_values) {
1347                                         ccode.add_expression (destroy_value (value));
1348                                 }
1349
1350                                 temp_ref_values.clear ();
1351
1352                                 pop_context ();
1353                         }
1354
1355                         if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_destroy (f.variable_type) && instance_finalize_context != null) {
1356                                 push_context (instance_finalize_context);
1357                                 ccode.add_expression (destroy_field (f, load_this_parameter ((TypeSymbol) f.parent_symbol)));
1358                                 pop_context ();
1359                         }
1360                 } else if (f.binding == MemberBinding.CLASS)  {
1361                         if (f.access == SymbolAccessibility.PRIVATE) {
1362                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function (cl)));
1363                                 ccall.add_argument (new CCodeIdentifier ("klass"));
1364                                 lhs = new CCodeMemberAccess (ccall, get_ccode_name (f), true);
1365                         } else {
1366                                 lhs = new CCodeMemberAccess (new CCodeIdentifier ("klass"), get_ccode_name (f), true);
1367                         }
1368
1369                         if (f.initializer != null) {
1370                                 push_context (class_init_context);
1371
1372                                 f.initializer.emit (this);
1373
1374                                 var rhs = get_cvalue (f.initializer);
1375
1376                                 ccode.add_assignment (lhs, rhs);
1377
1378                                 foreach (var value in temp_ref_values) {
1379                                         ccode.add_expression (destroy_value (value));
1380                                 }
1381
1382                                 temp_ref_values.clear ();
1383
1384                                 pop_context ();
1385                         }
1386                 } else {
1387                         generate_field_declaration (f, cfile);
1388
1389                         if (!f.is_internal_symbol ()) {
1390                                 generate_field_declaration (f, header_file);
1391                         }
1392                         if (!f.is_private_symbol ()) {
1393                                 generate_field_declaration (f, internal_header_file);
1394                         }
1395
1396                         if (!f.external) {
1397                                 lhs = new CCodeIdentifier (get_ccode_name (f));
1398
1399                                 var var_decl = new CCodeVariableDeclarator (get_ccode_name (f), null, get_ccode_declarator_suffix (f.variable_type));
1400                                 var_decl.initializer = default_value_for_type (f.variable_type, true);
1401
1402                                 if (class_init_context != null) {
1403                                         push_context (class_init_context);
1404                                 } else {
1405                                         push_context (new EmitContext ());
1406                                 }
1407
1408                                 if (f.initializer != null) {
1409                                         f.initializer.emit (this);
1410
1411                                         var init = get_cvalue (f.initializer);
1412                                         if (is_constant_ccode_expression (init)) {
1413                                                 var_decl.initializer = init;
1414                                         }
1415                                 }
1416
1417                                 var var_def = new CCodeDeclaration (get_ccode_name (f.variable_type));
1418                                 var_def.add_declarator (var_decl);
1419                                 if (!f.is_private_symbol ()) {
1420                                         var_def.modifiers = CCodeModifiers.EXTERN;
1421                                         requires_vala_extern = true;
1422                                 } else {
1423                                         var_def.modifiers = CCodeModifiers.STATIC;
1424                                 }
1425                                 if (f.version.deprecated) {
1426                                         var_def.modifiers |= CCodeModifiers.DEPRECATED;
1427                                 }
1428                                 if (f.is_volatile) {
1429                                         var_def.modifiers |= CCodeModifiers.VOLATILE;
1430                                 }
1431                                 cfile.add_type_member_declaration (var_def);
1432
1433                                 /* add array length fields where necessary */
1434                                 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1435                                         var array_type = (ArrayType) f.variable_type;
1436
1437                                         if (!array_type.fixed_length) {
1438                                                 var length_ctype = get_ccode_array_length_type (f);
1439
1440                                                 for (int dim = 1; dim <= array_type.rank; dim++) {
1441                                                         var len_def = new CCodeDeclaration (length_ctype);
1442                                                         len_def.add_declarator (new CCodeVariableDeclarator (get_variable_array_length_cname (f, dim), new CCodeConstant ("0")));
1443                                                         if (!f.is_private_symbol ()) {
1444                                                                 len_def.modifiers = CCodeModifiers.EXTERN;
1445                                                                 requires_vala_extern = true;
1446                                                         } else {
1447                                                                 len_def.modifiers = CCodeModifiers.STATIC;
1448                                                         }
1449                                                         cfile.add_type_member_declaration (len_def);
1450                                                 }
1451
1452                                                 if (array_type.rank == 1 && f.is_internal_symbol ()) {
1453                                                         var cdecl = new CCodeDeclaration (length_ctype);
1454                                                         cdecl.add_declarator (new CCodeVariableDeclarator (get_array_size_cname (get_ccode_name (f)), new CCodeConstant ("0")));
1455                                                         cdecl.modifiers = CCodeModifiers.STATIC;
1456                                                         cfile.add_type_member_declaration (cdecl);
1457                                                 }
1458                                         }
1459                                 } else if (get_ccode_delegate_target (f)) {
1460                                         var delegate_type = (DelegateType) f.variable_type;
1461                                         if (delegate_type.delegate_symbol.has_target) {
1462                                                 // create field to store delegate target
1463
1464                                                 var target_def = new CCodeDeclaration (get_ccode_name (delegate_target_type));
1465                                                 target_def.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_name (f), new CCodeConstant ("NULL")));
1466                                                 if (!f.is_private_symbol ()) {
1467                                                         target_def.modifiers = CCodeModifiers.EXTERN;
1468                                                         requires_vala_extern = true;
1469                                                 } else {
1470                                                         target_def.modifiers = CCodeModifiers.STATIC;
1471                                                 }
1472                                                 cfile.add_type_member_declaration (target_def);
1473
1474                                                 if (delegate_type.is_disposable ()) {
1475                                                         var target_destroy_notify_def = new CCodeDeclaration (get_ccode_name (delegate_target_destroy_type));
1476                                                         target_destroy_notify_def.add_declarator (new CCodeVariableDeclarator (get_ccode_delegate_target_destroy_notify_name (f), new CCodeConstant ("NULL")));
1477                                                         if (!f.is_private_symbol ()) {
1478                                                                 target_destroy_notify_def.modifiers = CCodeModifiers.EXTERN;
1479                                                                 requires_vala_extern = true;
1480                                                         } else {
1481                                                                 target_destroy_notify_def.modifiers = CCodeModifiers.STATIC;
1482                                                         }
1483                                                         cfile.add_type_member_declaration (target_destroy_notify_def);
1484
1485                                                 }
1486                                         }
1487                                 }
1488
1489                                 if (f.initializer != null) {
1490                                         var rhs = get_cvalue (f.initializer);
1491                                         if (!is_constant_ccode_expression (rhs)) {
1492                                                 if (is_gtypeinstance) {
1493                                                         if (f.initializer is InitializerList) {
1494                                                                 ccode.open_block ();
1495
1496                                                                 var temp_decl = get_temp_variable (f.variable_type);
1497                                                                 var vardecl = new CCodeVariableDeclarator.zero (temp_decl.name, rhs);
1498                                                                 ccode.add_declaration (get_ccode_name (temp_decl.variable_type), vardecl);
1499
1500                                                                 var tmp = get_variable_cexpression (temp_decl.name);
1501                                                                 ccode.add_assignment (lhs, tmp);
1502
1503                                                                 ccode.close ();
1504                                                         } else {
1505                                                                 ccode.add_assignment (lhs, rhs);
1506                                                         }
1507
1508                                                         if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
1509                                                                 var array_type = (ArrayType) f.variable_type;
1510                                                                 var field_value = get_field_cvalue (f, null);
1511
1512                                                                 var glib_value = (GLibValue) f.initializer.target_value;
1513                                                                 if (glib_value.array_length_cvalues != null) {
1514                                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
1515                                                                                 var array_len_lhs = get_array_length_cvalue (field_value, dim);
1516                                                                                 ccode.add_assignment (array_len_lhs, get_array_length_cvalue (glib_value, dim));
1517                                                                         }
1518                                                                 } else if (glib_value.array_null_terminated) {
1519                                                                         requires_array_length = true;
1520                                                                         var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1521                                                                         len_call.add_argument (get_cvalue_ (glib_value));
1522
1523                                                                         ccode.add_assignment (get_array_length_cvalue (field_value, 1), len_call);
1524                                                                 } else {
1525                                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
1526                                                                                 ccode.add_assignment (get_array_length_cvalue (field_value, dim), new CCodeConstant ("-1"));
1527                                                                         }
1528                                                                 }
1529                                                         }
1530                                                 } else {
1531                                                         f.error = true;
1532                                                         Report.error (f.source_reference, "Non-constant field initializers not supported in this context");
1533                                                         return;
1534                                                 }
1535                                         }
1536                                 }
1537
1538                                 pop_context ();
1539                         }
1540                 }
1541
1542                 pop_line ();
1543         }
1544
1545         public static bool is_constant_ccode_expression (CCodeExpression cexpr) {
1546                 if (cexpr is CCodeConstant || cexpr is CCodeConstantIdentifier) {
1547                         return true;
1548                 } else if (cexpr is CCodeCastExpression) {
1549                         var ccast = (CCodeCastExpression) cexpr;
1550                         return is_constant_ccode_expression (ccast.inner);
1551                 } else if (cexpr is CCodeUnaryExpression) {
1552                         var cunary = (CCodeUnaryExpression) cexpr;
1553                         switch (cunary.operator) {
1554                                 case CCodeUnaryOperator.PREFIX_INCREMENT:
1555                                 case CCodeUnaryOperator.PREFIX_DECREMENT:
1556                                 case CCodeUnaryOperator.POSTFIX_INCREMENT:
1557                                 case CCodeUnaryOperator.POSTFIX_DECREMENT:
1558                                         return false;
1559                                 default:
1560                                         break;
1561                         }
1562                         return is_constant_ccode_expression (cunary.inner);
1563                 } else if (cexpr is CCodeBinaryExpression) {
1564                         var cbinary = (CCodeBinaryExpression) cexpr;
1565                         return is_constant_ccode_expression (cbinary.left) && is_constant_ccode_expression (cbinary.right);
1566                 }
1567
1568                 var cparenthesized = (cexpr as CCodeParenthesizedExpression);
1569                 return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
1570         }
1571
1572         public static bool is_constant_ccode (CodeNode expr) {
1573                 if (expr is Constant) {
1574                         // Local constants are not considered constant in C
1575                         return !(((Constant) expr).parent_symbol is Block);
1576                 } else if (expr is IntegerLiteral) {
1577                         return ((IntegerLiteral) expr).is_constant ();
1578                 } else if (expr is MemberAccess) {
1579                         return is_constant_ccode (((MemberAccess) expr).symbol_reference);
1580                 } else if (expr is CastExpression) {
1581                         return is_constant_ccode (((CastExpression) expr).inner);
1582                 }
1583
1584                 return false;
1585         }
1586
1587         /**
1588          * Returns whether the passed cexpr is a pure expression, i.e. an
1589          * expression without side-effects.
1590          */
1591         public static bool is_pure_ccode_expression (CCodeExpression cexpr) {
1592                 if (cexpr is CCodeConstant || cexpr is CCodeIdentifier) {
1593                         return true;
1594                 } else if (cexpr is CCodeBinaryExpression) {
1595                         var cbinary = (CCodeBinaryExpression) cexpr;
1596                         return is_pure_ccode_expression (cbinary.left) && is_pure_ccode_expression (cbinary.right);
1597                 } else if (cexpr is CCodeUnaryExpression) {
1598                         var cunary = (CCodeUnaryExpression) cexpr;
1599                         switch (cunary.operator) {
1600                         case CCodeUnaryOperator.PREFIX_INCREMENT:
1601                         case CCodeUnaryOperator.PREFIX_DECREMENT:
1602                         case CCodeUnaryOperator.POSTFIX_INCREMENT:
1603                         case CCodeUnaryOperator.POSTFIX_DECREMENT:
1604                                 return false;
1605                         default:
1606                                 return is_pure_ccode_expression (cunary.inner);
1607                         }
1608                 } else if (cexpr is CCodeMemberAccess) {
1609                         var cma = (CCodeMemberAccess) cexpr;
1610                         return is_pure_ccode_expression (cma.inner);
1611                 } else if (cexpr is CCodeElementAccess) {
1612                         var cea = (CCodeElementAccess) cexpr;
1613                         return is_pure_ccode_expression (cea.container) && is_pure_ccode_expression (cea.indices[0]);
1614                 } else if (cexpr is CCodeCastExpression) {
1615                         var ccast = (CCodeCastExpression) cexpr;
1616                         return is_pure_ccode_expression (ccast.inner);
1617                 } else if (cexpr is CCodeParenthesizedExpression) {
1618                         var cparenthesized = (CCodeParenthesizedExpression) cexpr;
1619                         return is_pure_ccode_expression (cparenthesized.inner);
1620                 }
1621
1622                 return false;
1623         }
1624
1625         public override void visit_property (Property prop) {
1626                 visit_member (prop);
1627
1628                 if (prop.get_accessor != null) {
1629                         prop.get_accessor.accept (this);
1630                 }
1631                 if (prop.set_accessor != null) {
1632                         prop.set_accessor.accept (this);
1633                 }
1634         }
1635
1636         public void generate_type_declaration (DataType type, CCodeFile decl_space) {
1637                 if (type is ObjectType) {
1638                         var object_type = (ObjectType) type;
1639                         if (object_type.type_symbol is Class) {
1640                                 var cl = (Class) object_type.type_symbol;
1641                                 generate_class_declaration (cl, decl_space);
1642                                 if (!cl.is_compact && cl.has_type_parameters ()) {
1643                                         generate_struct_declaration ((Struct) gtype_type, decl_space);
1644                                 }
1645                         } else if (object_type.type_symbol is Interface) {
1646                                 var iface = (Interface) object_type.type_symbol;
1647                                 generate_interface_declaration (iface, decl_space);
1648                                 if (iface.has_type_parameters ()) {
1649                                         generate_struct_declaration ((Struct) gtype_type, decl_space);
1650                                 }
1651                         }
1652                 } else if (type is DelegateType) {
1653                         var deleg_type = (DelegateType) type;
1654                         var d = deleg_type.delegate_symbol;
1655                         generate_delegate_declaration (d, decl_space);
1656                         if (d.has_target) {
1657                                 generate_type_declaration (delegate_target_type, decl_space);
1658                                 if (deleg_type.is_disposable ()) {
1659                                         generate_type_declaration (delegate_target_destroy_type, decl_space);
1660                                 }
1661                         }
1662                 } else if (type.type_symbol is Enum) {
1663                         var en = (Enum) type.type_symbol;
1664                         generate_enum_declaration (en, decl_space);
1665                 } else if (type is ValueType) {
1666                         var value_type = (ValueType) type;
1667                         generate_struct_declaration ((Struct) value_type.type_symbol, decl_space);
1668                 } else if (type is ArrayType) {
1669                         var array_type = (ArrayType) type;
1670                         generate_type_declaration (array_type.element_type, decl_space);
1671                         if (array_type.length_type != null) {
1672                                 generate_type_declaration (array_type.length_type, decl_space);
1673                         }
1674                 } else if (type is ErrorType) {
1675                         var error_type = (ErrorType) type;
1676                         if (error_type.error_domain != null) {
1677                                 generate_error_domain_declaration (error_type.error_domain, decl_space);
1678                         } else {
1679                                 generate_class_declaration (gerror, decl_space);
1680                         }
1681                 } else if (type is PointerType) {
1682                         var pointer_type = (PointerType) type;
1683                         generate_type_declaration (pointer_type.base_type, decl_space);
1684                 } else if (type is MethodType) {
1685                         var method = ((MethodType) type).method_symbol;
1686                         if (method.has_type_parameters () && !get_ccode_simple_generics (method)) {
1687                                 generate_struct_declaration ((Struct) gtype_type, decl_space);
1688                         }
1689                 }
1690
1691                 foreach (DataType type_arg in type.get_type_arguments ()) {
1692                         generate_type_declaration (type_arg, decl_space);
1693                 }
1694         }
1695
1696         public virtual void generate_class_struct_declaration (Class cl, CCodeFile decl_space) {
1697         }
1698
1699         public virtual void generate_struct_declaration (Struct st, CCodeFile decl_space) {
1700         }
1701
1702         public virtual void generate_delegate_declaration (Delegate d, CCodeFile decl_space) {
1703         }
1704
1705         public virtual void generate_cparameters (Method m, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
1706         }
1707
1708         public void generate_property_accessor_declaration (PropertyAccessor acc, CCodeFile decl_space) {
1709                 if (add_symbol_declaration (decl_space, acc, get_ccode_name (acc))) {
1710                         return;
1711                 }
1712
1713                 var prop = (Property) acc.prop;
1714
1715                 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1716
1717
1718                 CCodeParameter cvalueparam;
1719                 if (returns_real_struct) {
1720                         cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (acc.value_type)));
1721                 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1722                         cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (acc.value_type)));
1723                 } else {
1724                         cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1725                 }
1726                 generate_type_declaration (acc.value_type, decl_space);
1727
1728                 CCodeFunction function;
1729                 if (acc.readable && !returns_real_struct) {
1730                         function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (acc.value_type));
1731                 } else {
1732                         function = new CCodeFunction (get_ccode_name (acc), "void");
1733                 }
1734
1735                 if (prop.binding == MemberBinding.INSTANCE) {
1736                         var t = (TypeSymbol) prop.parent_symbol;
1737                         var this_type = SemanticAnalyzer.get_data_type_for_symbol (t);
1738                         generate_type_declaration (this_type, decl_space);
1739                         var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1740                         if (t is Struct && !((Struct) t).is_simple_type ()) {
1741                                 cselfparam.type_name += "*";
1742                         }
1743
1744                         function.add_parameter (cselfparam);
1745                 }
1746
1747                 if (acc.writable || acc.construction || returns_real_struct) {
1748                         function.add_parameter (cvalueparam);
1749                 }
1750
1751                 if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1752                         var array_type = (ArrayType) acc.value_type;
1753                         var length_ctype = get_ccode_array_length_type (prop);
1754                         for (int dim = 1; dim <= array_type.rank; dim++) {
1755                                 function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? length_ctype + "*" : length_ctype));
1756                         }
1757                 } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1758                         function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? get_ccode_name (delegate_target_type) + "*" : get_ccode_name (delegate_target_type)));
1759                         if (!acc.readable && acc.value_type.value_owned) {
1760                                 function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), get_ccode_name (delegate_target_destroy_type)));
1761                         }
1762                 }
1763
1764                 if (prop.version.deprecated) {
1765                         if (context.profile == Profile.GOBJECT) {
1766                                 decl_space.add_include ("glib.h");
1767                         }
1768                         function.modifiers |= CCodeModifiers.DEPRECATED;
1769                 }
1770
1771                 if (!prop.is_abstract
1772                     && (prop.is_private_symbol () || (!acc.readable && !acc.writable) || acc.access == SymbolAccessibility.PRIVATE)) {
1773                         function.modifiers |= CCodeModifiers.STATIC;
1774                 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1775                         function.modifiers |= CCodeModifiers.INTERNAL;
1776                 } else {
1777                         function.modifiers |= CCodeModifiers.EXTERN;
1778                         requires_vala_extern = true;
1779                 }
1780                 decl_space.add_function_declaration (function);
1781         }
1782
1783         public override void visit_property_accessor (PropertyAccessor acc) {
1784                 push_context (new EmitContext (acc));
1785                 push_line (acc.source_reference);
1786
1787                 var prop = (Property) acc.prop;
1788
1789                 if (acc.comment != null) {
1790                         cfile.add_type_member_definition (new CCodeComment (acc.comment.content));
1791                 }
1792
1793                 bool returns_real_struct = acc.readable && prop.property_type.is_real_non_null_struct_type ();
1794
1795                 if (acc.result_var != null) {
1796                         acc.result_var.accept (this);
1797                 }
1798
1799                 var t = (TypeSymbol) prop.parent_symbol;
1800
1801                 // do not declare overriding properties and interface implementations
1802                 if (prop.is_abstract || prop.is_virtual
1803                     || (prop.base_property == null && prop.base_interface_property == null)) {
1804                         generate_property_accessor_declaration (acc, cfile);
1805
1806                         // do not declare construct-only properties in header files
1807                         if (acc.readable || acc.writable) {
1808                                 if (!prop.is_internal_symbol ()
1809                                     && (acc.access == SymbolAccessibility.PUBLIC
1810                                         || acc.access == SymbolAccessibility.PROTECTED)) {
1811                                         generate_property_accessor_declaration (acc, header_file);
1812                                 }
1813                                 if (!prop.is_private_symbol () && acc.access != SymbolAccessibility.PRIVATE) {
1814                                         generate_property_accessor_declaration (acc, internal_header_file);
1815                                 }
1816                         }
1817                 }
1818
1819                 if (acc.source_type == SourceFileType.FAST) {
1820                         pop_line ();
1821                         pop_context ();
1822                         return;
1823                 }
1824
1825                 var this_type = SemanticAnalyzer.get_data_type_for_symbol (t);
1826                 var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
1827                 if (t is Struct && !((Struct) t).is_simple_type ()) {
1828                         cselfparam.type_name += "*";
1829                 }
1830                 CCodeParameter cvalueparam;
1831                 if (returns_real_struct) {
1832                         cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (acc.value_type)));
1833                 } else if (!acc.readable && prop.property_type.is_real_non_null_struct_type ()) {
1834                         cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (acc.value_type)));
1835                 } else {
1836                         cvalueparam = new CCodeParameter ("value", get_ccode_name (acc.value_type));
1837                 }
1838
1839                 if (prop.is_abstract || prop.is_virtual) {
1840                         CCodeFunction function;
1841                         if (acc.readable && !returns_real_struct) {
1842                                 function = new CCodeFunction (get_ccode_name (acc), get_ccode_name (current_return_type));
1843                         } else {
1844                                 function = new CCodeFunction (get_ccode_name (acc), "void");
1845                         }
1846                         function.add_parameter (cselfparam);
1847                         if (acc.writable || acc.construction || returns_real_struct) {
1848                                 function.add_parameter (cvalueparam);
1849                         }
1850
1851                         if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1852                                 var array_type = (ArrayType) acc.value_type;
1853                                 var length_ctype = get_ccode_array_length_type (prop);
1854                                 for (int dim = 1; dim <= array_type.rank; dim++) {
1855                                         function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? length_ctype + "*": length_ctype));
1856                                 }
1857                         } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1858                                 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? get_ccode_name (delegate_target_type) + "*" : get_ccode_name (delegate_target_type)));
1859                                 if (!acc.readable && acc.value_type.value_owned) {
1860                                         function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), get_ccode_name (delegate_target_destroy_type)));
1861                                 }
1862                         }
1863
1864                         if (!prop.is_abstract
1865                             && (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE)) {
1866                                 // accessor function should be private if the property is an internal symbol or it's a construct-only setter
1867                                 function.modifiers |= CCodeModifiers.STATIC;
1868                         } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
1869                                 function.modifiers |= CCodeModifiers.INTERNAL;
1870                         }
1871
1872                         push_function (function);
1873
1874                         if (acc.value_type.is_non_null_simple_type () && default_value_for_type (acc.value_type, false) == null) {
1875                                 var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (acc.value_type, true));
1876                                 vardecl.init0 = true;
1877                                 ccode.add_declaration (get_ccode_name (acc.value_type), vardecl);
1878                         }
1879
1880                         if (prop.binding == MemberBinding.INSTANCE) {
1881                                 if (!acc.readable || returns_real_struct) {
1882                                         create_property_type_check_statement (prop, false, t, true, "self");
1883                                 } else {
1884                                         create_property_type_check_statement (prop, true, t, true, "self");
1885                                 }
1886                         }
1887
1888                         CCodeExpression vcast;
1889                         if (prop.parent_symbol is Interface) {
1890                                 var iface = (Interface) prop.parent_symbol;
1891
1892                                 vcast = new CCodeIdentifier ("_iface_");
1893                                 var vcastcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
1894                                 ((CCodeFunctionCall) vcastcall).add_argument (new CCodeIdentifier ("self"));
1895                                 ccode.add_declaration ("%s*".printf (get_ccode_type_name (iface)), new CCodeVariableDeclarator ("_iface_"));
1896                                 ccode.add_assignment (vcast, vcastcall);
1897                         } else {
1898                                 var cl = (Class) prop.parent_symbol;
1899                                 if (!cl.is_compact) {
1900                                         vcast = new CCodeIdentifier ("_klass_");
1901                                         var vcastcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
1902                                         ((CCodeFunctionCall) vcastcall).add_argument (new CCodeIdentifier ("self"));
1903                                         ccode.add_declaration ("%s*".printf (get_ccode_type_name (cl)), new CCodeVariableDeclarator ("_klass_"));
1904                                         ccode.add_assignment (vcast, vcastcall);
1905                                 } else {
1906                                         vcast = new CCodeIdentifier ("self");
1907                                 }
1908                         }
1909
1910                         if (acc.readable) {
1911                                 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
1912                                 vcall.add_argument (new CCodeIdentifier ("self"));
1913
1914                                 // check if vfunc pointer is properly set
1915                                 ccode.open_if (vcall.call);
1916
1917                                 if (returns_real_struct) {
1918                                         vcall.add_argument (new CCodeIdentifier ("result"));
1919                                         ccode.add_expression (vcall);
1920                                 } else {
1921                                         if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1922                                                 var array_type = (ArrayType) acc.value_type;
1923
1924                                                 for (int dim = 1; dim <= array_type.rank; dim++) {
1925                                                         var len_expr = new CCodeIdentifier (get_array_length_cname ("result", dim));
1926                                                         vcall.add_argument (len_expr);
1927                                                 }
1928                                         } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1929                                                 vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("result")));
1930                                         }
1931
1932                                         ccode.add_return (vcall);
1933                                 }
1934                                 ccode.close ();
1935
1936                                 if (acc.value_type.is_non_null_simple_type () && default_value_for_type (acc.value_type, false) == null) {
1937                                         ccode.add_return (new CCodeIdentifier ("result"));
1938                                 } else if (!(acc.value_type is VoidType)) {
1939                                         ccode.add_return (default_value_for_type (acc.value_type, false, true));
1940                                 }
1941                         } else {
1942                                 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
1943                                 vcall.add_argument (new CCodeIdentifier ("self"));
1944                                 vcall.add_argument (new CCodeIdentifier ("value"));
1945
1946                                 // check if vfunc pointer is properly set
1947                                 ccode.open_if (vcall.call);
1948
1949                                 if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
1950                                         var array_type = (ArrayType) acc.value_type;
1951
1952                                         for (int dim = 1; dim <= array_type.rank; dim++) {
1953                                                 var len_expr = new CCodeIdentifier (get_array_length_cname ("value", dim));
1954                                                 vcall.add_argument (len_expr);
1955                                         }
1956                                 } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
1957                                         vcall.add_argument (new CCodeIdentifier (get_delegate_target_cname ("value")));
1958                                         if (!acc.readable && acc.value_type.value_owned) {
1959                                                 vcall.add_argument (new CCodeIdentifier (get_delegate_target_destroy_notify_cname ("value")));
1960                                         }
1961                                 }
1962
1963                                 ccode.add_expression (vcall);
1964                                 ccode.close ();
1965                         }
1966
1967                         pop_function ();
1968
1969                         cfile.add_function (function);
1970                 }
1971
1972                 if (!prop.is_abstract && acc.body != null) {
1973                         bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
1974
1975                         string cname = get_ccode_real_name (acc);
1976
1977                         CCodeFunction function;
1978                         if (acc.writable || acc.construction || returns_real_struct) {
1979                                 function = new CCodeFunction (cname, "void");
1980                         } else {
1981                                 function = new CCodeFunction (cname, get_ccode_name (acc.value_type));
1982                         }
1983
1984                         ObjectType base_type = null;
1985                         if (prop.binding == MemberBinding.INSTANCE) {
1986                                 if (is_virtual) {
1987                                         if (prop.base_property != null) {
1988                                                 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
1989                                         } else if (prop.base_interface_property != null) {
1990                                                 base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
1991                                         }
1992                                         function.modifiers |= CCodeModifiers.STATIC;
1993                                         function.add_parameter (new CCodeParameter ("base", get_ccode_name (base_type)));
1994                                 } else {
1995                                         function.add_parameter (cselfparam);
1996                                 }
1997                         }
1998                         if (acc.writable || acc.construction || returns_real_struct) {
1999                                 function.add_parameter (cvalueparam);
2000                         }
2001
2002                         if (acc.value_type is ArrayType && get_ccode_array_length (prop)) {
2003                                 var array_type = (ArrayType) acc.value_type;
2004                                 var length_ctype = get_ccode_array_length_type (prop);
2005                                 for (int dim = 1; dim <= array_type.rank; dim++) {
2006                                         function.add_parameter (new CCodeParameter (get_array_length_cname (acc.readable ? "result" : "value", dim), acc.readable ? length_ctype + "*" : length_ctype));
2007                                 }
2008                         } else if ((acc.value_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) acc.value_type).delegate_symbol.has_target) {
2009                                 function.add_parameter (new CCodeParameter (get_delegate_target_cname (acc.readable ? "result" : "value"), acc.readable ? get_ccode_name (delegate_target_type) + "*" : get_ccode_name (delegate_target_type)));
2010                                 if (!acc.readable && acc.value_type.value_owned) {
2011                                         function.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), get_ccode_name (delegate_target_destroy_type)));
2012                                 }
2013                         }
2014
2015                         if (!is_virtual) {
2016                                 if (prop.is_private_symbol () || !(acc.readable || acc.writable) || acc.access == SymbolAccessibility.PRIVATE) {
2017                                         // accessor function should be private if the property is an internal symbol or it's a construct-only setter
2018                                         function.modifiers |= CCodeModifiers.STATIC;
2019                                 } else if (context.hide_internal && (prop.is_internal_symbol () || acc.access == SymbolAccessibility.INTERNAL)) {
2020                                         function.modifiers |= CCodeModifiers.INTERNAL;
2021                                 }
2022                         }
2023
2024                         push_function (function);
2025
2026                         if (prop.binding == MemberBinding.INSTANCE && !is_virtual) {
2027                                 if (!acc.readable || returns_real_struct) {
2028                                         create_property_type_check_statement (prop, false, t, true, "self");
2029                                 } else {
2030                                         create_property_type_check_statement (prop, true, t, true, "self");
2031                                 }
2032                         }
2033
2034                         if (acc.readable && !returns_real_struct) {
2035                                 // do not declare result variable if exit block is known to be unreachable
2036                                 if (acc.return_block == null || acc.return_block.get_predecessors ().size > 0) {
2037                                         ccode.add_declaration (get_ccode_name (acc.value_type), new CCodeVariableDeclarator ("result"));
2038                                 }
2039                         }
2040
2041                         if (is_virtual) {
2042                                 ccode.add_declaration (get_ccode_name (this_type), new CCodeVariableDeclarator ("self"));
2043                                 ccode.add_assignment (new CCodeIdentifier ("self"), get_cvalue_ (transform_value (new GLibValue (base_type, new CCodeIdentifier ("base"), true), this_type, acc)));
2044                         }
2045
2046                         // notify on property changes
2047                         if (context.analyzer.is_gobject_property (prop) &&
2048                             prop.notify &&
2049                             (acc.writable || acc.construction)) {
2050                                 var notify_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_notify_by_pspec"));
2051                                 notify_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
2052                                 notify_call.add_argument (get_param_spec_cexpression (prop));
2053
2054                                 var get_accessor = prop.get_accessor;
2055                                 if (get_accessor != null && get_accessor.automatic_body) {
2056                                         var property_type = prop.property_type;
2057                                         var get_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (get_accessor)));
2058                                         get_call.add_argument (new CCodeIdentifier (is_virtual ? "base" : "self"));
2059
2060                                         if (property_type is ArrayType && get_ccode_array_length (prop)) {
2061                                                 ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2062                                                 ccode.add_declaration (get_ccode_array_length_type (prop), new CCodeVariableDeclarator ("old_value_length"));
2063                                                 get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value_length")));
2064                                                 ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2065                                                 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("old_value"), new CCodeIdentifier ("value")));
2066                                         } else if (property_type.compatible (string_type)) {
2067                                                 ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2068                                                 ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2069                                                 CCodeFunctionCall ccall;
2070                                                 if (context.profile == Profile.POSIX) {
2071                                                         cfile.add_include ("string.h");
2072                                                         ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
2073                                                 } else {
2074                                                         ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
2075                                                 }
2076                                                 ccall.add_argument (new CCodeIdentifier ("value"));
2077                                                 ccall.add_argument (new CCodeIdentifier ("old_value"));
2078                                                 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("0")));
2079                                         } else if (property_type is StructValueType) {
2080                                                 ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2081                                                 if (property_type.nullable) {
2082                                                         ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2083                                                 } else {
2084                                                         get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value")));
2085                                                         ccode.add_expression (get_call);
2086                                                 }
2087                                                 var equalfunc = generate_struct_equal_function ((Struct) property_type.type_symbol);
2088                                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
2089                                                 ccall.add_argument (new CCodeIdentifier ("value"));
2090                                                 if (property_type.nullable) {
2091                                                         ccall.add_argument (new CCodeIdentifier ("old_value"));
2092                                                 } else {
2093                                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value")));
2094                                                 }
2095                                                 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("TRUE")));
2096                                         } else {
2097                                                 ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
2098                                                 ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
2099                                                 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("old_value"), new CCodeIdentifier ("value")));
2100                                         }
2101
2102                                         acc.body.emit (this);
2103                                         ccode.add_expression (notify_call);
2104                                         ccode.close ();
2105
2106                                         if (prop.get_accessor.value_type.is_disposable ()) {
2107                                                 var old_value = new GLibValue (prop.get_accessor.value_type, new CCodeIdentifier ("old_value"), true);
2108                                                 if (property_type is ArrayType && get_ccode_array_length (prop)) {
2109                                                         old_value.append_array_length_cvalue (new CCodeIdentifier ("old_value_length"));
2110                                                 }
2111                                                 ccode.add_expression (destroy_value (old_value));
2112                                         }
2113                                 } else {
2114                                         acc.body.emit (this);
2115                                         ccode.add_expression (notify_call);
2116                                 }
2117                         } else {
2118                                 acc.body.emit (this);
2119                         }
2120
2121                         if (current_method_inner_error) {
2122                                 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
2123                         }
2124
2125                         pop_function ();
2126
2127                         cfile.add_function (function);
2128                 }
2129
2130                 pop_line ();
2131                 pop_context ();
2132         }
2133
2134         public override void visit_destructor (Destructor d) {
2135                 if (d.binding == MemberBinding.STATIC && !in_plugin) {
2136                         Report.error (d.source_reference, "static destructors are only supported for dynamic types");
2137                         d.error = true;
2138                         return;
2139                 }
2140         }
2141
2142         public int get_block_id (Block b) {
2143                 int result = block_map[b];
2144                 if (result == 0) {
2145                         result = ++next_block_id;
2146                         block_map[b] = result;
2147                 }
2148                 return result;
2149         }
2150
2151         public bool no_implicit_copy (DataType type) {
2152                 // note: implicit copy of array is planned to be forbidden
2153                 unowned Class? cl = type.type_symbol as Class;
2154                 return (type is DelegateType ||
2155                                 type is ArrayType ||
2156                                 (cl != null && !cl.is_immutable && !is_reference_counting (cl) && !get_ccode_is_gboxed (cl)));
2157         }
2158
2159         void capture_parameter (Parameter param, CCodeStruct data, int block_id) {
2160                 generate_type_declaration (param.variable_type, cfile);
2161
2162                 var param_type = param.variable_type.copy ();
2163                 if (!param.variable_type.value_owned) {
2164                         param_type.value_owned = !no_implicit_copy (param.variable_type);
2165                 }
2166                 data.add_field (get_ccode_name (param_type), get_ccode_name (param), 0, get_ccode_declarator_suffix (param_type));
2167
2168                 // create copy if necessary as captured variables may need to be kept alive
2169                 param.captured = false;
2170                 var value = load_parameter (param);
2171
2172                 var array_type = param.variable_type as ArrayType;
2173                 var deleg_type = param.variable_type as DelegateType;
2174
2175                 if (array_type != null && get_ccode_array_length (param) && !((ArrayType) array_type).fixed_length) {
2176                         var length_ctype = get_ccode_array_length_type (param);
2177                         for (int dim = 1; dim <= array_type.rank; dim++) {
2178                                 data.add_field (length_ctype, get_variable_array_length_cname (param, dim));
2179                         }
2180                 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
2181                         data.add_field (get_ccode_name (delegate_target_type), get_ccode_delegate_target_name (param));
2182                         if (param.variable_type.is_disposable ()) {
2183                                 data.add_field (get_ccode_name (delegate_target_destroy_type), get_ccode_delegate_target_destroy_notify_name (param));
2184                                 // reference transfer for delegates
2185                                 var lvalue = get_parameter_cvalue (param);
2186                                 ((GLibValue) value).delegate_target_destroy_notify_cvalue = get_delegate_target_destroy_notify_cvalue (lvalue);
2187                         }
2188                 }
2189                 param.captured = true;
2190
2191                 store_parameter (param, value, true);
2192         }
2193
2194         public override void visit_block (Block b) {
2195                 emit_context.push_symbol (b);
2196
2197                 var local_vars = b.get_local_variables ();
2198
2199                 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
2200                         ccode.open_block ();
2201                 }
2202
2203                 if (b.parent_node is TryStatement && b == ((TryStatement) b.parent_node).finally_body) {
2204                         // finally-block with nested error handling
2205                         if (((TryStatement) b.parent_node).body.tree_can_fail) {
2206                                 if (is_in_coroutine ()) {
2207                                         // _inner_error0_ gets added to closure_struct in CCodeMethodModule.visit_method()
2208                                         if (current_inner_error_id > 0
2209                                             && (!method_inner_error_var_count.contains (current_method)
2210                                             || method_inner_error_var_count.get (current_method) < current_inner_error_id)) {
2211                                                 // no initialization necessary, closure struct is zeroed
2212                                                 closure_struct.add_field ("GError*", "_inner_error%d_".printf (current_inner_error_id));
2213                                                 method_inner_error_var_count.set (current_method, current_inner_error_id);
2214                                         }
2215                                 } else {
2216                                         ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
2217                                 }
2218                         }
2219                 }
2220
2221                 if (b.captured) {
2222                         var parent_block = next_closure_block (b.parent_symbol);
2223
2224                         int block_id = get_block_id (b);
2225                         string struct_name = "Block%dData".printf (block_id);
2226
2227                         var data = new CCodeStruct ("_" + struct_name);
2228                         data.add_field ("int", "_ref_count_");
2229                         if (parent_block != null) {
2230                                 int parent_block_id = get_block_id (parent_block);
2231
2232                                 data.add_field ("Block%dData *".printf (parent_block_id), "_data%d_".printf (parent_block_id));
2233                         } else {
2234                                 unowned DataType? this_type = get_this_type ();
2235                                 if (this_type != null) {
2236                                         data.add_field (get_ccode_name (this_type), "self");
2237                                 }
2238
2239                                 if (current_method != null) {
2240                                         // allow capturing generic type parameters
2241                                         foreach (var type_param in current_method.get_type_parameters ()) {
2242                                                 data.add_field ("GType", get_ccode_type_id (type_param));
2243                                                 data.add_field ("GBoxedCopyFunc", get_ccode_copy_function (type_param));
2244                                                 data.add_field ("GDestroyNotify", get_ccode_destroy_function (type_param));
2245                                         }
2246                                 }
2247                         }
2248                         foreach (var local in local_vars) {
2249                                 if (local.captured) {
2250                                         generate_type_declaration (local.variable_type, cfile);
2251
2252                                         data.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
2253
2254                                         if (local.variable_type is ArrayType && !((ArrayType) local.variable_type).fixed_length) {
2255                                                 var array_type = (ArrayType) local.variable_type;
2256                                                 var length_ctype = get_ccode_array_length_type (array_type);
2257                                                 for (int dim = 1; dim <= array_type.rank; dim++) {
2258                                                         data.add_field (length_ctype, get_array_length_cname (get_local_cname (local), dim));
2259                                                 }
2260                                                 data.add_field (length_ctype, get_array_size_cname (get_local_cname (local)));
2261                                         } else if (local.variable_type is DelegateType && ((DelegateType) local.variable_type).delegate_symbol.has_target) {
2262                                                 data.add_field (get_ccode_name (delegate_target_type), get_delegate_target_cname (get_local_cname (local)));
2263                                                 if (local.variable_type.is_disposable ()) {
2264                                                         data.add_field (get_ccode_name (delegate_target_destroy_type), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2265                                                 }
2266                                         } else if (local.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
2267                                                 Report.error (local.source_reference, "internal: Capturing `va_list' variable `%s' is not allowed", local.get_full_name ());
2268                                                 b.error = true;
2269                                         }
2270                                 }
2271                         }
2272
2273                         var data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
2274                         data_alloc.add_argument (new CCodeIdentifier (struct_name));
2275
2276                         if (is_in_coroutine ()) {
2277                                 closure_struct.add_field (struct_name + "*", "_data%d_".printf (block_id));
2278                         } else {
2279                                 ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id)));
2280                         }
2281                         ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), data_alloc);
2282
2283                         // initialize ref_count
2284                         ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_ref_count_"), new CCodeIdentifier ("1"));
2285
2286                         if (parent_block != null) {
2287                                 int parent_block_id = get_block_id (parent_block);
2288
2289                                 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (parent_block_id)));
2290                                 ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id)));
2291
2292                                 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call);
2293                         } else {
2294                                 // skip self assignment in toplevel block of creation methods with chainup as self is not set at the beginning of the method
2295                                 // the chainup statement takes care of assigning self in the closure struct
2296                                 bool in_creation_method_with_chainup = (current_method is CreationMethod && current_class != null && current_class.base_class != null);
2297
2298                                 unowned DataType? this_type = get_this_type ();
2299                                 if (this_type != null && (!in_creation_method_with_chainup || current_method.body != b)) {
2300                                         CCodeExpression instance;
2301                                         if (is_in_destructor ()) {
2302                                                 // never increase reference count for self in finalizers to avoid infinite recursion on following unref
2303                                                 instance = new CCodeIdentifier ("self");
2304                                         } else {
2305                                                 var ref_call = new CCodeFunctionCall (get_dup_func_expression (this_type, b.source_reference));
2306                                                 ref_call.add_argument (get_this_cexpression ());
2307                                                 instance = ref_call;
2308                                         }
2309
2310                                         ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "self"), instance);
2311                                 }
2312
2313                                 if (current_method != null) {
2314                                         // allow capturing generic type parameters
2315                                         var data_var = get_variable_cexpression ("_data%d_".printf (block_id));
2316                                         foreach (var type_param in current_method.get_type_parameters ()) {
2317                                                 var type = get_ccode_type_id (type_param);
2318                                                 var dup_func = get_ccode_copy_function (type_param);
2319                                                 var destroy_func = get_ccode_destroy_function (type_param);
2320                                                 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, type), get_variable_cexpression (type));
2321                                                 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, dup_func), get_variable_cexpression (dup_func));
2322                                                 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, destroy_func), get_variable_cexpression (destroy_func));
2323                                         }
2324                                 }
2325                         }
2326
2327                         if (b.parent_symbol is Method) {
2328                                 var m = (Method) b.parent_symbol;
2329
2330                                 // parameters are captured with the top-level block of the method
2331                                 foreach (var param in m.get_parameters ()) {
2332                                         if (param.captured) {
2333                                                 capture_parameter (param, data, block_id);
2334
2335                                                 if (param.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
2336                                                         Report.error (param.source_reference, "internal: Capturing `va_list' parameter `%s' is not allowed", param.get_full_name ());
2337                                                         b.error = true;
2338                                                 }
2339                                         }
2340                                 }
2341
2342                                 if (m.coroutine) {
2343                                         // capture async data to allow invoking callback from inside closure
2344                                         data.add_field (get_ccode_name (pointer_type), "_async_data_");
2345
2346                                         // async method is suspended while waiting for callback,
2347                                         // so we never need to care about memory management of async data
2348                                         ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_async_data_"), new CCodeIdentifier ("_data_"));
2349                                 }
2350                         } else if (b.parent_symbol is PropertyAccessor) {
2351                                 var acc = (PropertyAccessor) b.parent_symbol;
2352
2353                                 if (!acc.readable && acc.value_parameter.captured) {
2354                                         capture_parameter (acc.value_parameter, data, block_id);
2355                                 }
2356                         } else if (b.parent_symbol is ForeachStatement) {
2357                                 var stmt = (ForeachStatement) b.parent_symbol;
2358                                 if (!stmt.use_iterator && stmt.element_variable.captured) {
2359                                         ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_local_cname (stmt.element_variable)), get_variable_cexpression (get_local_cname (stmt.element_variable)));
2360                                 }
2361                         }
2362
2363                         var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name));
2364                         cfile.add_type_declaration (typedef);
2365                         cfile.add_type_definition (data);
2366
2367                         // create ref/unref functions
2368                         var ref_fun = new CCodeFunction ("block%d_data_ref".printf (block_id), struct_name + "*");
2369                         ref_fun.add_parameter (new CCodeParameter ("_data%d_".printf (block_id), struct_name + "*"));
2370                         ref_fun.modifiers = CCodeModifiers.STATIC;
2371
2372                         push_function (ref_fun);
2373
2374                         var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_inc"));
2375                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2376                         ccode.add_expression (ccall);
2377                         ccode.add_return (new CCodeIdentifier ("_data%d_".printf (block_id)));
2378
2379                         pop_function ();
2380
2381                         cfile.add_function_declaration (ref_fun);
2382                         cfile.add_function (ref_fun);
2383
2384                         var unref_fun = new CCodeFunction ("block%d_data_unref".printf (block_id), "void");
2385                         unref_fun.add_parameter (new CCodeParameter ("_userdata_", "void *"));
2386                         unref_fun.modifiers = CCodeModifiers.STATIC;
2387
2388                         push_function (unref_fun);
2389
2390                         ccode.add_declaration (struct_name + "*", new CCodeVariableDeclarator ("_data%d_".printf (block_id), new CCodeCastExpression (new CCodeIdentifier ("_userdata_"), struct_name + "*")));
2391                         ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_dec_and_test"));
2392                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_ref_count_")));
2393                         ccode.open_if (ccall);
2394
2395                         CCodeExpression outer_block = new CCodeIdentifier ("_data%d_".printf (block_id));
2396                         unowned Block parent_closure_block = b;
2397                         while (true) {
2398                                 parent_closure_block = next_closure_block (parent_closure_block.parent_symbol);
2399                                 if (parent_closure_block == null) {
2400                                         break;
2401                                 }
2402                                 int parent_block_id = get_block_id (parent_closure_block);
2403                                 outer_block = new CCodeMemberAccess.pointer (outer_block, "_data%d_".printf (parent_block_id));
2404                         }
2405
2406                         var this_type = get_this_type ();
2407                         if (this_type != null) {
2408                                 // assign "self" for type parameters
2409                                 ccode.add_declaration(get_ccode_name (this_type), new CCodeVariableDeclarator ("self"));
2410                                 ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeMemberAccess.pointer (outer_block, "self"));
2411                         }
2412
2413                         if (current_method != null) {
2414                                 // assign captured generic type parameters
2415                                 foreach (var type_param in current_method.get_type_parameters ()) {
2416                                         var type = get_ccode_type_id (type_param);
2417                                         var dup_func = get_ccode_copy_function (type_param);
2418                                         var destroy_func = get_ccode_destroy_function (type_param);
2419                                         ccode.add_declaration ("GType", new CCodeVariableDeclarator (type));
2420                                         ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (dup_func));
2421                                         ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (destroy_func));
2422                                         ccode.add_assignment (new CCodeIdentifier (type), new CCodeMemberAccess.pointer (outer_block, type));
2423                                         ccode.add_assignment (new CCodeIdentifier (dup_func), new CCodeMemberAccess.pointer (outer_block, dup_func));
2424                                         ccode.add_assignment (new CCodeIdentifier (destroy_func), new CCodeMemberAccess.pointer (outer_block, destroy_func));
2425                                 }
2426                         }
2427
2428                         // free in reverse order
2429                         for (int i = local_vars.size - 1; i >= 0; i--) {
2430                                 var local = local_vars[i];
2431                                 if (local.captured) {
2432                                         if (requires_destroy (local.variable_type)) {
2433                                                 bool old_coroutine = false;
2434                                                 if (current_method != null) {
2435                                                         old_coroutine = current_method.coroutine;
2436                                                         current_method.coroutine = false;
2437                                                 }
2438
2439                                                 ccode.add_expression (destroy_local (local));
2440
2441                                                 if (old_coroutine) {
2442                                                         current_method.coroutine = true;
2443                                                 }
2444                                         }
2445                                 }
2446                         }
2447
2448                         if (b.parent_symbol is Method) {
2449                                 var m = (Method) b.parent_symbol;
2450
2451                                 // parameters are captured with the top-level block of the method
2452                                 foreach (var param in m.get_parameters ()) {
2453                                         if (param.captured) {
2454                                                 var param_type = param.variable_type.copy ();
2455                                                 if (!param_type.value_owned) {
2456                                                         param_type.value_owned = !no_implicit_copy (param_type);
2457                                                 }
2458
2459                                                 if (requires_destroy (param_type)) {
2460                                                         bool old_coroutine = false;
2461                                                         if (m != null) {
2462                                                                 old_coroutine = m.coroutine;
2463                                                                 m.coroutine = false;
2464                                                         }
2465
2466                                                         ccode.add_expression (destroy_parameter (param));
2467
2468                                                         if (old_coroutine) {
2469                                                                 m.coroutine = true;
2470                                                         }
2471                                                 }
2472                                         }
2473                                 }
2474                         } else if (b.parent_symbol is PropertyAccessor) {
2475                                 var acc = (PropertyAccessor) b.parent_symbol;
2476
2477                                 if (!acc.readable && acc.value_parameter.captured) {
2478                                         var param_type = acc.value_parameter.variable_type.copy ();
2479                                         if (!param_type.value_owned) {
2480                                                 param_type.value_owned = !no_implicit_copy (param_type);
2481                                         }
2482
2483                                         if (requires_destroy (param_type)) {
2484                                                 ccode.add_expression (destroy_parameter (acc.value_parameter));
2485                                         }
2486                                 }
2487                         }
2488
2489                         // free parent block and "self" after captured variables
2490                         // because they may require type parameters
2491                         if (parent_block != null) {
2492                                 int parent_block_id = get_block_id (parent_block);
2493
2494                                 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (parent_block_id)));
2495                                 unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
2496                                 ccode.add_expression (unref_call);
2497                                 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), new CCodeConstant ("NULL"));
2498                         } else {
2499                                 this_type = get_this_type ();
2500                                 if (this_type != null) {
2501                                         this_type = this_type.copy ();
2502                                         this_type.value_owned = true;
2503                                         if (this_type.is_disposable () && !is_in_destructor ()) {
2504                                                 // reference count for self is not increased in finalizers
2505                                                 var this_value = new GLibValue (this_type, new CCodeIdentifier ("self"), true);
2506                                                 ccode.add_expression (destroy_value (this_value));
2507                                         }
2508                                 }
2509                         }
2510
2511                         var data_free = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
2512                         data_free.add_argument (new CCodeIdentifier (struct_name));
2513                         data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id)));
2514                         ccode.add_expression (data_free);
2515
2516                         ccode.close ();
2517
2518                         pop_function ();
2519
2520                         cfile.add_function_declaration (unref_fun);
2521                         cfile.add_function (unref_fun);
2522                 }
2523
2524                 foreach (Statement stmt in b.get_statements ()) {
2525                         push_line (stmt.source_reference);
2526                         stmt.emit (this);
2527                         pop_line ();
2528                 }
2529
2530                 if (!b.unreachable_exit) {
2531                         if (b.parent_symbol is Method) {
2532                                 unowned Method m = (Method) b.parent_symbol;
2533                                 // check postconditions
2534                                 foreach (var postcondition in m.get_postconditions ()) {
2535                                         create_postcondition_statement (postcondition);
2536                                 }
2537                         }
2538
2539                         // free in reverse order
2540                         for (int i = local_vars.size - 1; i >= 0; i--) {
2541                                 var local = local_vars[i];
2542                                 local.active = false;
2543                                 if (!local.unreachable && !local.captured && requires_destroy (local.variable_type)) {
2544                                         ccode.add_expression (destroy_local (local));
2545                                 }
2546                         }
2547
2548                         if (b.parent_symbol is Method) {
2549                                 var m = (Method) b.parent_symbol;
2550                                 foreach (Parameter param in m.get_parameters ()) {
2551                                         if (!param.captured && !param.ellipsis && !param.params_array && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
2552                                                 ccode.add_expression (destroy_parameter (param));
2553                                         } else if (param.direction == ParameterDirection.OUT && !m.coroutine) {
2554                                                 return_out_parameter (param);
2555                                         }
2556                                 }
2557                         } else if (b.parent_symbol is PropertyAccessor) {
2558                                 var acc = (PropertyAccessor) b.parent_symbol;
2559                                 if (acc.value_parameter != null && !acc.value_parameter.captured && requires_destroy (acc.value_parameter.variable_type)) {
2560                                         ccode.add_expression (destroy_parameter (acc.value_parameter));
2561                                 }
2562                         }
2563
2564                         if (b.captured) {
2565                                 int block_id = get_block_id (b);
2566
2567                                 var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
2568                                 data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
2569                                 ccode.add_expression (data_unref);
2570                                 ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
2571                         }
2572                 }
2573
2574                 if (b.parent_node is Block || b.parent_node is SwitchStatement || b.parent_node is TryStatement) {
2575                         ccode.close ();
2576                 }
2577
2578                 emit_context.pop_symbol ();
2579         }
2580
2581         public override void visit_declaration_statement (DeclarationStatement stmt) {
2582                 stmt.declaration.accept (this);
2583         }
2584
2585         public CCodeExpression get_cexpression (string name) {
2586                 if (is_in_coroutine ()) {
2587                         return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), name);
2588                 } else {
2589                         return new CCodeIdentifier (name);
2590                 }
2591         }
2592
2593         public CCodeExpression get_local_cexpression (LocalVariable local) {
2594                 return get_cexpression (get_local_cname (local));
2595         }
2596
2597         public CCodeExpression get_parameter_cexpression (Parameter param) {
2598                 return get_cexpression (get_ccode_name (param));
2599         }
2600
2601         public CCodeExpression get_variable_cexpression (string name) {
2602                 return get_cexpression (get_variable_cname (name));
2603         }
2604
2605         public CCodeExpression get_this_cexpression () {
2606                 return get_cexpression ("self");
2607         }
2608
2609         public CCodeExpression get_this_class_cexpression (Class cl, TargetValue? instance = null) {
2610                 CCodeExpression cast;
2611                 CCodeFunctionCall call;
2612                 if (instance != null) {
2613                         // Accessing the member of an instance
2614                         if (cl.external_package) {
2615                                 call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_CLASS"));
2616                                 call.add_argument (get_cvalue_ (instance));
2617                                 call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
2618                                 call.add_argument (new CCodeIdentifier (get_ccode_type_name (cl)));
2619                         } else {
2620                                 call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
2621                                 call.add_argument (get_cvalue_ (instance));
2622                         }
2623                         cast = call;
2624                 } else if (get_this_type () != null) {
2625                         // Accessing the member from within an instance method
2626                         if (cl.external_package) {
2627                                 call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_CLASS"));
2628                                 call.add_argument (get_this_cexpression ());
2629                                 call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
2630                                 call.add_argument (new CCodeIdentifier (get_ccode_type_name (cl)));
2631                         } else {
2632                                 call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
2633                                 call.add_argument (get_this_cexpression ());
2634                         }
2635                         cast = call;
2636                 } else {
2637                         // Accessing the member from a static or class constructor
2638                         if (current_class == cl) {
2639                                 cast = new CCodeIdentifier ("klass");
2640                         } else {
2641                                 call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (cl)));
2642                                 call.add_argument (new CCodeIdentifier ("klass"));
2643                                 cast = call;
2644                         }
2645                 }
2646                 return cast;
2647         }
2648
2649         public CCodeExpression get_this_interface_cexpression (Interface iface, TargetValue? instance = null) {
2650                 unowned Class? cl = current_class;
2651                 if (cl != null && cl.implements (iface)) {
2652                         return new CCodeIdentifier ("%s_%s_parent_iface".printf (get_ccode_lower_case_name (cl), get_ccode_lower_case_name (iface)));
2653                 }
2654
2655                 if (cl != null && !cl.is_a (iface)) {
2656                         Report.warning (cl.source_reference, "internal: `%s' is not a `%s'", cl.get_full_name (), iface.get_full_name ());
2657                 }
2658
2659                 CCodeExpression cast;
2660                 CCodeFunctionCall call;
2661                 if (instance != null) {
2662                         if (iface.external_package) {
2663                                 call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_INTERFACE"));
2664                                 call.add_argument (get_cvalue_ (instance));
2665                                 call.add_argument (new CCodeIdentifier (get_ccode_type_id (iface)));
2666                                 call.add_argument (new CCodeIdentifier (get_ccode_type_name (iface)));
2667                         } else {
2668                                 call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
2669                                 call.add_argument (get_cvalue_ (instance));
2670                         }
2671                         cast = call;
2672                 } else if (get_this_type () != null) {
2673                         if (iface.external_package) {
2674                                 call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_INSTANCE_GET_INTERFACE"));
2675                                 call.add_argument (get_this_cexpression ());
2676                                 call.add_argument (new CCodeIdentifier (get_ccode_type_id (iface)));
2677                                 call.add_argument (new CCodeIdentifier (get_ccode_type_name (iface)));
2678                         } else {
2679                                 call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
2680                                 call.add_argument (get_this_cexpression ());
2681                         }
2682                         cast = call;
2683                 } else {
2684                         Report.error (null, "internal: missing instance");
2685                         cast = null;
2686                         assert_not_reached ();
2687                 }
2688                 return cast;
2689         }
2690
2691         public CCodeExpression get_inner_error_cexpression () {
2692                 return get_cexpression ("_inner_error%d_".printf (current_inner_error_id));
2693         }
2694
2695         public string get_local_cname (LocalVariable local) {
2696                 var cname = get_variable_cname (local.name);
2697                 if (cname[0].isdigit ()) {
2698                         cname = "_%s_".printf (cname);
2699                 }
2700                 if (is_in_coroutine ()) {
2701                         var clash_index = emit_context.closure_variable_clash_map.get (local);
2702                         if (clash_index > 0) {
2703                                 cname = "_vala%d_%s".printf (clash_index, cname);
2704                         }
2705                 }
2706                 return cname;
2707         }
2708
2709         public string get_variable_cname (string name) {
2710                 if (name[0] == '.') {
2711                         if (name == ".result") {
2712                                 return "result";
2713                         }
2714                         // compiler-internal variable
2715                         if (!variable_name_map.contains (name)) {
2716                                 variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
2717                                 next_temp_var_id++;
2718                         }
2719                         return variable_name_map.get (name);
2720                 } else if (reserved_identifiers.contains (name)) {
2721                         return "_%s_".printf (name);
2722                 } else {
2723                         return name;
2724                 }
2725         }
2726
2727         public bool is_simple_struct_creation (Variable variable, Expression expr) {
2728                 unowned Struct? st = variable.variable_type.type_symbol as Struct;
2729                 var creation = expr as ObjectCreationExpression;
2730                 if (creation != null && st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list") && !variable.variable_type.nullable &&
2731                     variable.variable_type.type_symbol != gvalue_type && creation.get_object_initializer ().size == 0) {
2732                         return true;
2733                 } else {
2734                         return false;
2735                 }
2736         }
2737
2738         static bool is_foreach_element_variable (LocalVariable local) {
2739                 var block = local.parent_symbol;
2740                 if (block != null) {
2741                         var stmt = block.parent_symbol as ForeachStatement;
2742                         if (stmt != null && !stmt.use_iterator && stmt.element_variable == local) {
2743                                 return true;
2744                         }
2745                 }
2746                 return false;
2747         }
2748
2749         public override void visit_local_variable (LocalVariable local) {
2750                 /* Declaration */
2751
2752                 generate_type_declaration (local.variable_type, cfile);
2753
2754                 // captured element variables of foreach statements (without iterator) require local declaration
2755                 var declared = !local.captured || is_foreach_element_variable (local);
2756                 if (declared) {
2757                         if (is_in_coroutine ()) {
2758                                 var count = emit_context.closure_variable_count_map.get (local.name);
2759                                 if (count > 0) {
2760                                         emit_context.closure_variable_clash_map.set (local, count);
2761                                 }
2762                                 emit_context.closure_variable_count_map.set (local.name, count + 1);
2763
2764                                 closure_struct.add_field (get_ccode_name (local.variable_type), get_local_cname (local), 0, get_ccode_declarator_suffix (local.variable_type));
2765                         } else {
2766                                 var cvar = new CCodeVariableDeclarator (get_local_cname (local), null, get_ccode_declarator_suffix (local.variable_type));
2767
2768                                 // try to initialize uninitialized variables
2769                                 // initialization not necessary for variables stored in closure
2770                                 CCodeExpression? size = null;
2771                                 if (!requires_memset_init (local, out size)) {
2772                                         cvar.initializer = default_value_for_type (local.variable_type, true);
2773                                         cvar.init0 = true;
2774                                 } else if (size != null && local.initializer == null) {
2775                                         cfile.add_include ("string.h");
2776                                         var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
2777                                         memset_call.add_argument (get_variable_cexpression (local.name));
2778                                         memset_call.add_argument (new CCodeConstant ("0"));
2779                                         memset_call.add_argument (size);
2780                                         ccode.add_expression (memset_call);
2781                                 }
2782
2783                                 ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
2784                         }
2785                 }
2786
2787                 /* Emit initializer */
2788                 if (local.initializer != null) {
2789                         local.initializer.emit (this);
2790
2791                         visit_end_full_expression (local.initializer);
2792                 }
2793
2794
2795                 CCodeExpression rhs = null;
2796                 if (local.initializer != null && get_cvalue (local.initializer) != null) {
2797                         rhs = get_cvalue (local.initializer);
2798                 }
2799
2800                 /* Additional temp variables */
2801
2802                 if (declared) {
2803                         if (local.variable_type is ArrayType) {
2804                                 // create variables to store array dimensions
2805                                 var array_type = (ArrayType) local.variable_type;
2806
2807                                 if (!array_type.fixed_length) {
2808                                         for (int dim = 1; dim <= array_type.rank; dim++) {
2809                                                 var len_var = new LocalVariable (array_type.length_type.copy (), get_array_length_cname (get_local_cname (local), dim));
2810                                                 len_var.init = local.initializer == null;
2811                                                 emit_temp_var (len_var);
2812                                         }
2813
2814                                         if (array_type.rank == 1) {
2815                                                 var size_var = new LocalVariable (array_type.length_type.copy (), get_array_size_cname (get_local_cname (local)));
2816                                                 size_var.init = local.initializer == null;
2817                                                 emit_temp_var (size_var);
2818                                         }
2819                                 }
2820                         } else if (local.variable_type is DelegateType) {
2821                                 var deleg_type = (DelegateType) local.variable_type;
2822                                 if (deleg_type.delegate_symbol.has_target) {
2823                                         // create variable to store delegate target
2824                                         var target_var = new LocalVariable (delegate_target_type.copy (), get_delegate_target_cname (get_local_cname (local)));
2825                                         target_var.init = local.initializer == null;
2826                                         emit_temp_var (target_var);
2827                                         if (deleg_type.is_disposable ()) {
2828                                                 var target_destroy_notify_var = new LocalVariable (delegate_target_destroy_type.copy (), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
2829                                                 target_destroy_notify_var.init = local.initializer == null;
2830                                                 emit_temp_var (target_destroy_notify_var);
2831                                         }
2832                                 }
2833                         }
2834                 }
2835
2836                 /* Store the initializer */
2837
2838                 if (rhs != null) {
2839                         if (!is_simple_struct_creation (local, local.initializer)) {
2840                                 store_local (local, local.initializer.target_value, true, local.source_reference);
2841                         }
2842                 }
2843
2844                 if (local.initializer != null && local.initializer.tree_can_fail) {
2845                         add_simple_check (local.initializer);
2846                 }
2847
2848                 local.active = true;
2849         }
2850
2851         /**
2852          * Create a temporary variable and return lvalue access to it
2853          */
2854         public TargetValue create_temp_value (DataType type, bool init, CodeNode node_reference, bool? value_owned = null) {
2855                 if (type is VoidType) {
2856                         Report.error (node_reference.source_reference, "internal: 'void' not supported as variable type");
2857                 }
2858
2859                 var local = new LocalVariable (type.copy (), "_tmp%d_".printf (next_temp_var_id++), null, node_reference.source_reference);
2860                 local.init = init;
2861                 if (value_owned != null) {
2862                         local.variable_type.value_owned = value_owned;
2863                 }
2864
2865                 var array_type = local.variable_type as ArrayType;
2866                 var deleg_type = local.variable_type as DelegateType;
2867
2868                 emit_temp_var (local);
2869                 if (array_type != null) {
2870                         for (int dim = 1; dim <= array_type.rank; dim++) {
2871                                 var len_var = new LocalVariable (array_type.length_type.copy (), get_array_length_cname (local.name, dim), null, node_reference.source_reference);
2872                                 len_var.init = init;
2873                                 emit_temp_var (len_var);
2874                         }
2875                 } else if (deleg_type != null && deleg_type.delegate_symbol.has_target) {
2876                         var target_var = new LocalVariable (delegate_target_type.copy (), get_delegate_target_cname (local.name), null, node_reference.source_reference);
2877                         target_var.init = init;
2878                         emit_temp_var (target_var);
2879                         if (deleg_type.is_disposable ()) {
2880                                 var target_destroy_notify_var = new LocalVariable (delegate_target_destroy_type.copy (), get_delegate_target_destroy_notify_cname (local.name), null, node_reference.source_reference);
2881                                 target_destroy_notify_var.init = init;
2882                                 emit_temp_var (target_destroy_notify_var);
2883                         }
2884                 }
2885
2886                 var value = get_local_cvalue (local);
2887                 set_array_size_cvalue (value, null);
2888                 return value;
2889         }
2890
2891         /**
2892          * Load a temporary variable returning unowned or owned rvalue access to it, depending on the ownership of the value type.
2893          */
2894         public TargetValue load_temp_value (TargetValue lvalue) {
2895                 var value = ((GLibValue) lvalue).copy ();
2896                 var deleg_type = value.value_type as DelegateType;
2897                 if (deleg_type != null) {
2898                         if (!deleg_type.delegate_symbol.has_target) {
2899                                 value.delegate_target_cvalue = new CCodeConstant ("NULL");
2900                                 ((GLibValue) value).lvalue = false;
2901                         } else if (!deleg_type.is_disposable ()) {
2902                                 value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
2903                                 ((GLibValue) value).lvalue = false;
2904                         }
2905                 }
2906                 return value;
2907         }
2908
2909         /**
2910          * Store a value in a temporary variable and return unowned or owned rvalue access to it, depending on the ownership of the given type.
2911          */
2912         public TargetValue store_temp_value (TargetValue initializer, CodeNode node_reference, bool? value_owned = null) {
2913                 var lvalue = create_temp_value (initializer.value_type, false, node_reference, value_owned);
2914                 store_value (lvalue, initializer, node_reference.source_reference);
2915                 return load_temp_value (lvalue);
2916         }
2917
2918         public override void visit_initializer_list (InitializerList list) {
2919                 if (list.target_type.type_symbol is Struct) {
2920                         /* initializer is used as struct initializer */
2921                         unowned Struct st = (Struct) list.target_type.type_symbol;
2922                         while (st.base_struct != null) {
2923                                 st = st.base_struct;
2924                         }
2925
2926                         if (list.parent_node is Constant || list.parent_node is Field || list.parent_node is InitializerList) {
2927                                 var clist = new CCodeInitializerList ();
2928
2929                                 var field_it = st.get_fields ().iterator ();
2930                                 foreach (Expression expr in list.get_initializers ()) {
2931                                         Field field = null;
2932                                         while (field == null) {
2933                                                 field_it.next ();
2934                                                 field = field_it.get ();
2935                                                 if (field.binding != MemberBinding.INSTANCE) {
2936                                                         // we only initialize instance fields
2937                                                         field = null;
2938                                                 }
2939                                         }
2940
2941                                         var cexpr = get_cvalue (expr);
2942
2943                                         string ctype = get_ccode_type (field);
2944                                         if (ctype != null) {
2945                                                 cexpr = new CCodeCastExpression (cexpr, ctype);
2946                                         }
2947
2948                                         clist.append (cexpr);
2949
2950                                         var array_type = field.variable_type as ArrayType;
2951                                         if (array_type != null && !array_type.fixed_length && get_ccode_array_length (field) && !get_ccode_array_null_terminated (field)) {
2952                                                 for (int dim = 1; dim <= array_type.rank; dim++) {
2953                                                         clist.append (get_array_length_cvalue (expr.target_value, dim));
2954                                                 }
2955                                                 if (array_type.rank == 1 && field.is_internal_symbol ()) {
2956                                                         clist.append (get_array_length_cvalue (expr.target_value, 1));
2957                                                 }
2958                                         }
2959                                 }
2960
2961                                 if (list.size <= 0) {
2962                                         clist.append (new CCodeConstant ("0"));
2963                                 }
2964
2965                                 if (list.parent_node is Constant
2966                                     || (list.parent_node is Expression && ((Expression) list.parent_node).value_type is ArrayType)) {
2967                                         set_cvalue (list, clist);
2968                                 } else {
2969                                         set_cvalue (list, new CCodeCastExpression (clist, get_ccode_name (list.target_type.type_symbol)));
2970                                 }
2971                         } else {
2972                                 // used as expression
2973                                 var instance = create_temp_value (list.value_type, true, list);
2974
2975                                 var field_it = st.get_fields ().iterator ();
2976                                 foreach (Expression expr in list.get_initializers ()) {
2977                                         Field field = null;
2978                                         while (field == null) {
2979                                                 field_it.next ();
2980                                                 field = field_it.get ();
2981                                                 if (field.binding != MemberBinding.INSTANCE) {
2982                                                         // we only initialize instance fields
2983                                                         field = null;
2984                                                 }
2985                                         }
2986
2987                                         store_field (field, instance, expr.target_value, expr.source_reference);
2988                                 }
2989
2990                                 list.target_value = instance;
2991                         }
2992                 } else {
2993                         var clist = new CCodeInitializerList ();
2994                         foreach (Expression expr in list.get_initializers ()) {
2995                                 clist.append (get_cvalue (expr));
2996                         }
2997                         set_cvalue (list, clist);
2998                 }
2999         }
3000
3001         public LocalVariable get_temp_variable (DataType type, bool value_owned = true, CodeNode? node_reference = null, bool init = false) {
3002                 var var_type = type.copy ();
3003                 var_type.value_owned = value_owned;
3004                 var local = new LocalVariable (var_type, "_tmp%d_".printf (next_temp_var_id));
3005                 local.init = init;
3006
3007                 if (node_reference != null) {
3008                         local.source_reference = node_reference.source_reference;
3009                 }
3010
3011                 next_temp_var_id++;
3012
3013                 return local;
3014         }
3015
3016         bool is_in_generic_type (GenericType type) {
3017                 if (current_symbol != null && type.type_parameter.parent_symbol is TypeSymbol
3018                     && (current_method == null || current_method.binding == MemberBinding.INSTANCE)) {
3019                         return true;
3020                 } else {
3021                         return false;
3022                 }
3023         }
3024
3025         void require_generic_accessors (Interface iface) {
3026                 if (iface.get_attribute ("GenericAccessors") == null) {
3027                         Report.error (iface.source_reference,
3028                                       "missing generic type for interface `%s', add GenericAccessors attribute to interface declaration",
3029                                       iface.get_full_name ());
3030                 }
3031         }
3032
3033         CCodeExpression get_generic_type_expression (string identifier, GenericType type, bool is_chainup = false) {
3034                 if (type.type_parameter.parent_symbol is Interface) {
3035                         unowned Interface iface = (Interface) type.type_parameter.parent_symbol;
3036                         require_generic_accessors (iface);
3037
3038                         var cast_self = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
3039                         cast_self.add_argument (get_this_cexpression ());
3040                         var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, "get_%s".printf (identifier)));
3041                         function_call.add_argument (get_this_cexpression ());
3042                         return function_call;
3043                 }
3044
3045                 if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
3046                         return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_this_cexpression (), "priv"), identifier);
3047                 } else {
3048                         return get_variable_cexpression (identifier);
3049                 }
3050         }
3051
3052         public CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
3053                 if (type is GenericType) {
3054                         var type_parameter = ((GenericType) type).type_parameter;
3055                         string identifier = get_ccode_type_id (type_parameter);
3056                         return get_generic_type_expression (identifier, (GenericType) type, is_chainup);
3057                 } else {
3058                         string type_id = get_ccode_type_id (type);
3059                         if (type_id == "") {
3060                                 type_id = "G_TYPE_INVALID";
3061                         } else {
3062                                 generate_type_declaration (type, cfile);
3063                         }
3064                         return new CCodeIdentifier (type_id);
3065                 }
3066         }
3067
3068         public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup = false) {
3069                 if (type is ErrorType) {
3070                         return new CCodeIdentifier ("g_error_copy");
3071                 } else if (type is GenericType) {
3072                         var type_parameter = ((GenericType) type).type_parameter;
3073                         string identifier = get_ccode_copy_function (type_parameter);
3074                         return get_generic_type_expression (identifier, (GenericType) type, is_chainup);
3075                 } else if (type.type_symbol != null) {
3076                         string dup_function;
3077                         unowned Class? cl = type.type_symbol as Class;
3078                         if (is_reference_counting (type.type_symbol)) {
3079                                 dup_function = get_ccode_ref_function ((ObjectTypeSymbol) type.type_symbol);
3080                                 if (type.type_symbol is Interface && dup_function == null) {
3081                                         Report.error (source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure", type.type_symbol.get_full_name ());
3082                                         return new CCodeInvalidExpression();
3083                                 }
3084                         } else if (cl != null && cl.is_immutable) {
3085                                 // allow duplicates of immutable instances as for example strings
3086                                 dup_function = get_ccode_dup_function (type.type_symbol);
3087                                 if (dup_function == null) {
3088                                         dup_function = "";
3089                                 }
3090                         } else if (get_ccode_is_gboxed (type.type_symbol)) {
3091                                 // allow duplicates of gboxed instances
3092                                 dup_function = generate_dup_func_wrapper (type);
3093                                 if (dup_function == null) {
3094                                         dup_function = "";
3095                                 }
3096                         } else if (type is ValueType) {
3097                                 dup_function = get_ccode_dup_function (type.type_symbol);
3098                                 if (dup_function == null && type.nullable) {
3099                                         dup_function = generate_struct_dup_wrapper ((ValueType) type);
3100                                 } else if (dup_function == null) {
3101                                         dup_function = "";
3102                                 }
3103                         } else {
3104                                 // duplicating non-reference counted objects may cause side-effects (and performance issues)
3105                                 Report.error (source_reference, "duplicating `%s' instance, use unowned variable or explicitly invoke copy method", type.type_symbol.name);
3106                                 return new CCodeInvalidExpression();
3107                         }
3108
3109                         return new CCodeIdentifier (dup_function);
3110                 } else if (type is PointerType) {
3111                         var pointer_type = (PointerType) type;
3112                         return get_dup_func_expression (pointer_type.base_type, source_reference);
3113                 } else {
3114                         return new CCodeConstant ("NULL");
3115                 }
3116         }
3117
3118         void make_comparable_cexpression (ref DataType left_type, ref CCodeExpression cleft, ref DataType right_type, ref CCodeExpression cright) {
3119                 unowned Struct? left_type_as_struct = left_type.type_symbol as Struct;
3120                 unowned Struct? right_type_as_struct = right_type.type_symbol as Struct;
3121                 unowned ObjectTypeSymbol? left_type_as_object_type = left_type.type_symbol as ObjectTypeSymbol;
3122                 unowned ObjectTypeSymbol? right_type_as_object_type = right_type.type_symbol as ObjectTypeSymbol;
3123
3124                 if (left_type_as_object_type != null && (!(left_type_as_object_type is Class) || !((Class) left_type_as_object_type).is_compact)
3125                     && right_type_as_object_type != null && (!(right_type_as_object_type is Class) || !((Class) right_type_as_object_type).is_compact)) {
3126                         if (left_type_as_object_type != right_type_as_object_type) {
3127                                 if (left_type_as_object_type.is_subtype_of (right_type_as_object_type)) {
3128                                         cleft = generate_instance_cast (cleft, right_type_as_object_type);
3129                                 } else if (right_type_as_object_type.is_subtype_of (left_type_as_object_type)) {
3130                                         cright = generate_instance_cast (cright, left_type_as_object_type);
3131                                 }
3132                         }
3133                 } else if (left_type_as_struct != null && right_type_as_struct != null) {
3134                         if (left_type is StructValueType) {
3135                                 // real structs (uses compare/equal function)
3136                                 if (!left_type.nullable) {
3137                                         cleft = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft);
3138                                 }
3139                                 if (!right_type.nullable) {
3140                                         cright = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cright);
3141                                 }
3142                         } else {
3143                                 // integer or floating or boolean type
3144                                 if (left_type.nullable && right_type.nullable) {
3145                                         // FIXME also compare contents, not just address
3146                                 } else if (left_type.nullable) {
3147                                         // FIXME check left value is not null
3148                                         cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
3149                                 } else if (right_type.nullable) {
3150                                         // FIXME check right value is not null
3151                                         cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
3152                                 }
3153                         }
3154                 }
3155         }
3156
3157         private string generate_struct_equal_function (Struct st) {
3158                 if (st.base_struct != null) {
3159                         return generate_struct_equal_function (st.base_struct);
3160                 }
3161
3162                 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (st));
3163
3164                 if (!add_wrapper (equal_func)) {
3165                         // wrapper already defined
3166                         return equal_func;
3167                 }
3168
3169                 var function = new CCodeFunction (equal_func, get_ccode_name (bool_type));
3170                 function.modifiers = CCodeModifiers.STATIC;
3171
3172                 function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (st))));
3173                 function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (st))));
3174
3175                 push_function (function);
3176
3177                 // if (s1 == s2) return TRUE;
3178                 {
3179                         var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
3180                         ccode.open_if (cexp);
3181                         ccode.add_return (get_boolean_cconstant (true));
3182                         ccode.close ();
3183                 }
3184                 // if (s1 == NULL || s2 == NULL) return FALSE;
3185                 {
3186                         var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
3187                         ccode.open_if (cexp);
3188                         ccode.add_return (get_boolean_cconstant (false));
3189                         ccode.close ();
3190
3191                         cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
3192                         ccode.open_if (cexp);
3193                         ccode.add_return (get_boolean_cconstant (false));
3194                         ccode.close ();
3195                 }
3196
3197                 bool has_instance_fields = false;
3198                 foreach (Field f in st.get_fields ()) {
3199                         if (f.binding != MemberBinding.INSTANCE) {
3200                                 // we only compare instance fields
3201                                 continue;
3202                         }
3203
3204                         has_instance_fields = true;
3205
3206                         CCodeExpression cexp; // if (cexp) return FALSE;
3207                         var s1 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s1"), get_ccode_name (f)); // s1->f
3208                         var s2 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s2"), get_ccode_name (f)); // s2->f
3209
3210                         var variable_type = f.variable_type.copy ();
3211                         make_comparable_cexpression (ref variable_type, ref s1, ref variable_type, ref s2);
3212
3213                         if (!(f.variable_type is NullType) && f.variable_type.compatible (string_type)) {
3214                                 CCodeFunctionCall ccall;
3215                                 if (context.profile == Profile.POSIX) {
3216                                         cfile.add_include ("string.h");
3217                                         ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
3218                                 } else {
3219                                         ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
3220                                 }
3221                                 ccall.add_argument (s1);
3222                                 ccall.add_argument (s2);
3223                                 cexp = ccall;
3224                         } else if (f.variable_type is StructValueType) {
3225                                 var equalfunc = generate_struct_equal_function (f.variable_type.type_symbol as Struct);
3226                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
3227                                 ccall.add_argument (s1);
3228                                 ccall.add_argument (s2);
3229                                 cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
3230                         } else {
3231                                 cexp = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, s1, s2);
3232                         }
3233
3234                         ccode.open_if (cexp);
3235                         ccode.add_return (get_boolean_cconstant (false));
3236                         ccode.close ();
3237                 }
3238
3239                 if (!has_instance_fields) {
3240                         // either opaque structure or simple type
3241                         if (st.is_simple_type ()) {
3242                                 var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
3243                                 ccode.add_return (cexp);
3244                         } else {
3245                                 ccode.add_return (get_boolean_cconstant (false));
3246                         }
3247                 } else {
3248                         ccode.add_return (get_boolean_cconstant (true));
3249                 }
3250
3251                 pop_function ();
3252
3253                 cfile.add_function_declaration (function);
3254                 cfile.add_function (function);
3255
3256                 return equal_func;
3257         }
3258
3259         private string generate_numeric_equal_function (TypeSymbol sym) {
3260                 string equal_func = "_%sequal".printf (get_ccode_lower_case_prefix (sym));
3261
3262                 if (!add_wrapper (equal_func)) {
3263                         // wrapper already defined
3264                         return equal_func;
3265                 }
3266
3267                 var function = new CCodeFunction (equal_func, get_ccode_name (bool_type));
3268                 function.modifiers = CCodeModifiers.STATIC;
3269
3270                 function.add_parameter (new CCodeParameter ("s1", "const %s *".printf (get_ccode_name (sym))));
3271                 function.add_parameter (new CCodeParameter ("s2", "const %s *".printf (get_ccode_name (sym))));
3272
3273                 push_function (function);
3274
3275                 // if (s1 == s2) return TRUE;
3276                 {
3277                         var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
3278                         ccode.open_if (cexp);
3279                         ccode.add_return (get_boolean_cconstant (true));
3280                         ccode.close ();
3281                 }
3282                 // if (s1 == NULL || s2 == NULL) return FALSE;
3283                 {
3284                         var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
3285                         ccode.open_if (cexp);
3286                         ccode.add_return (get_boolean_cconstant (false));
3287                         ccode.close ();
3288
3289                         cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
3290                         ccode.open_if (cexp);
3291                         ccode.add_return (get_boolean_cconstant (false));
3292                         ccode.close ();
3293                 }
3294                 // return (*s1 == *s2);
3295                 {
3296                         var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s1")), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("s2")));
3297                         ccode.add_return (cexp);
3298                 }
3299
3300                 pop_function ();
3301
3302                 cfile.add_function_declaration (function);
3303                 cfile.add_function (function);
3304
3305                 return equal_func;
3306         }
3307
3308         private string generate_struct_dup_wrapper (ValueType value_type) {
3309                 string dup_func = "_%sdup".printf (get_ccode_lower_case_prefix (value_type.type_symbol));
3310
3311                 if (!add_wrapper (dup_func)) {
3312                         // wrapper already defined
3313                         return dup_func;
3314                 }
3315
3316                 var function = new CCodeFunction (dup_func, get_ccode_name (value_type));
3317                 function.modifiers = CCodeModifiers.STATIC;
3318
3319                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (value_type)));
3320
3321                 push_function (function);
3322
3323                 if (value_type.type_symbol == gvalue_type) {
3324                         var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
3325                         dup_call.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
3326                         dup_call.add_argument (new CCodeIdentifier ("self"));
3327
3328                         ccode.add_return (dup_call);
3329                 } else {
3330                         ccode.add_declaration (get_ccode_name (value_type), new CCodeVariableDeclarator ("dup"));
3331
3332                         CCodeFunctionCall creation_call;
3333                         if (context.profile == Profile.POSIX) {
3334                                 cfile.add_include ("stdlib.h");
3335                                 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
3336                                 creation_call.add_argument (new CCodeConstant ("1"));
3337                                 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
3338                                 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (value_type.type_symbol)));
3339                                 creation_call.add_argument (csizeof);
3340                         } else {
3341                                 cfile.add_include ("glib.h");
3342                                 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
3343                                 creation_call.add_argument (new CCodeIdentifier (get_ccode_name (value_type.type_symbol)));
3344                                 creation_call.add_argument (new CCodeConstant ("1"));
3345                         }
3346                         ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
3347
3348                         var st = value_type.type_symbol as Struct;
3349                         if (st != null && st.is_disposable ()) {
3350                                 if (!get_ccode_has_copy_function (st)) {
3351                                         generate_struct_copy_function (st);
3352                                 }
3353
3354                                 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
3355                                 copy_call.add_argument (new CCodeIdentifier ("self"));
3356                                 copy_call.add_argument (new CCodeIdentifier ("dup"));
3357                                 ccode.add_expression (copy_call);
3358                         } else {
3359                                 cfile.add_include ("string.h");
3360
3361                                 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
3362                                 sizeof_call.add_argument (new CCodeConstant (get_ccode_name (value_type.type_symbol)));
3363
3364                                 var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
3365                                 copy_call.add_argument (new CCodeIdentifier ("dup"));
3366                                 copy_call.add_argument (new CCodeIdentifier ("self"));
3367                                 copy_call.add_argument (sizeof_call);
3368                                 ccode.add_expression (copy_call);
3369                         }
3370
3371                         ccode.add_return (new CCodeIdentifier ("dup"));
3372                 }
3373
3374                 pop_function ();
3375
3376                 cfile.add_function_declaration (function);
3377                 cfile.add_function (function);
3378
3379                 return dup_func;
3380         }
3381
3382         protected string generate_dup_func_wrapper (DataType type) {
3383                 string destroy_func = "_vala_%s_copy".printf (get_ccode_name (type.type_symbol));
3384
3385                 if (!add_wrapper (destroy_func)) {
3386                         // wrapper already defined
3387                         return destroy_func;
3388                 }
3389
3390                 var function = new CCodeFunction (destroy_func, get_ccode_name (type));
3391                 function.modifiers = CCodeModifiers.STATIC;
3392                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3393
3394                 push_function (function);
3395
3396                 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_copy"));
3397                 free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (type.type_symbol)));
3398                 free_call.add_argument (new CCodeIdentifier ("self"));
3399
3400                 ccode.add_return (free_call);
3401
3402                 pop_function ();
3403
3404                 cfile.add_function_declaration (function);
3405                 cfile.add_function (function);
3406
3407                 return destroy_func;
3408         }
3409
3410         protected string generate_free_function_address_of_wrapper (DataType type) {
3411                 string destroy_func = "_vala_%s_free_function_address_of".printf (get_ccode_name (type.type_symbol));
3412
3413                 if (!add_wrapper (destroy_func)) {
3414                         // wrapper already defined
3415                         return destroy_func;
3416                 }
3417
3418                 var function = new CCodeFunction (destroy_func, "void");
3419                 function.modifiers = CCodeModifiers.STATIC;
3420                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3421
3422                 push_function (function);
3423
3424                 unowned Class? cl = type.type_symbol as Class;
3425                 assert (cl != null);
3426
3427                 var free_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (cl)));
3428                 free_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("self")));
3429
3430                 ccode.add_expression (free_call);
3431
3432                 pop_function ();
3433
3434                 cfile.add_function_declaration (function);
3435                 cfile.add_function (function);
3436
3437                 return destroy_func;
3438         }
3439
3440         protected string generate_destroy_function_content_of_wrapper (DataType type) {
3441                 // g_array_set_clear_func has a specific GDestroyNotify where the content of an element is given
3442                 string destroy_func = "_vala_%s_free_function_content_of".printf (get_ccode_name (type.type_symbol));
3443
3444                 if (!add_wrapper (destroy_func)) {
3445                         // wrapper already defined
3446                         return destroy_func;
3447                 }
3448
3449                 var function = new CCodeFunction (destroy_func, "void");
3450                 function.modifiers = CCodeModifiers.STATIC;
3451                 function.add_parameter (new CCodeParameter ("data", get_ccode_name (pointer_type)));
3452                 push_function (function);
3453
3454                 ccode.add_declaration (get_ccode_name (type), new CCodeVariableDeclarator ("self"));
3455                 var cast = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeCastExpression (new CCodeIdentifier ("data"), get_ccode_name (type) + "*"));
3456                 ccode.add_assignment (new CCodeIdentifier ("self"), cast);
3457
3458                 var free_call = new CCodeFunctionCall (get_destroy0_func_expression (type));
3459                 free_call.add_argument (new CCodeIdentifier ("self"));
3460
3461                 ccode.add_expression (free_call);
3462
3463                 pop_function ();
3464
3465                 cfile.add_function_declaration (function);
3466                 cfile.add_function (function);
3467
3468                 return destroy_func;
3469         }
3470
3471         protected string generate_free_func_wrapper (DataType type) {
3472                 string destroy_func = "_vala_%s_free".printf (get_ccode_name (type.type_symbol));
3473
3474                 if (!add_wrapper (destroy_func)) {
3475                         // wrapper already defined
3476                         return destroy_func;
3477                 }
3478
3479                 var function = new CCodeFunction (destroy_func, "void");
3480                 function.modifiers = CCodeModifiers.STATIC;
3481                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
3482
3483                 push_function (function);
3484
3485                 if (get_ccode_is_gboxed (type.type_symbol) || (gvalue_type != null && type.type_symbol == gvalue_type)) {
3486                         var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_free"));
3487                         free_call.add_argument (new CCodeIdentifier (get_ccode_type_id (type.type_symbol)));
3488                         free_call.add_argument (new CCodeIdentifier ("self"));
3489
3490                         ccode.add_expression (free_call);
3491                 } else {
3492                         unowned Struct? st = type.type_symbol as Struct;
3493                         if (st != null && st.is_disposable ()) {
3494                                 if (!get_ccode_has_destroy_function (st)) {
3495                                         generate_struct_destroy_function (st);
3496                                 }
3497
3498                                 var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (st)));
3499                                 destroy_call.add_argument (new CCodeIdentifier ("self"));
3500                                 ccode.add_expression (destroy_call);
3501                         }
3502
3503                         CCodeFunctionCall free_call;
3504                         if (context.profile == Profile.POSIX) {
3505                                 cfile.add_include ("stdlib.h");
3506                                 free_call = new CCodeFunctionCall (new CCodeIdentifier ("free"));
3507                         } else {
3508                                 cfile.add_include ("glib.h");
3509                                 free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
3510                         }
3511                         free_call.add_argument (new CCodeIdentifier ("self"));
3512
3513                         ccode.add_expression (free_call);
3514                 }
3515
3516                 pop_function ();
3517
3518                 cfile.add_function_declaration (function);
3519                 cfile.add_function (function);
3520
3521                 return destroy_func;
3522         }
3523
3524         public CCodeExpression? get_destroy0_func_expression (DataType type, bool is_chainup = false) {
3525                 var element_destroy_func_expression = get_destroy_func_expression (type, is_chainup);
3526
3527                 if (!(type is GenericType) && element_destroy_func_expression is CCodeIdentifier) {
3528                         var freeid = (CCodeIdentifier) element_destroy_func_expression;
3529                         string free0_func = "_%s0_".printf (freeid.name);
3530
3531                         if (add_wrapper (free0_func)) {
3532                                 var function = new CCodeFunction (free0_func, "void");
3533                                 function.modifiers = CCodeModifiers.STATIC;
3534
3535                                 function.add_parameter (new CCodeParameter ("var", get_ccode_name (pointer_type)));
3536
3537                                 push_function (function);
3538
3539                                 ccode.add_expression (destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true));
3540
3541                                 pop_function ();
3542
3543                                 cfile.add_function_declaration (function);
3544                                 cfile.add_function (function);
3545                         }
3546
3547                         element_destroy_func_expression = new CCodeIdentifier (free0_func);
3548                 }
3549
3550                 return element_destroy_func_expression;
3551         }
3552
3553         public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
3554                 if (context.profile == Profile.GOBJECT && (type.type_symbol == glist_type || type.type_symbol == gslist_type || type.type_symbol == gnode_type || type.type_symbol == gqueue_type)) {
3555                         // create wrapper function to free list elements if necessary
3556
3557                         bool elements_require_free = false;
3558                         bool generic_elements = false;
3559                         CCodeExpression element_destroy_func_expression = null;
3560
3561                         foreach (DataType type_arg in type.get_type_arguments ()) {
3562                                 elements_require_free = requires_destroy (type_arg);
3563                                 if (elements_require_free) {
3564                                         element_destroy_func_expression = get_destroy0_func_expression (type_arg);
3565                                         generic_elements = (type_arg is GenericType);
3566                                 }
3567                         }
3568
3569                         if (elements_require_free) {
3570                                 CCodeExpression? cexpr = null;
3571                                 if (element_destroy_func_expression is CCodeIdentifier || element_destroy_func_expression is CCodeMemberAccess) {
3572                                         cexpr = new CCodeIdentifier (generate_collection_free_wrapper (type, (generic_elements ? null : element_destroy_func_expression as CCodeIdentifier)));
3573                                         if (generic_elements) {
3574                                                 // adding second argument early, instance parameter will be inserted by destroy_value()
3575                                                 cexpr = new CCodeFunctionCall (cexpr);
3576                                                 ((CCodeFunctionCall) cexpr).add_argument (element_destroy_func_expression);
3577                                         }
3578                                 } else {
3579                                         Report.error (null, "internal error: No useable element_destroy_function found");
3580                                 }
3581                                 return cexpr;
3582                         } else {
3583                                 return new CCodeIdentifier (get_ccode_free_function (type.type_symbol));
3584                         }
3585                 } else if (type is ErrorType) {
3586                         cfile.add_include ("glib.h");
3587                         return new CCodeIdentifier ("g_error_free");
3588                 } else if (type is GenericType) {
3589                         var type_parameter = ((GenericType) type).type_parameter;
3590                         string identifier = get_ccode_destroy_function (type_parameter);
3591                         return get_generic_type_expression (identifier, (GenericType) type, is_chainup);
3592                 } else if (type.type_symbol != null) {
3593                         string unref_function;
3594                         if (type is ReferenceType) {
3595                                 if (is_reference_counting (type.type_symbol)) {
3596                                         unref_function = get_ccode_unref_function ((ObjectTypeSymbol) type.type_symbol);
3597                                         if (type.type_symbol is Interface && unref_function == null) {
3598                                                 Report.error (type.source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure", type.type_symbol.get_full_name ());
3599                                                 return null;
3600                                         }
3601                                 } else {
3602                                         if (get_ccode_is_gboxed (type.type_symbol)) {
3603                                                 unref_function = generate_free_func_wrapper (type);
3604                                         } else {
3605                                                 if (is_free_function_address_of (type)) {
3606                                                         unref_function = generate_free_function_address_of_wrapper (type);
3607                                                 } else {
3608                                                         unref_function = get_ccode_free_function (type.type_symbol);
3609                                                 }
3610                                         }
3611                                 }
3612                         } else {
3613                                 if (type.nullable) {
3614                                         if (get_ccode_is_gboxed (type.type_symbol)) {
3615                                                 unref_function = generate_free_func_wrapper (type);
3616                                         } else {
3617                                                 unref_function = get_ccode_free_function (type.type_symbol);
3618                                         }
3619                                         if (unref_function == null) {
3620                                                 if (type.type_symbol is Struct && ((Struct) type.type_symbol).is_disposable ()) {
3621                                                         unref_function = generate_free_func_wrapper (type);
3622                                                 } else {
3623                                                         if (context.profile == Profile.POSIX) {
3624                                                                 cfile.add_include ("stdlib.h");
3625                                                                 unref_function = "free";
3626                                                         } else {
3627                                                                 cfile.add_include ("glib.h");
3628                                                                 unref_function = "g_free";
3629                                                         }
3630                                                 }
3631                                         }
3632                                 } else if (type is EnumValueType) {
3633                                         unref_function = null;
3634                                 } else {
3635                                         unowned Struct? st = type.type_symbol as Struct;
3636                                         if (st != null && st.is_disposable ()) {
3637                                                 if (!get_ccode_has_destroy_function (st)) {
3638                                                         generate_struct_destroy_function (st);
3639                                                 }
3640                                                 unref_function = get_ccode_destroy_function (st);
3641                                         } else {
3642                                                 unref_function = null;
3643                                         }
3644                                 }
3645                         }
3646                         if (unref_function == null) {
3647                                 return new CCodeConstant ("NULL");
3648                         }
3649                         return new CCodeIdentifier (unref_function);
3650                 } else if (type is ArrayType) {
3651                         if (context.profile == Profile.POSIX) {
3652                                 cfile.add_include ("stdlib.h");
3653                                 return new CCodeIdentifier ("free");
3654                         } else {
3655                                 cfile.add_include ("glib.h");
3656                                 return new CCodeIdentifier ("g_free");
3657                         }
3658                 } else if (type is PointerType) {
3659                         if (context.profile == Profile.POSIX) {
3660                                 cfile.add_include ("stdlib.h");
3661                                 return new CCodeIdentifier ("free");
3662                         } else {
3663                                 cfile.add_include ("glib.h");
3664                                 return new CCodeIdentifier ("g_free");
3665                         }
3666                 } else {
3667                         return new CCodeConstant ("NULL");
3668                 }
3669         }
3670
3671         private string generate_collection_free_wrapper (DataType collection_type, CCodeIdentifier? element_destroy_func_expression) {
3672                 string destroy_func;
3673
3674                 string? destroy_func_wrapper = null;
3675                 if (element_destroy_func_expression != null) {
3676                         destroy_func_wrapper = "_%s_%s".printf (get_ccode_free_function (collection_type.type_symbol), element_destroy_func_expression.name);
3677                         if (!add_wrapper (destroy_func_wrapper)) {
3678                                 // wrapper already defined
3679                                 return destroy_func_wrapper;
3680                         }
3681                 }
3682
3683                 if (collection_type.type_symbol == gnode_type) {
3684                         destroy_func = "_g_node_free_all";
3685                         if (!add_wrapper (destroy_func)) {
3686                                 // wrapper already defined
3687                                 return destroy_func;
3688                         }
3689
3690                         var function = new CCodeFunction (destroy_func, "void");
3691                         function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3692                         function.add_parameter (new CCodeParameter ("free_func", "GDestroyNotify"));
3693
3694                         push_function (function);
3695
3696                         CCodeFunctionCall element_free_call;
3697                         string destroy_node_func = "%s_node".printf (destroy_func);
3698                         var wrapper = new CCodeFunction (destroy_node_func, get_ccode_name (bool_type));
3699                         wrapper.modifiers = CCodeModifiers.STATIC;
3700                         wrapper.add_parameter (new CCodeParameter ("node", get_ccode_name (collection_type)));
3701                         wrapper.add_parameter (new CCodeParameter ("free_func", "GDestroyNotify"));
3702                         push_function (wrapper);
3703
3704                         var free_call = new CCodeFunctionCall (new CCodeIdentifier ("free_func"));
3705                         free_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier("node"), "data"));
3706
3707                         var data_isnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeMemberAccess.pointer (new CCodeIdentifier("node"), "data"), new CCodeConstant ("NULL"));
3708                         var ccomma_data = new CCodeCommaExpression ();
3709                         ccomma_data.append_expression (new CCodeConditionalExpression (data_isnull, new CCodeConstant ("NULL"), free_call));
3710                         ccode.add_expression (ccomma_data);
3711
3712                         ccode.add_return (new CCodeConstant ("FALSE"));
3713
3714                         pop_function ();
3715                         cfile.add_function_declaration (wrapper);
3716                         cfile.add_function (wrapper);
3717
3718                         /* Now the code to call g_traverse with the above */
3719                         element_free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_node_traverse"));
3720                         element_free_call.add_argument (new CCodeIdentifier("self"));
3721                         element_free_call.add_argument (new CCodeConstant ("G_POST_ORDER"));
3722                         element_free_call.add_argument (new CCodeConstant ("G_TRAVERSE_ALL"));
3723                         element_free_call.add_argument (new CCodeConstant ("-1"));
3724                         element_free_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (destroy_node_func), "GNodeTraverseFunc"));
3725                         element_free_call.add_argument (new CCodeIdentifier ("free_func"));
3726
3727                         var free_func_isnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("free_func"), new CCodeConstant ("NULL"));
3728                         var ccomma = new CCodeCommaExpression ();
3729                         ccomma.append_expression (new CCodeConditionalExpression (free_func_isnull, new CCodeConstant ("NULL"), element_free_call));
3730
3731                         ccode.add_expression (ccomma);
3732
3733                         var cfreecall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_free_function (gnode_type)));
3734                         cfreecall.add_argument (new CCodeIdentifier ("self"));
3735                         ccode.add_expression (cfreecall);
3736
3737                         function.modifiers = CCodeModifiers.STATIC;
3738                         pop_function ();
3739
3740                         cfile.add_function_declaration (function);
3741                         cfile.add_function (function);
3742                 } else if (collection_type.type_symbol == glist_type) {
3743                         destroy_func = "g_list_free_full";
3744                 } else if (collection_type.type_symbol == gslist_type) {
3745                         destroy_func = "g_slist_free_full";
3746                 } else if (collection_type.type_symbol == gqueue_type) {
3747                         destroy_func = "g_queue_free_full";
3748                 } else {
3749                         Report.error (null, "internal error: type of collection not supported");
3750                         return "";
3751                 }
3752
3753                 if (element_destroy_func_expression != null) {
3754                         var function = new CCodeFunction (destroy_func_wrapper, "void");
3755                         function.add_parameter (new CCodeParameter ("self", get_ccode_name (collection_type)));
3756
3757                         push_function (function);
3758
3759                         var collection_free_call = new CCodeFunctionCall (new CCodeIdentifier (destroy_func));
3760                         collection_free_call.add_argument (new CCodeIdentifier ("self"));
3761                         collection_free_call.add_argument (new CCodeCastExpression (element_destroy_func_expression, "GDestroyNotify"));
3762                         ccode.add_expression (collection_free_call);
3763
3764                         function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
3765                         pop_function ();
3766
3767                         cfile.add_function_declaration (function);
3768                         cfile.add_function (function);
3769
3770                         return destroy_func_wrapper;
3771                 }
3772
3773                 return destroy_func;
3774         }
3775
3776         public virtual string? append_struct_array_destroy (Struct st) {
3777                 return null;
3778         }
3779
3780         public virtual string? append_struct_array_free (Struct st) {
3781                 return null;
3782         }
3783
3784         public CCodeExpression destroy_local (LocalVariable local) {
3785                 return destroy_value (get_local_cvalue (local));
3786         }
3787
3788         public CCodeExpression destroy_parameter (Parameter param) {
3789                 return destroy_value (get_parameter_cvalue (param));
3790         }
3791
3792         public CCodeExpression destroy_field (Field field, TargetValue? instance) {
3793                 return destroy_value (get_field_cvalue (field, instance));
3794         }
3795
3796         public virtual CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
3797                 var type = value.value_type;
3798                 if (value.actual_value_type != null) {
3799                         type = value.actual_value_type;
3800                 }
3801                 var cvar = get_cvalue_ (value);
3802
3803                 if (type is DelegateType) {
3804                         if (context.profile != Profile.GOBJECT) {
3805                                 // Required for NULL
3806                                 cfile.add_include ("stddef.h");
3807                         }
3808
3809                         var delegate_target = get_delegate_target_cvalue (value);
3810                         var delegate_target_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
3811
3812                         var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
3813                         ccall.add_argument (delegate_target);
3814
3815                         var destroy_call = new CCodeCommaExpression ();
3816                         destroy_call.append_expression (ccall);
3817                         destroy_call.append_expression (new CCodeConstant ("NULL"));
3818
3819                         var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
3820
3821                         var ccomma = new CCodeCommaExpression ();
3822                         ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), destroy_call));
3823                         ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
3824                         ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
3825                         ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
3826
3827                         return ccomma;
3828                 }
3829
3830                 bool is_gcollection = (type.type_symbol == glist_type || type.type_symbol == gslist_type || type.type_symbol == gnode_type || type.type_symbol == gqueue_type);
3831                 CCodeFunctionCall ccall;
3832                 var cexpr = get_destroy_func_expression (type);
3833                 if (is_gcollection && cexpr is CCodeFunctionCall) {
3834                         ccall = (CCodeFunctionCall) cexpr;
3835                 } else {
3836                         ccall = new CCodeFunctionCall (cexpr);
3837                 }
3838
3839                 if (type is ValueType && !type.nullable) {
3840                         // normal value type, no null check
3841                         unowned Struct? st = type.type_symbol as Struct;
3842                         if (st != null && st.is_simple_type ()) {
3843                                 // used for va_list
3844                                 ccall.add_argument (cvar);
3845                         } else {
3846                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3847                         }
3848
3849                         if (gvalue_type != null && type.type_symbol == gvalue_type) {
3850                                 // g_value_unset must not be called for already unset values
3851                                 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
3852                                 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
3853
3854                                 var ccomma = new CCodeCommaExpression ();
3855                                 ccomma.append_expression (ccall);
3856                                 ccomma.append_expression (new CCodeConstant ("NULL"));
3857
3858                                 return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
3859                         } else if ((type.type_symbol == gmutex_type ||
3860                                     type.type_symbol == grecmutex_type ||
3861                                     type.type_symbol == grwlock_type ||
3862                                     type.type_symbol == gcond_type)) {
3863                                 // g_mutex_clear must not be called for uninitialized mutex
3864                                 // also, g_mutex_clear does not clear the struct
3865                                 requires_clear_mutex = true;
3866                                 ccall.call = new CCodeIdentifier ("_vala_clear_" + get_ccode_name (type.type_symbol));
3867                                 return ccall;
3868                         } else {
3869                                 return ccall;
3870                         }
3871                 }
3872
3873                 if (!is_gcollection && ccall.call is CCodeIdentifier && !(type is ArrayType) && !(type is GenericType) && !is_macro_definition) {
3874                         // generate and use NULL-aware free macro to simplify code
3875
3876                         var freeid = (CCodeIdentifier) ccall.call;
3877                         string free0_func = "_%s0".printf (freeid.name);
3878
3879                         if (add_wrapper (free0_func)) {
3880                                 var macro = destroy_value (new GLibValue (type, new CCodeIdentifier ("var"), true), true);
3881                                 cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("%s(var)".printf (free0_func), macro));
3882                         }
3883
3884                         // FIXME this breaks in our macro, so this should not happen
3885                         while (cvar is CCodeCastExpression) {
3886                                 cvar = ((CCodeCastExpression) cvar).inner;
3887                         }
3888                         if (cvar is CCodeFunctionCall) {
3889                                 cvar = ((CCodeFunctionCall) cvar).get_arguments ()[0];
3890                         }
3891
3892                         ccall = new CCodeFunctionCall (new CCodeIdentifier (free0_func));
3893                         ccall.add_argument (cvar);
3894                         return ccall;
3895                 }
3896
3897                 if (context.profile != Profile.GOBJECT) {
3898                         // Required for NULL
3899                         cfile.add_include ("stddef.h");
3900                 }
3901
3902                 /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
3903
3904                 /* can be simplified to
3905                  * foo = (unref (foo), NULL)
3906                  * if foo is of static type non-null
3907                  */
3908
3909                 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
3910                 if (type is GenericType) {
3911                         var parent = ((GenericType) type).type_parameter.parent_symbol;
3912                         var cl = parent as Class;
3913                         if ((!(parent is Method) && !(parent is ObjectTypeSymbol)) || (cl != null && cl.is_compact)) {
3914                                 return new CCodeConstant ("NULL");
3915                         }
3916
3917                         // unref functions are optional for type parameters
3918                         var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
3919                         cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
3920                 }
3921
3922                 // glib collections already have the free_func argument, so make sure the instance parameter gets first
3923                 ccall.insert_argument (0, cvar);
3924
3925                 /* set freed references to NULL to prevent further use */
3926                 var ccomma = new CCodeCommaExpression ();
3927
3928                 if (context.profile == Profile.GOBJECT
3929                     && type.type_symbol != null && !is_reference_counting (type.type_symbol)
3930                     && type.type_symbol.is_subtype_of (gstringbuilder_type)) {
3931                         ccall.add_argument (new CCodeConstant ("TRUE"));
3932                 } else if (context.profile == Profile.GOBJECT
3933                     && type.type_symbol == gthreadpool_type) {
3934                         ccall.add_argument (new CCodeConstant ("FALSE"));
3935                         ccall.add_argument (new CCodeConstant ("TRUE"));
3936                 } else if (type is ArrayType) {
3937                         var array_type = (ArrayType) type;
3938                         if (requires_destroy (array_type.element_type)) {
3939                                 CCodeExpression csizeexpr = null;
3940                                 if (((GLibValue) value).array_length_cvalues != null) {
3941                                         csizeexpr = get_array_length_cvalue (value);
3942                                 } else if (get_array_null_terminated (value)) {
3943                                         requires_array_length = true;
3944                                         var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
3945                                         len_call.add_argument (cvar);
3946                                         csizeexpr = len_call;
3947                                 } else {
3948                                         csizeexpr = get_array_length_cexpr (value);
3949                                 }
3950
3951                                 if (csizeexpr != null) {
3952                                         unowned Struct? st = array_type.element_type.type_symbol as Struct;
3953                                         if (st != null && !array_type.element_type.nullable) {
3954                                                 ccall.call = new CCodeIdentifier (append_struct_array_free (st));
3955                                                 ccall.add_argument (csizeexpr);
3956                                         } else {
3957                                                 requires_array_free = true;
3958                                                 generate_type_declaration (delegate_target_destroy_type, cfile);
3959
3960                                                 ccall.call = new CCodeIdentifier ("_vala_array_free");
3961                                                 ccall.add_argument (csizeexpr);
3962                                                 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), get_ccode_name (delegate_target_destroy_type)));
3963                                         }
3964                                 }
3965                         }
3966                 }
3967
3968                 ccomma.append_expression (ccall);
3969                 ccomma.append_expression (new CCodeConstant ("NULL"));
3970
3971                 var cassign = new CCodeAssignment (cvar, ccomma);
3972
3973                 // g_free (NULL) is allowed
3974                 bool uses_gfree = (type.type_symbol != null && !is_reference_counting (type.type_symbol) && get_ccode_free_function (type.type_symbol) == "g_free");
3975                 uses_gfree = uses_gfree || type is ArrayType;
3976                 if (uses_gfree) {
3977                         return cassign;
3978                 }
3979
3980                 return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
3981         }
3982
3983         public override void visit_end_full_expression (Expression expr) {
3984                 /* expr is a full expression, i.e. an initializer, the
3985                  * expression in an expression statement, the controlling
3986                  * expression in if, while, for, or foreach statements
3987                  *
3988                  * we unref temporary variables at the end of a full
3989                  * expression
3990                  */
3991                 if (temp_ref_values.size == 0) {
3992                         /* nothing to do without temporary variables */
3993                         return;
3994                 }
3995
3996                 var local_decl = expr.parent_node as LocalVariable;
3997                 if (!(local_decl != null && is_simple_struct_creation (local_decl, local_decl.initializer))) {
3998                         expr.target_value = store_temp_value (expr.target_value, expr);
3999                 }
4000
4001                 foreach (var value in temp_ref_values) {
4002                         ccode.add_expression (destroy_value (value));
4003                 }
4004
4005                 temp_ref_values.clear ();
4006         }
4007
4008         public void emit_temp_var (LocalVariable local, bool on_error = false) {
4009                 generate_type_declaration (local.variable_type, cfile);
4010
4011                 var init = (!local.name.has_prefix ("*") && local.init);
4012                 if (is_in_coroutine ()) {
4013                         closure_struct.add_field (get_ccode_name (local.variable_type), local.name, 0, get_ccode_declarator_suffix (local.variable_type));
4014
4015                         // even though closure struct is zerod, we need to initialize temporary variables
4016                         // as they might be used multiple times when declared in a loop
4017
4018                         if (init) {
4019                                 var initializer = default_value_for_type (local.variable_type, false, on_error);
4020                                 if (initializer == null) {
4021                                         cfile.add_include ("string.h");
4022                                         var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4023                                         memset_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (local.name)));
4024                                         memset_call.add_argument (new CCodeConstant ("0"));
4025                                         CCodeExpression? size = null;
4026                                         requires_memset_init (local, out size);
4027                                         if (size == null) {
4028                                                 size = new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (local.variable_type)));
4029                                         }
4030                                         memset_call.add_argument (size);
4031                                         ccode.add_expression (memset_call);
4032                                 } else {
4033                                         ccode.add_assignment (get_variable_cexpression (local.name), initializer);
4034                                 }
4035                         }
4036                 } else {
4037                         var cvar = new CCodeVariableDeclarator (local.name, null, get_ccode_declarator_suffix (local.variable_type));
4038                         CCodeExpression? size = null;
4039                         if (init && !requires_memset_init (local, out size)) {
4040                                 cvar.initializer = default_value_for_type (local.variable_type, true, on_error);
4041                                 cvar.init0 = true;
4042                         } else if (init && size != null && local.initializer == null) {
4043                                 cfile.add_include ("string.h");
4044                                 var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
4045                                 memset_call.add_argument (get_variable_cexpression (local.name));
4046                                 memset_call.add_argument (new CCodeConstant ("0"));
4047                                 memset_call.add_argument (size);
4048                                 ccode.add_expression (memset_call);
4049                         }
4050                         ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
4051                 }
4052         }
4053
4054         public override void visit_expression_statement (ExpressionStatement stmt) {
4055                 if (stmt.expression.error) {
4056                         stmt.error = true;
4057                         return;
4058                 }
4059
4060                 /* free temporary objects and handle errors */
4061
4062                 foreach (var value in temp_ref_values) {
4063                         ccode.add_expression (destroy_value (value));
4064                 }
4065
4066                 if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
4067                         // simple case, no node breakdown necessary
4068                         add_simple_check (stmt.expression);
4069                 }
4070
4071                 temp_ref_values.clear ();
4072         }
4073
4074         protected virtual void append_scope_free (Symbol sym, CodeNode? stop_at = null) {
4075                 var b = (Block) sym;
4076
4077                 var local_vars = b.get_local_variables ();
4078                 // free in reverse order
4079                 for (int i = local_vars.size - 1; i >= 0; i--) {
4080                         var local = local_vars[i];
4081                         if (!local.unreachable && local.active && !local.captured && requires_destroy (local.variable_type)) {
4082                                 ccode.add_expression (destroy_local (local));
4083                         }
4084                 }
4085
4086                 if (b.captured) {
4087                         int block_id = get_block_id (b);
4088
4089                         var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
4090                         data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
4091                         ccode.add_expression (data_unref);
4092                         ccode.add_assignment (get_variable_cexpression ("_data%d_".printf (block_id)), new CCodeConstant ("NULL"));
4093                 }
4094         }
4095
4096         public void append_local_free (Symbol sym, Statement? jump_stmt = null, CodeNode? stop_at = null) {
4097                 var b = (Block) sym;
4098
4099                 append_scope_free (sym, stop_at);
4100
4101                 if (jump_stmt is BreakStatement) {
4102                         if (b.parent_node is LoopStatement ||
4103                             b.parent_node is ForeachStatement ||
4104                             b.parent_node is SwitchStatement) {
4105                                 return;
4106                         }
4107                 } else if (jump_stmt is ContinueStatement) {
4108                         if (b.parent_node is LoopStatement ||
4109                             b.parent_node is ForeachStatement) {
4110                                 return;
4111                         }
4112                 }
4113
4114                 if (stop_at != null && b.parent_node == stop_at) {
4115                         return;
4116                 }
4117
4118                 if (sym.parent_symbol is Block) {
4119                         append_local_free (sym.parent_symbol, jump_stmt, stop_at);
4120                 } else if (sym.parent_symbol is Method) {
4121                         append_param_free ((Method) sym.parent_symbol);
4122                 } else if (sym.parent_symbol is PropertyAccessor) {
4123                         var acc = (PropertyAccessor) sym.parent_symbol;
4124                         if (acc.value_parameter != null && requires_destroy (acc.value_parameter.variable_type)) {
4125                                 ccode.add_expression (destroy_parameter (acc.value_parameter));
4126                         }
4127                 }
4128         }
4129
4130         private void append_param_free (Method m) {
4131                 foreach (Parameter param in m.get_parameters ()) {
4132                         if (!param.captured && !param.ellipsis && !param.params_array && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
4133                                 ccode.add_expression (destroy_parameter (param));
4134                         }
4135                 }
4136         }
4137
4138         public void append_out_param_free (Method? m) {
4139                 if (m == null) {
4140                         return;
4141                 }
4142                 foreach (Parameter param in m.get_parameters ()) {
4143                         if (param.direction == ParameterDirection.OUT && param.variable_type.is_disposable ()) {
4144                                 ccode.add_expression (destroy_parameter (param));
4145                         }
4146                 }
4147         }
4148
4149         public bool variable_accessible_in_finally (LocalVariable local) {
4150                 if (current_try == null) {
4151                         return false;
4152                 }
4153
4154                 var sym = current_symbol;
4155
4156                 while (!(sym is Method || sym is PropertyAccessor) && sym.scope.lookup (local.name) == null) {
4157                         if ((sym.parent_node is TryStatement && ((TryStatement) sym.parent_node).finally_body != null) ||
4158                                 (sym.parent_node is CatchClause && ((TryStatement) sym.parent_node.parent_node).finally_body != null)) {
4159
4160                                 return true;
4161                         }
4162
4163                         sym = sym.parent_symbol;
4164                 }
4165
4166                 return false;
4167         }
4168
4169         public void return_out_parameter (Parameter param) {
4170                 var delegate_type = param.variable_type as DelegateType;
4171
4172                 var value = get_parameter_cvalue (param);
4173
4174                 var old_coroutine = is_in_coroutine ();
4175                 current_method.coroutine = false;
4176
4177                 ccode.open_if (get_parameter_cexpression (param));
4178                 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_parameter_cexpression (param)), get_cvalue_ (value));
4179
4180                 if (get_ccode_delegate_target (param) && delegate_type != null && delegate_type.delegate_symbol.has_target) {
4181                         ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cexpression (get_ccode_delegate_target_name (param))), get_delegate_target_cvalue (value));
4182                         if (delegate_type.is_disposable ()) {
4183                                 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cexpression (get_ccode_delegate_target_destroy_notify_name (param))), get_delegate_target_destroy_notify_cvalue (get_parameter_cvalue (param)));
4184                         }
4185                 }
4186
4187                 if (param.variable_type.is_disposable ()){
4188                         ccode.add_else ();
4189                         current_method.coroutine = old_coroutine;
4190                         ccode.add_expression (destroy_parameter (param));
4191                         current_method.coroutine = false;
4192                 }
4193                 ccode.close ();
4194
4195                 var array_type = param.variable_type as ArrayType;
4196                 if (array_type != null && !array_type.fixed_length && get_ccode_array_length (param)) {
4197                         for (int dim = 1; dim <= array_type.rank; dim++) {
4198                                 string length_cname = get_variable_array_length_cname (param, dim);
4199                                 ccode.open_if (get_cexpression (length_cname));
4200                                 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cexpression (length_cname)), get_array_length_cvalue (value, dim));
4201                                 ccode.close ();
4202                         }
4203                 }
4204
4205                 current_method.coroutine = old_coroutine;
4206         }
4207
4208         public override void visit_return_statement (ReturnStatement stmt) {
4209                 Symbol return_expression_symbol = null;
4210
4211                 if (stmt.return_expression != null) {
4212                         // avoid unnecessary ref/unref pair
4213                         var local = stmt.return_expression.symbol_reference as LocalVariable;
4214                         if (local != null && !local.active) {
4215                                 /* return expression is local variable taking ownership and
4216                                  * current method is transferring ownership */
4217
4218                                 return_expression_symbol = local;
4219                         }
4220                 }
4221
4222                 // return array length if appropriate
4223                 if (((current_method != null && get_ccode_array_length (current_method)) || (current_property_accessor != null && get_ccode_array_length (current_property_accessor))) && current_return_type is ArrayType) {
4224                         var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
4225
4226                         var array_type = (ArrayType) current_return_type;
4227                         for (int dim = 1; dim <= array_type.rank; dim++) {
4228                                 var len_l = get_cexpression (get_array_length_cname ("result", dim));
4229                                 var len_r = get_array_length_cvalue (temp_value, dim);
4230                                 if (!is_in_coroutine ()) {
4231                                         ccode.open_if (len_l);
4232                                         len_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, len_l);
4233                                         ccode.add_assignment (len_l, len_r);
4234                                         ccode.close ();
4235                                 } else {
4236                                         ccode.add_assignment (len_l, len_r);
4237                                 }
4238                         }
4239
4240                         stmt.return_expression.target_value = temp_value;
4241                 } else if (((current_method != null && get_ccode_delegate_target (current_method)) || (current_property_accessor != null && get_ccode_delegate_target (current_property_accessor))) && current_return_type is DelegateType) {
4242                         var delegate_type = (DelegateType) current_return_type;
4243                         if (delegate_type.delegate_symbol.has_target) {
4244                                 var temp_value = store_temp_value (stmt.return_expression.target_value, stmt);
4245
4246                                 var target_l = get_cexpression (get_delegate_target_cname ("result"));
4247                                 if (!is_in_coroutine ()) {
4248                                         target_l = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l);
4249                                 }
4250                                 var target_r = get_delegate_target_cvalue (temp_value);
4251                                 ccode.add_assignment (target_l, target_r);
4252                                 if (delegate_type.is_disposable ()) {
4253                                         var target_l_destroy_notify = get_cexpression (get_delegate_target_destroy_notify_cname ("result"));
4254                                         if (!is_in_coroutine ()) {
4255                                                 target_l_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_l_destroy_notify);
4256                                         }
4257                                         var target_r_destroy_notify = get_delegate_target_destroy_notify_cvalue (temp_value);
4258                                         ccode.add_assignment (target_l_destroy_notify, target_r_destroy_notify);
4259                                 }
4260
4261                                 stmt.return_expression.target_value = temp_value;
4262                         }
4263                 }
4264
4265                 if (stmt.return_expression != null) {
4266                         // assign method result to `result'
4267                         CCodeExpression result_lhs = get_cexpression ("result");
4268                         if (current_return_type.is_real_non_null_struct_type () && !is_in_coroutine ()) {
4269                                 result_lhs = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result_lhs);
4270                         }
4271                         ccode.add_assignment (result_lhs, get_cvalue (stmt.return_expression));
4272                 }
4273
4274                 if (current_method != null) {
4275                         // check postconditions
4276                         foreach (Expression postcondition in current_method.get_postconditions ()) {
4277                                 create_postcondition_statement (postcondition);
4278                         }
4279                 }
4280
4281                 // free local variables
4282                 append_local_free (current_symbol);
4283
4284                 if (current_method != null && !current_method.coroutine) {
4285                         // assign values to output parameters if they are not NULL
4286                         // otherwise, free the value if necessary
4287                         foreach (var param in current_method.get_parameters ()) {
4288                                 if (param.direction != ParameterDirection.OUT) {
4289                                         continue;
4290                                 }
4291
4292                                 return_out_parameter (param);
4293                         }
4294                 }
4295
4296                 // TODO: don't duplicate the code in CCodeMethodModule, we do this right now because it needs to be before return
4297                 if (current_method != null && current_method.get_attribute ("Profile") != null) {
4298                         string prefix = "_vala_prof_%s".printf (get_ccode_real_name (current_method));
4299
4300                         var level = new CCodeIdentifier (prefix + "_level");
4301                         ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
4302
4303                         var timer = new CCodeIdentifier (prefix + "_timer");
4304
4305                         var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
4306                         stop_call.add_argument (timer);
4307                         ccode.add_expression (stop_call);
4308
4309                         ccode.close ();
4310                 }
4311
4312                 if (is_in_constructor ()) {
4313                         ccode.add_return (new CCodeIdentifier ("obj"));
4314                 } else if (is_in_destructor ()) {
4315                         // do not call return as member cleanup and chain up to base finalizer
4316                         // still need to be executed
4317                         ccode.add_goto ("_return");
4318                 } else if (is_in_coroutine ()) {
4319                 } else if (current_method is CreationMethod) {
4320                         ccode.add_return (new CCodeIdentifier ("self"));
4321                 } else if (current_return_type is VoidType || current_return_type.is_real_non_null_struct_type ()) {
4322                         // structs are returned via out parameter
4323                         ccode.add_return ();
4324                 } else {
4325                         ccode.add_return (new CCodeIdentifier ("result"));
4326                 }
4327
4328                 if (return_expression_symbol != null) {
4329                         return_expression_symbol.active = true;
4330                 }
4331
4332                 // required for destructors
4333                 current_method_return = true;
4334         }
4335
4336         public string get_symbol_lock_name (string symname) {
4337                 return "__lock_%s".printf (symname.replace ("-", "_"));
4338         }
4339
4340         private CCodeExpression get_lock_expression (Statement stmt, Expression resource) {
4341                 CCodeExpression l = null;
4342                 var member = resource.symbol_reference;
4343                 var parent = (TypeSymbol)resource.symbol_reference.parent_symbol;
4344
4345                 if (member.is_instance_member ()) {
4346                         l = get_cvalue (((MemberAccess) resource).inner);
4347                         l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (get_ccode_name (member)));
4348                 } else if (member.is_class_member ()) {
4349                         unowned Class cl = (Class) parent;
4350                         var cast = get_this_class_cexpression (cl);
4351                         var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function (cl)));
4352                         get_class_private_call.add_argument (cast);
4353                         l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (get_ccode_name (member)));
4354                 } else {
4355                         string lock_name = "%s_%s".printf (get_ccode_lower_case_name (parent), get_ccode_name (member));
4356                         l = new CCodeIdentifier (get_symbol_lock_name (lock_name));
4357                 }
4358                 return l;
4359         }
4360
4361         public override void visit_lock_statement (LockStatement stmt) {
4362                 var l = get_lock_expression (stmt, stmt.resource);
4363
4364                 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("lock"))));
4365                 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
4366
4367                 ccode.add_expression (fc);
4368         }
4369
4370         public override void visit_unlock_statement (UnlockStatement stmt) {
4371                 var l = get_lock_expression (stmt, stmt.resource);
4372
4373                 var fc = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (mutex_type.scope.lookup ("unlock"))));
4374                 fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
4375
4376                 ccode.add_expression (fc);
4377         }
4378
4379         public override void visit_delete_statement (DeleteStatement stmt) {
4380                 unowned DataType type = stmt.expression.value_type;
4381                 unowned PointerType? pointer_type = type as PointerType;
4382                 if (pointer_type != null && pointer_type.base_type.type_symbol != null && pointer_type.base_type.type_symbol.is_reference_type ()) {
4383                         type = pointer_type.base_type;
4384                 }
4385
4386                 ccode.add_expression (destroy_value (new GLibValue (type, get_cvalue (stmt.expression))));
4387         }
4388
4389         static bool is_compact_class_destructor_call (Expression expr) {
4390                 unowned Class? cl = expr.value_type.type_symbol as Class;
4391                 if (cl != null && cl.is_compact && expr.parent_node is MemberAccess) {
4392                         unowned MethodType? mt = ((MemberAccess) expr.parent_node).value_type as MethodType;
4393                         if (mt != null && mt.method_symbol != null && mt.method_symbol.get_attribute ("DestroysInstance") != null) {
4394                                 return true;
4395                         }
4396                 }
4397                 return false;
4398         }
4399
4400         public override void visit_expression (Expression expr) {
4401                 if (get_cvalue (expr) != null && !expr.lvalue) {
4402                         if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
4403                                 var type_parameter = ((GenericType) expr.formal_value_type).type_parameter;
4404                                 var st = type_parameter.parent_symbol.parent_symbol as Struct;
4405                                 if (type_parameter.parent_symbol != garray_type &&
4406                                     (st == null || get_ccode_name (st) != "va_list")) {
4407                                         // GArray and va_list don't use pointer-based generics
4408                                         set_cvalue (expr, convert_from_generic_pointer (get_cvalue (expr), expr.value_type));
4409                                         ((GLibValue) expr.target_value).lvalue = false;
4410                                 }
4411                         }
4412
4413                         // memory management, implicit casts, and boxing/unboxing
4414                         if (expr.value_type != null) {
4415                                 // FIXME: temporary workaround until the refactoring is complete, not all target_value have a value_type
4416                                 expr.target_value.value_type = expr.value_type;
4417                                 expr.target_value = transform_value (expr.target_value, expr.target_type, expr);
4418                         }
4419
4420                         if (expr.target_value == null) {
4421                                 return;
4422                         }
4423
4424                         if (expr.formal_target_type is GenericType && !(expr.target_type is GenericType)) {
4425                                 if (((GenericType) expr.formal_target_type).type_parameter.parent_symbol != garray_type) {
4426                                         // GArray doesn't use pointer-based generics
4427                                         set_cvalue (expr, convert_to_generic_pointer (get_cvalue (expr), expr.target_type));
4428                                         ((GLibValue) expr.target_value).lvalue = false;
4429                                 }
4430                         }
4431
4432                         // Allow null to initialize non-null struct inside initializer list
4433                         if (expr is NullLiteral && expr.parent_node is InitializerList
4434                             && expr.target_type != null && expr.target_type.is_real_non_null_struct_type ()) {
4435                                 var clist = new CCodeInitializerList ();
4436                                 clist.append (new CCodeConstant ("0"));
4437                                 set_cvalue (expr, new CCodeCastExpression (clist, get_ccode_name (expr.target_type.type_symbol)));
4438                         }
4439
4440                         if (!(expr.value_type is ValueType && !expr.value_type.nullable)) {
4441                                 ((GLibValue) expr.target_value).non_null = expr.is_non_null ();
4442                         }
4443                 } else if (expr.value_type != null && is_compact_class_destructor_call (expr)) {
4444                         // transfer ownership here and consume given instance
4445                         var temp_value = store_temp_value (expr.target_value, expr);
4446                         ccode.add_assignment (get_cvalue (expr), new CCodeConstant ("NULL"));
4447                         expr.target_value = temp_value;
4448                 }
4449         }
4450
4451         public override void visit_boolean_literal (BooleanLiteral expr) {
4452                 set_cvalue (expr, get_boolean_cconstant (expr.value));
4453         }
4454
4455         public override void visit_character_literal (CharacterLiteral expr) {
4456                 if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
4457                         set_cvalue (expr, new CCodeConstant (expr.value));
4458                 } else {
4459                         set_cvalue (expr, new CCodeConstant ("%uU".printf (expr.get_char ())));
4460                 }
4461         }
4462
4463         public override void visit_integer_literal (IntegerLiteral expr) {
4464                 set_cvalue (expr, new CCodeConstant (expr.value + expr.type_suffix));
4465         }
4466
4467         public override void visit_real_literal (RealLiteral expr) {
4468                 string c_literal = expr.value;
4469                 if (c_literal.has_suffix ("d") || c_literal.has_suffix ("D")) {
4470                         // there is no suffix for double in C
4471                         c_literal = c_literal.substring (0, c_literal.length - 1);
4472                 }
4473                 if (!("." in c_literal || "e" in c_literal || "E" in c_literal)) {
4474                         // C requires period or exponent part for floating constants
4475                         if ("f" in c_literal || "F" in c_literal) {
4476                                 c_literal = c_literal.substring (0, c_literal.length - 1) + ".f";
4477                         } else {
4478                                 c_literal += ".";
4479                         }
4480                 }
4481                 set_cvalue (expr, new CCodeConstant (c_literal));
4482         }
4483
4484         public override void visit_string_literal (StringLiteral expr) {
4485                 set_cvalue (expr, new CCodeConstant.string (expr.value.replace ("\n", "\\n")));
4486
4487                 if (expr.translate) {
4488                         // translated string constant
4489                         var translate = new CCodeFunctionCall (new CCodeIdentifier ("_"));
4490                         translate.add_argument (get_cvalue (expr));
4491                         set_cvalue (expr, translate);
4492                 }
4493         }
4494
4495         public override void visit_regex_literal (RegexLiteral expr) {
4496                 string[] parts = expr.value.split ("/", 3);
4497                 string re = parts[2].escape ("");
4498                 string flags = "0";
4499
4500                 if (parts[1].contains ("i")) {
4501                         flags += " | G_REGEX_CASELESS";
4502                 }
4503                 if (parts[1].contains ("m")) {
4504                         flags += " | G_REGEX_MULTILINE";
4505                 }
4506                 if (parts[1].contains ("s")) {
4507                         flags += " | G_REGEX_DOTALL";
4508                 }
4509                 if (parts[1].contains ("x")) {
4510                         flags += " | G_REGEX_EXTENDED";
4511                 }
4512
4513                 var cdecl = new CCodeDeclaration ("GRegex*");
4514
4515                 var cname = "_tmp_regex_%d".printf (next_regex_id);
4516                 if (this.next_regex_id == 0) {
4517                         var fun = new CCodeFunction ("_thread_safe_regex_init", "GRegex*");
4518                         fun.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
4519                         fun.add_parameter (new CCodeParameter ("re", "GRegex**"));
4520                         fun.add_parameter (new CCodeParameter ("pattern", "const gchar *"));
4521                         fun.add_parameter (new CCodeParameter ("compile_flags", "GRegexCompileFlags"));
4522
4523                         push_function (fun);
4524
4525                         var once_enter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
4526                         if (context.require_glib_version (2, 68)) {
4527                                 once_enter_call.add_argument (new CCodeConstant ("(gsize*) re"));
4528                         } else {
4529                                 once_enter_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
4530                         }
4531                         ccode.open_if (once_enter_call);
4532
4533                         var regex_new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_regex_new"));
4534                         regex_new_call.add_argument (new CCodeConstant ("pattern"));
4535                         regex_new_call.add_argument (new CCodeConstant ("compile_flags"));
4536                         regex_new_call.add_argument (new CCodeConstant ("0"));
4537                         regex_new_call.add_argument (new CCodeConstant ("NULL"));
4538                         ccode.add_assignment (new CCodeIdentifier ("GRegex* val"), regex_new_call);
4539
4540                         var once_leave_call = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
4541                         if (context.require_glib_version (2, 68)) {
4542                                 once_leave_call.add_argument (new CCodeConstant ("(gsize*) re"));
4543                         } else {
4544                                 once_leave_call.add_argument (new CCodeConstant ("(volatile gsize*) re"));
4545                         }
4546                         once_leave_call.add_argument (new CCodeConstant ("(gsize) val"));
4547                         ccode.add_expression (once_leave_call);
4548
4549                         ccode.close ();
4550
4551                         ccode.add_return (new CCodeIdentifier ("*re"));
4552
4553                         pop_function ();
4554
4555                         cfile.add_function (fun);
4556                 }
4557                 this.next_regex_id++;
4558
4559                 cdecl.add_declarator (new CCodeVariableDeclarator (cname + " = NULL"));
4560                 cdecl.modifiers = CCodeModifiers.STATIC;
4561
4562                 var regex_const = new CCodeConstant ("_thread_safe_regex_init (&%s, \"%s\", %s)".printf (cname, re, flags));
4563
4564                 cfile.add_constant_declaration (cdecl);
4565                 set_cvalue (expr, regex_const);
4566         }
4567
4568         public override void visit_null_literal (NullLiteral expr) {
4569                 if (context.profile == Profile.GOBJECT) {
4570                         cfile.add_include ("glib.h");
4571                 } else {
4572                         cfile.add_include ("stddef.h");
4573                 }
4574                 set_cvalue (expr, new CCodeConstant ("NULL"));
4575
4576                 var array_type = expr.target_type as ArrayType;
4577                 var delegate_type = expr.target_type as DelegateType;
4578                 if (array_type != null) {
4579                         for (int dim = 1; dim <= array_type.rank; dim++) {
4580                                 append_array_length (expr, new CCodeConstant ("0"));
4581                         }
4582                 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
4583                         set_delegate_target (expr, new CCodeConstant ("NULL"));
4584                         set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
4585                 }
4586         }
4587
4588         public abstract TargetValue get_local_cvalue (LocalVariable local);
4589
4590         public abstract TargetValue get_parameter_cvalue (Parameter param);
4591
4592         public abstract TargetValue get_field_cvalue (Field field, TargetValue? instance);
4593
4594         public abstract TargetValue load_variable (Variable variable, TargetValue value, Expression? expr = null);
4595
4596         public abstract TargetValue load_this_parameter (TypeSymbol sym);
4597
4598         public abstract void store_value (TargetValue lvalue, TargetValue value, SourceReference? source_reference = null);
4599
4600         public virtual string get_delegate_target_cname (string delegate_cname) {
4601                 assert_not_reached ();
4602         }
4603
4604         public virtual CCodeExpression get_delegate_target_cexpression (Expression delegate_expr, out CCodeExpression delegate_target_destroy_notify) {
4605                 assert_not_reached ();
4606         }
4607
4608         public virtual CCodeExpression get_delegate_target_cvalue (TargetValue value) {
4609                 return new CCodeInvalidExpression ();
4610         }
4611
4612         public virtual CCodeExpression get_delegate_target_destroy_notify_cvalue (TargetValue value) {
4613                 return new CCodeInvalidExpression ();
4614         }
4615
4616         public virtual string get_delegate_target_destroy_notify_cname (string delegate_cname) {
4617                 assert_not_reached ();
4618         }
4619
4620         public override void visit_base_access (BaseAccess expr) {
4621                 unowned Class? cl = expr.value_type.type_symbol as Class;
4622                 if (cl != null && !cl.is_compact) {
4623                         set_cvalue (expr, generate_instance_cast (get_this_cexpression (), cl));
4624                 } else {
4625                         expr.target_value = load_this_parameter (expr.value_type.type_symbol);
4626                 }
4627         }
4628
4629         public override void visit_postfix_expression (PostfixExpression expr) {
4630                 MemberAccess ma = find_property_access (expr.inner);
4631                 if (ma != null) {
4632                         // property postfix expression
4633                         var prop = (Property) ma.symbol_reference;
4634
4635                         // increment/decrement property
4636                         var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4637                         var cexpr = new CCodeBinaryExpression (op, get_cvalue (expr.inner), new CCodeConstant ("1"));
4638                         store_property (prop, ma.inner, new GLibValue (expr.value_type, cexpr));
4639
4640                         // return previous value
4641                         expr.target_value = expr.inner.target_value;
4642                         return;
4643                 }
4644
4645                 // assign current value to temp variable
4646                 var temp_value = store_temp_value (expr.inner.target_value, expr);
4647
4648                 // increment/decrement variable
4649                 var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
4650                 var cexpr = new CCodeBinaryExpression (op, get_cvalue_ (temp_value), new CCodeConstant ("1"));
4651                 ccode.add_assignment (get_cvalue (expr.inner), cexpr);
4652
4653                 // return previous value
4654                 expr.target_value = temp_value;
4655         }
4656
4657         private MemberAccess? find_property_access (Expression expr) {
4658                 if (!(expr is MemberAccess)) {
4659                         return null;
4660                 }
4661
4662                 var ma = (MemberAccess) expr;
4663                 if (ma.symbol_reference is Property) {
4664                         return ma;
4665                 }
4666
4667                 return null;
4668         }
4669
4670         static bool is_limited_generic_type (GenericType type) {
4671                 unowned Class? cl = type.type_parameter.parent_symbol as Class;
4672                 unowned Struct? st = type.type_parameter.parent_symbol as Struct;
4673                 if ((cl != null && cl.is_compact) || st != null) {
4674                         // compact classes and structs only
4675                         // have very limited generics support
4676                         return true;
4677                 }
4678                 return false;
4679         }
4680
4681         public static bool requires_copy (DataType type) {
4682                 if (!type.is_disposable ()) {
4683                         return false;
4684                 }
4685
4686                 unowned Class? cl = type.type_symbol as Class;
4687                 if (cl != null && is_reference_counting (cl)
4688                     && get_ccode_ref_function (cl) == "") {
4689                         // empty ref_function => no ref necessary
4690                         return false;
4691                 }
4692
4693                 if (type is GenericType) {
4694                         if (is_limited_generic_type ((GenericType) type)) {
4695                                 return false;
4696                         }
4697                 }
4698
4699                 return true;
4700         }
4701
4702         public static bool requires_destroy (DataType type) {
4703                 if (!type.is_disposable ()) {
4704                         return false;
4705                 }
4706
4707                 var array_type = type as ArrayType;
4708                 if (array_type != null && array_type.fixed_length) {
4709                         return requires_destroy (array_type.element_type);
4710                 }
4711
4712                 unowned Class? cl = type.type_symbol as Class;
4713                 if (cl != null && is_reference_counting (cl)
4714                     && get_ccode_unref_function (cl) == "") {
4715                         // empty unref_function => no unref necessary
4716                         return false;
4717                 }
4718
4719                 if (type is GenericType) {
4720                         if (is_limited_generic_type ((GenericType) type)) {
4721                                 return false;
4722                         }
4723                 }
4724
4725                 return true;
4726         }
4727
4728         public virtual TargetValue? copy_value (TargetValue value, CodeNode node) {
4729                 var type = value.value_type;
4730                 var cexpr = get_cvalue_ (value);
4731                 var result = ((GLibValue) value).copy ();
4732
4733                 if (type is DelegateType) {
4734                         var delegate_type = (DelegateType) type;
4735                         if (get_ccode_delegate_target (node) && delegate_type.delegate_symbol.has_target && !context.deprecated) {
4736                                 Report.deprecated (node.source_reference, "copying delegates is not supported");
4737                         }
4738                         result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
4739                         return result;
4740                 }
4741
4742                 if (type is ValueType && !type.nullable) {
4743                         // normal value type, no null check
4744
4745                         // use temp-var for upcoming address-of operator
4746                         var temp_cvalue = create_temp_value (type, false, node);
4747                         store_value (temp_cvalue, value, node.source_reference);
4748                         cexpr = get_cvalue_ (temp_cvalue);
4749
4750                         var temp_value = create_temp_value (type, true, node, true);
4751                         var ctemp = get_cvalue_ (temp_value);
4752
4753                         var vt = (ValueType) type;
4754                         var st = (Struct) vt.type_symbol;
4755                         var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
4756                         copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4757                         copy_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4758
4759                         if (!get_ccode_has_copy_function (st)) {
4760                                 generate_struct_copy_function (st);
4761                         }
4762
4763                         if (gvalue_type != null && type.type_symbol == gvalue_type) {
4764                                 var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
4765                                 cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4766
4767                                 ccode.open_if (cisvalid);
4768
4769                                 // GValue requires g_value_init in addition to g_value_copy
4770                                 var value_type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
4771                                 value_type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr));
4772
4773                                 var init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
4774                                 init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
4775                                 init_call.add_argument (value_type_call);
4776                                 ccode.add_expression (init_call);
4777                                 ccode.add_expression (copy_call);
4778
4779                                 ccode.add_else ();
4780
4781                                 // g_value_init/copy must not be called for uninitialized values
4782                                 store_value (temp_value, temp_cvalue, node.source_reference);
4783                                 ccode.close ();
4784                         } else {
4785                                 ccode.add_expression (copy_call);
4786                         }
4787
4788                         return temp_value;
4789                 }
4790
4791                 /* (temp = expr, temp == NULL ? NULL : ref (temp))
4792                  *
4793                  * can be simplified to
4794                  * ref (expr)
4795                  * if static type of expr is non-null
4796                  */
4797
4798                 var dupexpr = get_dup_func_expression (type, node.source_reference);
4799
4800                 if (dupexpr == null) {
4801                         node.error = true;
4802                         return null;
4803                 }
4804
4805                 if (dupexpr is CCodeIdentifier && !(type is ArrayType) && !(type is GenericType) && !is_ref_function_void (type)) {
4806                         // generate and call NULL-aware ref function to reduce number
4807                         // of temporary variables and simplify code
4808
4809                         var dupid = (CCodeIdentifier) dupexpr;
4810                         string dup0_func = "_%s0".printf (dupid.name);
4811
4812                         // g_strdup is already NULL-safe
4813                         if (dupid.name == "g_strdup") {
4814                                 dup0_func = dupid.name;
4815                         } else if (add_wrapper (dup0_func)) {
4816                                 var dup0_fun = new CCodeFunction (dup0_func, get_ccode_name (pointer_type));
4817                                 dup0_fun.add_parameter (new CCodeParameter ("self", get_ccode_name (pointer_type)));
4818                                 dup0_fun.modifiers = CCodeModifiers.STATIC;
4819
4820                                 push_function (dup0_fun);
4821
4822                                 var dup_call = new CCodeFunctionCall (dupexpr);
4823                                 dup_call.add_argument (new CCodeIdentifier ("self"));
4824
4825                                 ccode.add_return (new CCodeConditionalExpression (new CCodeIdentifier ("self"), dup_call, new CCodeConstant ("NULL")));
4826
4827                                 pop_function ();
4828
4829                                 cfile.add_function (dup0_fun);
4830                         }
4831
4832                         var ccall = new CCodeFunctionCall (new CCodeIdentifier (dup0_func));
4833                         ccall.add_argument (cexpr);
4834                         result.cvalue = ccall;
4835                         result.value_type.value_owned = true;
4836                         return store_temp_value (result, node);
4837                 }
4838
4839                 var ccall = new CCodeFunctionCall (dupexpr);
4840
4841                 if (!(type is ArrayType) && get_non_null (value) && !is_ref_function_void (type)) {
4842                         // expression is non-null
4843                         ccall.add_argument (cexpr);
4844
4845                         return store_temp_value (new GLibValue (type, ccall), node);
4846                 } else {
4847                         CCodeExpression ccallarg;
4848                         if (node is SliceExpression) {
4849                                 ccallarg = cexpr;
4850                                 cexpr = get_cvalue (((SliceExpression) node).container);
4851                         } else {
4852                                 ccallarg = cexpr;
4853                         }
4854                         var cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cexpr, new CCodeConstant ("NULL"));
4855                         if (type is GenericType) {
4856                                 // dup functions are optional for type parameters
4857                                 var cdupnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_dup_func_expression (type, node.source_reference), new CCodeConstant ("NULL"));
4858                                 cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.AND, cnotnull, cdupnotnull);
4859                         }
4860
4861                         if (type is GenericType) {
4862                                 // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
4863                                 ccall.add_argument (new CCodeCastExpression (ccallarg, get_ccode_name (pointer_type)));
4864                         } else {
4865                                 ccall.add_argument (ccallarg);
4866                         }
4867
4868                         if (type is ArrayType) {
4869                                 var array_type = (ArrayType) type;
4870                                 ccall.add_argument (get_array_length_cvalue (value));
4871
4872                                 if (array_type.element_type is GenericType) {
4873                                         var elem_dupexpr = get_dup_func_expression (array_type.element_type, node.source_reference);
4874                                         if (elem_dupexpr == null) {
4875                                                 elem_dupexpr = new CCodeConstant ("NULL");
4876                                         }
4877                                         ccall.add_argument (elem_dupexpr);
4878                                 }
4879                         }
4880
4881                         CCodeExpression cifnull;
4882                         if (type is GenericType) {
4883                                 // the value might be non-null even when the dup function is null,
4884                                 // so we may not just use NULL for type parameters
4885
4886                                 // cast from gconstpointer to gpointer as methods in
4887                                 // generic classes may not return gconstpointer
4888                                 cifnull = new CCodeCastExpression (cexpr, get_ccode_name (pointer_type));
4889                         } else if (type.type_symbol != null) {
4890                                 cifnull = new CCodeConstant ("NULL");
4891                         } else {
4892                                 cifnull = cexpr;
4893                         }
4894
4895                         if (is_ref_function_void (type)) {
4896                                 ccode.open_if (cnotnull);
4897                                 ccode.add_expression (ccall);
4898                                 ccode.close ();
4899                         } else {
4900                                 if (get_non_null (value)) {
4901                                         result.cvalue = ccall;
4902                                 } else {
4903                                         var ccond = new CCodeConditionalExpression (cnotnull, ccall, cifnull);
4904                                         result.cvalue = ccond;
4905                                 }
4906                                 result = (GLibValue) store_temp_value (result, node, true);
4907                         }
4908                         return result;
4909                 }
4910         }
4911
4912         public virtual void generate_class_declaration (Class cl, CCodeFile decl_space) {
4913                 if (add_symbol_declaration (decl_space, cl, get_ccode_name (cl))) {
4914                         return;
4915                 }
4916         }
4917
4918         public virtual void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
4919         }
4920
4921         public virtual bool generate_method_declaration (Method m, CCodeFile decl_space) {
4922                 return false;
4923         }
4924
4925         public virtual void generate_error_domain_declaration (ErrorDomain edomain, CCodeFile decl_space) {
4926         }
4927
4928         public void add_generic_type_arguments (Method m, Map<int,CCodeExpression> arg_map, List<DataType> type_args, CodeNode expr, bool is_chainup = false, List<TypeParameter>? type_parameters = null) {
4929                 int type_param_index = 0;
4930                 foreach (var type_arg in type_args) {
4931                         if (get_ccode_simple_generics (m)) {
4932                                 if (requires_copy (type_arg)) {
4933                                         arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), get_destroy0_func_expression (type_arg, is_chainup));
4934                                 } else {
4935                                         arg_map.set (get_param_pos (-1 + 0.1 * type_param_index + 0.03), new CCodeConstant ("NULL"));
4936                                 }
4937                                 type_param_index++;
4938                                 continue;
4939                         }
4940
4941                         if (type_parameters != null) {
4942                                 var type_param_name = type_parameters.get (type_param_index).name.ascii_down ().replace ("_", "-");
4943                                 arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s-type\"".printf (type_param_name)));
4944                                 arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("\"%s-dup-func\"".printf (type_param_name)));
4945                                 arg_map.set (get_param_pos (0.1 * type_param_index + 0.05), new CCodeConstant ("\"%s-destroy-func\"".printf (type_param_name)));
4946                         }
4947
4948                         arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), get_type_id_expression (type_arg, is_chainup));
4949                         if (requires_copy (type_arg)) {
4950                                 var dup_func = get_dup_func_expression (type_arg, type_arg.source_reference ?? expr.source_reference, is_chainup);
4951                                 if (dup_func == null) {
4952                                         // type doesn't contain a copy function
4953                                         expr.error = true;
4954                                         return;
4955                                 }
4956                                 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeCastExpression (dup_func, "GBoxedCopyFunc"));
4957                                 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeCastExpression (get_destroy_func_expression (type_arg, is_chainup), "GDestroyNotify"));
4958                         } else {
4959                                 arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeConstant ("NULL"));
4960                                 arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeConstant ("NULL"));
4961                         }
4962                         type_param_index++;
4963                 }
4964         }
4965
4966         public override void visit_object_creation_expression (ObjectCreationExpression expr) {
4967                 CCodeExpression instance = null;
4968                 CCodeExpression creation_expr = null;
4969
4970                 unowned Struct? st = expr.type_reference.type_symbol as Struct;
4971                 if ((st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list")) || expr.get_object_initializer ().size > 0) {
4972                         // value-type initialization or object creation expression with object initializer
4973
4974                         var local = expr.parent_node as LocalVariable;
4975                         var field = expr.parent_node as Field;
4976                         var a = expr.parent_node as Assignment;
4977                         if (local != null && is_simple_struct_creation (local, local.initializer)) {
4978                                 instance = get_cvalue_ (get_local_cvalue (local));
4979                         } else if (field != null && is_simple_struct_creation (field, field.initializer)) {
4980                                 // field initialization
4981                                 var thisparam = load_this_parameter ((TypeSymbol) field.parent_symbol);
4982                                 instance = get_cvalue_ (get_field_cvalue (field, thisparam));
4983                         } else if (a != null && a.left.symbol_reference is Variable && is_simple_struct_creation ((Variable) a.left.symbol_reference, a.right)) {
4984                                 if (requires_destroy (a.left.value_type)) {
4985                                         /* unref old value */
4986                                         ccode.add_expression (destroy_value (a.left.target_value));
4987                                 }
4988
4989                                 local = a.left.symbol_reference as LocalVariable;
4990                                 field = a.left.symbol_reference as Field;
4991                                 var param = a.left.symbol_reference as Parameter;
4992                                 if (local != null) {
4993                                         instance = get_cvalue_ (get_local_cvalue (local));
4994                                 } else if (field != null) {
4995                                         var inner = ((MemberAccess) a.left).inner;
4996                                         instance = get_cvalue_ (get_field_cvalue (field, inner != null ? inner.target_value : null));
4997                                 } else if (param != null) {
4998                                         instance = get_cvalue_ (get_parameter_cvalue (param));
4999                                 }
5000                         } else if (expr.is_chainup) {
5001                                 instance = get_this_cexpression ();
5002                         } else {
5003                                 var temp_value = create_temp_value (expr.type_reference, true, expr);
5004                                 instance = get_cvalue_ (temp_value);
5005                         }
5006                 }
5007
5008                 if (expr.symbol_reference == null) {
5009                         // no creation method
5010                         if (expr.type_reference.type_symbol is Struct) {
5011                                 // memset needs string.h
5012                                 cfile.add_include ("string.h");
5013                                 var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
5014                                 creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
5015                                 creation_call.add_argument (new CCodeConstant ("0"));
5016                                 creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.type_reference))));
5017
5018                                 creation_expr = creation_call;
5019                         }
5020                 } else if (expr.type_reference.type_symbol == glist_type ||
5021                            expr.type_reference.type_symbol == gslist_type) {
5022                         // NULL is an empty list
5023                         set_cvalue (expr, new CCodeConstant ("NULL"));
5024                 } else if (expr.symbol_reference is Method) {
5025                         // use creation method
5026                         var m = (Method) expr.symbol_reference;
5027                         var params = m.get_parameters ();
5028                         CCodeFunctionCall creation_call;
5029
5030                         CCodeFunctionCall async_call = null;
5031                         CCodeFunctionCall finish_call = null;
5032
5033                         generate_method_declaration (m, cfile);
5034
5035                         if (m is CreationMethod && !m.external && m.external_package) {
5036                                 unowned CreationMethod cm = (CreationMethod) m;
5037                                 if (!cm.chain_up) {
5038                                         Report.error (cm.source_reference, "internal: Creation method implementation in binding must be chained up");
5039                                 }
5040                                 // internal VAPI creation methods
5041                                 // only add them once per source file
5042                                 if (add_generated_external_symbol (cm)) {
5043                                         visit_creation_method (cm);
5044                                 }
5045                         }
5046
5047                         unowned Class? cl = expr.type_reference.type_symbol as Class;
5048
5049                         if (!get_ccode_has_new_function (m)) {
5050                                 // use construct function directly
5051                                 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
5052                                 creation_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
5053                         } else {
5054                                 creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
5055                         }
5056
5057                         if ((st != null && !st.is_simple_type ()) && !(get_ccode_instance_pos (m) < 0)) {
5058                                 if (expr.is_chainup) {
5059                                         creation_call.add_argument (instance);
5060                                 } else {
5061                                         creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
5062                                 }
5063                         } else if (st != null && get_ccode_name (st) == "va_list") {
5064                                 creation_call.add_argument (instance);
5065                                 if (get_ccode_name (m) == "va_start") {
5066                                         unowned Class? parent = current_method.parent_symbol as Class;
5067                                         if (in_creation_method && parent != null && !parent.is_compact) {
5068                                                 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("va_copy"));
5069                                                 creation_call.add_argument (instance);
5070                                                 creation_call.add_argument (new CCodeIdentifier ("_vala_va_list"));
5071                                         } else {
5072                                                 Parameter last_param = null;
5073                                                 // FIXME: this doesn't take into account exception handling parameters
5074                                                 foreach (var param in current_method.get_parameters ()) {
5075                                                         if (param.ellipsis || param.params_array) {
5076                                                                 break;
5077                                                         }
5078                                                         last_param = param;
5079                                                 }
5080                                                 int nParams = ccode.get_parameter_count ();
5081                                                 if (nParams == 0 || !ccode.get_parameter (nParams - 1).ellipsis) {
5082                                                         Report.error (expr.source_reference, "`va_list' used in method with fixed args");
5083                                                 } else if (nParams == 1) {
5084                                                         Report.error (expr.source_reference, "`va_list' used in method without parameter");
5085                                                 } else {
5086                                                         creation_call.add_argument (new CCodeIdentifier (ccode.get_parameter (nParams - 2).name));
5087                                                 }
5088                                         }
5089                                 }
5090                         }
5091
5092                         generate_type_declaration (expr.type_reference, cfile);
5093
5094                         var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
5095                         var out_arg_map = in_arg_map;
5096
5097                         if (m != null && m.coroutine) {
5098                                 // async call
5099
5100                                 async_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
5101                                 finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
5102
5103                                 creation_call = finish_call;
5104
5105                                 // output arguments used separately
5106                                 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
5107                                 // pass GAsyncResult stored in closure to finish function
5108                                 out_arg_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
5109                         }
5110
5111                         if (cl != null && (!cl.is_compact || get_ccode_simple_generics (m))) {
5112                                 add_generic_type_arguments (m, in_arg_map, expr.type_reference.get_type_arguments (), expr);
5113                         }
5114
5115                         bool ellipsis = false;
5116
5117                         int i = 1;
5118                         int arg_pos;
5119                         Iterator<Parameter> params_it = params.iterator ();
5120                         foreach (Expression arg in expr.get_argument_list ()) {
5121                                 CCodeExpression cexpr = get_cvalue (arg);
5122
5123                                 var carg_map = in_arg_map;
5124
5125                                 Parameter param = null;
5126                                 if (params_it.next ()) {
5127                                         param = params_it.get ();
5128                                         ellipsis = param.ellipsis || param.params_array;
5129                                         if (!ellipsis) {
5130                                                 if (param.direction == ParameterDirection.OUT) {
5131                                                         carg_map = out_arg_map;
5132                                                 }
5133
5134                                                 if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
5135                                                         var array_type = (ArrayType) param.variable_type;
5136                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
5137                                                                 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_array_length_cexpression (arg, dim));
5138                                                         }
5139                                                 } else if (get_ccode_delegate_target (param) && param.variable_type is DelegateType) {
5140                                                         var deleg_type = (DelegateType) param.variable_type;
5141                                                         var d = deleg_type.delegate_symbol;
5142                                                         if (d.has_target) {
5143                                                                 CCodeExpression delegate_target_destroy_notify;
5144                                                                 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
5145                                                                 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
5146                                                                 if (deleg_type.is_disposable ()) {
5147                                                                         carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), delegate_target_destroy_notify);
5148                                                                 }
5149                                                         }
5150                                                 }
5151
5152                                                 cexpr = handle_struct_argument (param, arg, cexpr);
5153
5154                                                 if (get_ccode_type (param) != null) {
5155                                                         cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
5156                                                 }
5157                                         } else {
5158                                                 cexpr = handle_struct_argument (null, arg, cexpr);
5159                                         }
5160
5161                                         arg_pos = get_param_pos (get_ccode_pos (param), ellipsis);
5162                                 } else {
5163                                         // default argument position
5164                                         cexpr = handle_struct_argument (null, arg, cexpr);
5165                                         arg_pos = get_param_pos (i, ellipsis);
5166                                 }
5167
5168                                 carg_map.set (arg_pos, cexpr);
5169
5170                                 i++;
5171                         }
5172                         if (params_it.next ()) {
5173                                 var param = params_it.get ();
5174
5175                                 /* if there are more parameters than arguments,
5176                                  * the additional parameter is an ellipsis parameter
5177                                  * otherwise there is a bug in the semantic analyzer
5178                                  */
5179                                 assert (param.params_array || param.ellipsis);
5180                                 ellipsis = true;
5181                         }
5182
5183                         if (expr.tree_can_fail) {
5184                                 // method can fail
5185                                 current_method_inner_error = true;
5186                                 // add &inner_error before the ellipsis arguments
5187                                 out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
5188                         }
5189
5190                         if (ellipsis) {
5191                                 /* ensure variable argument list ends with NULL
5192                                  * except when using printf-style arguments */
5193                                 if (m == null) {
5194                                         in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
5195                                 } else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "") {
5196                                         in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
5197                                 }
5198                         }
5199
5200                         if ((st != null && !st.is_simple_type ()) && get_ccode_instance_pos (m) < 0) {
5201                                 // instance parameter is at the end in a struct creation method
5202                                 out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
5203                         }
5204
5205                         if (m != null && m.coroutine) {
5206                                 if (expr.is_yield_expression) {
5207                                         // asynchronous call
5208                                         in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
5209                                         in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
5210                                 }
5211                         }
5212
5213                         if (m != null && m.coroutine && m.parent_symbol is Class) {
5214                                 if (get_ccode_finish_instance (m)) {
5215                                         var tmp = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_source_object_");
5216                                         out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), tmp);
5217                                 }
5218                         }
5219
5220                         // append C arguments in the right order
5221
5222                         int last_pos;
5223                         int min_pos;
5224
5225                         if (async_call != creation_call) {
5226                                 // don't append out arguments for .begin() calls
5227                                 last_pos = -1;
5228                                 while (true) {
5229                                         min_pos = -1;
5230                                         foreach (int pos in out_arg_map.get_keys ()) {
5231                                                 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
5232                                                         min_pos = pos;
5233                                                 }
5234                                         }
5235                                         if (min_pos == -1) {
5236                                                 break;
5237                                         }
5238                                         creation_call.add_argument (out_arg_map.get (min_pos));
5239                                         last_pos = min_pos;
5240                                 }
5241                         }
5242
5243                         if (async_call != null) {
5244                                 last_pos = -1;
5245                                 while (true) {
5246                                         min_pos = -1;
5247                                         foreach (int pos in in_arg_map.get_keys ()) {
5248                                                 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
5249                                                         min_pos = pos;
5250                                                 }
5251                                         }
5252                                         if (min_pos == -1) {
5253                                                 break;
5254                                         }
5255                                         async_call.add_argument (in_arg_map.get (min_pos));
5256                                         last_pos = min_pos;
5257                                 }
5258                         }
5259
5260                         if (expr.is_yield_expression) {
5261                                 // set state before calling async function to support immediate callbacks
5262                                 int state = emit_context.next_coroutine_state++;
5263
5264                                 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
5265                                 ccode.add_expression (async_call);
5266                                 ccode.add_return (new CCodeConstant ("FALSE"));
5267                                 ccode.add_label ("_state_%d".printf (state));
5268                         }
5269
5270                         creation_expr = creation_call;
5271
5272                         // cast the return value of the creation method back to the intended type if
5273                         // it requested a special C return type
5274                         if (get_ccode_type (m) != null) {
5275                                 creation_expr = new CCodeCastExpression (creation_expr, get_ccode_name (expr.type_reference));
5276                         }
5277                 } else if (expr.symbol_reference is ErrorCode) {
5278                         var ecode = (ErrorCode) expr.symbol_reference;
5279                         var edomain = (ErrorDomain) ecode.parent_symbol;
5280                         CCodeFunctionCall creation_call;
5281
5282                         generate_error_domain_declaration (edomain, cfile);
5283
5284                         if (expr.get_argument_list ().size == 1) {
5285                                 // must not be a format argument
5286                                 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new_literal"));
5287                         } else {
5288                                 creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_new"));
5289                         }
5290                         creation_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (edomain)));
5291                         creation_call.add_argument (new CCodeIdentifier (get_ccode_name (ecode)));
5292
5293                         foreach (Expression arg in expr.get_argument_list ()) {
5294                                 creation_call.add_argument (get_cvalue (arg));
5295                         }
5296
5297                         creation_expr = creation_call;
5298                 } else {
5299                         assert (false);
5300                 }
5301
5302                 var local = expr.parent_node as LocalVariable;
5303                 if (local != null && is_simple_struct_creation (local, local.initializer)) {
5304                         // no temporary variable necessary
5305                         ccode.add_expression (creation_expr);
5306                         set_cvalue (expr, instance);
5307                 } else if (instance != null) {
5308                         if (expr.type_reference.type_symbol is Struct) {
5309                                 ccode.add_expression (creation_expr);
5310                         } else {
5311                                 ccode.add_assignment (instance, creation_expr);
5312                         }
5313
5314                         foreach (MemberInitializer init in expr.get_object_initializer ()) {
5315                                 if (init.symbol_reference is Field) {
5316                                         var f = (Field) init.symbol_reference;
5317                                         var instance_target_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
5318                                         var typed_inst = transform_value (new GLibValue (expr.type_reference, instance, true), instance_target_type, init);
5319                                         store_field (f, typed_inst, init.initializer.target_value, init.source_reference);
5320
5321                                         var cl = f.parent_symbol as Class;
5322                                         if (cl != null) {
5323                                                 generate_class_struct_declaration (cl, cfile);
5324                                         }
5325                                 } else if (init.symbol_reference is Property) {
5326                                         var p = (Property) init.symbol_reference;
5327                                         if (p.base_property != null) {
5328                                                 p = p.base_property;
5329                                         } else if (p.base_interface_property != null) {
5330                                                 p = p.base_interface_property;
5331                                         }
5332                                         var instance_target_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) p.parent_symbol);
5333                                         var typed_inst = transform_value (new GLibValue (expr.type_reference, instance), instance_target_type, init);
5334                                         var inst_ma = new MemberAccess.simple ("fake");
5335                                         inst_ma.target_value = typed_inst;
5336                                         store_property (p, inst_ma, init.initializer.target_value);
5337                                         // FIXME Do not ref/copy in the first place
5338                                         if (!p.set_accessor.value_type.value_owned && requires_destroy (init.initializer.target_value.value_type)) {
5339                                                 ccode.add_expression (destroy_value (init.initializer.target_value));
5340                                         }
5341                                 } else {
5342                                         Report.error (init.source_reference, "internal: Unsupported symbol");
5343                                 }
5344                         }
5345
5346                         set_cvalue (expr, instance);
5347                 } else if (creation_expr != null) {
5348                         var temp_value = create_temp_value (expr.value_type, false, expr);
5349                         ccode.add_assignment (get_cvalue_ (temp_value), creation_expr);
5350                         expr.target_value = temp_value;
5351
5352                         unowned Class? cl = expr.type_reference.type_symbol as Class;
5353                         if (context.gobject_tracing) {
5354                                 // GObject creation tracing enabled
5355
5356                                 if (cl != null && cl.is_subtype_of (gobject_type)) {
5357                                         // creating GObject
5358
5359                                         // instance can be NULL in error cases
5360                                         ccode.open_if (get_cvalue_ (expr.target_value));
5361
5362                                         var set_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set_data"));
5363                                         set_data_call.add_argument (new CCodeCastExpression (get_cvalue_ (expr.target_value), "GObject *"));
5364                                         set_data_call.add_argument (new CCodeConstant ("\"vala-creation-function\""));
5365
5366                                         string func_name = "";
5367                                         if (current_method != null) {
5368                                                 func_name = current_method.get_full_name ();
5369                                         } else if (current_property_accessor != null) {
5370                                                 func_name = current_property_accessor.get_full_name ();
5371                                         }
5372
5373                                         set_data_call.add_argument (new CCodeConstant ("\"%s\"".printf (func_name)));
5374
5375                                         ccode.add_expression (set_data_call);
5376
5377                                         ccode.close ();
5378                                 }
5379                         }
5380
5381                         // create a special GDestroyNotify for created GArray and set with g_array_set_clear_func (since glib 2.32)
5382                         if (cl != null && cl == garray_type) {
5383                                 var type_arg = expr.type_reference.get_type_arguments ().get (0);
5384                                 if (requires_destroy (type_arg)) {
5385                                         var clear_func = new CCodeFunctionCall (new CCodeIdentifier ("g_array_set_clear_func"));
5386                                         clear_func.add_argument (get_cvalue_ (expr.target_value));
5387                                         string destroy_func;
5388                                         if (type_arg.is_non_null_simple_type () || type_arg.is_real_non_null_struct_type ()) {
5389                                                 destroy_func = get_ccode_destroy_function (type_arg.type_symbol);
5390                                         } else {
5391                                                 destroy_func = generate_destroy_function_content_of_wrapper (type_arg);
5392                                         }
5393                                         clear_func.add_argument (new CCodeCastExpression (new CCodeIdentifier (destroy_func), "GDestroyNotify"));
5394                                         ccode.add_expression (clear_func);
5395                                 }
5396                         }
5397                 }
5398
5399                 ((GLibValue) expr.target_value).lvalue = true;
5400         }
5401
5402         public CCodeExpression? handle_struct_argument (Parameter? param, Expression arg, CCodeExpression? cexpr) {
5403                 DataType type;
5404                 if (param != null) {
5405                         type = param.variable_type;
5406                 } else {
5407                         // varargs
5408                         type = arg.value_type;
5409                 }
5410
5411                 var unary = arg as UnaryExpression;
5412                 // pass non-simple struct instances always by reference
5413                 if (!(arg.value_type is NullType) && type.is_real_struct_type ()) {
5414                         // we already use a reference for arguments of ref, out, and nullable parameters
5415                         if (!(unary != null && (unary.operator == UnaryOperator.OUT || unary.operator == UnaryOperator.REF)) && !type.nullable) {
5416                                 if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
5417                                         return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
5418                                 } else {
5419                                         // if cexpr is e.g. a function call, we can't take the address of the expression
5420                                         var temp_value = create_temp_value (type, false, arg);
5421                                         ccode.add_assignment (get_cvalue_ (temp_value), cexpr);
5422                                         return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value));
5423                                 }
5424                         }
5425                 }
5426
5427                 return cexpr;
5428         }
5429
5430         public override void visit_sizeof_expression (SizeofExpression expr) {
5431                 generate_type_declaration (expr.type_reference, cfile);
5432
5433                 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5434                 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.type_reference)));
5435                 set_cvalue (expr, csizeof);
5436         }
5437
5438         public override void visit_typeof_expression (TypeofExpression expr) {
5439                 cfile.add_include ("glib-object.h");
5440
5441                 set_cvalue (expr, get_type_id_expression (expr.type_reference));
5442         }
5443
5444         public override void visit_unary_expression (UnaryExpression expr) {
5445                 if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) {
5446                         var glib_value = (GLibValue) expr.inner.target_value;
5447
5448                         var ref_value = new GLibValue (glib_value.value_type);
5449                         if (expr.target_type != null && glib_value.value_type.is_real_struct_type () && glib_value.value_type.nullable != expr.target_type.nullable) {
5450                                 // the only possibility is that value_type is nullable and target_type is non-nullable
5451                                 ref_value.cvalue = glib_value.cvalue;
5452                         } else {
5453                                 ref_value.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.cvalue);
5454                         }
5455
5456                         if (glib_value.array_length_cvalues != null) {
5457                                 for (int i = 0; i < glib_value.array_length_cvalues.size; i++) {
5458                                         ref_value.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.array_length_cvalues[i]));
5459                                 }
5460                         }
5461
5462                         if (glib_value.delegate_target_cvalue != null) {
5463                                 ref_value.delegate_target_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_cvalue);
5464                         }
5465                         if (glib_value.delegate_target_destroy_notify_cvalue != null) {
5466                                 ref_value.delegate_target_destroy_notify_cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, glib_value.delegate_target_destroy_notify_cvalue);
5467                         }
5468
5469                         expr.target_value = ref_value;
5470                         return;
5471                 }
5472
5473                 if (expr.operator == UnaryOperator.INCREMENT || expr.operator == UnaryOperator.DECREMENT) {
5474                         // increment/decrement variable
5475                         var op = expr.operator == UnaryOperator.INCREMENT ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
5476                         var cexpr = new CCodeBinaryExpression (op, get_cvalue_ (expr.inner.target_value), new CCodeConstant ("1"));
5477                         ccode.add_assignment (get_cvalue (expr.inner), cexpr);
5478
5479                         // assign new value to temp variable
5480                         var temp_value = store_temp_value (expr.inner.target_value, expr);
5481
5482                         MemberAccess ma = find_property_access (expr.inner);
5483                         if (ma != null) {
5484                                 // property postfix expression
5485                                 var prop = (Property) ma.symbol_reference;
5486
5487                                 store_property (prop, ma.inner, temp_value);
5488                         }
5489
5490                         // return new value
5491                         expr.target_value = temp_value;
5492                         return;
5493                 }
5494
5495                 CCodeUnaryOperator op;
5496                 switch (expr.operator) {
5497                 case UnaryOperator.PLUS:
5498                         op = CCodeUnaryOperator.PLUS;
5499                         break;
5500                 case UnaryOperator.MINUS:
5501                         op = CCodeUnaryOperator.MINUS;
5502                         break;
5503                 case UnaryOperator.LOGICAL_NEGATION:
5504                         op = CCodeUnaryOperator.LOGICAL_NEGATION;
5505                         break;
5506                 case UnaryOperator.BITWISE_COMPLEMENT:
5507                         op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
5508                         break;
5509                 case UnaryOperator.INCREMENT:
5510                         op = CCodeUnaryOperator.PREFIX_INCREMENT;
5511                         break;
5512                 case UnaryOperator.DECREMENT:
5513                         op = CCodeUnaryOperator.PREFIX_DECREMENT;
5514                         break;
5515                 default:
5516                         assert_not_reached ();
5517                 }
5518                 set_cvalue (expr, new CCodeUnaryExpression (op, get_cvalue (expr.inner)));
5519         }
5520
5521         public virtual CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
5522                 assert_not_reached ();
5523         }
5524
5525         public virtual CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
5526                 assert_not_reached ();
5527         }
5528
5529         public override void visit_cast_expression (CastExpression expr) {
5530                 if (expr.is_silent_cast) {
5531                         set_cvalue (expr, new CCodeInvalidExpression ());
5532                         expr.error = true;
5533                         Report.error (expr.source_reference, "Operation not supported for this type");
5534                         return;
5535                 }
5536
5537                 generate_type_declaration (expr.type_reference, cfile);
5538
5539                 // recompute array length when casting to other array type
5540                 var array_type = expr.type_reference as ArrayType;
5541                 if (array_type != null && expr.inner.value_type is ArrayType) {
5542                         if (array_type.element_type is GenericType || ((ArrayType) expr.inner.value_type).element_type is GenericType) {
5543                                 // element size unknown for generic arrays, retain array length as is
5544                                 for (int dim = 1; dim <= array_type.rank; dim++) {
5545                                         append_array_length (expr, get_array_length_cexpression (expr.inner, dim));
5546                                 }
5547                         } else {
5548                                 var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5549                                 sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5550
5551                                 var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5552                                 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (((ArrayType) expr.inner.value_type).element_type)));
5553
5554                                 for (int dim = 1; dim <= array_type.rank; dim++) {
5555                                         append_array_length (expr, new CCodeBinaryExpression (CCodeBinaryOperator.DIV, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_array_length_cexpression (expr.inner, dim), sizeof_from), sizeof_to));
5556                                 }
5557                         }
5558                 } else if (array_type != null) {
5559                         CCodeExpression array_length_expr;
5560
5561                         var sizeof_to = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5562                         sizeof_to.add_argument (new CCodeConstant (get_ccode_name (array_type.element_type)));
5563                         var sizeof_from = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
5564
5565                         var value_type = expr.inner.value_type;
5566                         if (value_type is ValueType) {
5567                                 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (value_type.type_symbol)));
5568                                 array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5569                         } else if (value_type is PointerType && ((PointerType) value_type).base_type is ValueType) {
5570                                 sizeof_from.add_argument (new CCodeConstant (get_ccode_name (((PointerType) value_type).base_type.type_symbol)));
5571                                 array_length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.DIV, sizeof_from, sizeof_to);
5572                         } else {
5573                                 // cast from unsupported non-array to array, set invalid length
5574                                 // required by string.data, e.g.
5575                                 array_length_expr = new CCodeConstant ("-1");
5576                         }
5577
5578                         for (int dim = 1; dim <= array_type.rank; dim++) {
5579                                 append_array_length (expr, array_length_expr);
5580                         }
5581                 }
5582
5583                 var innercexpr = get_cvalue (expr.inner);
5584                 if (expr.type_reference is ValueType && !expr.type_reference.nullable &&
5585                         expr.inner.value_type is ValueType && expr.inner.value_type.nullable) {
5586                         // handle nested cast expressions
5587                         unowned Expression? inner_expr = expr.inner;
5588                         while (inner_expr is CastExpression) {
5589                                 inner_expr = ((CastExpression) inner_expr).inner;
5590                         }
5591                         if (inner_expr.value_type.value_owned
5592                             && !(inner_expr.symbol_reference is Variable || inner_expr is ElementAccess)) {
5593                                 // heap allocated struct leaked, destroy it
5594                                 var value = new GLibValue (new PointerType (new VoidType ()), innercexpr);
5595                                 temp_ref_values.insert (0, value);
5596                         }
5597                         // nullable integer or float or boolean or struct or enum cast to non-nullable
5598                         innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, innercexpr);
5599                 } else if (expr.type_reference is ValueType && expr.type_reference.nullable &&
5600                         expr.inner.value_type.is_real_non_null_struct_type ()) {
5601                         // real non-null struct cast to nullable
5602                         innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, innercexpr);
5603                 } else if (expr.type_reference is ArrayType && !(expr.inner is Literal)
5604                     && expr.inner.value_type is ValueType && !expr.inner.value_type.nullable) {
5605                         // integer or float or boolean or struct or enum to array cast
5606                         innercexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, innercexpr);
5607                 }
5608                 set_cvalue (expr, new CCodeCastExpression (innercexpr, get_ccode_name (expr.type_reference)));
5609                 //TODO Use get_non_null (expr.inner.target_value)
5610                 ((GLibValue) expr.target_value).non_null = expr.is_non_null ();
5611
5612                 if (expr.type_reference is DelegateType) {
5613                         var target = get_delegate_target (expr.inner);
5614                         if (target != null) {
5615                                 set_delegate_target (expr, target);
5616                         } else {
5617                                 set_delegate_target (expr, new CCodeConstant ("NULL"));
5618                         }
5619                         var target_destroy_notify = get_delegate_target_destroy_notify (expr.inner);
5620                         if (target_destroy_notify != null) {
5621                                 set_delegate_target_destroy_notify (expr, target_destroy_notify);
5622                         } else {
5623                                 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
5624                         }
5625                 }
5626         }
5627
5628         public override void visit_named_argument (NamedArgument expr) {
5629                 set_cvalue (expr, get_cvalue (expr.inner));
5630         }
5631
5632         public override void visit_pointer_indirection (PointerIndirection expr) {
5633                 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_cvalue (expr.inner)));
5634                 ((GLibValue) expr.target_value).lvalue = get_lvalue (expr.inner.target_value);
5635         }
5636
5637         public override void visit_addressof_expression (AddressofExpression expr) {
5638                 set_cvalue (expr, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5639         }
5640
5641         public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
5642                 /* tmp = expr.inner; expr.inner = NULL; expr = tmp; */
5643                 expr.target_value = store_temp_value (expr.inner.target_value, expr);
5644
5645                 if (expr.inner.value_type is StructValueType && !expr.inner.value_type.nullable) {
5646                         // memset needs string.h
5647                         cfile.add_include ("string.h");
5648                         var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
5649                         creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner)));
5650                         creation_call.add_argument (new CCodeConstant ("0"));
5651                         creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (expr.inner.value_type))));
5652                         ccode.add_expression (creation_call);
5653                 } else if (expr.value_type is DelegateType) {
5654                         ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5655                         var target = get_delegate_target_cvalue (expr.inner.target_value);
5656                         if (target != null) {
5657                                 ccode.add_assignment (target, new CCodeConstant ("NULL"));
5658                         }
5659                         var target_destroy_notify = get_delegate_target_destroy_notify_cvalue (expr.inner.target_value);
5660                         if (target_destroy_notify != null) {
5661                                 ccode.add_assignment (target_destroy_notify, new CCodeConstant ("NULL"));
5662                         }
5663                 } else if (expr.inner.value_type is ArrayType) {
5664                         var array_type = (ArrayType) expr.inner.value_type;
5665                         var glib_value = (GLibValue) expr.inner.target_value;
5666
5667                         ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5668                         if (glib_value.array_length_cvalues != null) {
5669                                 for (int dim = 1; dim <= array_type.rank; dim++) {
5670                                         ccode.add_assignment (get_array_length_cvalue (glib_value, dim), new CCodeConstant ("0"));
5671                                 }
5672                         }
5673                 } else {
5674                         ccode.add_assignment (get_cvalue (expr.inner), new CCodeConstant ("NULL"));
5675                 }
5676         }
5677
5678         public override void visit_binary_expression (BinaryExpression expr) {
5679                 var cleft = get_cvalue (expr.left);
5680                 var cright = get_cvalue (expr.right);
5681
5682                 CCodeExpression? left_chain = null;
5683                 if (expr.is_chained) {
5684                         var lbe = (BinaryExpression) expr.left;
5685
5686                         var temp_decl = get_temp_variable (lbe.right.target_type, true, null, false);
5687                         emit_temp_var (temp_decl);
5688                         var cvar = get_variable_cexpression (temp_decl.name);
5689                         var clbe = (CCodeBinaryExpression) get_cvalue (lbe);
5690                         if (lbe.is_chained) {
5691                                 clbe = (CCodeBinaryExpression) clbe.right;
5692                         }
5693                         ccode.add_assignment (cvar, get_cvalue (lbe.right));
5694                         clbe.right = get_variable_cexpression (temp_decl.name);
5695                         left_chain = cleft;
5696                         cleft = cvar;
5697                 }
5698
5699                 CCodeBinaryOperator op;
5700                 switch (expr.operator) {
5701                 case BinaryOperator.PLUS:
5702                         op = CCodeBinaryOperator.PLUS;
5703                         break;
5704                 case BinaryOperator.MINUS:
5705                         op = CCodeBinaryOperator.MINUS;
5706                         break;
5707                 case BinaryOperator.MUL:
5708                         op = CCodeBinaryOperator.MUL;
5709                         break;
5710                 case BinaryOperator.DIV:
5711                         op = CCodeBinaryOperator.DIV;
5712                         break;
5713                 case BinaryOperator.MOD:
5714                         // FIXME Code duplication with CCodeAssignmentModule.emit_simple_assignment()
5715                         if (expr.value_type.equals (double_type)) {
5716                                 cfile.add_include ("math.h");
5717                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
5718                                 ccall.add_argument (cleft);
5719                                 ccall.add_argument (cright);
5720                                 set_cvalue (expr, ccall);
5721                                 return;
5722                         } else if (expr.value_type.equals (float_type)) {
5723                                 cfile.add_include ("math.h");
5724                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
5725                                 ccall.add_argument (cleft);
5726                                 ccall.add_argument (cright);
5727                                 set_cvalue (expr, ccall);
5728                                 return;
5729                         } else {
5730                                 op = CCodeBinaryOperator.MOD;
5731                         }
5732                         break;
5733                 case BinaryOperator.SHIFT_LEFT:
5734                         op = CCodeBinaryOperator.SHIFT_LEFT;
5735                         break;
5736                 case BinaryOperator.SHIFT_RIGHT:
5737                         op = CCodeBinaryOperator.SHIFT_RIGHT;
5738                         break;
5739                 case BinaryOperator.LESS_THAN:
5740                         op = CCodeBinaryOperator.LESS_THAN;
5741                         break;
5742                 case BinaryOperator.GREATER_THAN:
5743                         op = CCodeBinaryOperator.GREATER_THAN;
5744                         break;
5745                 case BinaryOperator.LESS_THAN_OR_EQUAL:
5746                         op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
5747                         break;
5748                 case BinaryOperator.GREATER_THAN_OR_EQUAL:
5749                         op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
5750                         break;
5751                 case BinaryOperator.EQUALITY:
5752                         op = CCodeBinaryOperator.EQUALITY;
5753                         break;
5754                 case BinaryOperator.INEQUALITY:
5755                         op = CCodeBinaryOperator.INEQUALITY;
5756                         break;
5757                 case BinaryOperator.BITWISE_AND:
5758                         op = CCodeBinaryOperator.BITWISE_AND;
5759                         break;
5760                 case BinaryOperator.BITWISE_OR:
5761                         op = CCodeBinaryOperator.BITWISE_OR;
5762                         break;
5763                 case BinaryOperator.BITWISE_XOR:
5764                         op = CCodeBinaryOperator.BITWISE_XOR;
5765                         break;
5766                 case BinaryOperator.AND:
5767                         op = CCodeBinaryOperator.AND;
5768                         break;
5769                 case BinaryOperator.OR:
5770                         op = CCodeBinaryOperator.OR;
5771                         break;
5772                 case BinaryOperator.IN:
5773                         if (expr.right.value_type is ArrayType) {
5774                                 unowned ArrayType array_type = (ArrayType) expr.right.value_type;
5775                                 unowned DataType element_type = array_type.element_type;
5776                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_contains_wrapper (array_type)));
5777                                 CCodeExpression node = ccall;
5778
5779                                 ccall.add_argument (cright);
5780                                 ccall.add_argument (get_array_length_cexpression (expr.right));
5781                                 if (element_type is StructValueType) {
5782                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft));
5783                                 } else if (element_type is ValueType && !element_type.nullable
5784                                         && expr.left.value_type is ValueType && expr.left.value_type.nullable) {
5785                                         // null check
5786                                         var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cleft, new CCodeConstant ("NULL"));
5787                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft));
5788                                         node = new CCodeParenthesizedExpression (new CCodeConditionalExpression (cnull, new CCodeConstant ("FALSE"), ccall));
5789                                 } else {
5790                                         ccall.add_argument (cleft);
5791                                 }
5792                                 set_cvalue (expr, node);
5793                         } else {
5794                                 set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, cright, cleft), cleft));
5795                         }
5796                         return;
5797                 default:
5798                         assert_not_reached ();
5799                 }
5800
5801                 if (expr.operator == BinaryOperator.EQUALITY ||
5802                     expr.operator == BinaryOperator.INEQUALITY) {
5803                         var left_type = expr.left.target_type;
5804                         var right_type = expr.right.target_type;
5805                         make_comparable_cexpression (ref left_type, ref cleft, ref right_type, ref cright);
5806
5807                         if (left_type is StructValueType && right_type is StructValueType) {
5808                                 var equalfunc = generate_struct_equal_function ((Struct) left_type.type_symbol);
5809                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5810                                 ccall.add_argument (cleft);
5811                                 ccall.add_argument (cright);
5812                                 cleft = ccall;
5813                                 cright = get_boolean_cconstant (true);
5814                         } else if ((left_type is IntegerType || left_type is FloatingType || left_type is BooleanType || left_type is EnumValueType) && left_type.nullable &&
5815                                    (right_type is IntegerType || right_type is FloatingType || right_type is BooleanType || right_type is EnumValueType) && right_type.nullable) {
5816                                 var equalfunc = generate_numeric_equal_function ((TypeSymbol) left_type.type_symbol);
5817                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5818                                 ccall.add_argument (cleft);
5819                                 ccall.add_argument (cright);
5820                                 cleft = ccall;
5821                                 cright = get_boolean_cconstant (true);
5822                         }
5823                 }
5824
5825                 bool is_string_comparison = !(expr.left.value_type is NullType) && expr.left.value_type.compatible (string_type)
5826                         && !(expr.right.value_type is NullType) && expr.right.value_type.compatible (string_type);
5827                 bool has_string_literal = (expr.left is StringLiteral || expr.right is StringLiteral);
5828
5829                 if (is_string_comparison || (has_string_literal && expr.operator != BinaryOperator.PLUS)) {
5830                         switch (expr.operator) {
5831                         case BinaryOperator.PLUS:
5832                                 // string concatenation
5833                                 if (expr.left.is_constant () && expr.right.is_constant ()) {
5834                                         string left, right;
5835
5836                                         if (cleft is CCodeIdentifier) {
5837                                                 left = ((CCodeIdentifier) cleft).name;
5838                                         } else if (cleft is CCodeConstant) {
5839                                                 left = ((CCodeConstant) cleft).name;
5840                                         } else {
5841                                                 Report.error (expr.source_reference, "internal: Unsupported expression");
5842                                                 left = "NULL";
5843                                         }
5844                                         if (cright is CCodeIdentifier) {
5845                                                 right = ((CCodeIdentifier) cright).name;
5846                                         } else if (cright is CCodeConstant) {
5847                                                 right = ((CCodeConstant) cright).name;
5848                                         } else {
5849                                                 Report.error (expr.source_reference, "internal: Unsupported expression");
5850                                                 right = "NULL";
5851                                         }
5852
5853                                         set_cvalue (expr, new CCodeConstant ("%s %s".printf (left, right)));
5854                                 } else {
5855                                         var temp_value = create_temp_value (expr.value_type, false, expr);
5856                                         CCodeFunctionCall ccall;
5857
5858                                         if (context.profile == Profile.POSIX) {
5859                                                 // convert to strcat (strcpy (malloc (1 + strlen (a) + strlen (b)), a), b)
5860                                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("strcat"));
5861                                                 var strcpy = new CCodeFunctionCall (new CCodeIdentifier ("strcpy"));
5862                                                 var malloc = new CCodeFunctionCall (new CCodeIdentifier ("malloc"));
5863
5864                                                 var strlen_a = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
5865                                                 strlen_a.add_argument (cleft);
5866                                                 var strlen_b = new CCodeFunctionCall (new CCodeIdentifier ("strlen"));
5867                                                 strlen_b.add_argument (cright);
5868                                                 var newlength = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("1"),
5869                                                         new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, strlen_a, strlen_b));
5870                                                 malloc.add_argument (newlength);
5871
5872                                                 strcpy.add_argument (malloc);
5873                                                 strcpy.add_argument (cleft);
5874
5875                                                 ccall.add_argument (strcpy);
5876                                                 ccall.add_argument (cright);
5877                                         } else {
5878                                                 // convert to g_strconcat (a, b, NULL)
5879                                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
5880                                                 ccall.add_argument (cleft);
5881                                                 ccall.add_argument (cright);
5882                                                 ccall.add_argument (new CCodeConstant("NULL"));
5883                                         }
5884
5885                                         ccode.add_assignment (get_cvalue_ (temp_value), ccall);
5886                                         expr.target_value = temp_value;
5887                                 }
5888                                 return;
5889                         case BinaryOperator.EQUALITY:
5890                         case BinaryOperator.INEQUALITY:
5891                         case BinaryOperator.LESS_THAN:
5892                         case BinaryOperator.GREATER_THAN:
5893                         case BinaryOperator.LESS_THAN_OR_EQUAL:
5894                         case BinaryOperator.GREATER_THAN_OR_EQUAL:
5895                                 CCodeFunctionCall ccall;
5896                                 if (context.profile == Profile.POSIX) {
5897                                         cfile.add_include ("string.h");
5898                                         ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
5899                                 } else {
5900                                         ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5901                                 }
5902                                 ccall.add_argument (cleft);
5903                                 ccall.add_argument (cright);
5904                                 cleft = ccall;
5905                                 cright = new CCodeConstant ("0");
5906                                 break;
5907                         default:
5908                                 break;
5909                         }
5910                 }
5911
5912                 set_cvalue (expr, new CCodeBinaryExpression (op, cleft, cright));
5913                 if (left_chain != null) {
5914                         set_cvalue (expr, new CCodeBinaryExpression (CCodeBinaryOperator.AND, left_chain, get_cvalue (expr)));
5915                 }
5916         }
5917
5918         public CCodeExpression? create_type_check (CCodeNode ccodenode, DataType type) {
5919                 var et = type as ErrorType;
5920                 if (et != null && et.error_code != null) {
5921                         var matches_call = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
5922                         matches_call.add_argument ((CCodeExpression) ccodenode);
5923                         matches_call.add_argument (new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain)));
5924                         matches_call.add_argument (new CCodeIdentifier (get_ccode_name (et.error_code)));
5925                         return matches_call;
5926                 } else if (et != null && et.error_domain != null) {
5927                         var instance_domain = new CCodeMemberAccess.pointer ((CCodeExpression) ccodenode, "domain");
5928                         var type_domain = new CCodeIdentifier (get_ccode_upper_case_name (et.error_domain));
5929                         return new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, instance_domain, type_domain);
5930                 } else {
5931                         CCodeFunctionCall ccheck;
5932                         if (type is GenericType || type.type_symbol == null || type.type_symbol.external_package) {
5933                                 ccheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
5934                                 ccheck.add_argument ((CCodeExpression) ccodenode);
5935                                 ccheck.add_argument (get_type_id_expression (type));
5936                         } else {
5937                                 ccheck = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_check_function (type.type_symbol)));
5938                                 ccheck.add_argument ((CCodeExpression) ccodenode);
5939                         }
5940
5941                         return ccheck;
5942                 }
5943         }
5944
5945         string generate_array_contains_wrapper (ArrayType array_type) {
5946                 string array_contains_func = "_vala_%s_array_contains".printf (get_ccode_lower_case_name (array_type.element_type));
5947
5948                 if (!add_wrapper (array_contains_func)) {
5949                         return array_contains_func;
5950                 }
5951
5952                 generate_type_declaration (ssize_t_type, cfile);
5953
5954                 var function = new CCodeFunction (array_contains_func, get_ccode_name (bool_type));
5955                 function.modifiers = CCodeModifiers.STATIC;
5956
5957                 function.add_parameter (new CCodeParameter ("stack", "%s *".printf (get_ccode_name (array_type.element_type))));
5958                 function.add_parameter (new CCodeParameter ("stack_length", get_ccode_name (ssize_t_type)));
5959                 if (array_type.element_type is StructValueType) {
5960                         function.add_parameter (new CCodeParameter ("needle", "const %s *".printf (get_ccode_name (array_type.element_type))));
5961                 } else {
5962                         function.add_parameter (new CCodeParameter ("needle", "const %s".printf (get_ccode_name (array_type.element_type))));
5963                 }
5964
5965                 push_function (function);
5966
5967                 ccode.add_declaration (get_ccode_name (ssize_t_type), new CCodeVariableDeclarator ("i"));
5968
5969                 var cloop_initializer = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
5970                 var cloop_condition = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("stack_length"));
5971                 var cloop_iterator = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i"));
5972                 ccode.open_for (cloop_initializer, cloop_condition, cloop_iterator);
5973
5974                 var celement = new CCodeElementAccess (new CCodeIdentifier ("stack"), new CCodeIdentifier ("i"));
5975                 var cneedle = new CCodeIdentifier ("needle");
5976                 CCodeBinaryExpression cif_condition;
5977                 if (array_type.element_type.compatible (string_type)) {
5978                         CCodeFunctionCall ccall;
5979                         if (context.profile == Profile.POSIX) {
5980                                 cfile.add_include ("string.h");
5981                                 ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
5982                         } else {
5983                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
5984                         }
5985                         ccall.add_argument (celement);
5986                         ccall.add_argument (cneedle);
5987                         cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, new CCodeConstant ("0"));
5988                 } else if (array_type.element_type is StructValueType) {
5989                         var equalfunc = generate_struct_equal_function ((Struct) array_type.element_type.type_symbol);
5990                         var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
5991                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, celement));
5992                         ccall.add_argument (cneedle);
5993                         cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccall, get_boolean_cconstant (true));
5994                 } else {
5995                         cif_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cneedle, celement);
5996                 }
5997
5998                 ccode.open_if (cif_condition);
5999                 ccode.add_return (get_boolean_cconstant (true));
6000                 ccode.close ();
6001
6002                 ccode.close ();
6003
6004                 ccode.add_return (get_boolean_cconstant (false));
6005
6006                 pop_function ();
6007
6008                 cfile.add_function_declaration (function);
6009                 cfile.add_function (function);
6010
6011                 return array_contains_func;
6012         }
6013
6014         string generate_cmp_wrapper (CCodeIdentifier cmpid) {
6015                 // generate and call NULL-aware cmp function to reduce number
6016                 // of temporary variables and simplify code
6017
6018                 string cmp0_func = "_%s0".printf (cmpid.name);
6019
6020                 // g_strcmp0 is already NULL-safe
6021                 if (cmpid.name == "g_strcmp0") {
6022                         cmp0_func = cmpid.name;
6023                 } else if (add_wrapper (cmp0_func)) {
6024                         var cmp0_fun = new CCodeFunction (cmp0_func, get_ccode_name (int_type));
6025                         cmp0_fun.add_parameter (new CCodeParameter ("s1", "const void *"));
6026                         cmp0_fun.add_parameter (new CCodeParameter ("s2", "const void *"));
6027                         cmp0_fun.modifiers = CCodeModifiers.STATIC;
6028
6029                         push_function (cmp0_fun);
6030
6031                         // s1 != s2;
6032                         var noteq = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
6033
6034                         // if (!s1) return -(s1 != s2);
6035                         {
6036                                 var cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("s1"));
6037                                 ccode.open_if (cexp);
6038                                 ccode.add_return (new CCodeUnaryExpression (CCodeUnaryOperator.MINUS, noteq));
6039                                 ccode.close ();
6040                         }
6041                         // if (!s2) return s1 != s2;
6042                         {
6043                                 var cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("s2"));
6044                                 ccode.open_if (cexp);
6045                                 ccode.add_return (noteq);
6046                                 ccode.close ();
6047                         }
6048                         // return strcmp (s1, s2);
6049                         var cmp_call = new CCodeFunctionCall (cmpid);
6050                         cmp_call.add_argument (new CCodeIdentifier ("s1"));
6051                         cmp_call.add_argument (new CCodeIdentifier ("s2"));
6052                         ccode.add_return (cmp_call);
6053
6054                         pop_function ();
6055
6056                         cfile.add_function (cmp0_fun);
6057                 }
6058
6059                 return cmp0_func;
6060         }
6061
6062         public override void visit_type_check (TypeCheck expr) {
6063                 generate_type_declaration (expr.type_reference, cfile);
6064
6065                 var type = expr.expression.value_type;
6066                 var pointer_type = type as PointerType;
6067                 if (pointer_type != null) {
6068                         type = pointer_type.base_type;
6069                 }
6070                 unowned Class? cl = type.type_symbol as Class;
6071                 unowned Interface? iface = type.type_symbol as Interface;
6072                 if ((cl != null && !cl.is_compact) || iface != null || type is GenericType || type is ErrorType) {
6073                         set_cvalue (expr, create_type_check (get_cvalue (expr.expression), expr.type_reference));
6074                 } else {
6075                         set_cvalue (expr, new CCodeInvalidExpression ());
6076                 }
6077
6078                 if (get_cvalue (expr) is CCodeInvalidExpression) {
6079                         Report.error (expr.source_reference, "type check expressions not supported for compact classes, structs, and enums");
6080                 }
6081         }
6082
6083         public override void visit_lambda_expression (LambdaExpression lambda) {
6084                 var delegate_type = (DelegateType) lambda.target_type;
6085
6086                 lambda.accept_children (this);
6087
6088                 bool expr_owned = lambda.value_type.value_owned;
6089
6090                 set_cvalue (lambda, new CCodeIdentifier (get_ccode_name (lambda.method)));
6091
6092                 unowned DataType? this_type;
6093                 if (lambda.method.closure) {
6094                         int block_id = get_block_id (current_closure_block);
6095                         var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
6096                         if (expr_owned || delegate_type.is_called_once) {
6097                                 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
6098                                 ref_call.add_argument (delegate_target);
6099                                 delegate_target = ref_call;
6100                                 set_delegate_target_destroy_notify (lambda, new CCodeIdentifier ("block%d_data_unref".printf (block_id)));
6101                         } else {
6102                                 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
6103                         }
6104                         set_delegate_target (lambda, delegate_target);
6105                 } else if ((this_type = get_this_type ()) != null) {
6106                         CCodeExpression delegate_target = get_this_cexpression ();
6107                         delegate_target = convert_to_generic_pointer (delegate_target, this_type);
6108                         if (expr_owned || delegate_type.is_called_once) {
6109                                 var ref_call = new CCodeFunctionCall (get_dup_func_expression (this_type, lambda.source_reference));
6110                                 ref_call.add_argument (delegate_target);
6111                                 delegate_target = ref_call;
6112                                 set_delegate_target_destroy_notify (lambda, get_destroy_func_expression (this_type));
6113                         } else {
6114                                 set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
6115                         }
6116                         set_delegate_target (lambda, delegate_target);
6117                 } else {
6118                         set_delegate_target (lambda, new CCodeConstant ("NULL"));
6119                         set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
6120                 }
6121         }
6122
6123         public CCodeExpression convert_from_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
6124                 unowned SemanticAnalyzer analyzer = context.analyzer;
6125                 var result = cexpr;
6126                 if (analyzer.is_reference_type_argument (actual_type) || analyzer.is_nullable_value_type_argument (actual_type)) {
6127                         generate_type_declaration (actual_type, cfile);
6128                         result = new CCodeCastExpression (cexpr, get_ccode_name (actual_type));
6129                 } else if (analyzer.is_signed_integer_type_argument (actual_type)) {
6130                         // FIXME this should not happen
6131                         while (cexpr is CCodeCastExpression) {
6132                                 cexpr = ((CCodeCastExpression) cexpr).inner;
6133                         }
6134                         result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), get_ccode_name (actual_type));
6135                 } else if (analyzer.is_unsigned_integer_type_argument (actual_type)) {
6136                         // FIXME this should not happen
6137                         while (cexpr is CCodeCastExpression) {
6138                                 cexpr = ((CCodeCastExpression) cexpr).inner;
6139                         }
6140                         result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), get_ccode_name (actual_type));
6141                 }
6142                 return result;
6143         }
6144
6145         public CCodeExpression convert_to_generic_pointer (CCodeExpression cexpr, DataType actual_type) {
6146                 unowned SemanticAnalyzer analyzer = context.analyzer;
6147                 var result = cexpr;
6148                 if (analyzer.is_signed_integer_type_argument (actual_type)) {
6149                         // FIXME this should not happen
6150                         while (cexpr is CCodeCastExpression) {
6151                                 cexpr = ((CCodeCastExpression) cexpr).inner;
6152                         }
6153                         result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "gintptr"), get_ccode_name (pointer_type));
6154                 } else if (analyzer.is_unsigned_integer_type_argument (actual_type)) {
6155                         // FIXME this should not happen
6156                         while (cexpr is CCodeCastExpression) {
6157                                 cexpr = ((CCodeCastExpression) cexpr).inner;
6158                         }
6159                         result = new CCodeCastExpression (new CCodeCastExpression (cexpr, "guintptr"), get_ccode_name (pointer_type));
6160                 }
6161                 return result;
6162         }
6163
6164         int next_variant_function_id = 0;
6165
6166         public TargetValue transform_value (TargetValue value, DataType? target_type, CodeNode node) {
6167                 var type = value.value_type;
6168                 var result = ((GLibValue) value).copy ();
6169
6170                 if (type.value_owned
6171                     && (target_type == null || target_type is GenericType || !target_type.floating_reference)
6172                     && type.floating_reference) {
6173                         /* floating reference, sink it.
6174                          */
6175                         unowned ObjectTypeSymbol? cl = type.type_symbol as ObjectTypeSymbol;
6176                         var sink_func = (cl != null) ? get_ccode_ref_sink_function (cl) : "";
6177
6178                         if (sink_func != "") {
6179                                 if (type.nullable) {
6180                                         var is_not_null = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, result.cvalue, new CCodeConstant ("NULL"));
6181                                         ccode.open_if (is_not_null);
6182                                 }
6183
6184                                 var csink = new CCodeFunctionCall (new CCodeIdentifier (sink_func));
6185                                 csink.add_argument (result.cvalue);
6186                                 ccode.add_expression (csink);
6187
6188                                 if (type.nullable) {
6189                                         ccode.close ();
6190                                 }
6191                         } else {
6192                                 Report.error (node.source_reference, "type `%s' does not support floating references", type.type_symbol.name);
6193                         }
6194                 }
6195
6196                 bool boxing = (type is ValueType && !type.nullable
6197                                && target_type is ValueType && target_type.nullable);
6198                 bool unboxing = (type is ValueType && type.nullable
6199                                  && target_type is ValueType && !target_type.nullable);
6200
6201                 bool gvalue_boxing = (context.profile == Profile.GOBJECT
6202                                       && target_type != null
6203                                       && target_type.type_symbol == gvalue_type
6204                                       && !(type is NullType)
6205                                       && get_ccode_type_id (type) != "G_TYPE_VALUE");
6206                 bool gvariant_boxing = (context.profile == Profile.GOBJECT
6207                                         && target_type != null
6208                                         && target_type.type_symbol == gvariant_type
6209                                         && !(type is NullType)
6210                                         && type.type_symbol != gvariant_type);
6211
6212                 if (type.value_owned
6213                     && (target_type == null || !target_type.value_owned || boxing || unboxing || gvariant_boxing)
6214                     && !gvalue_boxing /* gvalue can assume ownership of value, no need to free it */) {
6215                         // value leaked, destroy it
6216                         if (target_type is PointerType) {
6217                                 // manual memory management for pointers
6218                         } else if (requires_destroy (type)) {
6219                                 if (!is_lvalue_access_allowed (type)) {
6220                                         // cannot assign to a temporary variable
6221                                         temp_ref_values.insert (0, result.copy ());
6222                                 } else {
6223                                         var temp_value = create_temp_value (type, false, node);
6224                                         temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
6225                                         store_value (temp_value, result, node.source_reference);
6226                                         result.cvalue = get_cvalue_ (temp_value);
6227                                 }
6228                         }
6229                 }
6230
6231                 if (target_type == null) {
6232                         // value will be destroyed, no need for implicit casts
6233                         return result;
6234                 }
6235
6236                 result.value_type = target_type.copy ();
6237
6238                 if (gvalue_boxing) {
6239                         // implicit conversion to GValue
6240                         var temp_value = create_temp_value (target_type, true, node, true);
6241
6242                         if (!target_type.value_owned) {
6243                                 // boxed GValue leaked, destroy it
6244                                 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
6245                         }
6246
6247                         if (target_type.nullable) {
6248                                 var newcall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
6249                                 newcall.add_argument (new CCodeConstant ("GValue"));
6250                                 newcall.add_argument (new CCodeConstant ("1"));
6251                                 var newassignment = new CCodeAssignment (get_cvalue_ (temp_value), newcall);
6252                                 ccode.add_expression (newassignment);
6253                         }
6254
6255                         var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
6256                         if (target_type.nullable) {
6257                                 ccall.add_argument (get_cvalue_ (temp_value));
6258                         } else {
6259                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
6260                         }
6261                         var type_id = get_ccode_type_id (type);
6262                         if (type_id == "") {
6263                                 Report.error (node.source_reference, "GValue boxing of type `%s' is not supported", type.to_string ());
6264                         }
6265                         ccall.add_argument (new CCodeIdentifier (type_id));
6266                         ccode.add_expression (ccall);
6267
6268                         if (requires_destroy (type)) {
6269                                 ccall = new CCodeFunctionCall (get_value_taker_function (type));
6270                         } else {
6271                                 ccall = new CCodeFunctionCall (get_value_setter_function (type));
6272                         }
6273                         if (target_type.nullable) {
6274                                 ccall.add_argument (get_cvalue_ (temp_value));
6275                         } else {
6276                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (temp_value)));
6277                         }
6278                         if (type.is_real_non_null_struct_type ()) {
6279                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue));
6280                         } else {
6281                                 ccall.add_argument (result.cvalue);
6282                         }
6283
6284                         ccode.add_expression (ccall);
6285
6286                         result = (GLibValue) temp_value;
6287                 } else if (gvariant_boxing) {
6288                         // implicit conversion to GVariant
6289                         string variant_func = "_variant_new%d".printf (++next_variant_function_id);
6290
6291                         var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
6292                         ccall.add_argument (result.cvalue);
6293
6294                         var cfunc = new CCodeFunction (variant_func, "GVariant*");
6295                         cfunc.modifiers = CCodeModifiers.STATIC;
6296                         cfunc.add_parameter (new CCodeParameter ("value", get_ccode_name (type)));
6297
6298                         if (type is ArrayType) {
6299                                 // return array length if appropriate
6300                                 var array_type = (ArrayType) type;
6301                                 var length_ctype = get_ccode_array_length_type (array_type);
6302                                 for (int dim = 1; dim <= array_type.rank; dim++) {
6303                                         ccall.add_argument (get_array_length_cvalue (value, dim));
6304                                         cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), length_ctype));
6305                                 }
6306                         }
6307
6308                         push_function (cfunc);
6309
6310                         // sink floating reference
6311                         var sink = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_ref_sink"));
6312                         sink.add_argument (serialize_expression (type, new CCodeIdentifier ("value")));
6313                         ccode.add_return (sink);
6314
6315                         pop_function ();
6316
6317                         cfile.add_function_declaration (cfunc);
6318                         cfile.add_function (cfunc);
6319
6320                         result.cvalue = ccall;
6321                         result.value_type.value_owned = true;
6322
6323                         result = (GLibValue) store_temp_value (result, node);
6324                         if (!target_type.value_owned) {
6325                                 // value leaked
6326                                 temp_ref_values.insert (0, ((GLibValue) result).copy ());
6327                         }
6328                 } else if (boxing) {
6329                         // value needs to be boxed
6330
6331                         result.value_type.nullable = false;
6332                         if (!result.lvalue || !result.value_type.equals (value.value_type)) {
6333                                 result.cvalue = get_implicit_cast_expression (result.cvalue, value.value_type, result.value_type, node);
6334                                 if (!(result.cvalue is CCodeConstantIdentifier)) {
6335                                         result = (GLibValue) store_temp_value (result, node);
6336                                 }
6337                         }
6338                         result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result.cvalue);
6339                         result.lvalue = false;
6340                         result.value_type.nullable = true;
6341                 } else if (unboxing) {
6342                         // unbox value
6343
6344                         result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result.cvalue);
6345                 } else {
6346                         // TODO: rewrite get_implicit_cast_expression to return a GLibValue
6347                         var old_cexpr = result.cvalue;
6348                         result.cvalue = get_implicit_cast_expression (result.cvalue, type, target_type, node);
6349                         result.lvalue = result.lvalue && result.cvalue == old_cexpr;
6350                 }
6351
6352                 bool array_needs_copy = false;
6353                 if (type is ArrayType && target_type is ArrayType) {
6354                         var array = (ArrayType) type;
6355                         var target_array = (ArrayType) target_type;
6356                         if (target_array.element_type.value_owned && !array.element_type.value_owned) {
6357                                 array_needs_copy = requires_copy (target_array.element_type);
6358                         }
6359                 }
6360
6361                 if (!gvalue_boxing && !gvariant_boxing && target_type.value_owned && (!type.value_owned || boxing || unboxing || array_needs_copy) && requires_copy (target_type) && !(type is NullType)) {
6362                         // need to copy value
6363                         var copy = (GLibValue) copy_value (result, node);
6364                         if (target_type.type_symbol is Interface && copy == null) {
6365                                 Report.error (node.source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure", target_type.type_symbol.get_full_name ());
6366                                 return result;
6367                         }
6368                         // need to free old array after copying it
6369                         if (array_needs_copy && requires_destroy (type)) {
6370                                 result.value_type = type.copy ();
6371                                 ccode.add_expression (destroy_value (result));
6372                         }
6373                         result = copy;
6374
6375                         // implicit array copying is deprecated, but allow it for internal codegen usage
6376                         var prop_acc = node as PropertyAccessor;
6377                         if ((prop_acc != null && !prop_acc.automatic_body)
6378                             && result.value_type is ArrayType) {
6379                                 Report.deprecated (node.source_reference, "implicit copy of array is deprecated, explicitly invoke the copy method instead");
6380                         }
6381                 }
6382
6383                 return result;
6384         }
6385
6386         public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, CodeNode? node) {
6387                 var cexpr = source_cexpr;
6388
6389                 if (expression_type.type_symbol != null && expression_type.type_symbol == target_type.type_symbol) {
6390                         // same type, no cast required
6391                         return cexpr;
6392                 }
6393
6394                 if (expression_type is NullType) {
6395                         // null literal, no cast required when not converting to generic type pointer
6396                         return cexpr;
6397                 }
6398
6399                 generate_type_declaration (target_type, cfile);
6400
6401                 unowned Class? cl = target_type.type_symbol as Class;
6402                 unowned Interface? iface = target_type.type_symbol as Interface;
6403                 if (context.checking && (iface != null || (cl != null && !cl.is_compact))) {
6404                         // checked cast for strict subtypes of GTypeInstance
6405                         return generate_instance_cast (cexpr, target_type.type_symbol);
6406                 } else if (target_type.type_symbol != null && get_ccode_name (expression_type) != get_ccode_name (target_type)) {
6407                         unowned Struct? st = target_type.type_symbol as Struct;
6408                         if (target_type.type_symbol.is_reference_type () || (st != null && st.is_simple_type ())) {
6409                                 // don't cast non-simple structs
6410                                 return new CCodeCastExpression (cexpr, get_ccode_name (target_type));
6411                         } else {
6412                                 return cexpr;
6413                         }
6414                 } else {
6415                         return cexpr;
6416                 }
6417         }
6418
6419         public void store_property (Property prop, Expression? instance, TargetValue value) {
6420                 unowned Property base_prop = prop;
6421                 if (prop.base_property != null) {
6422                         base_prop = prop.base_property;
6423                 } else if (prop.base_interface_property != null) {
6424                         base_prop = prop.base_interface_property;
6425                 }
6426                 if (instance is BaseAccess && (base_prop.is_abstract || base_prop.is_virtual)) {
6427                         CCodeExpression? vcast = null;
6428                         if (base_prop.parent_symbol is Class) {
6429                                 unowned Class base_class = (Class) base_prop.parent_symbol;
6430                                 vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
6431                                 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
6432                         } else if (base_prop.parent_symbol is Interface) {
6433                                 unowned Interface base_iface = (Interface) base_prop.parent_symbol;
6434                                 vcast = get_this_interface_cexpression (base_iface);
6435                         }
6436                         if (vcast != null) {
6437                                 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
6438                                 ccall.add_argument ((CCodeExpression) get_ccodenode (instance));
6439                                 var cexpr = get_cvalue_ (value);
6440                                 if (prop.property_type.is_real_non_null_struct_type ()) {
6441                                         //TODO Make use of get_lvalue (value)
6442                                         if (!(cexpr is CCodeConstant || cexpr is CCodeIdentifier)) {
6443                                                 var temp_value = store_temp_value (value, instance);
6444                                                 cexpr = get_cvalue_ (temp_value);
6445                                         }
6446                                         cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6447                                 }
6448                                 ccall.add_argument (cexpr);
6449
6450                                 ccode.add_expression (ccall);
6451                         } else {
6452                                 Report.error (instance.source_reference, "internal: Invalid assignment to `%s'", base_prop.get_full_name ());
6453                         }
6454                         return;
6455                 }
6456
6457                 var set_func = "g_object_set";
6458
6459                 if (!get_ccode_no_accessor_method (prop) && !(prop is DynamicProperty)) {
6460                         generate_property_accessor_declaration (base_prop.set_accessor, cfile);
6461                         set_func = get_ccode_name (base_prop.set_accessor);
6462
6463                         if (!prop.external && prop.external_package) {
6464                                 // internal VAPI properties
6465                                 // only add them once per source file
6466                                 if (add_generated_external_symbol (prop)) {
6467                                         visit_property (prop);
6468                                 }
6469                         }
6470                 }
6471
6472                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
6473
6474                 if (prop.binding == MemberBinding.INSTANCE) {
6475                         /* target instance is first argument */
6476                         var cinstance = (CCodeExpression) get_ccodenode (instance);
6477
6478                         if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
6479                                 // we need to pass struct instance by reference if it isn't a simple-type
6480                                 var instance_value = instance.target_value;
6481                                 if (!get_lvalue (instance_value)) {
6482                                         instance_value = store_temp_value (instance_value, instance);
6483                                 }
6484                                 cinstance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
6485                         }
6486
6487                         ccall.add_argument (cinstance);
6488                 }
6489
6490                 if (get_ccode_no_accessor_method (prop) || prop is DynamicProperty) {
6491                         /* property name is second argument of g_object_set */
6492                         ccall.add_argument (get_property_canonical_cconstant (prop));
6493                 }
6494
6495                 var cexpr = get_cvalue_ (value);
6496
6497                 if (prop.property_type.is_real_non_null_struct_type ()) {
6498                         //TODO Make use of get_lvalue (value)
6499                         if (!(cexpr is CCodeConstant || cexpr is CCodeIdentifier)) {
6500                                 var temp_value = store_temp_value (value, instance);
6501                                 cexpr = get_cvalue_ (temp_value);
6502                         }
6503                         cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
6504                 }
6505
6506                 var array_type = prop.property_type as ArrayType;
6507
6508                 ccall.add_argument (cexpr);
6509
6510                 if (array_type != null && get_ccode_array_length (prop)) {
6511                         for (int dim = 1; dim <= array_type.rank; dim++) {
6512                                 ccall.add_argument (get_array_length_cvalue (value, dim));
6513                         }
6514                 } else if (prop.property_type is DelegateType) {
6515                         var delegate_type = (DelegateType) prop.property_type;
6516                         if (get_ccode_delegate_target (prop) && delegate_type.delegate_symbol.has_target) {
6517                                 ccall.add_argument (get_delegate_target_cvalue (value));
6518                                 if (base_prop.set_accessor.value_type.value_owned) {
6519                                         ccall.add_argument (get_delegate_target_destroy_notify_cvalue (value));
6520                                 }
6521                         }
6522                 }
6523
6524                 if (get_ccode_no_accessor_method (prop) || prop is DynamicProperty) {
6525                         ccall.add_argument (new CCodeConstant ("NULL"));
6526                 }
6527
6528                 ccode.add_expression (ccall);
6529         }
6530
6531         public bool add_wrapper (string wrapper_name) {
6532                 return wrappers.add (wrapper_name);
6533         }
6534
6535         public bool add_generated_external_symbol (Symbol external_symbol) {
6536                 return generated_external_symbols.add (external_symbol);
6537         }
6538
6539         public static DataType get_callable_creturn_type (Callable c) {
6540                 assert (c is Method || c is Delegate);
6541                 var creturn_type = c.return_type.copy ();
6542                 if (c is CreationMethod) {
6543                         unowned Class? cl = c.parent_symbol as Class;
6544                         unowned Struct? st = c.parent_symbol as Struct;
6545                         if (cl != null) {
6546                                 // object creation methods return the new object in C
6547                                 // in Vala they have no return type
6548                                 creturn_type = new ObjectType (cl);
6549                         } else if (st != null && st.is_simple_type ()) {
6550                                 // constructors return simple type structs by value
6551                                 creturn_type = new StructValueType (st);
6552                         }
6553                 } else if (c.return_type.is_real_non_null_struct_type ()) {
6554                         // structs are returned via out parameter
6555                         creturn_type = new VoidType ();
6556                 }
6557                 return creturn_type;
6558         }
6559
6560         public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression, bool on_error = false) {
6561                 unowned Struct? st = type.type_symbol as Struct;
6562                 var array_type = type as ArrayType;
6563                 if (type.type_symbol != null && !type.nullable
6564                     && (on_error ? get_ccode_default_value_on_error (type.type_symbol) : get_ccode_default_value (type.type_symbol)) != "") {
6565                     CCodeExpression val = new CCodeConstant (on_error ? get_ccode_default_value_on_error (type.type_symbol) : get_ccode_default_value (type.type_symbol));
6566                     if (st != null && st.get_fields ().size > 0) {
6567                                 val = new CCodeCastExpression (val, get_ccode_name (st));
6568                         }
6569                         return val;
6570                 } else if (initializer_expression && !type.nullable &&
6571                                    (st != null || (array_type != null && array_type.fixed_length))) {
6572                         // 0-initialize struct with struct initializer { 0 }
6573                         // only allowed as initializer expression in C
6574                         var clist = new CCodeInitializerList ();
6575                         clist.append (new CCodeConstant ("0"));
6576                         return clist;
6577                 } else if ((type.type_symbol != null && type.type_symbol.is_reference_type ())
6578                            || type.nullable
6579                            || type is PointerType || type is DelegateType
6580                            || (array_type != null && !array_type.fixed_length)) {
6581                         return new CCodeConstant ("NULL");
6582                 } else if (type is GenericType) {
6583                         return new CCodeConstant ("NULL");
6584                 } else if (type is ErrorType) {
6585                         return new CCodeConstant ("NULL");
6586                 } else if (type is CType) {
6587                         return new CCodeConstant (((CType) type).cdefault_value);
6588                 }
6589                 return null;
6590         }
6591
6592         private void create_property_type_check_statement (Property prop, bool check_return_type, TypeSymbol t, bool non_null, string var_name) {
6593                 if (check_return_type) {
6594                         create_type_check_statement (prop, prop.property_type, t, non_null, var_name);
6595                 } else {
6596                         create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
6597                 }
6598         }
6599
6600         public virtual void create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
6601         }
6602
6603         public int get_param_pos (double param_pos, bool ellipsis = false) {
6604                 if (!ellipsis) {
6605                         if (param_pos >= 0) {
6606                                 return (int) (param_pos * 1000);
6607                         } else {
6608                                 return (int) ((100 + param_pos) * 1000);
6609                         }
6610                 } else {
6611                         if (param_pos >= 0) {
6612                                 return (int) ((100 + param_pos) * 1000);
6613                         } else {
6614                                 return (int) ((200 + param_pos) * 1000);
6615                         }
6616                 }
6617         }
6618
6619         public CCodeExpression? get_ccodenode (Expression node) {
6620                 if (get_cvalue (node) == null) {
6621                         node.emit (this);
6622                 }
6623                 return get_cvalue (node);
6624         }
6625
6626         public bool is_lvalue_access_allowed (DataType type) {
6627                 var array_type = type as ArrayType;
6628                 if (array_type != null && array_type.inline_allocated) {
6629                         return false;
6630                 }
6631                 if (type.type_symbol != null) {
6632                         return type.type_symbol.get_attribute_bool ("CCode", "lvalue_access", true);
6633                 }
6634                 return true;
6635         }
6636
6637         public bool requires_memset_init (Variable variable, out CCodeExpression? size) {
6638                 unowned ArrayType? array_type = variable.variable_type as ArrayType;
6639                 if (array_type != null && array_type.fixed_length) {
6640                         var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
6641                         sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
6642                         size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call);
6643                         return !is_constant_ccode (array_type.length);
6644                 }
6645                 size = null;
6646                 return false;
6647         }
6648
6649         public CCodeDeclaratorSuffix? get_ccode_declarator_suffix (DataType type) {
6650                 var array_type = type as ArrayType;
6651                 if (array_type != null) {
6652                         if (array_type.fixed_length) {
6653                                 return new CCodeDeclaratorSuffix.with_array (get_ccodenode (array_type.length));
6654                         } else if (array_type.inline_allocated) {
6655                                 return new CCodeDeclaratorSuffix.with_array ();
6656                         }
6657                 }
6658                 return null;
6659         }
6660
6661         public CCodeConstant get_signal_canonical_constant (Signal sig, string? detail = null) {
6662                 return new CCodeConstant ("\"%s%s\"".printf (get_ccode_name (sig), (detail != null ? "::%s".printf (detail) : "")));
6663         }
6664
6665         public CCodeConstant get_property_canonical_cconstant (Property prop) {
6666                 return new CCodeConstant ("\"%s\"".printf (get_ccode_name (prop)));
6667         }
6668
6669         public override void visit_class (Class cl) {
6670         }
6671
6672         public void create_postcondition_statement (Expression postcondition) {
6673                 var cassert = new CCodeFunctionCall (new CCodeIdentifier ("_vala_warn_if_fail"));
6674
6675                 postcondition.emit (this);
6676
6677                 string message = ((string) postcondition.source_reference.begin.pos).substring (0, (int) (postcondition.source_reference.end.pos - postcondition.source_reference.begin.pos));
6678                 cassert.add_argument (get_cvalue (postcondition));
6679                 cassert.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
6680                 requires_assert = true;
6681
6682                 ccode.add_expression (cassert);
6683
6684                 foreach (var value in temp_ref_values) {
6685                         ccode.add_expression (destroy_value (value));
6686                 }
6687
6688                 temp_ref_values.clear ();
6689         }
6690
6691         public unowned DataType? get_this_type () {
6692                 if (current_method != null && current_method.binding == MemberBinding.INSTANCE) {
6693                         return current_method.this_parameter.variable_type;
6694                 } else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) {
6695                         return current_property_accessor.prop.this_parameter.variable_type;
6696                 } else if (current_constructor != null && current_constructor.binding == MemberBinding.INSTANCE) {
6697                         return current_constructor.this_parameter.variable_type;
6698                 } else if (current_destructor != null && current_destructor.binding == MemberBinding.INSTANCE) {
6699                         return current_destructor.this_parameter.variable_type;
6700                 }
6701                 return null;
6702         }
6703
6704         public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
6705                 var result = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_CAST"));
6706                 result.add_argument (expr);
6707                 result.add_argument (new CCodeIdentifier (get_ccode_type_id (type)));
6708                 result.add_argument (new CCodeIdentifier (get_ccode_name (type)));
6709                 return result;
6710         }
6711
6712         void generate_struct_destroy_function (Struct st) {
6713                 if (cfile.add_declaration (get_ccode_destroy_function (st))) {
6714                         // only generate function once per source file
6715                         return;
6716                 }
6717
6718                 var function = new CCodeFunction (get_ccode_destroy_function (st), "void");
6719                 function.modifiers = CCodeModifiers.STATIC;
6720                 function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (st))));
6721
6722                 push_context (new EmitContext ());
6723                 push_function (function);
6724
6725                 var this_value = load_this_parameter (st);
6726                 foreach (Field f in st.get_fields ()) {
6727                         if (f.binding == MemberBinding.INSTANCE) {
6728                                 if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_destroy (f.variable_type)) {
6729                                         ccode.add_expression (destroy_field (f, this_value));
6730                                 }
6731                         }
6732                 }
6733
6734                 pop_function ();
6735                 pop_context ();
6736
6737                 cfile.add_function_declaration (function);
6738                 cfile.add_function (function);
6739         }
6740
6741         void generate_struct_copy_function (Struct st) {
6742                 if (cfile.add_declaration (get_ccode_copy_function (st))) {
6743                         // only generate function once per source file
6744                         return;
6745                 }
6746
6747                 var function = new CCodeFunction (get_ccode_copy_function (st), "void");
6748                 function.modifiers = CCodeModifiers.STATIC;
6749                 function.add_parameter (new CCodeParameter ("self", "const %s *".printf (get_ccode_name (st))));
6750                 function.add_parameter (new CCodeParameter ("dest", "%s *".printf (get_ccode_name (st))));
6751
6752                 push_context (new EmitContext ());
6753                 push_function (function);
6754
6755                 var dest_struct = new GLibValue (SemanticAnalyzer.get_data_type_for_symbol (st), new CCodeIdentifier ("(*dest)"), true);
6756                 foreach (Field f in st.get_fields ()) {
6757                         if (f.binding == MemberBinding.INSTANCE) {
6758                                 var value = load_field (f, load_this_parameter ((TypeSymbol) st));
6759                                 if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_copy (f.variable_type))  {
6760                                         value = copy_value (value, f);
6761                                         if (value == null) {
6762                                                 // error case, continue to avoid critical
6763                                                 continue;
6764                                         }
6765                                 }
6766                                 store_field (f, dest_struct, value);
6767                         }
6768                 }
6769
6770                 pop_function ();
6771                 pop_context ();
6772
6773                 cfile.add_function_declaration (function);
6774                 cfile.add_function (function);
6775         }
6776
6777         public void return_default_value (DataType return_type, bool on_error = false) {
6778                 unowned Struct? st = return_type.type_symbol as Struct;
6779                 if (st != null && st.is_simple_type () && !return_type.nullable) {
6780                         // 0-initialize struct with struct initializer { 0 }
6781                         // only allowed as initializer expression in C
6782                         var ret_temp_var = get_temp_variable (return_type, true, null, true);
6783                         emit_temp_var (ret_temp_var, on_error);
6784                         ccode.add_return (new CCodeIdentifier (ret_temp_var.name));
6785                 } else {
6786                         ccode.add_return (default_value_for_type (return_type, false, on_error));
6787                 }
6788         }
6789
6790         public virtual void generate_dynamic_method_wrapper (DynamicMethod method) {
6791         }
6792
6793         public virtual CCodeExpression get_param_spec_cexpression (Property prop) {
6794                 return new CCodeInvalidExpression ();
6795         }
6796
6797         public virtual CCodeExpression get_param_spec (Property prop) {
6798                 return new CCodeInvalidExpression ();
6799         }
6800
6801         public virtual CCodeExpression get_signal_creation (Signal sig, ObjectTypeSymbol type) {
6802                 return new CCodeInvalidExpression ();
6803         }
6804
6805         public virtual CCodeExpression get_value_getter_function (DataType type_reference) {
6806                 return new CCodeInvalidExpression ();
6807         }
6808
6809         public virtual CCodeExpression get_value_setter_function (DataType type_reference) {
6810                 return new CCodeInvalidExpression ();
6811         }
6812
6813         public virtual CCodeExpression get_value_taker_function (DataType type_reference) {
6814                 return new CCodeInvalidExpression ();
6815         }
6816
6817         public virtual void register_dbus_info (CCodeBlock block, ObjectTypeSymbol bindable) {
6818         }
6819
6820         public virtual string get_dynamic_signal_cname (DynamicSignal node) {
6821                 return "";
6822         }
6823
6824         public virtual string get_array_length_cname (string array_cname, int dim) {
6825                 return "";
6826         }
6827
6828         public virtual string get_variable_array_length_cname (Variable variable, int dim) {
6829                 return "";
6830         }
6831
6832         public virtual CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
6833                 return new CCodeInvalidExpression ();
6834         }
6835
6836         public virtual CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
6837                 return new CCodeInvalidExpression ();
6838         }
6839
6840         public virtual string get_array_size_cname (string array_cname) {
6841                 return "";
6842         }
6843
6844         public virtual void add_simple_check (CodeNode node, bool always_fails = false) {
6845         }
6846
6847         public virtual string generate_ready_function (Method m) {
6848                 return "";
6849         }
6850
6851         public CCodeExpression get_boolean_cconstant (bool b) {
6852                 if (context.profile == Profile.GOBJECT) {
6853                         return new CCodeConstant (b ? "TRUE" : "FALSE");
6854                 } else {
6855                         cfile.add_include ("stdbool.h");
6856                         return new CCodeConstant (b ? "true" : "false");
6857                 }
6858         }
6859 }