From b33efa373943f8e13dc432f37862da7ee8bf1b6e Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Thu, 22 Jul 2021 09:17:54 -0700 Subject: [PATCH] translate-c: Handle ambiguous cast or call macro Fixes #9425 --- lib/std/zig/c_translation.zig | 52 +++++++++++++++++++++++++++++++++++ src/translate_c.zig | 3 ++ 2 files changed, 55 insertions(+) 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))); +} diff --git a/src/translate_c.zig b/src/translate_c.zig index 2ac720a209..395a314f7c 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -4868,6 +4868,8 @@ const PatternList = struct { [2][]const u8{ "Ull_SUFFIX(X) (X ## Ull)", "ULL_SUFFIX" }, [2][]const u8{ "ULL_SUFFIX(X) (X ## ULL)", "ULL_SUFFIX" }, + [2][]const u8{ "CAST_OR_CALL(X, Y) (X)(Y)", "CAST_OR_CALL" }, + [2][]const u8{ \\wl_container_of(ptr, sample, member) \ \\(__typeof__(sample))((char *)(ptr) - \ @@ -5048,6 +5050,7 @@ test "Macro matching" { , "WL_CONTAINER_OF"); try helper.checkMacro(allocator, pattern_list, "NO_MATCH(X, Y) (X + Y)", null); + try helper.checkMacro(allocator, pattern_list, "CAST_OR_CALL(X, Y) (X)(Y)", "CAST_OR_CALL"); } const MacroCtx = struct {