Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions src/Type.zig
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,7 @@ pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {
return zcu.intern_pool.isNoReturn(ty.toIntern());
}

/// Returns `none` if the pointer is naturally aligned and the element type is 0-bit.
/// Never returns `none`. Asserts that all necessary type resolution is already done.
pub fn ptrAlignment(ty: Type, zcu: *Zcu) Alignment {
return ptrAlignmentInner(ty, .normal, zcu, {}) catch unreachable;
}
Expand All @@ -823,15 +823,9 @@ pub fn ptrAlignmentInner(
) !Alignment {
return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
.ptr_type => |ptr_type| {
if (ptr_type.flags.alignment != .none)
return ptr_type.flags.alignment;

if (strat == .sema) {
const res = try Type.fromInterned(ptr_type.child).abiAlignmentInner(.sema, zcu, tid);
return res.scalar;
}

return Type.fromInterned(ptr_type.child).abiAlignment(zcu);
if (ptr_type.flags.alignment != .none) return ptr_type.flags.alignment;
const res = try Type.fromInterned(ptr_type.child).abiAlignmentInner(strat.toLazy(), zcu, tid);
return res.scalar;
},
.opt_type => |child| Type.fromInterned(child).ptrAlignmentInner(strat, zcu, tid),
else => unreachable,
Expand Down
2 changes: 1 addition & 1 deletion src/Value.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3690,7 +3690,7 @@ pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type };
pub const empty_tuple: Value = .{ .ip_index = .empty_tuple };

pub fn makeBool(x: bool) Value {
return if (x) Value.true else Value.false;
return if (x) .true else .false;
}

/// `parent_ptr` must be a single-pointer to some optional.
Expand Down
153 changes: 88 additions & 65 deletions src/link/Dwarf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3248,75 +3248,72 @@ fn updateLazyType(
},
.opt_type => |opt_child_type_index| {
const opt_child_type: Type = .fromInterned(opt_child_type_index);
const opt_repr = optRepr(opt_child_type, zcu);
try wip_nav.abbrevCode(.generated_union_type);
try wip_nav.strp(name);
try uleb128(diw, ty.abiSize(zcu));
try uleb128(diw, ty.abiAlignment(zcu).toByteUnits().?);
if (opt_child_type.isNoReturn(zcu)) {
try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("null");
try wip_nav.refType(.null);
try uleb128(diw, 0);
} else {
try wip_nav.abbrevCode(.tagged_union);
try wip_nav.infoSectionOffset(
.debug_info,
wip_nav.unit,
wip_nav.entry,
@intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
);
{
switch (opt_repr) {
.opv_null => {
try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("has_value");
const repr: enum { unpacked, error_set, pointer } = switch (opt_child_type_index) {
.anyerror_type => .error_set,
else => switch (ip.indexToKey(opt_child_type_index)) {
else => .unpacked,
.error_set_type, .inferred_error_set_type => .error_set,
.ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer,
},
};
switch (repr) {
.unpacked => {
try wip_nav.refType(.bool);
try uleb128(diw, if (opt_child_type.hasRuntimeBits(zcu))
opt_child_type.abiSize(zcu)
else
0);
},
.error_set => {
try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
.bits = zcu.errorSetBits(),
} })));
try uleb128(diw, 0);
},
.pointer => {
try wip_nav.refType(.usize);
try uleb128(diw, 0);
},
}

try wip_nav.abbrevCode(.unsigned_tagged_union_field);
try wip_nav.strp("null");
try wip_nav.refType(.null);
try uleb128(diw, 0);
},
.unpacked, .error_set, .pointer => {
try wip_nav.abbrevCode(.tagged_union);
try wip_nav.infoSectionOffset(
.debug_info,
wip_nav.unit,
wip_nav.entry,
@intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
);
{
try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("null");
try wip_nav.refType(.null);
try uleb128(diw, 0);
}
try uleb128(diw, @intFromEnum(AbbrevCode.null));
try wip_nav.strp("has_value");
switch (opt_repr) {
.opv_null => unreachable,
.unpacked => {
try wip_nav.refType(.bool);
try uleb128(diw, if (opt_child_type.hasRuntimeBits(zcu))
opt_child_type.abiSize(zcu)
else
0);
},
.error_set => {
try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
.bits = zcu.errorSetBits(),
} })));
try uleb128(diw, 0);
},
.pointer => {
try wip_nav.refType(.usize);
try uleb128(diw, 0);
},
}

