Commit a553947a51

Vexu <git@vexu.eu>
2020-08-20 09:45:55
translate-c: correctly put static and extern local variables in global scope
1 parent adc5bce
Changed files (3)
src-self-hosted/translate_c.zig
@@ -498,7 +498,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
             _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
         },
         .Var => {
-            return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl));
+            return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl), null);
         },
         .Empty => {
             // Do nothing
@@ -679,12 +679,13 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
     return addTopLevelDecl(c, fn_name, &proto_node.base);
 }
 
-fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
-    const var_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl)));
+/// if mangled_name is not null, this var decl was declared in a block scope.
+fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl, mangled_name: ?[]const u8) Error!void {
+    const var_name = mangled_name orelse try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl)));
     if (c.global_scope.sym_table.contains(var_name))
         return; // Avoid processing this decl twice
     const rp = makeRestorePoint(c);
-    const visib_tok = try appendToken(c, .Keyword_pub, "pub");
+    const visib_tok = if (mangled_name) |_| null else try appendToken(c, .Keyword_pub, "pub");
 
     const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
         null
@@ -1582,15 +1583,22 @@ fn transDeclStmtOne(
         .Var => {
             const var_decl = @ptrCast(*const ZigClangVarDecl, decl);
 
-            const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
-                null
-            else
-                try appendToken(c, .Keyword_threadlocal, "threadlocal");
             const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
             const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(
                 @ptrCast(*const ZigClangNamedDecl, var_decl),
             ));
             const mangled_name = try block_scope.makeMangledName(c, name);
+
+            switch (ZigClangVarDecl_getStorageClass(var_decl)) {
+                .Extern, .Static => {
+                    // This is actually a global variable, put it in the global scope and reference it.
+                    // `_ = mangled_name;`
+                    try visitVarDecl(rp.c, var_decl, mangled_name);
+                    return try maybeSuppressResult(rp, scope, .unused, try transCreateNodeIdentifier(rp.c, mangled_name));
+                },
+                else => {},
+            }
+
             const mut_tok = if (ZigClangQualType_isConstQualified(qual_type))
                 try appendToken(c, .Keyword_const, "const")
             else
@@ -1618,7 +1626,6 @@ fn transDeclStmtOne(
                 .mut_token = mut_tok,
                 .semicolon_token = semicolon_token,
             }, .{
-                .thread_local_token = thread_local_token,
                 .eq_token = eq_token,
                 .type_node = type_node,
                 .init_node = init_node,
test/run_translated_c.zig
@@ -3,6 +3,20 @@ const tests = @import("tests.zig");
 const nl = std.cstr.line_sep;
 
 pub fn addCases(cases: *tests.RunTranslatedCContext) void {
+    cases.add("static variable in block scope",
+        \\#include <stdlib.h>
+        \\int foo() {
+        \\    static int bar;
+        \\    bar += 1;
+        \\    return bar;
+        \\}
+        \\int main() {
+        \\    foo();
+        \\    foo();
+        \\    if (foo() != 3) abort();
+        \\}
+    , "");
+
     cases.add("array initializer",
         \\#include <stdlib.h>
         \\int main(int argc, char **argv) {
test/translate_c.zig
@@ -3,6 +3,20 @@ const std = @import("std");
 const CrossTarget = std.zig.CrossTarget;
 
 pub fn addCases(cases: *tests.TranslateCContext) void {
+    cases.add("extern variable in block scope",
+        \\float bar;
+        \\int foo() {
+        \\    _Thread_local static int bar = 2;
+        \\}
+    , &[_][]const u8{
+        \\pub export var bar: f32 = @import("std").mem.zeroes(f32);
+        \\threadlocal var bar_1: c_int = 2;
+        \\pub export fn foo() c_int {
+        \\    _ = bar_1;
+        \\    return 0;
+        \\}
+    });
+
     cases.add("missing return stmt",
         \\int foo() {}
         \\int bar() {
@@ -480,8 +494,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    static const char v2[] = "2.2.2";
         \\}
     , &[_][]const u8{
+        \\const v2: [*c]const u8 = "2.2.2";
         \\pub export fn foo() void {
-        \\    const v2: [*c]const u8 = "2.2.2";
+        \\    _ = v2;
         \\}
     });