aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorEvan Haas <evan@lagerdata.com>2021-07-22 09:17:54 -0700
committerEvan Haas <evan@lagerdata.com>2021-07-22 11:50:12 -0700
commitb33efa373943f8e13dc432f37862da7ee8bf1b6e (patch)
tree052b2e4ca7114b69e55730e36865fc3c1c636078 /lib/std
parentdc4fa83dd767096595ae4e84c3a7dbfd80cbf115 (diff)
downloadzig-b33efa373943f8e13dc432f37862da7ee8bf1b6e.tar.gz
zig-b33efa373943f8e13dc432f37862da7ee8bf1b6e.zip
translate-c: Handle ambiguous cast or call macro
Fixes #9425
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/zig/c_translation.zig52
1 files changed, 52 insertions, 0 deletions
diff --git a/lib/std/zig/c_translation.zig b/lib/std/zig/c_translation.zig
index 071ce01396..bcf3b310ea 100644
--- a/lib/std/zig/c_translation.zig
+++ b/lib/std/zig/c_translation.zig
@@ -390,6 +390,20 @@ pub const Macros = struct {
pub fn WL_CONTAINER_OF(ptr: anytype, sample: anytype, comptime member: []const u8) @TypeOf(sample) {
return @fieldParentPtr(@TypeOf(sample.*), member, ptr);
}
+
+ /// A 2-argument function-like macro defined as #define FOO(A, B) (A)(B)
+ /// could be either: cast B to A, or call A with the value B.
+ pub fn CAST_OR_CALL(a: anytype, b: anytype) switch (@typeInfo(@TypeOf(a))) {
+ .Type => a,
+ .Fn => |fn_info| fn_info.return_type orelse void,
+ else => |info| @compileError("Unexpected argument type: " ++ @tagName(info)),
+ } {
+ switch (@typeInfo(@TypeOf(a))) {
+ .Type => return cast(a, b),
+ .Fn => return a(b),
+ else => unreachable, // return type will be a compile error otherwise
+ }
+ }
};
test "Macro suffix functions" {
@@ -430,3 +444,41 @@ test "WL_CONTAINER_OF" {
var ptr = Macros.WL_CONTAINER_OF(&x.b, &y, "b");
try testing.expectEqual(&x, ptr);
}
+
+test "CAST_OR_CALL casting" {
+ var arg = @as(c_int, 1000);
+ var casted = Macros.CAST_OR_CALL(u8, arg);
+ try testing.expectEqual(cast(u8, arg), casted);
+
+ const S = struct {
+ x: u32 = 0,
+ };
+ var s = S{};
+ var casted_ptr = Macros.CAST_OR_CALL(*u8, &s);
+ try testing.expectEqual(cast(*u8, &s), casted_ptr);
+}
+
+test "CAST_OR_CALL calling" {
+ const Helper = struct {
+ var last_val: bool = false;
+ fn returnsVoid(val: bool) void {
+ last_val = val;
+ }
+ fn returnsBool(f: f32) bool {
+ return f > 0;
+ }
+ fn identity(self: c_uint) c_uint {
+ return self;
+ }
+ };
+
+ Macros.CAST_OR_CALL(Helper.returnsVoid, true);
+ try testing.expectEqual(true, Helper.last_val);
+ Macros.CAST_OR_CALL(Helper.returnsVoid, false);
+ try testing.expectEqual(false, Helper.last_val);
+
+ try testing.expectEqual(Helper.returnsBool(1), Macros.CAST_OR_CALL(Helper.returnsBool, @as(f32, 1)));
+ try testing.expectEqual(Helper.returnsBool(-1), Macros.CAST_OR_CALL(Helper.returnsBool, @as(f32, -1)));
+
+ try testing.expectEqual(Helper.identity(@as(c_uint, 100)), Macros.CAST_OR_CALL(Helper.identity, @as(c_uint, 100)));
+}