Skip to content

Commit 511fd39

Browse files
Resolve peer types for C pointers
1 parent 59ebb5a commit 511fd39

File tree

2 files changed

+131
-1
lines changed

2 files changed

+131
-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+
switch (ty.data) {
4100+
.optional => |child| {
4101+
const p = child.pointerInfo(analyser) orelse return false;
4102+
return switch (p.flags.size) {
4103+
.slice, .c => false,
4104+
.many, .one => !p.flags.is_allowzero,
4105+
};
4106+
},
4107+
else => {
4108+
const info = ty.pointerInfo(analyser) orelse return false;
4109+
return switch (info.flags.size) {
4110+
.slice => false,
4111+
.one, .many, .c => true,
4112+
};
4113+
},
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);
@@ -6648,7 +6705,64 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
66486705

66496706
.vector => return null, // TODO
66506707

6651-
.c_ptr => return null, // TODO
6708+
.c_ptr => {
6709+
var opt_ptr_info: ?Type.PointerInfo = null;
6710+
for (peer_tys) |opt_ty| {
6711+
const ty = opt_ty orelse continue;
6712+
switch (ty.zigTypeTag(analyser).?) {
6713+
.comptime_int => continue,
6714+
.int => {
6715+
const ptr_bits = builtin.target.ptrBitWidth();
6716+
const bits = analyser.ip.intInfo(ty.data.ip_index.index.?, builtin.target).bits;
6717+
if (bits >= ptr_bits) continue;
6718+
},
6719+
.null => continue,
6720+
else => {},
6721+
}
6722+
6723+
if (!ty.isPointerAtRuntime(analyser)) {
6724+
return null;
6725+
}
6726+
6727+
const peer_info = ty.pointerInfo(analyser).?;
6728+
6729+
var ptr_info = opt_ptr_info orelse {
6730+
opt_ptr_info = peer_info;
6731+
continue;
6732+
};
6733+
6734+
if (!ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6735+
// TODO: coerce C pointer element types
6736+
return null;
6737+
}
6738+
6739+
if (ptr_info.flags.alignment != ptr_info.flags.alignment) {
6740+
// TODO: find minimum C pointer alignment
6741+
return null;
6742+
}
6743+
6744+
if (ptr_info.flags.address_space != peer_info.flags.address_space) {
6745+
return null;
6746+
}
6747+
6748+
ptr_info.flags.is_const = ptr_info.flags.is_const or peer_info.flags.is_const;
6749+
ptr_info.flags.is_volatile = ptr_info.flags.is_volatile or peer_info.flags.is_volatile;
6750+
6751+
opt_ptr_info = ptr_info;
6752+
}
6753+
const info = opt_ptr_info.?;
6754+
return .{
6755+
.data = .{
6756+
.pointer = .{
6757+
.elem_ty = try analyser.allocType(info.elem_ty),
6758+
.sentinel = .none,
6759+
.size = .c,
6760+
.is_const = info.flags.is_const,
6761+
},
6762+
},
6763+
.is_type_val = true,
6764+
};
6765+
},
66526766

66536767
.ptr => return null, // TODO
66546768

tests/analysis/peer_type_resolution.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,22 @@ pub fn main() !void {
226226
_ = coercible_array_1;
227227
// ^^^^^^^^^^^^^^^^^ (either type)() TODO this should be `[2]?*const S`
228228

229+
const coercible_c_pointer_0 = if (runtime_bool) @as([*c]bool, &runtime_bool) else @as([*c]const bool, &comptime_bool);
230+
_ = coercible_c_pointer_0;
231+
// ^^^^^^^^^^^^^^^^^^^^^ ([*c]const bool)()
232+
233+
const coercible_c_pointer_1 = if (runtime_bool) @as([*c]const bool, &comptime_bool) else @as([*c]bool, &runtime_bool);
234+
_ = coercible_c_pointer_1;
235+
// ^^^^^^^^^^^^^^^^^^^^^ ([*c]const bool)()
236+
237+
const coercible_c_pointer_2 = if (runtime_bool) @as([*c]const *const u8, &&0) else @as([*c]const ?*const u8, &&0);
238+
_ = coercible_c_pointer_2;
239+
// ^^^^^^^^^^^^^^^^^^^^^ (either type)() TODO this should be `[*c]const ?*const u8`
240+
241+
const coercible_c_pointer_3 = if (runtime_bool) @as([*c]const ?*const u8, &&0) else @as([*c]const *const u8, &&0);
242+
_ = coercible_c_pointer_3;
243+
// ^^^^^^^^^^^^^^^^^^^^^ (either type)() TODO this should be `[*c]const ?*const u8`
244+
229245
// Use @compileLog to verify the expected type with the compiler:
230246
// @compileLog(error_union_0);
231247

0 commit comments

Comments
 (0)