diff options
| author | Evan Haas <evan@lagerdata.com> | 2021-07-22 09:17:54 -0700 |
|---|---|---|
| committer | Evan Haas <evan@lagerdata.com> | 2021-07-22 11:50:12 -0700 |
| commit | b33efa373943f8e13dc432f37862da7ee8bf1b6e (patch) | |
| tree | 052b2e4ca7114b69e55730e36865fc3c1c636078 /lib/std | |
| parent | dc4fa83dd767096595ae4e84c3a7dbfd80cbf115 (diff) | |
| download | zig-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.zig | 52 |
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))); +} |
