LCOV - code coverage report
Current view: top level - codegen - valaccodebasemodule.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 91.9 % 4066 3736
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

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

Generated by: LCOV version 2.0-1