From 40b8c993f54fce9075044252d2802452dcf1df5e Mon Sep 17 00:00:00 2001 From: Garrett <138411610+garrettlennoxbeck@users.noreply.github.com> Date: Tue, 21 Nov 2023 07:54:46 -0600 Subject: [PATCH] translate-c: skip blank macros when translating defines --- src/aro_translate_c.zig | 2 +- src/translate_c.zig | 64 ++++++++++++++++++++++++++-- src/translate_c/common.zig | 3 ++ test/behavior/translate_c_macros.h | 6 +++ test/behavior/translate_c_macros.zig | 9 ++++ 5 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/aro_translate_c.zig b/src/aro_translate_c.zig index cd9e4fa5cb..4b29ec1edd 100644 --- a/src/aro_translate_c.zig +++ b/src/aro_translate_c.zig @@ -141,7 +141,7 @@ pub fn translate( defer mapper.deinit(tree.comp.gpa); var arena_allocator = std.heap.ArenaAllocator.init(gpa); - errdefer arena_allocator.deinit(); + defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); var context = Context{ diff --git a/src/translate_c.zig b/src/translate_c.zig index 1fa535378d..ec9f6977de 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -139,7 +139,7 @@ pub fn translate( // For memory that has the same lifetime as the Ast that we return // from this function. var arena_allocator = std.heap.ArenaAllocator.init(gpa); - errdefer arena_allocator.deinit(); + defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); var context = Context{ @@ -5497,6 +5497,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { const str_node = try Tag.string_literal.create(c.arena, "\"\""); const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = name, .init = str_node }); try c.global_scope.macro_table.put(name, var_decl); + try c.global_scope.blank_macros.put(name, {}); continue; }, .LParen => { @@ -5527,6 +5528,29 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { .invalid_arg_usage => unreachable, // no args }; + // Check if the macro only uses other blank macros. + while (true) { + switch (m.peek().?) { + .Identifier => { + const tok = m.list[m.i + 1]; + const slice = m.source[tok.start..tok.end]; + if (c.global_scope.blank_macros.contains(slice)) { + m.i += 1; + continue; + } + }, + .Eof, .Nl => { + try c.global_scope.blank_macros.put(m.name, {}); + const init_node = try Tag.string_literal.create(c.arena, "\"\""); + const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); + try c.global_scope.macro_table.put(m.name, var_decl); + return; + }, + else => {}, + } + break; + } + const init_node = try parseCExpr(c, m, scope); const last = m.next().?; if (last != .Eof and last != .Nl) @@ -5960,6 +5984,9 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N return parseCNumLit(c, m); }, .Identifier => { + if (c.global_scope.blank_macros.contains(slice)) { + return parseCPrimaryExprInner(c, m, scope); + } const mangled_name = scope.getAlias(slice); if (builtin_typedef_map.get(mangled_name)) |ty| return Tag.type.create(c.arena, ty); const identifier = try Tag.identifier.create(c.arena, mangled_name); @@ -5992,10 +6019,19 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { // after a primary expression. while (true) { switch (m.peek().?) { - .StringLiteral, .Identifier => {}, + .StringLiteral => {}, + .Identifier => { + const tok = m.list[m.i + 1]; + const slice = m.source[tok.start..tok.end]; + if (c.global_scope.blank_macros.contains(slice)) { + m.i += 1; + continue; + } + }, else => break, } - node = try Tag.array_cat.create(c.arena, .{ .lhs = node, .rhs = try parseCPrimaryExprInner(c, m, scope) }); + const rhs = try parseCPrimaryExprInner(c, m, scope); + node = try Tag.array_cat.create(c.arena, .{ .lhs = node, .rhs = rhs }); } return node; } @@ -6211,7 +6247,24 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { switch (m.next().?) { .LParen => { if (try parseCTypeName(c, m, scope, true)) |type_name| { - try m.skip(c, .RParen); + while (true) { + const next_token = m.next().?; + switch (next_token) { + .RParen => break, + else => |next_tag| { + // Skip trailing blank defined before the RParen. + if (next_tag == .Identifier and c.global_scope.blank_macros.contains(m.slice())) { + continue; + } + try m.fail( + c, + "unable to translate C expr: expected ')' instead got '{s}'", + .{next_token.symbol()}, + ); + return error.ParseError; + }, + } + } if (m.peek().? == .LBrace) { // initializer list return parseCPostfixExpr(c, m, scope, type_name); @@ -6239,6 +6292,9 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_ const tok = m.next().?; switch (tok) { .Identifier => { + if (c.global_scope.blank_macros.contains(m.slice())) { + return try parseCSpecifierQualifierList(c, m, scope, allow_fail); + } const mangled_name = scope.getAlias(m.slice()); if (!allow_fail or c.typedefs.contains(mangled_name)) { if (builtin_typedef_map.get(mangled_name)) |ty| return try Tag.type.create(c.arena, ty); diff --git a/src/translate_c/common.zig b/src/translate_c/common.zig index 478f41626b..afbb63d05e 100644 --- a/src/translate_c/common.zig +++ b/src/translate_c/common.zig @@ -184,6 +184,7 @@ pub fn ScopeExtra(comptime Context: type, comptime Type: type) type { base: Scope, sym_table: SymbolTable, macro_table: SymbolTable, + blank_macros: std.StringArrayHashMap(void), context: *Context, nodes: std.ArrayList(Node), @@ -195,6 +196,7 @@ pub fn ScopeExtra(comptime Context: type, comptime Type: type) type { }, .sym_table = SymbolTable.init(c.gpa), .macro_table = SymbolTable.init(c.gpa), + .blank_macros = std.StringArrayHashMap(void).init(c.gpa), .context = c, .nodes = std.ArrayList(Node).init(c.gpa), }; @@ -203,6 +205,7 @@ pub fn ScopeExtra(comptime Context: type, comptime Type: type) type { pub fn deinit(scope: *Root) void { scope.sym_table.deinit(); scope.macro_table.deinit(); + scope.blank_macros.deinit(); scope.nodes.deinit(); } diff --git a/test/behavior/translate_c_macros.h b/test/behavior/translate_c_macros.h index d9ad9b682f..c6e2e381e2 100644 --- a/test/behavior/translate_c_macros.h +++ b/test/behavior/translate_c_macros.h @@ -62,3 +62,9 @@ typedef _Bool uintptr_t; #define LONG(x) x##L #define X LONG(10) + +#define BLANK_MACRO +#define BLANK_CHILD_MACRO BLANK_MACRO BLANK_MACRO BLANK_MACRO +#define MACRO_VALUE 0 +typedef long def_type; +#define BLANK_MACRO_CAST (BLANK_CHILD_MACRO def_type BLANK_CHILD_MACRO)MACRO_VALUE diff --git a/test/behavior/translate_c_macros.zig b/test/behavior/translate_c_macros.zig index c1689285f4..3895acdf7a 100644 --- a/test/behavior/translate_c_macros.zig +++ b/test/behavior/translate_c_macros.zig @@ -231,3 +231,12 @@ test "Macro that uses Long type concatenation casting" { try expect((@TypeOf(h.X)) == c_long); try expectEqual(h.X, @as(c_long, 10)); } + +test "Blank macros" { + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + + try expectEqual(h.BLANK_MACRO, ""); + try expectEqual(h.BLANK_CHILD_MACRO, ""); + try expect(@TypeOf(h.BLANK_MACRO_CAST) == h.def_type); + try expectEqual(h.BLANK_MACRO_CAST, @as(c_long, 0)); +}