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