mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 12:27:41 +00:00
codegen/sema: handle unions with unknown tags in more places
This commit is contained in:
parent
4e9f5f25c8
commit
9f4649b197
@ -32879,7 +32879,7 @@ fn unionToTag(
|
||||
return Air.internedToRef(opv.toIntern());
|
||||
}
|
||||
if (try sema.resolveMaybeUndefVal(un)) |un_val| {
|
||||
return Air.internedToRef(un_val.unionTag(mod).toIntern());
|
||||
return Air.internedToRef(un_val.unionTag(mod).?.toIntern());
|
||||
}
|
||||
try sema.requireRuntimeBlock(block, un_src, null);
|
||||
return block.addTyOp(.get_union_tag, enum_ty, un);
|
||||
|
||||
@ -87,18 +87,19 @@ pub fn print(
|
||||
const union_val = val.castTag(.@"union").?.data;
|
||||
try writer.writeAll(".{ ");
|
||||
|
||||
try print(.{
|
||||
.ty = ip.indexToKey(ty.toIntern()).union_type.enum_tag_ty.toType(),
|
||||
.val = union_val.tag,
|
||||
}, writer, level - 1, mod);
|
||||
try writer.writeAll(" = ");
|
||||
if (ty.unionFieldType(union_val.tag, mod)) |field_ty| {
|
||||
if (union_val.tag.toIntern() != .none) {
|
||||
try print(.{
|
||||
.ty = ip.indexToKey(ty.toIntern()).union_type.enum_tag_ty.toType(),
|
||||
.val = union_val.tag,
|
||||
}, writer, level - 1, mod);
|
||||
try writer.writeAll(" = ");
|
||||
const field_ty = ty.unionFieldType(union_val.tag, mod).?;
|
||||
try print(.{
|
||||
.ty = field_ty,
|
||||
.val = union_val.val,
|
||||
}, writer, level - 1, mod);
|
||||
} else {
|
||||
return writer.writeAll("(no tag)");
|
||||
return writer.writeAll("(unknown tag)");
|
||||
}
|
||||
|
||||
return writer.writeAll(" }");
|
||||
@ -408,18 +409,19 @@ pub fn print(
|
||||
.un => |un| {
|
||||
try writer.writeAll(".{ ");
|
||||
if (level > 0) {
|
||||
try print(.{
|
||||
.ty = ty.unionTagTypeHypothetical(mod),
|
||||
.val = un.tag.toValue(),
|
||||
}, writer, level - 1, mod);
|
||||
try writer.writeAll(" = ");
|
||||
if (ty.unionFieldType(un.tag.toValue(), mod)) |field_ty| {
|
||||
if (un.tag != .none) {
|
||||
try print(.{
|
||||
.ty = ty.unionTagTypeHypothetical(mod),
|
||||
.val = un.tag.toValue(),
|
||||
}, writer, level - 1, mod);
|
||||
try writer.writeAll(" = ");
|
||||
const field_ty = ty.unionFieldType(un.tag.toValue(), mod).?;
|
||||
try print(.{
|
||||
.ty = field_ty,
|
||||
.val = un.val.toValue(),
|
||||
}, writer, level - 1, mod);
|
||||
} else {
|
||||
try writer.writeAll("(no tag)");
|
||||
try writer.writeAll("(unknown tag)");
|
||||
}
|
||||
} else try writer.writeAll("...");
|
||||
return writer.writeAll(" }");
|
||||
|
||||
@ -583,24 +583,33 @@ pub fn generateSymbol(
|
||||
}
|
||||
|
||||
const union_obj = mod.typeToUnion(typed_value.ty).?;
|
||||
const field_index = typed_value.ty.unionTagFieldIndex(un.tag.toValue(), mod).?;
|
||||
if (un.tag != .none) {
|
||||
const field_index = typed_value.ty.unionTagFieldIndex(un.tag.toValue(), mod).?;
|
||||
const field_ty = union_obj.field_types.get(ip)[field_index].toType();
|
||||
if (!field_ty.hasRuntimeBits(mod)) {
|
||||
try code.appendNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);
|
||||
} else {
|
||||
switch (try generateSymbol(bin_file, src_loc, .{
|
||||
.ty = field_ty,
|
||||
.val = un.val.toValue(),
|
||||
}, code, debug_output, reloc_info)) {
|
||||
.ok => {},
|
||||
.fail => |em| return Result{ .fail = em },
|
||||
}
|
||||
|
||||
const field_ty = union_obj.field_types.get(ip)[field_index].toType();
|
||||
if (!field_ty.hasRuntimeBits(mod)) {
|
||||
try code.appendNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);
|
||||
const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(mod)) orelse return error.Overflow;
|
||||
if (padding > 0) {
|
||||
try code.appendNTimes(0, padding);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (try generateSymbol(bin_file, src_loc, .{
|
||||
.ty = field_ty,
|
||||
.ty = ip.typeOf(un.val).toType(),
|
||||
.val = un.val.toValue(),
|
||||
}, code, debug_output, reloc_info)) {
|
||||
.ok => {},
|
||||
.fail => |em| return Result{ .fail = em },
|
||||
}
|
||||
|
||||
const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(mod)) orelse return error.Overflow;
|
||||
if (padding > 0) {
|
||||
try code.appendNTimes(0, padding);
|
||||
}
|
||||
}
|
||||
|
||||
if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) {
|
||||
|
||||
@ -706,8 +706,8 @@ pub const Value = struct {
|
||||
.Auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already
|
||||
.Extern => {
|
||||
const union_obj = mod.typeToUnion(ty).?;
|
||||
const union_tag = val.unionTag(mod);
|
||||
if (mod.unionTagFieldIndex(union_obj, union_tag)) |field_index| {
|
||||
if (val.unionTag(mod)) |union_tag| {
|
||||
const field_index = mod.unionTagFieldIndex(union_obj, union_tag).?;
|
||||
const field_type = union_obj.field_types.get(&mod.intern_pool)[field_index].toType();
|
||||
const field_val = try val.fieldValue(mod, field_index);
|
||||
const byte_count = @as(usize, @intCast(field_type.abiSize(mod)));
|
||||
@ -715,7 +715,7 @@ pub const Value = struct {
|
||||
} else {
|
||||
const union_size = ty.abiSize(mod);
|
||||
const array_type = try mod.arrayType(.{ .len = union_size, .child = .u8_type });
|
||||
return writeToMemory(val.unionValue(mod), array_type, mod, buffer[0..union_size]);
|
||||
return writeToMemory(val.unionValue(mod), array_type, mod, buffer[0..@as(usize, @intCast(union_size))]);
|
||||
}
|
||||
},
|
||||
.Packed => {
|
||||
@ -832,10 +832,16 @@ pub const Value = struct {
|
||||
switch (union_obj.getLayout(ip)) {
|
||||
.Auto, .Extern => unreachable, // Handled in non-packed writeToMemory
|
||||
.Packed => {
|
||||
const field_index = mod.unionTagFieldIndex(union_obj, val.unionTag(mod)).?;
|
||||
const field_type = union_obj.field_types.get(ip)[field_index].toType();
|
||||
const field_val = try val.fieldValue(mod, field_index);
|
||||
return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
|
||||
if (val.unionTag(mod)) |union_tag| {
|
||||
const field_index = mod.unionTagFieldIndex(union_obj, union_tag).?;
|
||||
const field_type = union_obj.field_types.get(ip)[field_index].toType();
|
||||
const field_val = try val.fieldValue(mod, field_index);
|
||||
return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
|
||||
} else {
|
||||
const union_bits: u16 = @intCast(ty.bitSize(mod));
|
||||
const int_ty = try mod.intType(.unsigned, union_bits);
|
||||
return val.unionValue(mod).writeToPackedMemory(int_ty, mod, buffer, bit_offset);
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -1137,7 +1143,6 @@ pub const Value = struct {
|
||||
.Auto, .Extern => unreachable, // Handled by non-packed readFromMemory
|
||||
.Packed => {
|
||||
const union_bits: u16 = @intCast(ty.bitSize(mod));
|
||||
// TODO: Remove after tests pass
|
||||
assert(union_bits != 0);
|
||||
const int_ty = try mod.intType(.unsigned, union_bits);
|
||||
const val = (try readFromPackedMemory(int_ty, mod, buffer, bit_offset, arena)).toIntern();
|
||||
@ -1754,11 +1759,11 @@ pub const Value = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn unionTag(val: Value, mod: *Module) Value {
|
||||
pub fn unionTag(val: Value, mod: *Module) ?Value {
|
||||
if (val.ip_index == .none) return val.castTag(.@"union").?.data.tag;
|
||||
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.undef, .enum_tag => val,
|
||||
.un => |un| un.tag.toValue(),
|
||||
.un => |un| if (un.tag != .none) un.tag.toValue() else return null,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user