commit b77679039fd40aa1693781f99ac89f2dc705e5c2 (tree)
parent 0f2339f55b2fa45a8af94c26a7ceb8377e3acfef
Author: Andrew Kelley <andrew@ziglang.org>
Date: Tue, 20 Jun 2023 16:41:58 -0700
Merge pull request #15415 from ehaas/c-char-signedness
Set `c_char` signedness based on the target
Diffstat:
6 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/lib/std/target.zig b/lib/std/target.zig
@@ -1910,6 +1910,32 @@ pub const Target = struct {
}
}
+ /// Default signedness of `char` for the native C compiler for this target
+ /// Note that char signedness is implementation-defined and many compilers provide
+ /// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char
+ pub fn charSignedness(target: Target) std.builtin.Signedness {
+ switch (target.cpu.arch) {
+ .aarch64,
+ .aarch64_32,
+ .aarch64_be,
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ => return if (target.os.tag.isDarwin() or target.os.tag == .windows) .signed else .unsigned,
+ .powerpc, .powerpc64 => return if (target.os.tag.isDarwin()) .signed else .unsigned,
+ .powerpc64le,
+ .s390x,
+ .xcore,
+ .arc,
+ .msp430,
+ .riscv32,
+ .riscv64,
+ => return .unsigned,
+ else => return .signed,
+ }
+ }
+
pub const CType = enum {
char,
short,
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
@@ -1880,7 +1880,7 @@ pub const DeclGen = struct {
if (cty.isBool())
signAbbrev(.unsigned)
else if (cty.isInteger())
- signAbbrev(cty.signedness() orelse .unsigned)
+ signAbbrev(cty.signedness(dg.module.getTarget()))
else if (cty.isFloat())
@as(u8, 'f')
else if (cty.isPointer())
diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig
@@ -537,9 +537,9 @@ pub const CType = extern union {
};
}
- pub fn signedness(self: CType) ?std.builtin.Signedness {
+ pub fn signedness(self: CType, target: std.Target) std.builtin.Signedness {
return switch (self.tag()) {
- .char => null, // unknown signedness
+ .char => target.charSignedness(),
.@"signed char",
.short,
.int,
diff --git a/src/type.zig b/src/type.zig
@@ -2216,7 +2216,8 @@ pub const Type = struct {
/// Returns true if and only if the type is a fixed-width, signed integer.
pub fn isSignedInt(ty: Type, mod: *const Module) bool {
return switch (ty.toIntern()) {
- .c_char_type, .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true,
+ .c_char_type => mod.getTarget().charSignedness() == .signed,
+ .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true,
else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
.int_type => |int_type| int_type.signedness == .signed,
else => false,
@@ -2227,6 +2228,7 @@ pub const Type = struct {
/// Returns true if and only if the type is a fixed-width, unsigned integer.
pub fn isUnsignedInt(ty: Type, mod: *const Module) bool {
return switch (ty.toIntern()) {
+ .c_char_type => mod.getTarget().charSignedness() == .unsigned,
.usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true,
else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
.int_type => |int_type| int_type.signedness == .unsigned,
@@ -2257,7 +2259,7 @@ pub const Type = struct {
},
.usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() },
.isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() },
- .c_char_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.char) },
+ .c_char_type => return .{ .signedness = mod.getTarget().charSignedness(), .bits = target.c_type_bit_size(.char) },
.c_short_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.short) },
.c_ushort_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ushort) },
.c_int_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.int) },
diff --git a/test/behavior.zig b/test/behavior.zig
@@ -145,6 +145,7 @@ test {
_ = @import("behavior/bugs/15778.zig");
_ = @import("behavior/byteswap.zig");
_ = @import("behavior/byval_arg_var.zig");
+ _ = @import("behavior/c_char_signedness.zig");
_ = @import("behavior/call.zig");
_ = @import("behavior/cast.zig");
_ = @import("behavior/cast_int.zig");
diff --git a/test/behavior/c_char_signedness.zig b/test/behavior/c_char_signedness.zig
@@ -0,0 +1,10 @@
+const std = @import("std");
+const expectEqual = std.testing.expectEqual;
+const c = @cImport({
+ @cInclude("limits.h");
+});
+
+test "c_char signedness" {
+ try expectEqual(@as(c_char, c.CHAR_MIN), std.math.minInt(c_char));
+ try expectEqual(@as(c_char, c.CHAR_MAX), std.math.maxInt(c_char));
+}