| author | |
| committer | |
| log | 9bbfb09fc33366bff0a53c02cd78bdd14bed9f9b |
| tree | 4808fb1d3e1392b6f1c910b8d83a6d7b84c5193d |
| parent | 8f27fdb84e3788bf6ea9ae7c992f3cf667a4f9ed |
| signature |
5 files changed, 80 insertions(+), 32 deletions(-)
lib/compiler/aro_translate_c.zig+1-4| ... | ... | @@ -1381,7 +1381,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ |
| 1381 | 1381 | pub const Root = struct { |
| 1382 | 1382 | base: ScopeExtraScope, |
| 1383 | 1383 | sym_table: SymbolTable, |
| 1384 | macro_table: SymbolTable, | |
| 1385 | 1384 | blank_macros: std.StringArrayHashMap(void), |
| 1386 | 1385 | context: *ScopeExtraContext, |
| 1387 | 1386 | nodes: std.ArrayList(ast.Node), |
| ... | ... | @@ -1393,7 +1392,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ |
| 1393 | 1392 | .parent = null, |
| 1394 | 1393 | }, |
| 1395 | 1394 | .sym_table = SymbolTable.init(c.gpa), |
| 1396 | .macro_table = SymbolTable.init(c.gpa), | |
| 1397 | 1395 | .blank_macros = std.StringArrayHashMap(void).init(c.gpa), |
| 1398 | 1396 | .context = c, |
| 1399 | 1397 | .nodes = std.ArrayList(ast.Node).init(c.gpa), |
| ... | ... | @@ -1402,7 +1400,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ |
| 1402 | 1400 | |
| 1403 | 1401 | pub fn deinit(scope: *Root) void { |
| 1404 | 1402 | scope.sym_table.deinit(); |
| 1405 | scope.macro_table.deinit(); | |
| 1406 | 1403 | scope.blank_macros.deinit(); |
| 1407 | 1404 | scope.nodes.deinit(); |
| 1408 | 1405 | } |
| ... | ... | @@ -1410,7 +1407,7 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ |
| 1410 | 1407 | /// Check if the global scope contains this name, without looking into the "future", e.g. |
| 1411 | 1408 | /// ignore the preprocessed decl and macro names. |
| 1412 | 1409 | pub fn containsNow(scope: *Root, name: []const u8) bool { |
| 1413 | return scope.sym_table.contains(name) or scope.macro_table.contains(name); | |
| 1410 | return scope.sym_table.contains(name); | |
| 1414 | 1411 | } |
| 1415 | 1412 | |
| 1416 | 1413 | /// Check if the global scope contains the name, includes all decls that haven't been translated yet. |
lib/compiler/aro_translate_c/ast.zig+1| ... | ... | @@ -875,6 +875,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 875 | 875 | .declaration => unreachable, |
| 876 | 876 | .warning => { |
| 877 | 877 | const payload = node.castTag(.warning).?.data; |
| 878 | try c.buf.append('\n'); | |
| 878 | 879 | try c.buf.appendSlice(payload); |
| 879 | 880 | try c.buf.append('\n'); |
| 880 | 881 | return @as(NodeIndex, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32' |
src/translate_c.zig+36-21| ... | ... | @@ -177,7 +177,6 @@ pub fn translate( |
| 177 | 177 | |
| 178 | 178 | try transPreprocessorEntities(&context, ast_unit); |
| 179 | 179 | |
| 180 | try addMacros(&context); | |
| 181 | 180 | for (context.alias_list.items) |alias| { |
| 182 | 181 | const node = try Tag.alias.create(arena, .{ .actual = alias.alias, .mangled = alias.name }); |
| 183 | 182 | try addTopLevelDecl(&context, alias.alias, node); |
| ... | ... | @@ -5105,6 +5104,7 @@ const MacroCtx = struct { |
| 5105 | 5104 | i: usize = 0, |
| 5106 | 5105 | loc: clang.SourceLocation, |
| 5107 | 5106 | name: []const u8, |
| 5107 | refs_var_decl: bool = false, | |
| 5108 | 5108 | |
| 5109 | 5109 | fn peek(self: *MacroCtx) ?CToken.Id { |
| 5110 | 5110 | if (self.i >= self.list.len) return null; |
| ... | ... | @@ -5244,7 +5244,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { |
| 5244 | 5244 | // We define it as an empty string so that it can still be used with ++ |
| 5245 | 5245 | const str_node = try Tag.string_literal.create(c.arena, "\"\""); |
| 5246 | 5246 | const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = name, .init = str_node }); |
| 5247 | try c.global_scope.macro_table.put(name, var_decl); | |
| 5247 | try addTopLevelDecl(c, name, var_decl); | |
| 5248 | 5248 | try c.global_scope.blank_macros.put(name, {}); |
| 5249 | 5249 | continue; |
| 5250 | 5250 | }, |
| ... | ... | @@ -5291,7 +5291,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5291 | 5291 | try c.global_scope.blank_macros.put(m.name, {}); |
| 5292 | 5292 | const init_node = try Tag.string_literal.create(c.arena, "\"\""); |
| 5293 | 5293 | const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); |
| 5294 | try c.global_scope.macro_table.put(m.name, var_decl); | |
| 5294 | try addTopLevelDecl(c, m.name, var_decl); | |
| 5295 | 5295 | return; |
| 5296 | 5296 | }, |
| 5297 | 5297 | else => {}, |
| ... | ... | @@ -5304,8 +5304,32 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5304 | 5304 | if (last != .eof and last != .nl) |
| 5305 | 5305 | return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()}); |
| 5306 | 5306 | |
| 5307 | const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); | |
| 5308 | try c.global_scope.macro_table.put(m.name, var_decl); | |
| 5307 | const node = node: { | |
| 5308 | const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); | |
| 5309 | ||
| 5310 | if (getFnProto(c, var_decl)) |proto_node| { | |
| 5311 | // If a macro aliases a global variable which is a function pointer, we conclude that | |
| 5312 | // the macro is intended to represent a function that assumes the function pointer | |
| 5313 | // variable is non-null and calls it. | |
| 5314 | break :node try transCreateNodeMacroFn(c, m.name, var_decl, proto_node); | |
| 5315 | } else if (m.refs_var_decl) { | |
| 5316 | const return_type = try Tag.typeof.create(c.arena, init_node); | |
| 5317 | const return_expr = try Tag.@"return".create(c.arena, init_node); | |
| 5318 | const block = try Tag.block_single.create(c.arena, return_expr); | |
| 5319 | try warn(c, scope, m.loc, "macro '{s}' contains a runtime value, translated to function", .{m.name}); | |
| 5320 | ||
| 5321 | break :node try Tag.pub_inline_fn.create(c.arena, .{ | |
| 5322 | .name = m.name, | |
| 5323 | .params = &.{}, | |
| 5324 | .return_type = return_type, | |
| 5325 | .body = block, | |
| 5326 | }); | |
| 5327 | } | |
| 5328 | ||
| 5329 | break :node var_decl; | |
| 5330 | }; | |
| 5331 | ||
| 5332 | try addTopLevelDecl(c, m.name, node); | |
| 5309 | 5333 | } |
| 5310 | 5334 | |
| 5311 | 5335 | fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| ... | ... | @@ -5315,7 +5339,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5315 | 5339 | .name = m.name, |
| 5316 | 5340 | .init = try Tag.helpers_macro.create(c.arena, pattern.impl), |
| 5317 | 5341 | }); |
| 5318 | try c.global_scope.macro_table.put(m.name, decl); | |
| 5342 | try addTopLevelDecl(c, m.name, decl); | |
| 5319 | 5343 | return; |
| 5320 | 5344 | } |
| 5321 | 5345 | |
| ... | ... | @@ -5380,7 +5404,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5380 | 5404 | .return_type = return_type, |
| 5381 | 5405 | .body = try block_scope.complete(c), |
| 5382 | 5406 | }); |
| 5383 | try c.global_scope.macro_table.put(m.name, fn_decl); | |
| 5407 | try addTopLevelDecl(c, m.name, fn_decl); | |
| 5384 | 5408 | } |
| 5385 | 5409 | |
| 5386 | 5410 | const ParseError = Error || error{ParseError}; |
| ... | ... | @@ -5768,6 +5792,11 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5768 | 5792 | if (builtin_typedef_map.get(mangled_name)) |ty| return Tag.type.create(c.arena, ty); |
| 5769 | 5793 | const identifier = try Tag.identifier.create(c.arena, mangled_name); |
| 5770 | 5794 | scope.skipVariableDiscard(identifier.castTag(.identifier).?.data); |
| 5795 | refs_var: { | |
| 5796 | const ident_node = c.global_scope.sym_table.get(slice) orelse break :refs_var; | |
| 5797 | const var_decl_node = ident_node.castTag(.var_decl) orelse break :refs_var; | |
| 5798 | if (!var_decl_node.data.is_const) m.refs_var_decl = true; | |
| 5799 | } | |
| 5771 | 5800 | return identifier; |
| 5772 | 5801 | }, |
| 5773 | 5802 | .l_paren => { |
| ... | ... | @@ -6496,17 +6525,3 @@ fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func { |
| 6496 | 6525 | } |
| 6497 | 6526 | return null; |
| 6498 | 6527 | } |
| 6499 | ||
| 6500 | fn addMacros(c: *Context) !void { | |
| 6501 | var it = c.global_scope.macro_table.iterator(); | |
| 6502 | while (it.next()) |entry| { | |
| 6503 | if (getFnProto(c, entry.value_ptr.*)) |proto_node| { | |
| 6504 | // If a macro aliases a global variable which is a function pointer, we conclude that | |
| 6505 | // the macro is intended to represent a function that assumes the function pointer | |
| 6506 | // variable is non-null and calls it. | |
| 6507 | try addTopLevelDecl(c, entry.key_ptr.*, try transCreateNodeMacroFn(c, entry.key_ptr.*, entry.value_ptr.*, proto_node)); | |
| 6508 | } else { | |
| 6509 | try addTopLevelDecl(c, entry.key_ptr.*, entry.value_ptr.*); | |
| 6510 | } | |
| 6511 | } | |
| 6512 | } |
test/cases/translate_c/macro_referencing_var.c created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | extern float foo; | |
| 2 | #define FOO_TWICE foo * 2.0f | |
| 3 | #define FOO_NEGATIVE -foo | |
| 4 | ||
| 5 | #define BAR 10.0f | |
| 6 | #define BAR_TWICE BAR * 2.0f | |
| 7 | ||
| 8 | // translate-c | |
| 9 | // c_frontend=clang | |
| 10 | // | |
| 11 | // pub extern var foo: f32; | |
| 12 | // | |
| 13 | // pub inline fn FOO_TWICE() @TypeOf(foo * @as(f32, 2.0)) { | |
| 14 | // return foo * @as(f32, 2.0); | |
| 15 | // } | |
| 16 | // | |
| 17 | // pub inline fn FOO_NEGATIVE() @TypeOf(-foo) { | |
| 18 | // return -foo; | |
| 19 | // } | |
| 20 | // pub const BAR = @as(f32, 10.0); | |
| 21 | // pub const BAR_TWICE = BAR * @as(f32, 2.0); |
test/translate_c.zig+21-7| ... | ... | @@ -223,7 +223,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 223 | 223 | \\ | (*((unsigned char *)(p) + 1) << 8) \ |
| 224 | 224 | \\ | (*((unsigned char *)(p) + 2) << 16)) |
| 225 | 225 | , &[_][]const u8{ |
| 226 | \\pub const FOO = (foo + @as(c_int, 2)).*; | |
| 226 | \\pub inline fn FOO() @TypeOf((foo + @as(c_int, 2)).*) { | |
| 227 | \\ return (foo + @as(c_int, 2)).*; | |
| 228 | \\} | |
| 227 | 229 | , |
| 228 | 230 | \\pub const VALUE = ((((@as(c_int, 1) + (@as(c_int, 2) * @as(c_int, 3))) + (@as(c_int, 4) * @as(c_int, 5))) + @as(c_int, 6)) << @as(c_int, 7)) | @intFromBool(@as(c_int, 8) == @as(c_int, 9)); |
| 229 | 231 | , |
| ... | ... | @@ -452,7 +454,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 452 | 454 | \\#define FOO -\ |
| 453 | 455 | \\BAR |
| 454 | 456 | , &[_][]const u8{ |
| 455 | \\pub const FOO = -BAR; | |
| 457 | \\pub inline fn FOO() @TypeOf(-BAR) { | |
| 458 | \\ return -BAR; | |
| 459 | \\} | |
| 456 | 460 | }); |
| 457 | 461 | |
| 458 | 462 | cases.add("struct with atomic field", |
| ... | ... | @@ -2453,9 +2457,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2453 | 2457 | \\ _ = c.*.b; |
| 2454 | 2458 | \\} |
| 2455 | 2459 | , |
| 2456 | \\pub const DOT = a.b; | |
| 2460 | \\pub inline fn ARROW() @TypeOf(a.*.b) { | |
| 2461 | \\ return a.*.b; | |
| 2462 | \\} | |
| 2457 | 2463 | , |
| 2458 | \\pub const ARROW = a.*.b; | |
| 2464 | \\pub inline fn DOT() @TypeOf(a.b) { | |
| 2465 | \\ return a.b; | |
| 2466 | \\} | |
| 2459 | 2467 | }); |
| 2460 | 2468 | |
| 2461 | 2469 | cases.add("array access", |
| ... | ... | @@ -2472,7 +2480,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2472 | 2480 | \\ return array[@as(c_uint, @intCast(index))]; |
| 2473 | 2481 | \\} |
| 2474 | 2482 | , |
| 2475 | \\pub const ACCESS = array[@as(usize, @intCast(@as(c_int, 2)))]; | |
| 2483 | \\pub inline fn ACCESS() @TypeOf(array[@as(usize, @intCast(@as(c_int, 2)))]) { | |
| 2484 | \\ return array[@as(usize, @intCast(@as(c_int, 2)))]; | |
| 2485 | \\} | |
| 2476 | 2486 | }); |
| 2477 | 2487 | |
| 2478 | 2488 | cases.add("cast signed array index to unsigned", |
| ... | ... | @@ -3130,7 +3140,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3130 | 3140 | \\ int a, b, c; |
| 3131 | 3141 | \\#define FOO a ? b : c |
| 3132 | 3142 | , &[_][]const u8{ |
| 3133 | \\pub const FOO = if (a) b else c; | |
| 3143 | \\pub inline fn FOO() @TypeOf(if (a) b else c) { | |
| 3144 | \\ return if (a) b else c; | |
| 3145 | \\} | |
| 3134 | 3146 | }); |
| 3135 | 3147 | |
| 3136 | 3148 | cases.add("do while as expr", |
| ... | ... | @@ -3624,7 +3636,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3624 | 3636 | \\#define FOO _ |
| 3625 | 3637 | \\int _ = 42; |
| 3626 | 3638 | , &[_][]const u8{ |
| 3627 | \\pub const FOO = @"_"; | |
| 3639 | \\pub inline fn FOO() @TypeOf(@"_") { | |
| 3640 | \\ return @"_"; | |
| 3641 | \\} | |
| 3628 | 3642 | , |
| 3629 | 3643 | \\pub export var @"_": c_int = 42; |
| 3630 | 3644 | }); |