Skip to content

Commit 96a84f1

Browse files
committed
fix int promotion for >8-bit stdint.h types
1 parent f6feb29 commit 96a84f1

File tree

3 files changed

+35
-7
lines changed

3 files changed

+35
-7
lines changed

src/helpers.zig

+10
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,16 @@ test "ArithmeticConversion" {
203203
try Test.checkPromotion(c_uint, c_long, c_long);
204204

205205
try Test.checkPromotion(c_ulong, c_longlong, c_ulonglong);
206+
207+
// stdint.h
208+
try Test.checkPromotion(u8, i8, c_int);
209+
try Test.checkPromotion(u16, i16, c_int);
210+
try Test.checkPromotion(i32, c_int, c_int);
211+
try Test.checkPromotion(u32, c_int, c_uint);
212+
try Test.checkPromotion(i64, c_int, c_long);
213+
try Test.checkPromotion(u64, c_int, c_ulong);
214+
try Test.checkPromotion(isize, c_int, c_long);
215+
try Test.checkPromotion(usize, c_int, c_ulong);
206216
}
207217

208218
const F_SUFFIX = @import("helpers/F_SUFFIX.zig").F_SUFFIX;

src/helpers/arithmetic_conversion.zig

+16-7
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,24 @@ pub fn ArithmeticConversion(comptime A: type, comptime B: type) type {
3535
/// Integer promotion described in C11 6.3.1.1.2
3636
fn PromotedIntType(comptime T: type) type {
3737
return switch (T) {
38-
bool, u8, i8, c_short => c_int,
38+
bool, c_short => c_int,
3939
c_ushort => if (@sizeOf(c_ushort) == @sizeOf(c_int)) c_uint else c_int,
4040
c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong => T,
41-
else => if (T == comptime_int) {
42-
@compileError("Cannot promote `" ++ @typeName(T) ++ "`; a fixed-size number type is required");
43-
} else if (@typeInfo(T) == .int) {
44-
@compileError("Cannot promote `" ++ @typeName(T) ++ "`; a C ABI type is required");
45-
} else {
46-
@compileError("Attempted to promote invalid type `" ++ @typeName(T) ++ "`");
41+
else => switch (@typeInfo(T)) {
42+
.comptime_int => @compileError("Cannot promote `" ++ @typeName(T) ++ "`; a fixed-size number type is required"),
43+
// promote to c_int if it can represent all values of T
44+
.int => |int_info| if (int_info.bits < @bitSizeOf(c_int))
45+
c_int
46+
// otherwise, restore the original C type
47+
else if (int_info.bits == @bitSizeOf(c_int))
48+
if (int_info.signedness == .unsigned) c_uint else c_int
49+
else if (int_info.bits <= @bitSizeOf(c_long))
50+
if (int_info.signedness == .unsigned) c_ulong else c_long
51+
else if (int_info.bits <= @bitSizeOf(c_longlong))
52+
if (int_info.signedness == .unsigned) c_ulonglong else c_longlong
53+
else
54+
@compileError("Cannot promote `" ++ @typeName(T) ++ "`; a C ABI type is required"),
55+
else => @compileError("Attempted to promote invalid type `" ++ @typeName(T) ++ "`"),
4756
},
4857
};
4958
}

test/macros.zig

+9
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ test "Macro that uses division operator" {
130130
true,
131131
),
132132
);
133+
133134
try expectEqual(
134135
@as(c_int, 21),
135136
macros.DIVIDE_ARGS(
@@ -138,6 +139,14 @@ test "Macro that uses division operator" {
138139
),
139140
);
140141

142+
try expectEqual(
143+
@as(c_uint, 21),
144+
macros.DIVIDE_ARGS(
145+
@as(u32, 42),
146+
@as(u32, 2),
147+
),
148+
);
149+
141150
try expectEqual(
142151
@as(c_int, 21),
143152
macros.DIVIDE_ARGS(

0 commit comments

Comments
 (0)