From 679910ecec5cb8d77cbb599ce5df9459615e2d50 Mon Sep 17 00:00:00 2001 From: xackus <14938807+xackus@users.noreply.github.com> Date: Tue, 2 Mar 2021 17:40:34 +0100 Subject: [PATCH 1/5] translate-c: promote int literals to bigger types --- lib/std/meta.zig | 30 +++++++++++++++++++++++++++ src/translate_c.zig | 46 +++++++++++++++++++++++++++++++++-------- src/translate_c/ast.zig | 29 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 9 deletions(-) diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 7ec29dcd0e..7fe0df3dea 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -1094,6 +1094,36 @@ test "sizeof" { 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 /// correspond to the argument types. /// 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, From 5f53b77c2bed56e53717315eef2c92bfbf0a3ee0 Mon Sep 17 00:00:00 2001 From: Maciej Walczak <14938807+xackus@users.noreply.github.com> Date: Fri, 5 Mar 2021 15:32:18 +0100 Subject: [PATCH 2/5] remove redundant cast Co-authored-by: Veikka Tuominen --- lib/std/meta.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 7fe0df3dea..46d31a87c3 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -1121,7 +1121,7 @@ fn PromoteIntLiteralReturnType(comptime SuffixType: type, comptime target: compt /// 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); + return target; } /// For a given function type, returns a tuple type which fields will From b4ef6fa09d945c6e7d0f8a73e77c4c03ba262fd7 Mon Sep 17 00:00:00 2001 From: xackus <14938807+xackus@users.noreply.github.com> Date: Fri, 5 Mar 2021 19:42:21 +0100 Subject: [PATCH 3/5] fix test-translate-c --- test/translate_c.zig | 78 ++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/test/translate_c.zig b/test/translate_c.zig index 367f69745b..6134190efb 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -232,12 +232,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ | (*((unsigned char *)(p) + 1) << 8) \ \\ | (*((unsigned char *)(p) + 2) << 16)) , &[_][]const u8{ - \\pub const FOO = (foo + 2).*; + \\pub const FOO = (foo + @as(c_int, 2)).*; , - \\pub const VALUE = ((((1 + (2 * 3)) + (4 * 5)) + 6) << 7) | @boolToInt(8 == 9); + \\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)) | @boolToInt(@as(c_int, 8) == @as(c_int, 9)); , - \\pub fn _AL_READ3BYTES(p: anytype) callconv(.Inline) @TypeOf((@import("std").meta.cast([*c]u8, p).* | ((@import("std").meta.cast([*c]u8, p) + 1).* << 8)) | ((@import("std").meta.cast([*c]u8, p) + 2).* << 16)) { - \\ return (@import("std").meta.cast([*c]u8, p).* | ((@import("std").meta.cast([*c]u8, p) + 1).* << 8)) | ((@import("std").meta.cast([*c]u8, p) + 2).* << 16); + \\pub fn _AL_READ3BYTES(p: anytype) callconv(.Inline) @TypeOf((@import("std").meta.cast([*c]u8, p).* | ((@import("std").meta.cast([*c]u8, p) + @as(c_int, 1)).* << @as(c_int, 8))) | ((@import("std").meta.cast([*c]u8, p) + @as(c_int, 2)).* << @as(c_int, 16))) { + \\ return (@import("std").meta.cast([*c]u8, p).* | ((@import("std").meta.cast([*c]u8, p) + @as(c_int, 1)).* << @as(c_int, 8))) | ((@import("std").meta.cast([*c]u8, p) + @as(c_int, 2)).* << @as(c_int, 16)); \\} }); @@ -312,14 +312,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return type_1; \\} , - \\pub const LIGHTGRAY = @import("std").mem.zeroInit(CLITERAL(Color), .{ 200, 200, 200, 255 }); + \\pub const LIGHTGRAY = @import("std").mem.zeroInit(CLITERAL(Color), .{ @as(c_int, 200), @as(c_int, 200), @as(c_int, 200), @as(c_int, 255) }); , \\pub const struct_boom_t = extern struct { \\ i1: c_int, \\}; \\pub const boom_t = struct_boom_t; , - \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{1}); + \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{@as(c_int, 1)}); }); cases.add("complex switch", @@ -343,8 +343,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("correct semicolon after infixop", \\#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0) , &[_][]const u8{ - \\pub fn __ferror_unlocked_body(_fp: anytype) callconv(.Inline) @TypeOf((_fp.*._flags & _IO_ERR_SEEN) != 0) { - \\ return (_fp.*._flags & _IO_ERR_SEEN) != 0; + \\pub fn __ferror_unlocked_body(_fp: anytype) callconv(.Inline) @TypeOf((_fp.*._flags & _IO_ERR_SEEN) != @as(c_int, 0)) { + \\ return (_fp.*._flags & _IO_ERR_SEEN) != @as(c_int, 0); \\} }); @@ -352,11 +352,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define FOO(x) ((x >= 0) + (x >= 0)) \\#define BAR 1 && 2 > 4 , &[_][]const u8{ - \\pub fn FOO(x: anytype) callconv(.Inline) @TypeOf(@boolToInt(x >= 0) + @boolToInt(x >= 0)) { - \\ return @boolToInt(x >= 0) + @boolToInt(x >= 0); + \\pub fn FOO(x: anytype) callconv(.Inline) @TypeOf(@boolToInt(x >= @as(c_int, 0)) + @boolToInt(x >= @as(c_int, 0))) { + \\ return @boolToInt(x >= @as(c_int, 0)) + @boolToInt(x >= @as(c_int, 0)); \\} , - \\pub const BAR = (1 != 0) and (2 > 4); + \\pub const BAR = (@as(c_int, 1) != 0) and (@as(c_int, 2) > @as(c_int, 4)); }); cases.add("struct with aligned fields", @@ -401,15 +401,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ break :blk bar; \\}; , - \\pub fn bar(x: anytype) callconv(.Inline) @TypeOf(baz(1, 2)) { + \\pub fn bar(x: anytype) callconv(.Inline) @TypeOf(baz(@as(c_int, 1), @as(c_int, 2))) { \\ return blk: { \\ _ = &x; - \\ _ = 3; - \\ _ = 4 == 4; - \\ _ = 5 * 6; - \\ _ = baz(1, 2); - \\ _ = 2 % 2; - \\ break :blk baz(1, 2); + \\ _ = @as(c_int, 3); + \\ _ = @as(c_int, 4) == @as(c_int, 4); + \\ _ = @as(c_int, 5) * @as(c_int, 6); + \\ _ = baz(@as(c_int, 1), @as(c_int, 2)); + \\ _ = @as(c_int, 2) % @as(c_int, 2); + \\ break :blk baz(@as(c_int, 1), @as(c_int, 2)); \\ }; \\} }); @@ -418,9 +418,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define foo 1 \\#define inline 2 , &[_][]const u8{ - \\pub const foo = 1; + \\pub const foo = @as(c_int, 1); , - \\pub const @"inline" = 2; + \\pub const @"inline" = @as(c_int, 2); }); cases.add("macro line continuation", @@ -507,7 +507,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("#define hex literal with capital X", \\#define VAL 0XF00D , &[_][]const u8{ - \\pub const VAL = 0xF00D; + \\pub const VAL = @import("std").meta.promoteIntLiteral(c_int, 0xF00D, .hexadecimal); }); cases.add("anonymous struct & unions", @@ -872,7 +872,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("macro with left shift", \\#define REDISMODULE_READ (1<<0) , &[_][]const u8{ - \\pub const REDISMODULE_READ = 1 << 0; + \\pub const REDISMODULE_READ = @as(c_int, 1) << @as(c_int, 0); }); cases.add("macro with right shift", @@ -881,7 +881,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub const FLASH_SIZE = @as(c_ulong, 0x200000); , - \\pub const FLASH_BANK_SIZE = FLASH_SIZE >> 1; + \\pub const FLASH_BANK_SIZE = FLASH_SIZE >> @as(c_int, 1); }); cases.add("double define struct", @@ -949,14 +949,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("#define an unsigned integer literal", \\#define CHANNEL_COUNT 24 , &[_][]const u8{ - \\pub const CHANNEL_COUNT = 24; + \\pub const CHANNEL_COUNT = @as(c_int, 24); }); cases.add("#define referencing another #define", \\#define THING2 THING1 \\#define THING1 1234 , &[_][]const u8{ - \\pub const THING1 = 1234; + \\pub const THING1 = @as(c_int, 1234); , \\pub const THING2 = THING1; }); @@ -1002,7 +1002,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("macro with parens around negative number", \\#define LUA_GLOBALSINDEX (-10002) , &[_][]const u8{ - \\pub const LUA_GLOBALSINDEX = -10002; + \\pub const LUA_GLOBALSINDEX = -@as(c_int, 10002); }); cases.add( @@ -1085,8 +1085,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define foo 1 //foo \\#define bar /* bar */ 2 , &[_][]const u8{ - "pub const foo = 1;", - "pub const bar = 2;", + "pub const foo = @as(c_int, 1);", + "pub const bar = @as(c_int, 2);", }); cases.add("string prefix", @@ -1716,7 +1716,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("comment after integer literal", \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = 0x00000020; + \\pub const SDL_INIT_VIDEO = @as(c_int, 0x00000020); }); cases.add("u integer suffix after hex literal", @@ -1830,8 +1830,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub extern var c: c_int; , - \\pub fn BASIC(c_1: anytype) callconv(.Inline) @TypeOf(c_1 * 2) { - \\ return c_1 * 2; + \\pub fn BASIC(c_1: anytype) callconv(.Inline) @TypeOf(c_1 * @as(c_int, 2)) { + \\ return c_1 * @as(c_int, 2); \\} , \\pub fn FOO(L: anytype, b: anytype) callconv(.Inline) @TypeOf(L + b) { @@ -2475,7 +2475,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return array[@intCast(c_uint, index)]; \\} , - \\pub const ACCESS = array[2]; + \\pub const ACCESS = array[@as(c_int, 2)]; }); cases.add("cast signed array index to unsigned", @@ -3091,7 +3091,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const BAR = @import("std").meta.cast(?*c_void, a); , - \\pub const BAZ = @import("std").meta.cast(u32, 2); + \\pub const BAZ = @import("std").meta.cast(u32, @as(c_int, 2)); }); cases.add("macro with cast to unsigned short, long, and long long", @@ -3099,9 +3099,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define CURLAUTH_BASIC ((unsigned long) 1) \\#define CURLAUTH_BASIC_BUT_ULONGLONG ((unsigned long long) 1) , &[_][]const u8{ - \\pub const CURLAUTH_BASIC_BUT_USHORT = @import("std").meta.cast(c_ushort, 1); - \\pub const CURLAUTH_BASIC = @import("std").meta.cast(c_ulong, 1); - \\pub const CURLAUTH_BASIC_BUT_ULONGLONG = @import("std").meta.cast(c_ulonglong, 1); + \\pub const CURLAUTH_BASIC_BUT_USHORT = @import("std").meta.cast(c_ushort, @as(c_int, 1)); + \\pub const CURLAUTH_BASIC = @import("std").meta.cast(c_ulong, @as(c_int, 1)); + \\pub const CURLAUTH_BASIC_BUT_ULONGLONG = @import("std").meta.cast(c_ulonglong, @as(c_int, 1)); }); cases.add("macro conditional operator", @@ -3196,7 +3196,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ bar_1 = 2; \\} , - \\pub const bar = 4; + \\pub const bar = @as(c_int, 4); }); cases.add("don't export inline functions", @@ -3325,9 +3325,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define NULL ((void*)0) \\#define FOO ((int)0x8000) , &[_][]const u8{ - \\pub const NULL = @import("std").meta.cast(?*c_void, 0); + \\pub const NULL = @import("std").meta.cast(?*c_void, @as(c_int, 0)); , - \\pub const FOO = @import("std").meta.cast(c_int, 0x8000); + \\pub const FOO = @import("std").meta.cast(c_int, @import("std").meta.promoteIntLiteral(c_int, 0x8000, .hexadecimal)); }); if (std.Target.current.abi == .msvc) { From eee43a65aec2e2b104ff64cb23488a86437578e4 Mon Sep 17 00:00:00 2001 From: xackus <14938807+xackus@users.noreply.github.com> Date: Fri, 5 Mar 2021 20:51:19 +0100 Subject: [PATCH 4/5] add tests --- lib/std/meta.zig | 32 +++++++++++++++++++++++++++----- test/translate_c.zig | 20 ++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 46d31a87c3..fd3e03bdbd 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -1096,7 +1096,7 @@ test "sizeof" { pub const CIntLiteralRadix = enum { decimal, octal, hexadecimal }; -fn PromoteIntLiteralReturnType(comptime SuffixType: type, comptime target: comptime_int, comptime radix: CIntLiteralRadix) type { +fn PromoteIntLiteralReturnType(comptime SuffixType: type, comptime number: 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 }; @@ -1111,17 +1111,39 @@ fn PromoteIntLiteralReturnType(comptime SuffixType: type, comptime target: compt 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])) { + if (number >= math.minInt(list[pos]) and number <= math.maxInt(list[pos])) { return list[pos]; } } - @compileError("Integer literal does not fit in compatible types"); + @compileError("Integer literal is too large"); } /// 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 target; +pub fn promoteIntLiteral( + comptime SuffixType: type, + comptime number: comptime_int, + comptime radix: CIntLiteralRadix, +) PromoteIntLiteralReturnType(SuffixType, number, radix) { + return number; +} + +test "promoteIntLiteral" { + const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hexadecimal); + testing.expectEqual(c_uint, @TypeOf(signed_hex)); + + if (math.maxInt(c_longlong) == math.maxInt(c_int)) return; + + const signed_decimal = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .decimal); + const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hexadecimal); + + if (math.maxInt(c_long) > math.maxInt(c_int)) { + testing.expectEqual(c_long, @TypeOf(signed_decimal)); + testing.expectEqual(c_ulong, @TypeOf(unsigned)); + } else { + testing.expectEqual(c_longlong, @TypeOf(signed_decimal)); + testing.expectEqual(c_ulonglong, @TypeOf(unsigned)); + } } /// For a given function type, returns a tuple type which fields will diff --git a/test/translate_c.zig b/test/translate_c.zig index 6134190efb..5785d07311 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -3392,4 +3392,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ unnamed_0: struct_unnamed_2, \\}; }); + + cases.add("integer literal promotion", + \\#define GUARANTEED_TO_FIT_1 1024 + \\#define GUARANTEED_TO_FIT_2 10241024L + \\#define GUARANTEED_TO_FIT_3 20482048LU + \\#define MAY_NEED_PROMOTION_1 10241024 + \\#define MAY_NEED_PROMOTION_2 307230723072L + \\#define MAY_NEED_PROMOTION_3 819281928192LU + \\#define MAY_NEED_PROMOTION_HEX 0x80000000 + \\#define MAY_NEED_PROMOTION_OCT 020000000000 + , &[_][]const u8{ + \\pub const GUARANTEED_TO_FIT_1 = @as(c_int, 1024); + \\pub const GUARANTEED_TO_FIT_2 = @as(c_long, 10241024); + \\pub const GUARANTEED_TO_FIT_3 = @as(c_ulong, 20482048); + \\pub const MAY_NEED_PROMOTION_1 = @import("std").meta.promoteIntLiteral(c_int, 10241024, .decimal); + \\pub const MAY_NEED_PROMOTION_2 = @import("std").meta.promoteIntLiteral(c_long, 307230723072, .decimal); + \\pub const MAY_NEED_PROMOTION_3 = @import("std").meta.promoteIntLiteral(c_ulong, 819281928192, .decimal); + \\pub const MAY_NEED_PROMOTION_HEX = @import("std").meta.promoteIntLiteral(c_int, 0x80000000, .hexadecimal); + \\pub const MAY_NEED_PROMOTION_OCT = @import("std").meta.promoteIntLiteral(c_int, 0o020000000000, .octal); + }); } From eda1b53723447c0fe0bc15bf29abcee2abe90153 Mon Sep 17 00:00:00 2001 From: xackus <14938807+xackus@users.noreply.github.com> Date: Fri, 5 Mar 2021 21:03:25 +0100 Subject: [PATCH 5/5] strip the leading zero from octal literals --- src/translate_c.zig | 2 +- test/translate_c.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/translate_c.zig b/src/translate_c.zig index 34655d3bb5..3656c1e244 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -4436,7 +4436,7 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { switch (lit_bytes[1]) { '0'...'7' => { // 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[1..]}); radix = "octal"; }, 'X' => { diff --git a/test/translate_c.zig b/test/translate_c.zig index 5785d07311..e8054c87ad 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -3410,6 +3410,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const MAY_NEED_PROMOTION_2 = @import("std").meta.promoteIntLiteral(c_long, 307230723072, .decimal); \\pub const MAY_NEED_PROMOTION_3 = @import("std").meta.promoteIntLiteral(c_ulong, 819281928192, .decimal); \\pub const MAY_NEED_PROMOTION_HEX = @import("std").meta.promoteIntLiteral(c_int, 0x80000000, .hexadecimal); - \\pub const MAY_NEED_PROMOTION_OCT = @import("std").meta.promoteIntLiteral(c_int, 0o020000000000, .octal); + \\pub const MAY_NEED_PROMOTION_OCT = @import("std").meta.promoteIntLiteral(c_int, 0o20000000000, .octal); }); }