| 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,7 +1381,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ |
| 1381 | pub const Root = struct { | 1381 | pub const Root = struct { |
| 1382 | base: ScopeExtraScope, | 1382 | base: ScopeExtraScope, |
| 1383 | sym_table: SymbolTable, | 1383 | sym_table: SymbolTable, |
| 1384 | macro_table: SymbolTable, | ||
| 1385 | blank_macros: std.StringArrayHashMap(void), | 1384 | blank_macros: std.StringArrayHashMap(void), |
| 1386 | context: *ScopeExtraContext, | 1385 | context: *ScopeExtraContext, |
| 1387 | nodes: std.ArrayList(ast.Node), | 1386 | nodes: std.ArrayList(ast.Node), |
| ... | @@ -1393,7 +1392,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ | ... | @@ -1393,7 +1392,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ |
| 1393 | .parent = null, | 1392 | .parent = null, |
| 1394 | }, | 1393 | }, |
| 1395 | .sym_table = SymbolTable.init(c.gpa), | 1394 | .sym_table = SymbolTable.init(c.gpa), |
| 1396 | .macro_table = SymbolTable.init(c.gpa), | ||
| 1397 | .blank_macros = std.StringArrayHashMap(void).init(c.gpa), | 1395 | .blank_macros = std.StringArrayHashMap(void).init(c.gpa), |
| 1398 | .context = c, | 1396 | .context = c, |
| 1399 | .nodes = std.ArrayList(ast.Node).init(c.gpa), | 1397 | .nodes = std.ArrayList(ast.Node).init(c.gpa), |
| ... | @@ -1402,7 +1400,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ | ... | @@ -1402,7 +1400,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ |
| 1402 | 1400 | ||
| 1403 | pub fn deinit(scope: *Root) void { | 1401 | pub fn deinit(scope: *Root) void { |
| 1404 | scope.sym_table.deinit(); | 1402 | scope.sym_table.deinit(); |
| 1405 | scope.macro_table.deinit(); | ||
| 1406 | scope.blank_macros.deinit(); | 1403 | scope.blank_macros.deinit(); |
| 1407 | scope.nodes.deinit(); | 1404 | scope.nodes.deinit(); |
| 1408 | } | 1405 | } |
| ... | @@ -1410,7 +1407,7 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ | ... | @@ -1410,7 +1407,7 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ |
| 1410 | /// Check if the global scope contains this name, without looking into the "future", e.g. | 1407 | /// Check if the global scope contains this name, without looking into the "future", e.g. |
| 1411 | /// ignore the preprocessed decl and macro names. | 1408 | /// ignore the preprocessed decl and macro names. |
| 1412 | pub fn containsNow(scope: *Root, name: []const u8) bool { | 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 | /// Check if the global scope contains the name, includes all decls that haven't been translated yet. | 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,6 +875,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 875 | .declaration => unreachable, | 875 | .declaration => unreachable, |
| 876 | .warning => { | 876 | .warning => { |
| 877 | const payload = node.castTag(.warning).?.data; | 877 | const payload = node.castTag(.warning).?.data; |
| 878 | try c.buf.append('\n'); | ||
| 878 | try c.buf.appendSlice(payload); | 879 | try c.buf.appendSlice(payload); |
| 879 | try c.buf.append('\n'); | 880 | try c.buf.append('\n'); |
| 880 | return @as(NodeIndex, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32' | 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,7 +177,6 @@ pub fn translate( |
| 177 | 177 | ||
| 178 | try transPreprocessorEntities(&context, ast_unit); | 178 | try transPreprocessorEntities(&context, ast_unit); |
| 179 | 179 | ||
| 180 | try addMacros(&context); | ||
| 181 | for (context.alias_list.items) |alias| { | 180 | for (context.alias_list.items) |alias| { |
| 182 | const node = try Tag.alias.create(arena, .{ .actual = alias.alias, .mangled = alias.name }); | 181 | const node = try Tag.alias.create(arena, .{ .actual = alias.alias, .mangled = alias.name }); |
| 183 | try addTopLevelDecl(&context, alias.alias, node); | 182 | try addTopLevelDecl(&context, alias.alias, node); |
| ... | @@ -5105,6 +5104,7 @@ const MacroCtx = struct { | ... | @@ -5105,6 +5104,7 @@ const MacroCtx = struct { |
| 5105 | i: usize = 0, | 5104 | i: usize = 0, |
| 5106 | loc: clang.SourceLocation, | 5105 | loc: clang.SourceLocation, |
| 5107 | name: []const u8, | 5106 | name: []const u8, |
| 5107 | refs_var_decl: bool = false, | ||
| 5108 | 5108 | ||
| 5109 | fn peek(self: *MacroCtx) ?CToken.Id { | 5109 | fn peek(self: *MacroCtx) ?CToken.Id { |
| 5110 | if (self.i >= self.list.len) return null; | 5110 | if (self.i >= self.list.len) return null; |
| ... | @@ -5244,7 +5244,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { | ... | @@ -5244,7 +5244,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { |
| 5244 | // We define it as an empty string so that it can still be used with ++ | 5244 | // We define it as an empty string so that it can still be used with ++ |
| 5245 | const str_node = try Tag.string_literal.create(c.arena, "\"\""); | 5245 | const str_node = try Tag.string_literal.create(c.arena, "\"\""); |
| 5246 | const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = name, .init = str_node }); | 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 | try c.global_scope.blank_macros.put(name, {}); | 5248 | try c.global_scope.blank_macros.put(name, {}); |
| 5249 | continue; | 5249 | continue; |
| 5250 | }, | 5250 | }, |
| ... | @@ -5291,7 +5291,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { | ... | @@ -5291,7 +5291,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5291 | try c.global_scope.blank_macros.put(m.name, {}); | 5291 | try c.global_scope.blank_macros.put(m.name, {}); |
| 5292 | const init_node = try Tag.string_literal.create(c.arena, "\"\""); | 5292 | const init_node = try Tag.string_literal.create(c.arena, "\"\""); |
| 5293 | const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); | 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 | return; | 5295 | return; |
| 5296 | }, | 5296 | }, |
| 5297 | else => {}, | 5297 | else => {}, |
| ... | @@ -5304,8 +5304,32 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { | ... | @@ -5304,8 +5304,32 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5304 | if (last != .eof and last != .nl) | 5304 | if (last != .eof and last != .nl) |
| 5305 | return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()}); | 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 }); | 5307 | const node = node: { |
| 5308 | try c.global_scope.macro_table.put(m.name, var_decl); | 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 | fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { | 5335 | fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| ... | @@ -5315,7 +5339,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { | ... | @@ -5315,7 +5339,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5315 | .name = m.name, | 5339 | .name = m.name, |
| 5316 | .init = try Tag.helpers_macro.create(c.arena, pattern.impl), | 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 | return; | 5343 | return; |
| 5320 | } | 5344 | } |
| 5321 | 5345 | ||
| ... | @@ -5380,7 +5404,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { | ... | @@ -5380,7 +5404,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5380 | .return_type = return_type, | 5404 | .return_type = return_type, |
| 5381 | .body = try block_scope.complete(c), | 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 | const ParseError = Error || error{ParseError}; | 5410 | const ParseError = Error || error{ParseError}; |
| ... | @@ -5768,6 +5792,11 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { | ... | @@ -5768,6 +5792,11 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5768 | if (builtin_typedef_map.get(mangled_name)) |ty| return Tag.type.create(c.arena, ty); | 5792 | if (builtin_typedef_map.get(mangled_name)) |ty| return Tag.type.create(c.arena, ty); |
| 5769 | const identifier = try Tag.identifier.create(c.arena, mangled_name); | 5793 | const identifier = try Tag.identifier.create(c.arena, mangled_name); |
| 5770 | scope.skipVariableDiscard(identifier.castTag(.identifier).?.data); | 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 | return identifier; | 5800 | return identifier; |
| 5772 | }, | 5801 | }, |
| 5773 | .l_paren => { | 5802 | .l_paren => { |
| ... | @@ -6496,17 +6525,3 @@ fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func { | ... | @@ -6496,17 +6525,3 @@ fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func { |
| 6496 | } | 6525 | } |
| 6497 | return null; | 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,7 +223,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 223 | \\ | (*((unsigned char *)(p) + 1) << 8) \ | 223 | \\ | (*((unsigned char *)(p) + 1) << 8) \ |
| 224 | \\ | (*((unsigned char *)(p) + 2) << 16)) | 224 | \\ | (*((unsigned char *)(p) + 2) << 16)) |
| 225 | , &[_][]const u8{ | 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 | \\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)); | 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,7 +454,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 452 | \\#define FOO -\ | 454 | \\#define FOO -\ |
| 453 | \\BAR | 455 | \\BAR |
| 454 | , &[_][]const u8{ | 456 | , &[_][]const u8{ |
| 455 | \\pub const FOO = -BAR; | 457 | \\pub inline fn FOO() @TypeOf(-BAR) { |
| 458 | \\ return -BAR; | ||
| 459 | \\} | ||
| 456 | }); | 460 | }); |
| 457 | 461 | ||
| 458 | cases.add("struct with atomic field", | 462 | cases.add("struct with atomic field", |
| ... | @@ -2453,9 +2457,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -2453,9 +2457,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2453 | \\ _ = c.*.b; | 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 | cases.add("array access", | 2469 | cases.add("array access", |
| ... | @@ -2472,7 +2480,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -2472,7 +2480,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2472 | \\ return array[@as(c_uint, @intCast(index))]; | 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 | cases.add("cast signed array index to unsigned", | 2488 | cases.add("cast signed array index to unsigned", |
| ... | @@ -3130,7 +3140,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -3130,7 +3140,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3130 | \\ int a, b, c; | 3140 | \\ int a, b, c; |
| 3131 | \\#define FOO a ? b : c | 3141 | \\#define FOO a ? b : c |
| 3132 | , &[_][]const u8{ | 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 | cases.add("do while as expr", | 3148 | cases.add("do while as expr", |
| ... | @@ -3624,7 +3636,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -3624,7 +3636,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3624 | \\#define FOO _ | 3636 | \\#define FOO _ |
| 3625 | \\int _ = 42; | 3637 | \\int _ = 42; |
| 3626 | , &[_][]const u8{ | 3638 | , &[_][]const u8{ |
| 3627 | \\pub const FOO = @"_"; | 3639 | \\pub inline fn FOO() @TypeOf(@"_") { |
| 3640 | \\ return @"_"; | ||
| 3641 | \\} | ||
| 3628 | , | 3642 | , |
| 3629 | \\pub export var @"_": c_int = 42; | 3643 | \\pub export var @"_": c_int = 42; |
| 3630 | }); | 3644 | }); |