Skip to content

Commit 7e55f40

Browse files
Resolve peer C pointer types
1 parent 0b75665 commit 7e55f40

File tree

2 files changed

+143
-1
lines changed

2 files changed

+143
-1
lines changed

src/analysis.zig

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3137,6 +3137,7 @@ pub const Type = struct {
31373137
const b_type = b.pointer;
31383138
if (a_type.size != b_type.size) return false;
31393139
if (a_type.sentinel != b_type.sentinel) return false;
3140+
if (a_type.is_const != b_type.is_const) return false;
31403141
if (!a_type.elem_ty.eql(b_type.elem_ty.*)) return false;
31413142
},
31423143
.array => |a_type| {
@@ -6622,7 +6623,64 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
66226623

66236624
.vector => return null, // TODO
66246625

6625-
.c_ptr => return null, // TODO
6626+
.c_ptr => {
6627+
var opt_ptr_info: ?PointerInfo = null;
6628+
for (peer_tys) |opt_ty| {
6629+
const ty = opt_ty orelse continue;
6630+
switch (ty.zigTypeTag(analyser).?) {
6631+
.comptime_int => continue,
6632+
.int => {
6633+
const ptr_bits = builtin.target.ptrBitWidth();
6634+
const bits = analyser.ip.intInfo(ty.data.ip_index.index.?, builtin.target).bits;
6635+
if (bits >= ptr_bits) continue;
6636+
},
6637+
.null => continue,
6638+
else => {},
6639+
}
6640+
6641+
if (!analyser.typeIsPointerAtRuntime(ty)) {
6642+
return null;
6643+
}
6644+
6645+
const peer_info = analyser.typePointerInfo(ty).?;
6646+
6647+
var ptr_info = opt_ptr_info orelse {
6648+
opt_ptr_info = peer_info;
6649+
continue;
6650+
};
6651+
6652+
if (!ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6653+
// TODO: coerce C pointer types
6654+
return null;
6655+
}
6656+
6657+
if (ptr_info.flags.alignment != ptr_info.flags.alignment) {
6658+
// TODO: find minimum C pointer alignment
6659+
return null;
6660+
}
6661+
6662+
if (ptr_info.flags.address_space != peer_info.flags.address_space) {
6663+
return null;
6664+
}
6665+
6666+
ptr_info.flags.is_const = ptr_info.flags.is_const or peer_info.flags.is_const;
6667+
ptr_info.flags.is_volatile = ptr_info.flags.is_volatile or peer_info.flags.is_volatile;
6668+
6669+
opt_ptr_info = ptr_info;
6670+
}
6671+
const info = opt_ptr_info.?;
6672+
return .{
6673+
.data = .{
6674+
.pointer = .{
6675+
.elem_ty = try analyser.allocType(info.elem_ty),
6676+
.sentinel = .none,
6677+
.size = .c,
6678+
.is_const = info.flags.is_const,
6679+
},
6680+
},
6681+
.is_type_val = true,
6682+
};
6683+
},
66266684

66276685
.ptr => return null, // TODO
66286686

@@ -6749,3 +6807,65 @@ fn typeIsArrayLike(analyser: *Analyser, ty: Type) ?ArrayLike {
67496807
else => null,
67506808
};
67516809
}
6810+
6811+
const PointerInfo = struct {
6812+
is_optional: bool,
6813+
elem_ty: Type,
6814+
sentinel: InternPool.Index,
6815+
flags: InternPool.Key.Pointer.Flags,
6816+
};
6817+
fn typePointerInfo(analyser: *Analyser, ty: Type) ?PointerInfo {
6818+
std.debug.assert(ty.is_type_val);
6819+
const ip_index = switch (ty.data) {
6820+
.ip_index => |payload| payload.index orelse return null,
6821+
.pointer => |p| return .{
6822+
.is_optional = false,
6823+
.elem_ty = p.elem_ty.*,
6824+
.sentinel = p.sentinel,
6825+
.flags = .{
6826+
.size = p.size,
6827+
.is_const = p.is_const,
6828+
},
6829+
},
6830+
.optional => |child| switch (child.data) {
6831+
.pointer => |p| return .{
6832+
.is_optional = true,
6833+
.elem_ty = p.elem_ty.*,
6834+
.sentinel = p.sentinel,
6835+
.flags = .{
6836+
.size = p.size,
6837+
.is_const = p.is_const,
6838+
},
6839+
},
6840+
else => return null,
6841+
},
6842+
else => return null,
6843+
};
6844+
return switch (analyser.ip.indexToKey(ip_index)) {
6845+
.pointer_type => |p| .{
6846+
.is_optional = false,
6847+
.elem_ty = Type.fromIP(analyser, .type_type, p.elem_type),
6848+
.sentinel = p.sentinel,
6849+
.flags = p.flags,
6850+
},
6851+
.optional_type => |info| switch (analyser.ip.indexToKey(info.payload_type)) {
6852+
.pointer_type => |p| .{
6853+
.is_optional = true,
6854+
.elem_ty = Type.fromIP(analyser, .type_type, p.elem_type),
6855+
.sentinel = p.sentinel,
6856+
.flags = p.flags,
6857+
},
6858+
else => null,
6859+
},
6860+
else => null,
6861+
};
6862+
}
6863+
6864+
fn typeIsPointerAtRuntime(analyser: *Analyser, ty: Type) bool {
6865+
const ptr_info = analyser.typePointerInfo(ty) orelse return false;
6866+
return switch (ptr_info.flags.size) {
6867+
.slice => false,
6868+
.c => !ptr_info.is_optional,
6869+
.one, .many => !ptr_info.is_optional or !ptr_info.flags.is_allowzero,
6870+
};
6871+
}

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)