try wip_nav.abbrevCode(.tagged_union_default_field);
{
try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("?");
try wip_nav.refType(opt_child_type);
try wip_nav.abbrevCode(.unsigned_tagged_union_field);
try uleb128(diw, 0);
{
try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("null");
try wip_nav.refType(.null);
try uleb128(diw, 0);
}
try uleb128(diw, @intFromEnum(AbbrevCode.null));

try wip_nav.abbrevCode(.tagged_union_default_field);
{
try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("?");
try wip_nav.refType(opt_child_type);
try uleb128(diw, 0);
}
try uleb128(diw, @intFromEnum(AbbrevCode.null));
}
try uleb128(diw, @intFromEnum(AbbrevCode.null));
}
try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
}
try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
Expand Down Expand Up @@ -3850,22 +3847,31 @@ fn updateLazyValue(
try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
.opt => |opt| {
const child_type: Type = .fromInterned(ip.indexToKey(opt.ty).opt_type);
const opt_child_type: Type = .fromInterned(ip.indexToKey(opt.ty).opt_type);
try wip_nav.abbrevCode(.aggregate_comptime_value);
try wip_nav.refType(.fromInterned(opt.ty));
{
try wip_nav.abbrevCode(.comptime_value_field_runtime_bits);
try wip_nav.strp("has_value");
if (Type.fromInterned(opt.ty).optionalReprIsPayload(zcu)) {
try wip_nav.blockValue(src_loc, .fromInterned(opt.val));
} else {
try uleb128(diw, 1);
try diw.writeByte(@intFromBool(opt.val != .none));
switch (optRepr(opt_child_type, zcu)) {
.opv_null => try uleb128(diw, 0),
.unpacked => try wip_nav.blockValue(src_loc, .makeBool(opt.val != .none)),
.error_set => try wip_nav.blockValue(src_loc, .fromInterned(value_index)),
.pointer => if (opt_child_type.comptimeOnly(zcu)) {
var buf: [8]u8 = undefined;
const bytes = buf[0..@divExact(zcu.getTarget().ptrBitWidth(), 8)];
dwarf.writeInt(bytes, switch (opt.val) {
.none => 0,
else => opt_child_type.ptrAlignment(zcu).toByteUnits().?,
});
try uleb128(diw, bytes.len);
try diw.writeAll(bytes);
} else try wip_nav.blockValue(src_loc, .fromInterned(value_index)),
}
}
if (opt.val != .none) child_field: {
const has_runtime_bits = child_type.hasRuntimeBits(zcu);
const has_comptime_state = child_type.comptimeOnly(zcu) and try child_type.onePossibleValue(pt) == null;
const has_runtime_bits = opt_child_type.hasRuntimeBits(zcu);
const has_comptime_state = opt_child_type.comptimeOnly(zcu) and try opt_child_type.onePossibleValue(pt) == null;
try wip_nav.abbrevCode(if (has_comptime_state)
.comptime_value_field_comptime_state
else if (has_runtime_bits)
Expand Down Expand Up @@ -3995,6 +4001,23 @@ fn updateLazyValue(
try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
}

fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum {
unpacked,
opv_null,
error_set,
pointer,
} {
if (opt_child_type.isNoReturn(zcu)) return .opv_null;
return switch (opt_child_type.toIntern()) {
.anyerror_type => .error_set,
else => switch (zcu.intern_pool.indexToKey(opt_child_type.toIntern())) {
else => .unpacked,
.error_set_type, .inferred_error_set_type => .error_set,
.ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer,
},
};
}

pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternPool.Index) UpdateError!void {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
Expand Down
11 changes: 11 additions & 0 deletions test/behavior/optional.zig
Original file line number Diff line number Diff line change
Expand Up @@ -656,3 +656,14 @@ test "result location initialization of optional with OPV payload" {
_ = &c;
try expectEqual(0, (c orelse return error.TestFailed).x);
}

test "global comptime only optional" {
const S = struct {
const @"null": ?*type = null;
const @"void": ?*const type = &void;
};
comptime {
assert(S.null == null);
assert(S.void.?.* == void);
}
}