authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-11 14:32:37-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-03-11 14:32:37-05:00
log4fc6f631e044b5ddfff6c610f04f3619a1bbeb8d
treec692820cc0b740efec91ff7e8f023f44873a4d0a
parentbdb917006c9920f2a0d2091cb0f3d52454e039f0
parenteda1b53723447c0fe0bc15bf29abcee2abe90153
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #8126 from xackus/translate_c_int_literal_promotion

translate-c: promote int literals to bigger types

4 files changed, 178 insertions(+), 49 deletions(-)

lib/std/meta.zig+52
......@@ -1094,6 +1094,58 @@ test "sizeof" {
10941094 testing.expect(sizeof(c_void) == 1);
10951095}
10961096
1097pub const CIntLiteralRadix = enum { decimal, octal, hexadecimal };
1098
1099fn PromoteIntLiteralReturnType(comptime SuffixType: type, comptime number: comptime_int, comptime radix: CIntLiteralRadix) type {
1100 const signed_decimal = [_]type{ c_int, c_long, c_longlong };
1101 const signed_oct_hex = [_]type{ c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong };
1102 const unsigned = [_]type{ c_uint, c_ulong, c_ulonglong };
1103
1104 const list: []const type = if (@typeInfo(SuffixType).Int.signedness == .unsigned)
1105 &unsigned
1106 else if (radix == .decimal)
1107 &signed_decimal
1108 else
1109 &signed_oct_hex;
1110
1111 var pos = mem.indexOfScalar(type, list, SuffixType).?;
1112
1113 while (pos < list.len) : (pos += 1) {
1114 if (number >= math.minInt(list[pos]) and number <= math.maxInt(list[pos])) {
1115 return list[pos];
1116 }
1117 }
1118 @compileError("Integer literal is too large");
1119}
1120
1121/// Promote the type of an integer literal until it fits as C would.
1122/// This is for translate-c and is not intended for general use.
1123pub fn promoteIntLiteral(
1124 comptime SuffixType: type,
1125 comptime number: comptime_int,
1126 comptime radix: CIntLiteralRadix,
1127) PromoteIntLiteralReturnType(SuffixType, number, radix) {
1128 return number;
1129}
1130
1131test "promoteIntLiteral" {
1132 const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hexadecimal);
1133 testing.expectEqual(c_uint, @TypeOf(signed_hex));
1134
1135 if (math.maxInt(c_longlong) == math.maxInt(c_int)) return;
1136
1137 const signed_decimal = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .decimal);
1138 const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hexadecimal);
1139
1140 if (math.maxInt(c_long) > math.maxInt(c_int)) {
1141 testing.expectEqual(c_long, @TypeOf(signed_decimal));
1142 testing.expectEqual(c_ulong, @TypeOf(unsigned));
1143 } else {
1144 testing.expectEqual(c_longlong, @TypeOf(signed_decimal));
1145 testing.expectEqual(c_ulonglong, @TypeOf(unsigned));
1146 }
1147}
1148
10971149/// For a given function type, returns a tuple type which fields will
10981150/// correspond to the argument types.
10991151///
src/translate_c.zig+38-10
......@@ -4435,40 +4435,68 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
44354435
44364436 switch (m.list[m.i].id) {
44374437 .IntegerLiteral => |suffix| {
4438 var radix: []const u8 = "decimal";
44384439 if (lit_bytes.len > 2 and lit_bytes[0] == '0') {
44394440 switch (lit_bytes[1]) {
44404441 '0'...'7' => {
44414442 // Octal
4442 lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes});
4443 lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes[1..]});
4444 radix = "octal";
44434445 },
44444446 'X' => {
44454447 // Hexadecimal with capital X, valid in C but not in Zig
44464448 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]});
4449 radix = "hexadecimal";
4450 },
4451 'x' => {
4452 radix = "hexadecimal";
44474453 },
44484454 else => {},
44494455 }
44504456 }
44514457
4452 if (suffix == .none) {
4453 return transCreateNodeNumber(c, lit_bytes, .int);
4454 }
4455
44564458 const type_node = try Tag.type.create(c.arena, switch (suffix) {
4459 .none => "c_int",
44574460 .u => "c_uint",
44584461 .l => "c_long",
44594462 .lu => "c_ulong",
44604463 .ll => "c_longlong",
44614464 .llu => "c_ulonglong",
4462 else => unreachable,
4465 .f => unreachable,
44634466 });
44644467 lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (suffix) {
4465 .u, .l => @as(u8, 1),
4468 .none => @as(u8, 0),
4469 .u, .l => 1,
44664470 .lu, .ll => 2,
44674471 .llu => 3,
4468 else => unreachable,
4472 .f => unreachable,
44694473 }];
4470 const rhs = try transCreateNodeNumber(c, lit_bytes, .int);
4471 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
4474
4475 const value = std.fmt.parseInt(i128, lit_bytes, 0) catch math.maxInt(i128);
4476
4477 // make the output less noisy by skipping promoteIntLiteral where
4478 // it's guaranteed to not be required because of C standard type constraints
4479 const guaranteed_to_fit = switch (suffix) {
4480 .none => if (math.cast(i16, value)) |_| true else |_| false,
4481 .u => if (math.cast(u16, value)) |_| true else |_| false,
4482 .l => if (math.cast(i32, value)) |_| true else |_| false,
4483 .lu => if (math.cast(u32, value)) |_| true else |_| false,
4484 .ll => if (math.cast(i64, value)) |_| true else |_| false,
4485 .llu => if (math.cast(u64, value)) |_| true else |_| false,
4486 .f => unreachable,
4487 };
4488
4489 const literal_node = try transCreateNodeNumber(c, lit_bytes, .int);
4490
4491 if (guaranteed_to_fit) {
4492 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = literal_node });
4493 } else {
4494 return Tag.std_meta_promoteIntLiteral.create(c.arena, .{
4495 .type = type_node,
4496 .value = literal_node,
4497 .radix = try Tag.enum_literal.create(c.arena, radix),
4498 });
4499 }
44724500 },
44734501 .FloatLiteral => |suffix| {
44744502 if (lit_bytes[0] == '.')
src/translate_c/ast.zig+29
......@@ -39,6 +39,7 @@ pub const Node = extern union {
3939 float_literal,
4040 string_literal,
4141 char_literal,
42 enum_literal,
4243 identifier,
4344 @"if",
4445 /// if (!operand) break;
......@@ -117,6 +118,7 @@ pub const Node = extern union {
117118 /// @intCast(lhs, rhs)
118119 int_cast,
119120 /// @rem(lhs, rhs)
121 std_meta_promoteIntLiteral,
120122 rem,
121123 /// @divTrunc(lhs, rhs)
122124 div_trunc,
......@@ -312,6 +314,7 @@ pub const Node = extern union {
312314 .float_literal,
313315 .string_literal,
314316 .char_literal,
317 .enum_literal,
315318 .identifier,
316319 .warning,
317320 .type,
......@@ -328,6 +331,7 @@ pub const Node = extern union {
328331 .tuple => Payload.TupleInit,
329332 .container_init => Payload.ContainerInit,
330333 .std_meta_cast => Payload.Infix,
334 .std_meta_promoteIntLiteral => Payload.PromoteIntLiteral,
331335 .block => Payload.Block,
332336 .c_pointer, .single_pointer => Payload.Pointer,
333337 .array_type => Payload.Array,
......@@ -651,6 +655,15 @@ pub const Payload = struct {
651655 field_name: []const u8,
652656 },
653657 };
658
659 pub const PromoteIntLiteral = struct {
660 base: Payload,
661 data: struct {
662 value: Node,
663 type: Node,
664 radix: Node,
665 },
666 };
654667};
655668
656669/// Converts the nodes into a Zig ast.
......@@ -821,6 +834,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
821834 const import_node = try renderStdImport(c, "meta", "cast");
822835 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
823836 },
837 .std_meta_promoteIntLiteral => {
838 const payload = node.castTag(.std_meta_promoteIntLiteral).?.data;
839 const import_node = try renderStdImport(c, "meta", "promoteIntLiteral");
840 return renderCall(c, import_node, &.{ payload.type, payload.value, payload.radix });
841 },
824842 .std_meta_sizeof => {
825843 const payload = node.castTag(.std_meta_sizeof).?.data;
826844 const import_node = try renderStdImport(c, "meta", "sizeof");
......@@ -988,6 +1006,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
9881006 .data = undefined,
9891007 });
9901008 },
1009 .enum_literal => {
1010 const payload = node.castTag(.enum_literal).?.data;
1011 _ = try c.addToken(.period, ".");
1012 return c.addNode(.{
1013 .tag = .enum_literal,
1014 .main_token = try c.addToken(.identifier, payload),
1015 .data = undefined,
1016 });
1017 },
9911018 .fail_decl => {
9921019 const payload = node.castTag(.fail_decl).?.data;
9931020 // pub const name = @compileError(msg);
......@@ -1982,11 +2009,13 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
19822009 .typeof,
19832010 .std_meta_sizeof,
19842011 .std_meta_cast,
2012 .std_meta_promoteIntLiteral,
19852013 .std_mem_zeroinit,
19862014 .integer_literal,
19872015 .float_literal,
19882016 .string_literal,
19892017 .char_literal,
2018 .enum_literal,
19902019 .identifier,
19912020 .field_access,
19922021 .ptr_cast,
test/translate_c.zig+59-39
......@@ -232,12 +232,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
232232 \\ | (*((unsigned char *)(p) + 1) << 8) \
233233 \\ | (*((unsigned char *)(p) + 2) << 16))
234234 , &[_][]const u8{
235 \\pub const FOO = (foo + 2).*;
235 \\pub const FOO = (foo + @as(c_int, 2)).*;
236236 ,
237 \\pub const VALUE = ((((1 + (2 * 3)) + (4 * 5)) + 6) << 7) | @boolToInt(8 == 9);
237 \\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));
238238 ,
239 \\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)) {
240 \\ 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);
239 \\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))) {
240 \\ 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));
241241 \\}
242242 });
243243
......@@ -312,14 +312,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
312312 \\ return type_1;
313313 \\}
314314 ,
315 \\pub const LIGHTGRAY = @import("std").mem.zeroInit(CLITERAL(Color), .{ 200, 200, 200, 255 });
315 \\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) });
316316 ,
317317 \\pub const struct_boom_t = extern struct {
318318 \\ i1: c_int,
319319 \\};
320320 \\pub const boom_t = struct_boom_t;
321321 ,
322 \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{1});
322 \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{@as(c_int, 1)});
323323 });
324324
325325 cases.add("complex switch",
......@@ -343,8 +343,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
343343 cases.add("correct semicolon after infixop",
344344 \\#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0)
345345 , &[_][]const u8{
346 \\pub fn __ferror_unlocked_body(_fp: anytype) callconv(.Inline) @TypeOf((_fp.*._flags & _IO_ERR_SEEN) != 0) {
347 \\ return (_fp.*._flags & _IO_ERR_SEEN) != 0;
346 \\pub fn __ferror_unlocked_body(_fp: anytype) callconv(.Inline) @TypeOf((_fp.*._flags & _IO_ERR_SEEN) != @as(c_int, 0)) {
347 \\ return (_fp.*._flags & _IO_ERR_SEEN) != @as(c_int, 0);
348348 \\}
349349 });
350350
......@@ -352,11 +352,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
352352 \\#define FOO(x) ((x >= 0) + (x >= 0))
353353 \\#define BAR 1 && 2 > 4
354354 , &[_][]const u8{
355 \\pub fn FOO(x: anytype) callconv(.Inline) @TypeOf(@boolToInt(x >= 0) + @boolToInt(x >= 0)) {
356 \\ return @boolToInt(x >= 0) + @boolToInt(x >= 0);
355 \\pub fn FOO(x: anytype) callconv(.Inline) @TypeOf(@boolToInt(x >= @as(c_int, 0)) + @boolToInt(x >= @as(c_int, 0))) {
356 \\ return @boolToInt(x >= @as(c_int, 0)) + @boolToInt(x >= @as(c_int, 0));
357357 \\}
358358 ,
359 \\pub const BAR = (1 != 0) and (2 > 4);
359 \\pub const BAR = (@as(c_int, 1) != 0) and (@as(c_int, 2) > @as(c_int, 4));
360360 });
361361
362362 cases.add("struct with aligned fields",
......@@ -401,15 +401,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
401401 \\ break :blk bar;
402402 \\};
403403 ,
404 \\pub fn bar(x: anytype) callconv(.Inline) @TypeOf(baz(1, 2)) {
404 \\pub fn bar(x: anytype) callconv(.Inline) @TypeOf(baz(@as(c_int, 1), @as(c_int, 2))) {
405405 \\ return blk: {
406406 \\ _ = &x;
407 \\ _ = 3;
408 \\ _ = 4 == 4;
409 \\ _ = 5 * 6;
410 \\ _ = baz(1, 2);
411 \\ _ = 2 % 2;
412 \\ break :blk baz(1, 2);
407 \\ _ = @as(c_int, 3);
408 \\ _ = @as(c_int, 4) == @as(c_int, 4);
409 \\ _ = @as(c_int, 5) * @as(c_int, 6);
410 \\ _ = baz(@as(c_int, 1), @as(c_int, 2));
411 \\ _ = @as(c_int, 2) % @as(c_int, 2);
412 \\ break :blk baz(@as(c_int, 1), @as(c_int, 2));
413413 \\ };
414414 \\}
415415 });
......@@ -418,9 +418,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
418418 \\#define foo 1
419419 \\#define inline 2
420420 , &[_][]const u8{
421 \\pub const foo = 1;
421 \\pub const foo = @as(c_int, 1);
422422 ,
423 \\pub const @"inline" = 2;
423 \\pub const @"inline" = @as(c_int, 2);
424424 });
425425
426426 cases.add("macro line continuation",
......@@ -507,7 +507,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
507507 cases.add("#define hex literal with capital X",
508508 \\#define VAL 0XF00D
509509 , &[_][]const u8{
510 \\pub const VAL = 0xF00D;
510 \\pub const VAL = @import("std").meta.promoteIntLiteral(c_int, 0xF00D, .hexadecimal);
511511 });
512512
513513 cases.add("anonymous struct & unions",
......@@ -878,7 +878,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
878878 cases.add("macro with left shift",
879879 \\#define REDISMODULE_READ (1<<0)
880880 , &[_][]const u8{
881 \\pub const REDISMODULE_READ = 1 << 0;
881 \\pub const REDISMODULE_READ = @as(c_int, 1) << @as(c_int, 0);
882882 });
883883
884884 cases.add("macro with right shift",
......@@ -887,7 +887,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
887887 , &[_][]const u8{
888888 \\pub const FLASH_SIZE = @as(c_ulong, 0x200000);
889889 ,
890 \\pub const FLASH_BANK_SIZE = FLASH_SIZE >> 1;
890 \\pub const FLASH_BANK_SIZE = FLASH_SIZE >> @as(c_int, 1);
891891 });
892892
893893 cases.add("double define struct",
......@@ -955,14 +955,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
955955 cases.add("#define an unsigned integer literal",
956956 \\#define CHANNEL_COUNT 24
957957 , &[_][]const u8{
958 \\pub const CHANNEL_COUNT = 24;
958 \\pub const CHANNEL_COUNT = @as(c_int, 24);
959959 });
960960
961961 cases.add("#define referencing another #define",
962962 \\#define THING2 THING1
963963 \\#define THING1 1234
964964 , &[_][]const u8{
965 \\pub const THING1 = 1234;
965 \\pub const THING1 = @as(c_int, 1234);
966966 ,
967967 \\pub const THING2 = THING1;
968968 });
......@@ -1008,7 +1008,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10081008 cases.add("macro with parens around negative number",
10091009 \\#define LUA_GLOBALSINDEX (-10002)
10101010 , &[_][]const u8{
1011 \\pub const LUA_GLOBALSINDEX = -10002;
1011 \\pub const LUA_GLOBALSINDEX = -@as(c_int, 10002);
10121012 });
10131013
10141014 cases.add(
......@@ -1091,8 +1091,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10911091 \\#define foo 1 //foo
10921092 \\#define bar /* bar */ 2
10931093 , &[_][]const u8{
1094 "pub const foo = 1;",
1095 "pub const bar = 2;",
1094 "pub const foo = @as(c_int, 1);",
1095 "pub const bar = @as(c_int, 2);",
10961096 });
10971097
10981098 cases.add("string prefix",
......@@ -1722,7 +1722,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17221722 cases.add("comment after integer literal",
17231723 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
17241724 , &[_][]const u8{
1725 \\pub const SDL_INIT_VIDEO = 0x00000020;
1725 \\pub const SDL_INIT_VIDEO = @as(c_int, 0x00000020);
17261726 });
17271727
17281728 cases.add("u integer suffix after hex literal",
......@@ -1836,8 +1836,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18361836 , &[_][]const u8{
18371837 \\pub extern var c: c_int;
18381838 ,
1839 \\pub fn BASIC(c_1: anytype) callconv(.Inline) @TypeOf(c_1 * 2) {
1840 \\ return c_1 * 2;
1839 \\pub fn BASIC(c_1: anytype) callconv(.Inline) @TypeOf(c_1 * @as(c_int, 2)) {
1840 \\ return c_1 * @as(c_int, 2);
18411841 \\}
18421842 ,
18431843 \\pub fn FOO(L: anytype, b: anytype) callconv(.Inline) @TypeOf(L + b) {
......@@ -2481,7 +2481,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
24812481 \\ return array[@intCast(c_uint, index)];
24822482 \\}
24832483 ,
2484 \\pub const ACCESS = array[2];
2484 \\pub const ACCESS = array[@as(c_int, 2)];
24852485 });
24862486
24872487 cases.add("cast signed array index to unsigned",
......@@ -3097,7 +3097,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
30973097 ,
30983098 \\pub const BAR = @import("std").meta.cast(?*c_void, a);
30993099 ,
3100 \\pub const BAZ = @import("std").meta.cast(u32, 2);
3100 \\pub const BAZ = @import("std").meta.cast(u32, @as(c_int, 2));
31013101 });
31023102
31033103 cases.add("macro with cast to unsigned short, long, and long long",
......@@ -3105,9 +3105,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
31053105 \\#define CURLAUTH_BASIC ((unsigned long) 1)
31063106 \\#define CURLAUTH_BASIC_BUT_ULONGLONG ((unsigned long long) 1)
31073107 , &[_][]const u8{
3108 \\pub const CURLAUTH_BASIC_BUT_USHORT = @import("std").meta.cast(c_ushort, 1);
3109 \\pub const CURLAUTH_BASIC = @import("std").meta.cast(c_ulong, 1);
3110 \\pub const CURLAUTH_BASIC_BUT_ULONGLONG = @import("std").meta.cast(c_ulonglong, 1);
3108 \\pub const CURLAUTH_BASIC_BUT_USHORT = @import("std").meta.cast(c_ushort, @as(c_int, 1));
3109 \\pub const CURLAUTH_BASIC = @import("std").meta.cast(c_ulong, @as(c_int, 1));
3110 \\pub const CURLAUTH_BASIC_BUT_ULONGLONG = @import("std").meta.cast(c_ulonglong, @as(c_int, 1));
31113111 });
31123112
31133113 cases.add("macro conditional operator",
......@@ -3202,7 +3202,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
32023202 \\ bar_1 = 2;
32033203 \\}
32043204 ,
3205 \\pub const bar = 4;
3205 \\pub const bar = @as(c_int, 4);
32063206 });
32073207
32083208 cases.add("don't export inline functions",
......@@ -3331,9 +3331,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
33313331 \\#define NULL ((void*)0)
33323332 \\#define FOO ((int)0x8000)
33333333 , &[_][]const u8{
3334 \\pub const NULL = @import("std").meta.cast(?*c_void, 0);
3334 \\pub const NULL = @import("std").meta.cast(?*c_void, @as(c_int, 0));
33353335 ,
3336 \\pub const FOO = @import("std").meta.cast(c_int, 0x8000);
3336 \\pub const FOO = @import("std").meta.cast(c_int, @import("std").meta.promoteIntLiteral(c_int, 0x8000, .hexadecimal));
33373337 });
33383338
33393339 if (std.Target.current.abi == .msvc) {
......@@ -3398,4 +3398,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
33983398 \\ unnamed_0: struct_unnamed_2,
33993399 \\};
34003400 });
3401
3402 cases.add("integer literal promotion",
3403 \\#define GUARANTEED_TO_FIT_1 1024
3404 \\#define GUARANTEED_TO_FIT_2 10241024L
3405 \\#define GUARANTEED_TO_FIT_3 20482048LU
3406 \\#define MAY_NEED_PROMOTION_1 10241024
3407 \\#define MAY_NEED_PROMOTION_2 307230723072L
3408 \\#define MAY_NEED_PROMOTION_3 819281928192LU
3409 \\#define MAY_NEED_PROMOTION_HEX 0x80000000
3410 \\#define MAY_NEED_PROMOTION_OCT 020000000000
3411 , &[_][]const u8{
3412 \\pub const GUARANTEED_TO_FIT_1 = @as(c_int, 1024);
3413 \\pub const GUARANTEED_TO_FIT_2 = @as(c_long, 10241024);
3414 \\pub const GUARANTEED_TO_FIT_3 = @as(c_ulong, 20482048);
3415 \\pub const MAY_NEED_PROMOTION_1 = @import("std").meta.promoteIntLiteral(c_int, 10241024, .decimal);
3416 \\pub const MAY_NEED_PROMOTION_2 = @import("std").meta.promoteIntLiteral(c_long, 307230723072, .decimal);
3417 \\pub const MAY_NEED_PROMOTION_3 = @import("std").meta.promoteIntLiteral(c_ulong, 819281928192, .decimal);
3418 \\pub const MAY_NEED_PROMOTION_HEX = @import("std").meta.promoteIntLiteral(c_int, 0x80000000, .hexadecimal);
3419 \\pub const MAY_NEED_PROMOTION_OCT = @import("std").meta.promoteIntLiteral(c_int, 0o20000000000, .octal);
3420 });
34013421}