Skip to content

Commit 2c88153

Browse files
committed
translate _Static_asserts
1 parent 24f7fa0 commit 2c88153

File tree

4 files changed

+116
-9
lines changed

4 files changed

+116
-9
lines changed

src/Translator.zig

+48-6
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ pub fn translate(
469469
context.decl_table.deinit(gpa);
470470
context.alias_list.deinit();
471471
context.global_names.deinit(gpa);
472+
context.weak_global_names.deinit(gpa);
472473
context.opaque_demotes.deinit(gpa);
473474
context.unnamed_typedefs.deinit(gpa);
474475
context.typedefs.deinit(gpa);
@@ -610,7 +611,9 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
610611
=> {
611612
try transVarDecl(c, decl);
612613
},
613-
.static_assert => try warn(c, &c.global_scope.base, c.tokenIndex(decl) orelse 0, "ignoring _Static_assert declaration", .{}),
614+
.static_assert => {
615+
try transStaticAssert(c, &c.global_scope.base, decl);
616+
},
614617
else => unreachable,
615618
}
616619
}
@@ -991,6 +994,40 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_
991994
}
992995
}
993996

997+
fn transStaticAssert(c: *Context, scope: *Scope, static_assert_node: NodeIndex) Error!void {
998+
const node_data = c.tree.nodes.items(.data)[@intFromEnum(static_assert_node)];
999+
1000+
const condition = c.transExpr(node_data.bin.lhs, .used) catch |err| switch (err) {
1001+
error.UnsupportedTranslation, error.UnsupportedType => {
1002+
return try warn(c, &c.global_scope.base, c.tokenIndex(node_data.bin.lhs).?, "unable to translate _Static_assert condition", .{});
1003+
},
1004+
error.OutOfMemory => |e| return e,
1005+
};
1006+
1007+
// generate @compileError message that matches C compiler output
1008+
const diagnostic = if (node_data.bin.rhs != .none) str: {
1009+
// Aro guarantees this to be a string literal.
1010+
const str_val = c.tree.value_map.get(node_data.bin.rhs).?;
1011+
const str_ty = c.tree.nodes.items(.ty)[@intFromEnum(node_data.bin.rhs)];
1012+
1013+
const bytes = c.comp.interner.get(str_val.ref()).bytes;
1014+
var buf = std.ArrayList(u8).init(c.gpa);
1015+
defer buf.deinit();
1016+
1017+
try buf.appendSlice("\"static assertion failed \\");
1018+
1019+
try buf.ensureUnusedCapacity(bytes.len);
1020+
try aro.Value.printString(bytes, str_ty, c.comp, buf.writer());
1021+
_ = buf.pop(); // printString adds a terminating " so we need to remove it
1022+
try buf.appendSlice("\\\"\"");
1023+
1024+
break :str try ZigTag.string_literal.create(c.arena, try c.arena.dupe(u8, buf.items));
1025+
} else try ZigTag.string_literal.create(c.arena, "\"static assertion failed\"");
1026+
1027+
const assert_node = try ZigTag.static_assert.create(c.arena, .{ .lhs = condition, .rhs = diagnostic });
1028+
try scope.appendNode(assert_node);
1029+
}
1030+
9941031
fn getTypeStr(c: *Context, ty: Type) ![]const u8 {
9951032
var buf: std.ArrayListUnmanaged(u8) = .empty;
9961033
defer buf.deinit(c.gpa);
@@ -1316,16 +1353,21 @@ fn transFnType(
13161353
return ZigNode.initPayload(&payload.base);
13171354
}
13181355

1319-
fn transStmt(c: *Context, node: NodeIndex) TransError!ZigNode {
1320-
_ = c;
1321-
_ = node;
1322-
return error.UnsupportedTranslation;
1356+
fn transStmt(c: *Context, scope: *Scope, stmt: NodeIndex) TransError!ZigNode {
1357+
const node_tags = c.tree.nodes.items(.tag);
1358+
switch (node_tags[@intFromEnum(stmt)]) {
1359+
.static_assert => {
1360+
try transStaticAssert(c, scope, stmt);
1361+
return ZigTag.declaration.init();
1362+
},
1363+
else => return fail(c, error.UnsupportedTranslation, c.tokenIndex(stmt).?, "TODO implement translation of stmt {s}", .{@tagName(node_tags[@intFromEnum(stmt)])}),
1364+
}
13231365
}
13241366

13251367
fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block) TransError!void {
13261368
const stmts = c.tree.childNodes(compound);
13271369
for (stmts) |stmt| {
1328-
const result = try transStmt(c, stmt);
1370+
const result = try transStmt(c, &block.base, stmt);
13291371
switch (result.tag()) {
13301372
.declaration, .empty_block => {},
13311373
else => try block.statements.append(result),

src/ast.zig

+62-2
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ pub const Node = extern union {
227227
/// [1]type{val} ** count
228228
array_filler,
229229

230+
/// comptime { if (!(lhs)) @compileError(rhs); }
231+
static_assert,
232+
230233
pub const last_no_payload_tag = Tag.@"break";
231234
pub const no_payload_count = @intFromEnum(last_no_payload_tag) + 1;
232235

@@ -336,6 +339,7 @@ pub const Node = extern union {
336339
.div_exact,
337340
.offset_of,
338341
.helpers_cast,
342+
.static_assert,
339343
=> Payload.BinOp,
340344

341345
.integer_literal,
@@ -753,7 +757,7 @@ pub const Payload = struct {
753757
/// Converts the nodes into a Zig Ast.
754758
/// Caller must free the source slice.
755759
pub fn render(gpa: Allocator, nodes: []const Node) !std.zig.Ast {
756-
var ctx = Context{
760+
var ctx: Context = .{
757761
.gpa = gpa,
758762
.buf = std.ArrayList(u8).init(gpa),
759763
};
@@ -803,7 +807,7 @@ pub fn render(gpa: Allocator, nodes: []const Node) !std.zig.Ast {
803807
.start = @as(u32, @intCast(ctx.buf.items.len)),
804808
});
805809

806-
return std.zig.Ast{
810+
return .{
807811
.source = try ctx.buf.toOwnedSliceSentinel(0),
808812
.tokens = ctx.tokens.toOwnedSlice(),
809813
.nodes = ctx.nodes.toOwnedSlice(),
@@ -2127,6 +2131,61 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
21272131
},
21282132
};
21292133
},
2134+
.static_assert => {
2135+
const payload = node.castTag(.static_assert).?.data;
2136+
const comptime_tok = try c.addToken(.keyword_comptime, "comptime");
2137+
const l_brace = try c.addToken(.l_brace, "{");
2138+
2139+
const if_tok = try c.addToken(.keyword_if, "if");
2140+
_ = try c.addToken(.l_paren, "(");
2141+
const cond = try c.addNode(.{
2142+
.tag = .bool_not,
2143+
.main_token = try c.addToken(.bang, "!"),
2144+
.data = .{
2145+
.lhs = try renderNodeGrouped(c, payload.lhs),
2146+
.rhs = undefined,
2147+
},
2148+
});
2149+
_ = try c.addToken(.r_paren, ")");
2150+
2151+
const compile_error_tok = try c.addToken(.builtin, "@compileError");
2152+
_ = try c.addToken(.l_paren, "(");
2153+
const err_msg = try renderNode(c, payload.rhs);
2154+
_ = try c.addToken(.r_paren, ")");
2155+
const compile_error = try c.addNode(.{
2156+
.tag = .builtin_call_two,
2157+
.main_token = compile_error_tok,
2158+
.data = .{ .lhs = err_msg, .rhs = 0 },
2159+
});
2160+
2161+
const if_node = try c.addNode(.{
2162+
.tag = .if_simple,
2163+
.main_token = if_tok,
2164+
.data = .{
2165+
.lhs = cond,
2166+
.rhs = compile_error,
2167+
},
2168+
});
2169+
_ = try c.addToken(.semicolon, ";");
2170+
_ = try c.addToken(.r_brace, "}");
2171+
const block_node = try c.addNode(.{
2172+
.tag = .block_two_semicolon,
2173+
.main_token = l_brace,
2174+
.data = .{
2175+
.lhs = if_node,
2176+
.rhs = 0,
2177+
},
2178+
});
2179+
2180+
return c.addNode(.{
2181+
.tag = .@"comptime",
2182+
.main_token = comptime_tok,
2183+
.data = .{
2184+
.lhs = block_node,
2185+
.rhs = undefined,
2186+
},
2187+
});
2188+
},
21302189
.@"anytype" => unreachable, // Handled in renderParams
21312190
}
21322191
}
@@ -2527,6 +2586,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
25272586
.assign,
25282587
.helpers_macro,
25292588
.import_c_builtin,
2589+
.static_assert,
25302590
=> {
25312591
// these should never appear in places where grouping might be needed.
25322592
unreachable;

src/main.zig

+5-1
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,12 @@ fn translate(d: *aro.Driver, args: []const []const u8) !void {
8686
return;
8787
}
8888

89+
// TODO this should probably pass an arraylist for the generated source.
8990
var zig_tree = try Translator.translate(gpa, d.comp, c_tree);
90-
defer zig_tree.deinit(gpa);
91+
defer {
92+
gpa.free(zig_tree.source);
93+
zig_tree.deinit(gpa);
94+
}
9195

9296
const formatted = try zig_tree.render(gpa);
9397
defer gpa.free(formatted);

test/cases/translate/_Static_assert.c

+1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ _Static_assert(1 == 1, "");
22

33
// translate
44
// target=x86_64-linux
5+
// expect=fail
56
//
67
// tmp.c:1:1: warning: ignoring _Static_assert declaration

0 commit comments

Comments
 (0)