| ... | ... | @@ -701,8 +701,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 701 | 701 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| 702 | 702 | const storage_class = ZigClangVarDecl_getStorageClass(var_decl); |
| 703 | 703 | const is_const = ZigClangQualType_isConstQualified(qual_type); |
| 704 | | |
| 705 | | const extern_tok = if (storage_class == .Extern) |
| 704 | const has_init = ZigClangVarDecl_hasInit(var_decl); |
| 705 | |
| 706 | // In C extern variables with initializers behave like Zig exports. |
| 707 | // extern int foo = 2; |
| 708 | // does the same as: |
| 709 | // extern int foo; |
| 710 | // int foo = 2; |
| 711 | const extern_tok = if (storage_class == .Extern and !has_init) |
| 706 | 712 | try appendToken(c, .Keyword_extern, "extern") |
| 707 | 713 | else if (storage_class != .Static) |
| 708 | 714 | try appendToken(c, .Keyword_export, "export") |
| ... | ... | @@ -730,7 +736,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 730 | 736 | // If the initialization expression is not present, initialize with undefined. |
| 731 | 737 | // If it is an integer literal, we can skip the @as since it will be redundant |
| 732 | 738 | // with the variable type. |
| 733 | | if (ZigClangVarDecl_hasInit(var_decl)) { |
| 739 | if (has_init) { |
| 734 | 740 | eq_tok = try appendToken(c, .Equal, "="); |
| 735 | 741 | init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| |
| 736 | 742 | transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) { |
| ... | ... | @@ -745,7 +751,22 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 745 | 751 | try transCreateNodeUndefinedLiteral(c); |
| 746 | 752 | } else if (storage_class != .Extern) { |
| 747 | 753 | eq_tok = try appendToken(c, .Equal, "="); |
| 748 | | init_node = try transCreateNodeIdentifierUnchecked(c, "undefined"); |
| 754 | // The C language specification states that variables with static or threadlocal |
| 755 | // storage without an initializer are initialized to a zero value. |
| 756 | |
| 757 | // @import("std").mem.zeroes(T) |
| 758 | const import_fn_call = try c.createBuiltinCall("@import", 1); |
| 759 | const std_node = try transCreateNodeStringLiteral(c, "\"std\""); |
| 760 | import_fn_call.params()[0] = std_node; |
| 761 | import_fn_call.rparen_token = try appendToken(c, .RParen, ")"); |
| 762 | const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem"); |
| 763 | const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroes"); |
| 764 | |
| 765 | const zero_init_call = try c.createCall(outer_field_access, 1); |
| 766 | zero_init_call.params()[0] = type_node; |
| 767 | zero_init_call.rtoken = try appendToken(c, .RParen, ")"); |
| 768 | |
| 769 | init_node = &zero_init_call.base; |
| 749 | 770 | } |
| 750 | 771 | |
| 751 | 772 | const linksection_expr = blk: { |