mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
translate-c: promote int literals to bigger types
This commit is contained in:
parent
9cd038d73a
commit
679910ecec
@ -1094,6 +1094,36 @@ test "sizeof" {
|
|||||||
testing.expect(sizeof(c_void) == 1);
|
testing.expect(sizeof(c_void) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const CIntLiteralRadix = enum { decimal, octal, hexadecimal };
|
||||||
|
|
||||||
|
fn PromoteIntLiteralReturnType(comptime SuffixType: type, comptime target: comptime_int, comptime radix: CIntLiteralRadix) type {
|
||||||
|
const signed_decimal = [_]type{ c_int, c_long, c_longlong };
|
||||||
|
const signed_oct_hex = [_]type{ c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong };
|
||||||
|
const unsigned = [_]type{ c_uint, c_ulong, c_ulonglong };
|
||||||
|
|
||||||
|
const list: []const type = if (@typeInfo(SuffixType).Int.signedness == .unsigned)
|
||||||
|
&unsigned
|
||||||
|
else if (radix == .decimal)
|
||||||
|
&signed_decimal
|
||||||
|
else
|
||||||
|
&signed_oct_hex;
|
||||||
|
|
||||||
|
var pos = mem.indexOfScalar(type, list, SuffixType).?;
|
||||||
|
|
||||||
|
while (pos < list.len) : (pos += 1) {
|
||||||
|
if (target >= math.minInt(list[pos]) and target <= math.maxInt(list[pos])) {
|
||||||
|
return list[pos];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@compileError("Integer literal does not fit in compatible types");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Promote the type of an integer literal until it fits as C would.
|
||||||
|
/// This is for translate-c and is not intended for general use.
|
||||||
|
pub fn promoteIntLiteral(comptime SuffixType: type, comptime target: comptime_int, comptime radix: CIntLiteralRadix) PromoteIntLiteralReturnType(SuffixType, target, radix) {
|
||||||
|
return @as(PromoteIntLiteralReturnType(SuffixType, target, radix), target);
|
||||||
|
}
|
||||||
|
|
||||||
/// For a given function type, returns a tuple type which fields will
|
/// For a given function type, returns a tuple type which fields will
|
||||||
/// correspond to the argument types.
|
/// correspond to the argument types.
|
||||||
///
|
///
|
||||||
|
|||||||
@ -4431,40 +4431,68 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
|
|||||||
|
|
||||||
switch (m.list[m.i].id) {
|
switch (m.list[m.i].id) {
|
||||||
.IntegerLiteral => |suffix| {
|
.IntegerLiteral => |suffix| {
|
||||||
|
var radix: []const u8 = "decimal";
|
||||||
if (lit_bytes.len > 2 and lit_bytes[0] == '0') {
|
if (lit_bytes.len > 2 and lit_bytes[0] == '0') {
|
||||||
switch (lit_bytes[1]) {
|
switch (lit_bytes[1]) {
|
||||||
'0'...'7' => {
|
'0'...'7' => {
|
||||||
// Octal
|
// Octal
|
||||||
lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes});
|
lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes});
|
||||||
|
radix = "octal";
|
||||||
},
|
},
|
||||||
'X' => {
|
'X' => {
|
||||||
// Hexadecimal with capital X, valid in C but not in Zig
|
// Hexadecimal with capital X, valid in C but not in Zig
|
||||||
lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]});
|
lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]});
|
||||||
|
radix = "hexadecimal";
|
||||||
|
},
|
||||||
|
'x' => {
|
||||||
|
radix = "hexadecimal";
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (suffix == .none) {
|
|
||||||
return transCreateNodeNumber(c, lit_bytes, .int);
|
|
||||||
}
|
|
||||||
|
|
||||||
const type_node = try Tag.type.create(c.arena, switch (suffix) {
|
const type_node = try Tag.type.create(c.arena, switch (suffix) {
|
||||||
|
.none => "c_int",
|
||||||
.u => "c_uint",
|
.u => "c_uint",
|
||||||
.l => "c_long",
|
.l => "c_long",
|
||||||
.lu => "c_ulong",
|
.lu => "c_ulong",
|
||||||
.ll => "c_longlong",
|
.ll => "c_longlong",
|
||||||
.llu => "c_ulonglong",
|
.llu => "c_ulonglong",
|
||||||
else => unreachable,
|
.f => unreachable,
|
||||||
});
|
});
|
||||||
lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (suffix) {
|
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,
|
.lu, .ll => 2,
|
||||||
.llu => 3,
|
.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| {
|
.FloatLiteral => |suffix| {
|
||||||
if (lit_bytes[0] == '.')
|
if (lit_bytes[0] == '.')
|
||||||
|
|||||||
@ -39,6 +39,7 @@ pub const Node = extern union {
|
|||||||
float_literal,
|
float_literal,
|
||||||
string_literal,
|
string_literal,
|
||||||
char_literal,
|
char_literal,
|
||||||
|
enum_literal,
|
||||||
identifier,
|
identifier,
|
||||||
@"if",
|
@"if",
|
||||||
/// if (!operand) break;
|
/// if (!operand) break;
|
||||||
@ -117,6 +118,7 @@ pub const Node = extern union {
|
|||||||
/// @intCast(lhs, rhs)
|
/// @intCast(lhs, rhs)
|
||||||
int_cast,
|
int_cast,
|
||||||
/// @rem(lhs, rhs)
|
/// @rem(lhs, rhs)
|
||||||
|
std_meta_promoteIntLiteral,
|
||||||
rem,
|
rem,
|
||||||
/// @divTrunc(lhs, rhs)
|
/// @divTrunc(lhs, rhs)
|
||||||
div_trunc,
|
div_trunc,
|
||||||
@ -312,6 +314,7 @@ pub const Node = extern union {
|
|||||||
.float_literal,
|
.float_literal,
|
||||||
.string_literal,
|
.string_literal,
|
||||||
.char_literal,
|
.char_literal,
|
||||||
|
.enum_literal,
|
||||||
.identifier,
|
.identifier,
|
||||||
.warning,
|
.warning,
|
||||||
.type,
|
.type,
|
||||||
@ -328,6 +331,7 @@ pub const Node = extern union {
|
|||||||
.tuple => Payload.TupleInit,
|
.tuple => Payload.TupleInit,
|
||||||
.container_init => Payload.ContainerInit,
|
.container_init => Payload.ContainerInit,
|
||||||
.std_meta_cast => Payload.Infix,
|
.std_meta_cast => Payload.Infix,
|
||||||
|
.std_meta_promoteIntLiteral => Payload.PromoteIntLiteral,
|
||||||
.block => Payload.Block,
|
.block => Payload.Block,
|
||||||
.c_pointer, .single_pointer => Payload.Pointer,
|
.c_pointer, .single_pointer => Payload.Pointer,
|
||||||
.array_type => Payload.Array,
|
.array_type => Payload.Array,
|
||||||
@ -651,6 +655,15 @@ pub const Payload = struct {
|
|||||||
field_name: []const u8,
|
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.
|
/// 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");
|
const import_node = try renderStdImport(c, "meta", "cast");
|
||||||
return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
|
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 => {
|
.std_meta_sizeof => {
|
||||||
const payload = node.castTag(.std_meta_sizeof).?.data;
|
const payload = node.castTag(.std_meta_sizeof).?.data;
|
||||||
const import_node = try renderStdImport(c, "meta", "sizeof");
|
const import_node = try renderStdImport(c, "meta", "sizeof");
|
||||||
@ -988,6 +1006,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
|
|||||||
.data = undefined,
|
.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 => {
|
.fail_decl => {
|
||||||
const payload = node.castTag(.fail_decl).?.data;
|
const payload = node.castTag(.fail_decl).?.data;
|
||||||
// pub const name = @compileError(msg);
|
// pub const name = @compileError(msg);
|
||||||
@ -1982,11 +2009,13 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
|
|||||||
.typeof,
|
.typeof,
|
||||||
.std_meta_sizeof,
|
.std_meta_sizeof,
|
||||||
.std_meta_cast,
|
.std_meta_cast,
|
||||||
|
.std_meta_promoteIntLiteral,
|
||||||
.std_mem_zeroinit,
|
.std_mem_zeroinit,
|
||||||
.integer_literal,
|
.integer_literal,
|
||||||
.float_literal,
|
.float_literal,
|
||||||
.string_literal,
|
.string_literal,
|
||||||
.char_literal,
|
.char_literal,
|
||||||
|
.enum_literal,
|
||||||
.identifier,
|
.identifier,
|
||||||
.field_access,
|
.field_access,
|
||||||
.ptr_cast,
|
.ptr_cast,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user