translate-c: Handle ambiguous cast or call macro

Fixes #9425
This commit is contained in:
Evan Haas 2021-07-22 09:17:54 -07:00
parent dc4fa83dd7
commit b33efa3739
No known key found for this signature in database
GPG Key ID: F0DEE3724F3290B3
2 changed files with 55 additions and 0 deletions

View File

@ -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)));
}

View File

@ -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 {