Commit 9298b9a4aa

Andrew Kelley <andrew@ziglang.org>
2020-01-02 00:53:08
translate-c: prevent name clashing of globals declared after locals
1 parent dc28526
Changed files (2)
src-self-hosted
test
src-self-hosted/translate_c.zig
@@ -122,6 +122,7 @@ const Scope = struct {
         base: Scope,
         sym_table: SymbolTable,
         macro_table: SymbolTable,
+        context: *Context,
 
         fn init(c: *Context) Root {
             return .{
@@ -131,14 +132,20 @@ const Scope = struct {
                 },
                 .sym_table = SymbolTable.init(c.a()),
                 .macro_table = SymbolTable.init(c.a()),
+                .context = c,
             };
         }
 
-        fn contains(scope: *Root, name: []const u8) bool {
-            return isZigPrimitiveType(name) or
-                scope.sym_table.contains(name) or
+        fn localContains(scope: *Root, name: []const u8) bool {
+            return scope.sym_table.contains(name) or
                 scope.macro_table.contains(name);
         }
+
+        fn contains(scope: *Root, name: []const u8) bool {
+            return scope.localContains(name) or
+                isZigPrimitiveType(name) or
+                scope.context.global_names.contains(name);
+        }
     };
 
     fn findBlockScope(inner: *Scope, c: *Context) !*Scope.Block {
@@ -207,6 +214,12 @@ pub const Context = struct {
     clang_context: *ZigClangASTContext,
     mangle_count: u32 = 0,
 
+    /// This one is different than the root scope's name table. This contains
+    /// a list of names that we found by visiting all the top level decls without
+    /// translating them. The other maps are updated as we translate; this one is updated
+    /// up front in a pre-processing step.
+    global_names: std.StringHashMap(void),
+
     fn getMangle(c: *Context) u32 {
         c.mangle_count += 1;
         return c.mangle_count;
@@ -291,9 +304,14 @@ pub fn translate(
         .alias_list = AliasList.init(arena),
         .global_scope = try arena.create(Scope.Root),
         .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
+        .global_names = std.StringHashMap(void).init(arena),
     };
     context.global_scope.* = Scope.Root.init(&context);
 
+    if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorNamesOnlyC)) {
+        return context.err;
+    }
+
     if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
         return context.err;
     }
@@ -321,6 +339,15 @@ pub fn translate(
     return tree;
 }
 
+extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bool {
+    const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
+    declVisitorNamesOnly(c, decl) catch |err| {
+        c.err = err;
+        return false;
+    };
+    return true;
+}
+
 extern fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) bool {
     const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
     declVisitor(c, decl) catch |err| {
@@ -330,6 +357,11 @@ extern fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) bool {
     return true;
 }
 
+fn declVisitorNamesOnly(c: *Context, decl: *const ZigClangDecl) Error!void {
+    const decl_name = try c.str(ZigClangDecl_getName_bytes_begin(decl));
+    _ = try c.global_names.put(decl_name, {});
+}
+
 fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
     switch (ZigClangDecl_getKind(decl)) {
         .Function => {
test/translate_c.zig
@@ -2275,4 +2275,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return @bitCast(c_ushort, @truncate(c_short, x));
         \\}
     });
+
+    cases.add("arg name aliasing decl which comes after",
+        \\int foo(int bar) {
+        \\    bar = 2;
+        \\}
+        \\int bar = 4;
+    , &[_][]const u8{
+        \\pub export fn foo(arg_bar_1: c_int) c_int {
+        \\    var bar_1 = arg_bar_1;
+        \\    bar_1 = 2;
+        \\}
+        \\pub export var bar: c_int = 4;
+    });
 }