diff options
| author | kcbanner <kcbanner@gmail.com> | 2023-09-23 14:33:31 -0400 |
|---|---|---|
| committer | kcbanner <kcbanner@gmail.com> | 2023-09-23 14:34:01 -0400 |
| commit | 9f4649b197b720dbc168ced25eee0805d3b678b1 (patch) | |
| tree | edc09234b4d8385fce36a306bb36c55cfadd823c | |
| parent | 4e9f5f25c8226144eff8d9c1df79cfcffbae5492 (diff) | |
| download | zig-9f4649b197b720dbc168ced25eee0805d3b678b1.tar.gz zig-9f4649b197b720dbc168ced25eee0805d3b678b1.zip | |
codegen/sema: handle unions with unknown tags in more places
| -rw-r--r-- | src/Sema.zig | 2 | ||||
| -rw-r--r-- | src/TypedValue.zig | 30 | ||||
| -rw-r--r-- | src/codegen.zig | 29 | ||||
| -rw-r--r-- | src/value.zig | 25 |
4 files changed, 51 insertions, 35 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index e43804b521..cb54843da7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -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); diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 86f42813f7..cf705cdf89 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -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(" }"); diff --git a/src/codegen.zig b/src/codegen.zig index 13aefaa8e5..738281cf55 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -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)) { diff --git a/src/value.zig b/src/value.zig index 6dd6ce5d32..279f52e3e0 100644 --- a/src/value.zig +++ b/src/value.zig @@ -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, }; } |
