authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-07-22 09:17:54-07:00
committergravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-07-22 11:50:12-07:00
logb33efa373943f8e13dc432f37862da7ee8bf1b6e
tree052b2e4ca7114b69e55730e36865fc3c1c636078
parentdc4fa83dd767096595ae4e84c3a7dbfd80cbf115
signaturelock-open Commit is signed but in an unrecognized format.

translate-c: Handle ambiguous cast or call macro

Fixes #9425

2 files changed, 55 insertions(+), 0 deletions(-)

lib/std/zig/c_translation.zig+52
...@@ -390,6 +390,20 @@ pub const Macros = struct {...@@ -390,6 +390,20 @@ pub const Macros = struct {
390 pub fn WL_CONTAINER_OF(ptr: anytype, sample: anytype, comptime member: []const u8) @TypeOf(sample) {390 pub fn WL_CONTAINER_OF(ptr: anytype, sample: anytype, comptime member: []const u8) @TypeOf(sample) {
391 return @fieldParentPtr(@TypeOf(sample.*), member, ptr);391 return @fieldParentPtr(@TypeOf(sample.*), member, ptr);
392 }392 }
393
394 /// A 2-argument function-like macro defined as #define FOO(A, B) (A)(B)
395 /// could be either: cast B to A, or call A with the value B.
396 pub fn CAST_OR_CALL(a: anytype, b: anytype) switch (@typeInfo(@TypeOf(a))) {
397 .Type => a,
398 .Fn => |fn_info| fn_info.return_type orelse void,
399 else => |info| @compileError("Unexpected argument type: " ++ @tagName(info)),
400 } {
401 switch (@typeInfo(@TypeOf(a))) {
402 .Type => return cast(a, b),
403 .Fn => return a(b),
404 else => unreachable, // return type will be a compile error otherwise
405 }
406 }
393};407};
394408
395test "Macro suffix functions" {409test "Macro suffix functions" {
...@@ -430,3 +444,41 @@ test "WL_CONTAINER_OF" {...@@ -430,3 +444,41 @@ test "WL_CONTAINER_OF" {
430 var ptr = Macros.WL_CONTAINER_OF(&x.b, &y, "b");444 var ptr = Macros.WL_CONTAINER_OF(&x.b, &y, "b");
431 try testing.expectEqual(&x, ptr);445 try testing.expectEqual(&x, ptr);
432}446}
447
448test "CAST_OR_CALL casting" {
449 var arg = @as(c_int, 1000);
450 var casted = Macros.CAST_OR_CALL(u8, arg);
451 try testing.expectEqual(cast(u8, arg), casted);
452
453 const S = struct {
454 x: u32 = 0,
455 };
456 var s = S{};
457 var casted_ptr = Macros.CAST_OR_CALL(*u8, &s);
458 try testing.expectEqual(cast(*u8, &s), casted_ptr);
459}
460
461test "CAST_OR_CALL calling" {
462 const Helper = struct {
463 var last_val: bool = false;
464 fn returnsVoid(val: bool) void {
465 last_val = val;
466 }
467 fn returnsBool(f: f32) bool {
468 return f > 0;
469 }
470 fn identity(self: c_uint) c_uint {
471 return self;
472 }
473 };
474
475 Macros.CAST_OR_CALL(Helper.returnsVoid, true);
476 try testing.expectEqual(true, Helper.last_val);
477 Macros.CAST_OR_CALL(Helper.returnsVoid, false);
478 try testing.expectEqual(false, Helper.last_val);
479
480 try testing.expectEqual(Helper.returnsBool(1), Macros.CAST_OR_CALL(Helper.returnsBool, @as(f32, 1)));
481 try testing.expectEqual(Helper.returnsBool(-1), Macros.CAST_OR_CALL(Helper.returnsBool, @as(f32, -1)));
482
483 try testing.expectEqual(Helper.identity(@as(c_uint, 100)), Macros.CAST_OR_CALL(Helper.identity, @as(c_uint, 100)));
484}
src/translate_c.zig+3
...@@ -4868,6 +4868,8 @@ const PatternList = struct {...@@ -4868,6 +4868,8 @@ const PatternList = struct {
4868 [2][]const u8{ "Ull_SUFFIX(X) (X ## Ull)", "ULL_SUFFIX" },4868 [2][]const u8{ "Ull_SUFFIX(X) (X ## Ull)", "ULL_SUFFIX" },
4869 [2][]const u8{ "ULL_SUFFIX(X) (X ## ULL)", "ULL_SUFFIX" },4869 [2][]const u8{ "ULL_SUFFIX(X) (X ## ULL)", "ULL_SUFFIX" },
48704870
4871 [2][]const u8{ "CAST_OR_CALL(X, Y) (X)(Y)", "CAST_OR_CALL" },
4872
4871 [2][]const u8{4873 [2][]const u8{
4872 \\wl_container_of(ptr, sample, member) \4874 \\wl_container_of(ptr, sample, member) \
4873 \\(__typeof__(sample))((char *)(ptr) - \4875 \\(__typeof__(sample))((char *)(ptr) - \
...@@ -5048,6 +5050,7 @@ test "Macro matching" {...@@ -5048,6 +5050,7 @@ test "Macro matching" {
5048 , "WL_CONTAINER_OF");5050 , "WL_CONTAINER_OF");
50495051
5050 try helper.checkMacro(allocator, pattern_list, "NO_MATCH(X, Y) (X + Y)", null);5052 try helper.checkMacro(allocator, pattern_list, "NO_MATCH(X, Y) (X + Y)", null);
5053 try helper.checkMacro(allocator, pattern_list, "CAST_OR_CALL(X, Y) (X)(Y)", "CAST_OR_CALL");
5051}5054}
50525055
5053const MacroCtx = struct {5056const MacroCtx = struct {