| author | |
| committer | |
| log | c558de6655e2e9b72c5733b2d477ff18520d1c6b |
| tree | 279830f956fc27ba8f18e8959efc8a657c4fc0c8 |
| parent | d3b4b2edf140c002da4c9c1396c26e0f66835eb0 |
Closes #126563 files changed, 50 insertions(+), 9 deletions(-)
src/Sema.zig+6-6| ... | ... | @@ -21933,6 +21933,7 @@ fn unionFieldPtr( |
| 21933 | 21933 | .mutable = union_ptr_ty.ptrIsMutable(), |
| 21934 | 21934 | .@"addrspace" = union_ptr_ty.ptrAddressSpace(), |
| 21935 | 21935 | }); |
| 21936 | const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?); | |
| 21936 | 21937 | |
| 21937 | 21938 | if (initializing and field.ty.zigTypeTag() == .NoReturn) { |
| 21938 | 21939 | const msg = msg: { |
| ... | ... | @@ -21954,11 +21955,10 @@ fn unionFieldPtr( |
| 21954 | 21955 | if (union_val.isUndef()) { |
| 21955 | 21956 | return sema.failWithUseOfUndef(block, src); |
| 21956 | 21957 | } |
| 21957 | const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?; | |
| 21958 | 21958 | const tag_and_val = union_val.castTag(.@"union").?.data; |
| 21959 | 21959 | var field_tag_buf: Value.Payload.U32 = .{ |
| 21960 | 21960 | .base = .{ .tag = .enum_field_index }, |
| 21961 | .data = @intCast(u32, enum_field_index), | |
| 21961 | .data = enum_field_index, | |
| 21962 | 21962 | }; |
| 21963 | 21963 | const field_tag = Value.initPayload(&field_tag_buf.base); |
| 21964 | 21964 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); |
| ... | ... | @@ -21990,7 +21990,7 @@ fn unionFieldPtr( |
| 21990 | 21990 | if (!initializing and union_obj.layout == .Auto and block.wantSafety() and |
| 21991 | 21991 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) |
| 21992 | 21992 | { |
| 21993 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); | |
| 21993 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); | |
| 21994 | 21994 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); |
| 21995 | 21995 | // TODO would it be better if get_union_tag supported pointers to unions? |
| 21996 | 21996 | const union_val = try block.addTyOp(.load, union_ty, union_ptr); |
| ... | ... | @@ -22020,15 +22020,15 @@ fn unionFieldVal( |
| 22020 | 22020 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; |
| 22021 | 22021 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 22022 | 22022 | const field = union_obj.fields.values()[field_index]; |
| 22023 | const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?); | |
| 22023 | 22024 | |
| 22024 | 22025 | if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| { |
| 22025 | 22026 | if (union_val.isUndef()) return sema.addConstUndef(field.ty); |
| 22026 | 22027 | |
| 22027 | 22028 | const tag_and_val = union_val.castTag(.@"union").?.data; |
| 22028 | const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?; | |
| 22029 | 22029 | var field_tag_buf: Value.Payload.U32 = .{ |
| 22030 | 22030 | .base = .{ .tag = .enum_field_index }, |
| 22031 | .data = @intCast(u32, enum_field_index), | |
| 22031 | .data = enum_field_index, | |
| 22032 | 22032 | }; |
| 22033 | 22033 | const field_tag = Value.initPayload(&field_tag_buf.base); |
| 22034 | 22034 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); |
| ... | ... | @@ -22064,7 +22064,7 @@ fn unionFieldVal( |
| 22064 | 22064 | if (union_obj.layout == .Auto and block.wantSafety() and |
| 22065 | 22065 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) |
| 22066 | 22066 | { |
| 22067 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); | |
| 22067 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); | |
| 22068 | 22068 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); |
| 22069 | 22069 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval); |
| 22070 | 22070 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); |
src/codegen/llvm.zig+16-3| ... | ... | @@ -8527,12 +8527,26 @@ pub const FuncGen = struct { |
| 8527 | 8527 | const union_llvm_ty = try self.dg.lowerType(union_ty); |
| 8528 | 8528 | const target = self.dg.module.getTarget(); |
| 8529 | 8529 | const layout = union_ty.unionGetLayout(target); |
| 8530 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | |
| 8531 | const tag_int = blk: { | |
| 8532 | const tag_ty = union_ty.unionTagTypeHypothetical(); | |
| 8533 | const union_field_name = union_obj.fields.keys()[extra.field_index]; | |
| 8534 | const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?; | |
| 8535 | var tag_val_payload: Value.Payload.U32 = .{ | |
| 8536 | .base = .{ .tag = .enum_field_index }, | |
| 8537 | .data = @intCast(u32, enum_field_index), | |
| 8538 | }; | |
| 8539 | const tag_val = Value.initPayload(&tag_val_payload.base); | |
| 8540 | var int_payload: Value.Payload.U64 = undefined; | |
| 8541 | const tag_int_val = tag_val.enumToInt(tag_ty, &int_payload); | |
| 8542 | break :blk tag_int_val.toUnsignedInt(target); | |
| 8543 | }; | |
| 8530 | 8544 | if (layout.payload_size == 0) { |
| 8531 | 8545 | if (layout.tag_size == 0) { |
| 8532 | 8546 | return null; |
| 8533 | 8547 | } |
| 8534 | 8548 | assert(!isByRef(union_ty)); |
| 8535 | return union_llvm_ty.constInt(extra.field_index, .False); | |
| 8549 | return union_llvm_ty.constInt(tag_int, .False); | |
| 8536 | 8550 | } |
| 8537 | 8551 | assert(isByRef(union_ty)); |
| 8538 | 8552 | // The llvm type of the alloca will the the named LLVM union type, which will not |
| ... | ... | @@ -8541,7 +8555,6 @@ pub const FuncGen = struct { |
| 8541 | 8555 | // then set the fields appropriately. |
| 8542 | 8556 | const result_ptr = self.buildAlloca(union_llvm_ty); |
| 8543 | 8557 | const llvm_payload = try self.resolveInst(extra.init); |
| 8544 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | |
| 8545 | 8558 | assert(union_obj.haveFieldTypes()); |
| 8546 | 8559 | const field = union_obj.fields.values()[extra.field_index]; |
| 8547 | 8560 | const field_llvm_ty = try self.dg.lowerType(field.ty); |
| ... | ... | @@ -8625,7 +8638,7 @@ pub const FuncGen = struct { |
| 8625 | 8638 | }; |
| 8626 | 8639 | const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, indices.len, ""); |
| 8627 | 8640 | const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty); |
| 8628 | const llvm_tag = tag_llvm_ty.constInt(extra.field_index, .False); | |
| 8641 | const llvm_tag = tag_llvm_ty.constInt(tag_int, .False); | |
| 8629 | 8642 | const store_inst = self.builder.buildStore(llvm_tag, field_ptr); |
| 8630 | 8643 | store_inst.setAlignment(union_obj.tag_ty.abiAlignment(target)); |
| 8631 | 8644 | } |
test/behavior/union.zig+28| ... | ... | @@ -1324,3 +1324,31 @@ test "union and enum field order doesn't match" { |
| 1324 | 1324 | x = .b; |
| 1325 | 1325 | try expect(x == .b); |
| 1326 | 1326 | } |
| 1327 | ||
| 1328 | test "@unionInit uses tag value instead of field index" { | |
| 1329 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 1330 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 1331 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1332 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1333 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 1334 | ||
| 1335 | const E = enum(u8) { | |
| 1336 | b = 255, | |
| 1337 | a = 3, | |
| 1338 | }; | |
| 1339 | const U = union(E) { | |
| 1340 | a: usize, | |
| 1341 | b: isize, | |
| 1342 | }; | |
| 1343 | var i: isize = -1; | |
| 1344 | var u = @unionInit(U, "b", i); | |
| 1345 | { | |
| 1346 | var a = u.b; | |
| 1347 | try expect(a == i); | |
| 1348 | } | |
| 1349 | { | |
| 1350 | var a = &u.b; | |
| 1351 | try expect(a.* == i); | |
| 1352 | } | |
| 1353 | try expect(@enumToInt(u) == 255); | |
| 1354 | } |