aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorxackus <14938807+xackus@users.noreply.github.com>2021-03-02 17:40:34 +0100
committerxackus <14938807+xackus@users.noreply.github.com>2021-03-05 21:04:27 +0100
commit679910ecec5cb8d77cbb599ce5df9459615e2d50 (patch)
tree4a47a31015f91168cbaee4b0faa2895c685f0c09 /src
parent9cd038d73a174706ec0a51ab9db0c04b095e019d (diff)
downloadzig-679910ecec5cb8d77cbb599ce5df9459615e2d50.tar.gz
zig-679910ecec5cb8d77cbb599ce5df9459615e2d50.zip
translate-c: promote int literals to bigger types
Diffstat (limited to 'src')
-rw-r--r--src/translate_c.zig46
-rw-r--r--src/translate_c/ast.zig29
2 files changed, 66 insertions, 9 deletions
diff --git a/src/translate_c.zig b/src/translate_c.zig
index 2770ffb4cb..34655d3bb5 100644
--- a/src/translate_c.zig
+++ b/src/translate_c.zig
@@ -4431,40 +4431,68 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
switch (m.list[m.i].id) {
.IntegerLiteral => |suffix| {
+ var radix: []const u8 = "decimal";
if (lit_bytes.len > 2 and lit_bytes[0] == '0') {
switch (lit_bytes[1]) {
'0'...'7' => {
// Octal
lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes});
+ radix = "octal";
},
'X' => {
// Hexadecimal with capital X, valid in C but not in Zig
lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]});
+ radix = "hexadecimal";
+ },
+ 'x' => {
+ radix = "hexadecimal";
},
else => {},
}
}
- if (suffix == .none) {
- return transCreateNodeNumber(c, lit_bytes, .int);
- }
-
const type_node = try Tag.type.create(c.arena, switch (suffix) {
+ .none => "c_int",
.u => "c_uint",
.l => "c_long",
.lu => "c_ulong",
.ll => "c_longlong",
.llu => "c_ulonglong",
- else => unreachable,
+ .f => unreachable,
});
lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (suffix) {
- .u, .l => @as(u8, 1),
+ .none => @as(u8, 0),
+ .u, .l => 1,
.lu, .ll => 2,
.llu => 3,
- else => unreachable,
+ .f => unreachable,
}];
- const rhs = try transCreateNodeNumber(c, lit_bytes, .int);
- return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
+
+ const value = std.fmt.parseInt(i128, lit_bytes, 0) catch math.maxInt(i128);
+
+ // make the output less noisy by skipping promoteIntLiteral where
+ // it's guaranteed to not be required because of C standard type constraints
+ const guaranteed_to_fit = switch (suffix) {
+ .none => if (math.cast(i16, value)) |_| true else |_| false,
+ .u => if (math.cast(u16, value)) |_| true else |_| false,
+ .l => if (math.cast(i32, value)) |_| true else |_| false,
+ .lu => if (math.cast(u32, value)) |_| true else |_| false,
+ .ll => if (math.cast(i64, value)) |_| true else |_| false,
+ .llu => if (math.cast(u64, value)) |_| true else |_| false,
+ .f => unreachable,
+ };
+
+ const literal_node = try transCreateNodeNumber(c, lit_bytes, .int);
+
+ if (guaranteed_to_fit) {
+ return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = literal_node });
+ } else {
+ return Tag.std_meta_promoteIntLiteral.create(c.arena, .{
+ .type = type_node,
+ .value = literal_node,
+ .radix = try Tag.enum_literal.create(c.arena, radix),
+ });
+ }
},
.FloatLiteral => |suffix| {
if (lit_bytes[0] == '.')
diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig
index e984274c75..e5f76cc1de 100644
--- a/src/translate_c/ast.zig
+++ b/src/translate_c/ast.zig
@@ -39,6 +39,7 @@ pub const Node = extern union {
float_literal,
string_literal,
char_literal,
+ enum_literal,
identifier,
@"if",
/// if (!operand) break;
@@ -117,6 +118,7 @@ pub const Node = extern union {
/// @intCast(lhs, rhs)
int_cast,
/// @rem(lhs, rhs)
+ std_meta_promoteIntLiteral,
rem,
/// @divTrunc(lhs, rhs)
div_trunc,
@@ -312,6 +314,7 @@ pub const Node = extern union {
.float_literal,
.string_literal,
.char_literal,
+ .enum_literal,
.identifier,
.warning,
.type,
@@ -328,6 +331,7 @@ pub const Node = extern union {
.tuple => Payload.TupleInit,
.container_init => Payload.ContainerInit,
.std_meta_cast => Payload.Infix,
+ .std_meta_promoteIntLiteral => Payload.PromoteIntLiteral,
.block => Payload.Block,
.c_pointer, .single_pointer => Payload.Pointer,
.array_type => Payload.Array,
@@ -651,6 +655,15 @@ pub const Payload = struct {
field_name: []const u8,
},
};
+
+ pub const PromoteIntLiteral = struct {
+ base: Payload,
+ data: struct {
+ value: Node,
+ type: Node,
+ radix: Node,
+ },
+ };
};
/// Converts the nodes into a Zig ast.
@@ -821,6 +834,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
const import_node = try renderStdImport(c, "meta", "cast");
return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
},
+ .std_meta_promoteIntLiteral => {
+ const payload = node.castTag(.std_meta_promoteIntLiteral).?.data;
+ const import_node = try renderStdImport(c, "meta", "promoteIntLiteral");
+ return renderCall(c, import_node, &.{ payload.type, payload.value, payload.radix });
+ },
.std_meta_sizeof => {
const payload = node.castTag(.std_meta_sizeof).?.data;
const import_node = try renderStdImport(c, "meta", "sizeof");
@@ -988,6 +1006,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
.data = undefined,
});
},
+ .enum_literal => {
+ const payload = node.castTag(.enum_literal).?.data;
+ _ = try c.addToken(.period, ".");
+ return c.addNode(.{
+ .tag = .enum_literal,
+ .main_token = try c.addToken(.identifier, payload),
+ .data = undefined,
+ });
+ },
.fail_decl => {
const payload = node.castTag(.fail_decl).?.data;
// pub const name = @compileError(msg);
@@ -1982,11 +2009,13 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
.typeof,
.std_meta_sizeof,
.std_meta_cast,
+ .std_meta_promoteIntLiteral,
.std_mem_zeroinit,
.integer_literal,
.float_literal,
.string_literal,
.char_literal,
+ .enum_literal,
.identifier,
.field_access,
.ptr_cast,