authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-20 10:08:27+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-20 10:08:27+03:00
logadc5bce5e8487cf9507ab5dd2b1b60dd7f54cc3d
tree542edd9771b0a550642497108ab75fbc779f71db
parent91de5c212fe847a309f047e3097491bba6f86ae1
signature Commit is signed but in an unrecognized format.

translate-c: correct translation of global variables

* externs with intializers are translated as exports * non extern without explicit initialization are zero initalized

3 files changed, 46 insertions(+), 7 deletions(-)

lib/std/mem.zig+19-1
...@@ -221,9 +221,19 @@ pub fn zeroes(comptime T: type) T {...@@ -221,9 +221,19 @@ pub fn zeroes(comptime T: type) T {
221 .Vector => |info| {221 .Vector => |info| {
222 return @splat(info.len, zeroes(info.child));222 return @splat(info.len, zeroes(info.child));
223 },223 },
224 .Union => |info| {
225 if (comptime meta.containerLayout(T) == .Extern) {
226 // The C language specification states that (global) unions
227 // should be zero initialized to the first named member.
228 var item: T = undefined;
229 @field(item, info.fields[0].name) = zeroes(@TypeOf(@field(item, info.fields[0].name)));
230 return item;
231 }
232
233 @compileError("Can't set a " ++ @typeName(T) ++ " to zero.");
234 },
224 .ErrorUnion,235 .ErrorUnion,
225 .ErrorSet,236 .ErrorSet,
226 .Union,
227 .Fn,237 .Fn,
228 .BoundFn,238 .BoundFn,
229 .Type,239 .Type,
...@@ -312,6 +322,14 @@ test "mem.zeroes" {...@@ -312,6 +322,14 @@ test "mem.zeroes" {
312 for (b.sentinel) |e| {322 for (b.sentinel) |e| {
313 testing.expectEqual(@as(u8, 0), e);323 testing.expectEqual(@as(u8, 0), e);
314 }324 }
325
326 const C_union = extern union {
327 a: u8,
328 b: u32,
329 };
330
331 var c = zeroes(C_union);
332 testing.expectEqual(@as(u8, 0), c.a);
315}333}
316334
317/// Sets a slice to zeroes.335/// Sets a slice to zeroes.
src-self-hosted/translate_c.zig+25-4
...@@ -701,8 +701,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -701,8 +701,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
701 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);701 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
702 const storage_class = ZigClangVarDecl_getStorageClass(var_decl);702 const storage_class = ZigClangVarDecl_getStorageClass(var_decl);
703 const is_const = ZigClangQualType_isConstQualified(qual_type);703 const is_const = ZigClangQualType_isConstQualified(qual_type);
704704 const has_init = ZigClangVarDecl_hasInit(var_decl);
705 const extern_tok = if (storage_class == .Extern)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 try appendToken(c, .Keyword_extern, "extern")712 try appendToken(c, .Keyword_extern, "extern")
707 else if (storage_class != .Static)713 else if (storage_class != .Static)
708 try appendToken(c, .Keyword_export, "export")714 try appendToken(c, .Keyword_export, "export")
...@@ -730,7 +736,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -730,7 +736,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
730 // If the initialization expression is not present, initialize with undefined.736 // If the initialization expression is not present, initialize with undefined.
731 // If it is an integer literal, we can skip the @as since it will be redundant737 // If it is an integer literal, we can skip the @as since it will be redundant
732 // with the variable type.738 // with the variable type.
733 if (ZigClangVarDecl_hasInit(var_decl)) {739 if (has_init) {
734 eq_tok = try appendToken(c, .Equal, "=");740 eq_tok = try appendToken(c, .Equal, "=");
735 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|741 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
736 transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {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,7 +751,22 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
745 try transCreateNodeUndefinedLiteral(c);751 try transCreateNodeUndefinedLiteral(c);
746 } else if (storage_class != .Extern) {752 } else if (storage_class != .Extern) {
747 eq_tok = try appendToken(c, .Equal, "=");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 }
750771
751 const linksection_expr = blk: {772 const linksection_expr = blk: {
test/translate_c.zig+2-2
...@@ -466,7 +466,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -466,7 +466,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
466 , &[_][]const u8{466 , &[_][]const u8{
467 \\pub extern var extern_var: c_int;467 \\pub extern var extern_var: c_int;
468 \\pub const int_var: c_int = 13;468 \\pub const int_var: c_int = 13;
469 \\pub export var foo: c_int = undefined;469 \\pub export var foo: c_int = @import("std").mem.zeroes(c_int);
470 });470 });
471471
472 cases.add("const ptr initializer",472 cases.add("const ptr initializer",
...@@ -1327,7 +1327,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1327,7 +1327,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1327 \\static char arr1[] = "hello";1327 \\static char arr1[] = "hello";
1328 \\char arr2[] = "hello";1328 \\char arr2[] = "hello";
1329 , &[_][]const u8{1329 , &[_][]const u8{
1330 \\pub extern var arr0: [*c]u8 = "hello";1330 \\pub export var arr0: [*c]u8 = "hello";
1331 \\pub var arr1: [*c]u8 = "hello";1331 \\pub var arr1: [*c]u8 = "hello";
1332 \\pub export var arr2: [*c]u8 = "hello";1332 \\pub export var arr2: [*c]u8 = "hello";
1333 });1333 });