Skip to content

Commit 5762efb

Browse files
Resolve peer types for C pointers
1 parent fa6bda6 commit 5762efb

File tree

2 files changed

+137
-1
lines changed

2 files changed

+137
-1
lines changed

src/analysis.zig

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3134,6 +3134,7 @@ pub const Type = struct {
31343134
const b_type = b.pointer;
31353135
if (a_type.size != b_type.size) return false;
31363136
if (a_type.sentinel != b_type.sentinel) return false;
3137+
if (a_type.is_const != b_type.is_const) return false;
31373138
if (!a_type.elem_ty.eql(b_type.elem_ty.*)) return false;
31383139
},
31393140
.array => |a_type| {
@@ -4057,6 +4058,62 @@ pub const Type = struct {
40574058
};
40584059
}
40594060

4061+
const PointerInfo = struct {
4062+
elem_ty: Type,
4063+
sentinel: InternPool.Index,
4064+
flags: InternPool.Key.Pointer.Flags,
4065+
};
4066+
4067+
fn pointerInfo(ty: Type, analyser: *Analyser) ?PointerInfo {
4068+
if (!ty.is_type_val) return null;
4069+
return blk: switch (ty.data) {
4070+
.pointer => |info| .{
4071+
.elem_ty = info.elem_ty.*,
4072+
.sentinel = info.sentinel,
4073+
.flags = .{
4074+
.size = info.size,
4075+
.is_const = info.is_const,
4076+
},
4077+
},
4078+
.ip_index => |payload| switch (analyser.ip.indexToKey(payload.index orelse return null)) {
4079+
.pointer_type => |info| .{
4080+
.elem_ty = Type.fromIP(analyser, .type_type, info.elem_type),
4081+
.sentinel = info.sentinel,
4082+
.flags = info.flags,
4083+
},
4084+
else => null,
4085+
},
4086+
.optional => |child| switch (child.data) {
4087+
.pointer => continue :blk child.data,
4088+
.ip_index => |payload| switch (analyser.ip.indexToKey(payload.index orelse return null)) {
4089+
.pointer_type => continue :blk child.data,
4090+
else => null,
4091+
},
4092+
else => null,
4093+
},
4094+
else => null,
4095+
};
4096+
}
4097+
4098+
fn isPointerAtRuntime(ty: Type, analyser: *Analyser) bool {
4099+
if (ty.pointerInfo(analyser)) |info| {
4100+
return switch (info.flags.size) {
4101+
.slice => false,
4102+
.one, .many, .c => true,
4103+
};
4104+
}
4105+
switch (ty.data) {
4106+
.optional => |child| {
4107+
const p = child.pointerInfo(analyser) orelse return false;
4108+
return switch (p.flags.size) {
4109+
.slice, .c => false,
4110+
.many, .one => !p.flags.is_allowzero,
4111+
};
4112+
},
4113+
else => return false,
4114+
}
4115+
}
4116+
40604117
pub fn stringifyTypeOf(ty: Type, analyser: *Analyser, options: FormatOptions) error{OutOfMemory}![]const u8 {
40614118
const typeof = try ty.typeOf(analyser);
40624119
var aw: std.io.Writer.Allocating = .init(analyser.arena);
@@ -6619,7 +6676,64 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
66196676

66206677
.vector => return null, // TODO
66216678

6622-
.c_ptr => return null, // TODO
6679+
.c_ptr => {
6680+
var opt_ptr_info: ?Type.PointerInfo = null;
6681+
for (peer_tys) |opt_ty| {
6682+
const ty = opt_ty orelse continue;
6683+
switch (ty.zigTypeTag(analyser).?) {
6684+
.comptime_int => continue,
6685+
.int => {
6686+
const ptr_bits = builtin.target.ptrBitWidth();
6687+
const bits = analyser.ip.intInfo(ty.data.ip_index.index.?, builtin.target).bits;
6688+
if (bits >= ptr_bits) continue;
6689+
},
6690+
.null => continue,
6691+
else => {},
6692+
}
6693+
6694+
if (!ty.isPointerAtRuntime(analyser)) {
6695+
return null;
6696+
}
6697+
6698+
const peer_info = ty.pointerInfo(analyser).?;
6699+
6700+
var ptr_info = opt_ptr_info orelse {
6701+
opt_ptr_info = peer_info;
6702+
continue;
6703+
};
6704+
6705+
if (!ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6706+
// TODO: coerce C pointer types
6707+
return null;
6708+
}
6709+
6710+
if (ptr_info.flags.alignment != ptr_info.flags.alignment) {
6711+
// TODO: find minimum C pointer alignment
6712+
return null;
6713+
}
6714+
6715+
if (ptr_info.flags.address_space != peer_info.flags.address_space) {
6716+
return null;
6717+
}
6718+
6719+
ptr_info.flags.is_const = ptr_info.flags.is_const or peer_info.flags.is_const;
6720+
ptr_info.flags.is_volatile = ptr_info.flags.is_volatile or peer_info.flags.is_volatile;
6721+
6722+
opt_ptr_info = ptr_info;
6723+
}
6724+
const info = opt_ptr_info.?;
6725+
return .{
6726+
.data = .{
6727+
.pointer = .{
6728+
.elem_ty = try analyser.allocType(info.elem_ty),
6729+
.sentinel = .none,
6730+
.size = .c,
6731+
.is_const = info.flags.is_const,
6732+
},
6733+
},
6734+
.is_type_val = true,
6735+
};
6736+
},
66236737

66246738
.ptr => return null, // TODO
66256739

tests/analysis/pointer.zig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ const one_minus_slice = one_u32 - slice_u32;
6565
const one_minus_c = one_u32 - c_u32;
6666
// ^^^^^^^^^^^ (usize)()
6767

68+
//
69+
// array pointer *[n]T
70+
//
71+
72+
const array_u32: *const [2]u32 = &[_]u32{ 1, 2 };
73+
// ^^^^^^^^^ (*const [2]u32)()
74+
6875
//
6976
// many item pointer [*]T
7077
//
@@ -234,6 +241,21 @@ const c_minus_slice = c_u32 - slice_u32;
234241
const c_minus_c = c_u32 - c_u32;
235242
// ^^^^^^^^^ (usize)()
236243

244+
const c_u32_or_one_u32 = if (runtime_bool) c_u32 else one_u32;
245+
// ^^^^^^^^^^^^^^^^ ([*c]const u32)()
246+
247+
const c_u32_or_array_u32 = if (runtime_bool) c_u32 else array_u32;
248+
// ^^^^^^^^^^^^^^^^^^ (either type)()
249+
250+
const c_u32_or_many_u32 = if (runtime_bool) c_u32 else many_u32;
251+
// ^^^^^^^^^^^^^^^^^ ([*c]const u32)()
252+
253+
const c_u32_or_slice_u32 = if (runtime_bool) c_u32 else slice_u32;
254+
// ^^^^^^^^^^^^^^^^^^ (either type)()
255+
256+
const c_u32_or_c_u32 = if (runtime_bool) c_u32 else c_u32;
257+
// ^^^^^^^^^^^^^^ ([*c]const u32)()
258+
237259
var runtime_index: usize = 5;
238260
var runtime_u8: u8 = 1;
239261
var runtime_i8: i8 = -1;

0 commit comments

Comments
 (0)