From 657fe557115d9fde5de5b8c6b65a4db4e3a2e567 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Sat, 22 Apr 2023 10:26:27 -0700 Subject: [PATCH 1/3] std.Target: Add a function for determining char signedess Copied from arocc https://github.com/Vexu/arocc/blob/c1955a474270562a4640217e62c888b52c79d39e/src/target.zig#L7 --- lib/std/target.zig | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/std/target.zig b/lib/std/target.zig index 912eb141ea..5d5e71c20b 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1910,6 +1910,30 @@ 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, + => return .unsigned, + else => return .signed, + } + } + pub const CType = enum { char, short, From fb9d6b8bd96b1d0403f04fd31b1ebc0881105f48 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 20 Jun 2023 00:20:32 -0700 Subject: [PATCH 2/3] codegen: Set c_char signedness based on the target --- src/codegen/c.zig | 2 +- src/codegen/c/type.zig | 4 ++-- src/type.zig | 6 ++++-- test/behavior.zig | 1 + test/behavior/c_char_signedness.zig | 10 ++++++++++ 5 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 test/behavior/c_char_signedness.zig diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 498eca4ce2..566510d152 100644 --- 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 index 86324c9a7c..63be71df92 100644 --- 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 index ac5305b3f4..bce97b65cb 100644 --- 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 index 6e9435c49e..06637faf69 100644 --- 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 new file mode 100644 index 0000000000..2484f9c5dc --- /dev/null +++ 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)); +} From c205521aea01e332209a28e7518a787d1c1e8f26 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 20 Jun 2023 08:27:55 -0700 Subject: [PATCH 3/3] std.Target: c_char is unsigned on RISC-V --- lib/std/target.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/std/target.zig b/lib/std/target.zig index 5d5e71c20b..ec61292360 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1929,6 +1929,8 @@ pub const Target = struct { .xcore, .arc, .msp430, + .riscv32, + .riscv64, => return .unsigned, else => return .signed, }