Skip to content

Commit f79b31c

Browse files
Resolve peer C pointer types
1 parent ece585d commit f79b31c

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| {
@@ -6627,7 +6628,64 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
66276628

66286629
.vector => return null, // TODO
66296630

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

66326690
.ptr => return null, // TODO
66336691

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

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)