diff options
| -rw-r--r-- | lib/std/zig/c_translation.zig | 33 | ||||
| -rw-r--r-- | test/c_import/macros.zig | 9 |
2 files changed, 35 insertions, 7 deletions
diff --git a/lib/std/zig/c_translation.zig b/lib/std/zig/c_translation.zig index 92a20ac62d..bc3e893596 100644 --- a/lib/std/zig/c_translation.zig +++ b/lib/std/zig/c_translation.zig @@ -436,15 +436,24 @@ pub const Macros = struct { /// Integer promotion described in C11 6.3.1.1.2 fn PromotedIntType(comptime T: type) type { return switch (T) { - bool, u8, i8, c_short => c_int, + bool, c_short => c_int, c_ushort => if (@sizeOf(c_ushort) == @sizeOf(c_int)) c_uint else c_int, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong => T, - else => if (T == comptime_int) { - @compileError("Cannot promote `" ++ @typeName(T) ++ "`; a fixed-size number type is required"); - } else if (@typeInfo(T) == .int) { - @compileError("Cannot promote `" ++ @typeName(T) ++ "`; a C ABI type is required"); - } else { - @compileError("Attempted to promote invalid type `" ++ @typeName(T) ++ "`"); + else => switch (@typeInfo(T)) { + .comptime_int => @compileError("Cannot promote `" ++ @typeName(T) ++ "`; a fixed-size number type is required"), + // promote to c_int if it can represent all values of T + .int => |int_info| if (int_info.bits < @bitSizeOf(c_int)) + c_int + // otherwise, restore the original C type + else if (int_info.bits == @bitSizeOf(c_int)) + if (int_info.signedness == .unsigned) c_uint else c_int + else if (int_info.bits <= @bitSizeOf(c_long)) + if (int_info.signedness == .unsigned) c_ulong else c_long + else if (int_info.bits <= @bitSizeOf(c_longlong)) + if (int_info.signedness == .unsigned) c_ulonglong else c_longlong + else + @compileError("Cannot promote `" ++ @typeName(T) ++ "`; a C ABI type is required"), + else => @compileError("Attempted to promote invalid type `" ++ @typeName(T) ++ "`"), }, }; } @@ -533,6 +542,16 @@ test "ArithmeticConversion" { try Test.checkPromotion(c_uint, c_long, c_long); try Test.checkPromotion(c_ulong, c_longlong, c_ulonglong); + + // stdint.h + try Test.checkPromotion(u8, i8, c_int); + try Test.checkPromotion(u16, i16, c_int); + try Test.checkPromotion(i32, c_int, c_int); + try Test.checkPromotion(u32, c_int, c_uint); + try Test.checkPromotion(i64, c_int, c_long); + try Test.checkPromotion(u64, c_int, c_ulong); + try Test.checkPromotion(isize, c_int, c_long); + try Test.checkPromotion(usize, c_int, c_ulong); } pub const MacroArithmetic = struct { diff --git a/test/c_import/macros.zig b/test/c_import/macros.zig index 4ef026fecd..55edb57b19 100644 --- a/test/c_import/macros.zig +++ b/test/c_import/macros.zig @@ -167,6 +167,7 @@ test "Macro that uses division operator. Issue #13162" { true, ), ); + try expectEqual( @as(c_int, 21), h.DIVIDE_ARGS( @@ -176,6 +177,14 @@ test "Macro that uses division operator. Issue #13162" { ); try expectEqual( + @as(c_uint, 21), + h.DIVIDE_ARGS( + @as(u32, 42), + @as(u32, 2), + ), + ); + + try expectEqual( @as(c_int, 21), h.DIVIDE_ARGS( @as(c_ushort, 42), |
