| author | |
| committer | |
| log | ff7ec4efb5a6da565b92bc7b129d03680a4a72bd |
| tree | 14006dc9e492015837a97328ccb85ac77f3e27e3 |
| parent | 55fe34100f8b516480cf530eb58d00ea8b665765 |
15 files changed, 194 insertions(+), 90 deletions(-)
src/AstGen.zig+2-1| ... | ... | @@ -1729,7 +1729,7 @@ fn structInitExprRlPtrInner( |
| 1729 | 1729 | for (struct_init.ast.fields) |field_init| { |
| 1730 | 1730 | const name_token = tree.firstToken(field_init) - 2; |
| 1731 | 1731 | const str_index = try astgen.identAsString(name_token); |
| 1732 | const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{ | |
| 1732 | const field_ptr = try gz.addPlNode(.field_ptr_init, field_init, Zir.Inst.Field{ | |
| 1733 | 1733 | .lhs = result_ptr, |
| 1734 | 1734 | .field_name_start = str_index, |
| 1735 | 1735 | }); |
| ... | ... | @@ -2287,6 +2287,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2287 | 2287 | .elem_ptr_imm, |
| 2288 | 2288 | .elem_val_node, |
| 2289 | 2289 | .field_ptr, |
| 2290 | .field_ptr_init, | |
| 2290 | 2291 | .field_val, |
| 2291 | 2292 | .field_call_bind, |
| 2292 | 2293 | .field_ptr_named, |
src/Module.zig+1-1| ... | ... | @@ -787,7 +787,7 @@ pub const Decl = struct { |
| 787 | 787 | const opaque_obj = ty.cast(Type.Payload.Opaque).?.data; |
| 788 | 788 | return &opaque_obj.namespace; |
| 789 | 789 | }, |
| 790 | .@"union", .union_tagged => { | |
| 790 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 791 | 791 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 792 | 792 | return &union_obj.namespace; |
| 793 | 793 | }, |
src/Sema.zig+90-41| ... | ... | @@ -739,7 +739,8 @@ fn analyzeBodyInner( |
| 739 | 739 | .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false), |
| 740 | 740 | .error_union_type => try sema.zirErrorUnionType(block, inst), |
| 741 | 741 | .error_value => try sema.zirErrorValue(block, inst), |
| 742 | .field_ptr => try sema.zirFieldPtr(block, inst), | |
| 742 | .field_ptr => try sema.zirFieldPtr(block, inst, false), | |
| 743 | .field_ptr_init => try sema.zirFieldPtr(block, inst, true), | |
| 743 | 744 | .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), |
| 744 | 745 | .field_val => try sema.zirFieldVal(block, inst), |
| 745 | 746 | .field_val_named => try sema.zirFieldValNamed(block, inst), |
| ... | ... | @@ -1547,11 +1548,11 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) |
| 1547 | 1548 | const st_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty)); |
| 1548 | 1549 | |
| 1549 | 1550 | // st.instruction_addresses = &addrs; |
| 1550 | const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src); | |
| 1551 | const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src, true); | |
| 1551 | 1552 | try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store); |
| 1552 | 1553 | |
| 1553 | 1554 | // st.index = 0; |
| 1554 | const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src); | |
| 1555 | const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true); | |
| 1555 | 1556 | const zero = try sema.addConstant(Type.usize, Value.zero); |
| 1556 | 1557 | try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, zero, src, .store); |
| 1557 | 1558 | |
| ... | ... | @@ -2614,7 +2615,14 @@ fn zirUnionDecl( |
| 2614 | 2615 | const new_decl_arena_allocator = new_decl_arena.allocator(); |
| 2615 | 2616 | |
| 2616 | 2617 | const union_obj = try new_decl_arena_allocator.create(Module.Union); |
| 2617 | const type_tag: Type.Tag = if (small.has_tag_type or small.auto_enum_tag) .union_tagged else .@"union"; | |
| 2618 | const type_tag = if (small.has_tag_type or small.auto_enum_tag) | |
| 2619 | Type.Tag.union_tagged | |
| 2620 | else if (small.layout != .Auto) | |
| 2621 | Type.Tag.@"union" | |
| 2622 | else switch (block.sema.mod.optimizeMode()) { | |
| 2623 | .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged, | |
| 2624 | .ReleaseFast, .ReleaseSmall => Type.Tag.@"union", | |
| 2625 | }; | |
| 2618 | 2626 | const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union); |
| 2619 | 2627 | union_payload.* = .{ |
| 2620 | 2628 | .base = .{ .tag = type_tag }, |
| ... | ... | @@ -7923,7 +7931,7 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 7923 | 7931 | return sema.fieldVal(block, src, object, field_name, field_name_src); |
| 7924 | 7932 | } |
| 7925 | 7933 | |
| 7926 | fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 7934 | fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: bool) CompileError!Air.Inst.Ref { | |
| 7927 | 7935 | const tracy = trace(@src()); |
| 7928 | 7936 | defer tracy.end(); |
| 7929 | 7937 | |
| ... | ... | @@ -7933,7 +7941,7 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 7933 | 7941 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 7934 | 7942 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); |
| 7935 | 7943 | const object_ptr = try sema.resolveInst(extra.lhs); |
| 7936 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src); | |
| 7944 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing); | |
| 7937 | 7945 | } |
| 7938 | 7946 | |
| 7939 | 7947 | fn zirFieldCallBind(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -7972,7 +7980,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 7972 | 7980 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; |
| 7973 | 7981 | const object_ptr = try sema.resolveInst(extra.lhs); |
| 7974 | 7982 | const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known"); |
| 7975 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src); | |
| 7983 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false); | |
| 7976 | 7984 | } |
| 7977 | 7985 | |
| 7978 | 7986 | fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -14536,7 +14544,7 @@ fn zirStructInit( |
| 14536 | 14544 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 14537 | 14545 | }); |
| 14538 | 14546 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 14539 | const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty); | |
| 14547 | const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true); | |
| 14540 | 14548 | try sema.storePtr(block, src, field_ptr, init_inst); |
| 14541 | 14549 | const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val); |
| 14542 | 14550 | _ = try block.addBinOp(.set_union_tag, alloc, new_tag); |
| ... | ... | @@ -15604,13 +15612,21 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15604 | 15612 | if (decls_val.sliceLen(mod) > 0) { |
| 15605 | 15613 | return sema.fail(block, src, "reified unions must have no decls", .{}); |
| 15606 | 15614 | } |
| 15615 | const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout); | |
| 15607 | 15616 | |
| 15608 | 15617 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); |
| 15609 | 15618 | errdefer new_decl_arena.deinit(); |
| 15610 | 15619 | const new_decl_arena_allocator = new_decl_arena.allocator(); |
| 15611 | 15620 | |
| 15612 | 15621 | const union_obj = try new_decl_arena_allocator.create(Module.Union); |
| 15613 | const type_tag: Type.Tag = if (!tag_type_val.isNull()) .union_tagged else .@"union"; | |
| 15622 | const type_tag = if (!tag_type_val.isNull()) | |
| 15623 | Type.Tag.union_tagged | |
| 15624 | else if (layout != .Auto) | |
| 15625 | Type.Tag.@"union" | |
| 15626 | else switch (block.sema.mod.optimizeMode()) { | |
| 15627 | .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged, | |
| 15628 | .ReleaseFast, .ReleaseSmall => Type.Tag.@"union", | |
| 15629 | }; | |
| 15614 | 15630 | const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union); |
| 15615 | 15631 | union_payload.* = .{ |
| 15616 | 15632 | .base = .{ .tag = type_tag }, |
| ... | ... | @@ -15631,7 +15647,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15631 | 15647 | .fields = .{}, |
| 15632 | 15648 | .node_offset = src.node_offset.x, |
| 15633 | 15649 | .zir_index = inst, |
| 15634 | .layout = layout_val.toEnum(std.builtin.Type.ContainerLayout), | |
| 15650 | .layout = layout, | |
| 15635 | 15651 | .status = .have_field_types, |
| 15636 | 15652 | .namespace = .{ |
| 15637 | 15653 | .parent = block.namespace, |
| ... | ... | @@ -15641,11 +15657,15 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15641 | 15657 | }; |
| 15642 | 15658 | |
| 15643 | 15659 | // Tag type |
| 15660 | var enum_field_names: ?*Module.EnumNumbered.NameMap = null; | |
| 15644 | 15661 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); |
| 15645 | union_obj.tag_ty = if (tag_type_val.optionalValue()) |payload_val| blk: { | |
| 15662 | if (tag_type_val.optionalValue()) |payload_val| { | |
| 15646 | 15663 | var buffer: Value.ToTypeBuffer = undefined; |
| 15647 | break :blk try payload_val.toType(&buffer).copy(new_decl_arena_allocator); | |
| 15648 | } else try sema.generateUnionTagTypeSimple(block, fields_len, null); | |
| 15664 | union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator); | |
| 15665 | } else { | |
| 15666 | union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null); | |
| 15667 | enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; | |
| 15668 | } | |
| 15649 | 15669 | |
| 15650 | 15670 | // Fields |
| 15651 | 15671 | if (fields_len > 0) { |
| ... | ... | @@ -15669,6 +15689,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15669 | 15689 | sema.mod, |
| 15670 | 15690 | ); |
| 15671 | 15691 | |
| 15692 | if (enum_field_names) |set| { | |
| 15693 | set.putAssumeCapacity(field_name, {}); | |
| 15694 | } | |
| 15695 | ||
| 15672 | 15696 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 15673 | 15697 | if (gop.found_existing) { |
| 15674 | 15698 | // TODO: better source location |
| ... | ... | @@ -18898,6 +18922,8 @@ pub const PanicId = enum { |
| 18898 | 18922 | divide_by_zero, |
| 18899 | 18923 | remainder_division_zero_negative, |
| 18900 | 18924 | exact_division_remainder, |
| 18925 | /// TODO make this call `std.builtin.panicInactiveUnionField`. | |
| 18926 | inactive_union_field, | |
| 18901 | 18927 | }; |
| 18902 | 18928 | |
| 18903 | 18929 | fn addSafetyCheck( |
| ... | ... | @@ -19120,6 +19146,7 @@ fn safetyPanic( |
| 19120 | 19146 | .divide_by_zero => "division by zero", |
| 19121 | 19147 | .remainder_division_zero_negative => "remainder division by zero or negative value", |
| 19122 | 19148 | .exact_division_remainder => "exact division produced remainder", |
| 19149 | .inactive_union_field => "access of inactive union field", | |
| 19123 | 19150 | }; |
| 19124 | 19151 | |
| 19125 | 19152 | const msg_inst = msg_inst: { |
| ... | ... | @@ -19339,7 +19366,7 @@ fn fieldVal( |
| 19339 | 19366 | }, |
| 19340 | 19367 | .Union => if (is_pointer_to) { |
| 19341 | 19368 | // Avoid loading the entire union by fetching a pointer and loading that |
| 19342 | const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty); | |
| 19369 | const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); | |
| 19343 | 19370 | return sema.analyzeLoad(block, src, field_ptr, object_src); |
| 19344 | 19371 | } else { |
| 19345 | 19372 | return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty); |
| ... | ... | @@ -19356,6 +19383,7 @@ fn fieldPtr( |
| 19356 | 19383 | object_ptr: Air.Inst.Ref, |
| 19357 | 19384 | field_name: []const u8, |
| 19358 | 19385 | field_name_src: LazySrcLoc, |
| 19386 | initializing: bool, | |
| 19359 | 19387 | ) CompileError!Air.Inst.Ref { |
| 19360 | 19388 | // When editing this function, note that there is corresponding logic to be edited |
| 19361 | 19389 | // in `fieldVal`. This function takes a pointer and returns a pointer. |
| ... | ... | @@ -19547,7 +19575,7 @@ fn fieldPtr( |
| 19547 | 19575 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) |
| 19548 | 19576 | else |
| 19549 | 19577 | object_ptr; |
| 19550 | return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty); | |
| 19578 | return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); | |
| 19551 | 19579 | }, |
| 19552 | 19580 | else => {}, |
| 19553 | 19581 | } |
| ... | ... | @@ -19995,6 +20023,7 @@ fn unionFieldPtr( |
| 19995 | 20023 | field_name: []const u8, |
| 19996 | 20024 | field_name_src: LazySrcLoc, |
| 19997 | 20025 | unresolved_union_ty: Type, |
| 20026 | initializing: bool, | |
| 19998 | 20027 | ) CompileError!Air.Inst.Ref { |
| 19999 | 20028 | const arena = sema.arena; |
| 20000 | 20029 | assert(unresolved_union_ty.zigTypeTag() == .Union); |
| ... | ... | @@ -20010,30 +20039,32 @@ fn unionFieldPtr( |
| 20010 | 20039 | .@"addrspace" = union_ptr_ty.ptrAddressSpace(), |
| 20011 | 20040 | }); |
| 20012 | 20041 | |
| 20013 | if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| { | |
| 20042 | if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: { | |
| 20014 | 20043 | switch (union_obj.layout) { |
| 20015 | .Auto => { | |
| 20016 | // TODO emit the access of inactive union field error commented out below. | |
| 20017 | // In order to do that, we need to first solve the problem that AstGen | |
| 20018 | // emits field_ptr instructions in order to initialize union values. | |
| 20019 | // In such case we need to know that the field_ptr instruction (which is | |
| 20020 | // calling this unionFieldPtr function) is *initializing* the union, | |
| 20021 | // in which case we would skip this check, and in fact we would actually | |
| 20022 | // set the union tag here and the payload to undefined. | |
| 20023 | ||
| 20024 | //const tag_and_val = union_val.castTag(.@"union").?.data; | |
| 20025 | //var field_tag_buf: Value.Payload.U32 = .{ | |
| 20026 | // .base = .{ .tag = .enum_field_index }, | |
| 20027 | // .data = field_index, | |
| 20028 | //}; | |
| 20029 | //const field_tag = Value.initPayload(&field_tag_buf.base); | |
| 20030 | //const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, mod); | |
| 20031 | //if (!tag_matches) { | |
| 20032 | // // TODO enhance this saying which one was active | |
| 20033 | // // and which one was accessed, and showing where the union was declared. | |
| 20034 | // return sema.fail(block, src, "access of inactive union field", .{}); | |
| 20035 | //} | |
| 20036 | // TODO add runtime safety check for the active tag | |
| 20044 | .Auto => if (!initializing) { | |
| 20045 | const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse | |
| 20046 | break :ct; | |
| 20047 | if (union_val.isUndef()) { | |
| 20048 | return sema.failWithUseOfUndef(block, src); | |
| 20049 | } | |
| 20050 | const tag_and_val = union_val.castTag(.@"union").?.data; | |
| 20051 | var field_tag_buf: Value.Payload.U32 = .{ | |
| 20052 | .base = .{ .tag = .enum_field_index }, | |
| 20053 | .data = field_index, | |
| 20054 | }; | |
| 20055 | const field_tag = Value.initPayload(&field_tag_buf.base); | |
| 20056 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); | |
| 20057 | if (!tag_matches) { | |
| 20058 | const msg = msg: { | |
| 20059 | const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; | |
| 20060 | const active_field_name = union_obj.fields.keys()[active_index]; | |
| 20061 | const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); | |
| 20062 | errdefer msg.destroy(sema.gpa); | |
| 20063 | try sema.addDeclaredHereNote(msg, union_ty); | |
| 20064 | break :msg msg; | |
| 20065 | }; | |
| 20066 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 20067 | } | |
| 20037 | 20068 | }, |
| 20038 | 20069 | .Packed, .Extern => {}, |
| 20039 | 20070 | } |
| ... | ... | @@ -20048,6 +20079,16 @@ fn unionFieldPtr( |
| 20048 | 20079 | } |
| 20049 | 20080 | |
| 20050 | 20081 | try sema.requireRuntimeBlock(block, src, null); |
| 20082 | if (!initializing and union_obj.layout == .Auto and block.wantSafety() and union_ty.unionTagTypeSafety() != null) { | |
| 20083 | const enum_ty = union_ty.unionTagTypeHypothetical(); | |
| 20084 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); | |
| 20085 | const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val); | |
| 20086 | // TODO would it be better if get_union_tag supported pointers to unions? | |
| 20087 | const union_val = try block.addTyOp(.load, union_ty, union_ptr); | |
| 20088 | const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_val); | |
| 20089 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); | |
| 20090 | try sema.addSafetyCheck(block, ok, .inactive_union_field); | |
| 20091 | } | |
| 20051 | 20092 | return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty); |
| 20052 | 20093 | } |
| 20053 | 20094 | |
| ... | ... | @@ -20106,6 +20147,14 @@ fn unionFieldVal( |
| 20106 | 20147 | } |
| 20107 | 20148 | |
| 20108 | 20149 | try sema.requireRuntimeBlock(block, src, null); |
| 20150 | if (union_obj.layout == .Auto and block.wantSafety() and union_ty.unionTagTypeSafety() != null) { | |
| 20151 | const enum_ty = union_ty.unionTagTypeHypothetical(); | |
| 20152 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); | |
| 20153 | const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val); | |
| 20154 | const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_byval); | |
| 20155 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); | |
| 20156 | try sema.addSafetyCheck(block, ok, .inactive_union_field); | |
| 20157 | } | |
| 20109 | 20158 | return block.addStructFieldVal(union_byval, field_index, field.ty); |
| 20110 | 20159 | } |
| 20111 | 20160 | |
| ... | ... | @@ -25424,7 +25473,7 @@ pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) |
| 25424 | 25473 | try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj); |
| 25425 | 25474 | return ty; |
| 25426 | 25475 | }, |
| 25427 | .@"union", .union_tagged => { | |
| 25476 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 25428 | 25477 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 25429 | 25478 | try sema.resolveTypeFieldsUnion(block, src, ty, union_obj); |
| 25430 | 25479 | return ty; |
| ... | ... | @@ -26449,7 +26498,7 @@ pub fn typeHasOnePossibleValue( |
| 26449 | 26498 | return null; |
| 26450 | 26499 | } |
| 26451 | 26500 | }, |
| 26452 | .@"union", .union_tagged => { | |
| 26501 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 26453 | 26502 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); |
| 26454 | 26503 | const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; |
| 26455 | 26504 | const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse |
| ... | ... | @@ -27081,7 +27130,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 27081 | 27130 | } |
| 27082 | 27131 | }, |
| 27083 | 27132 | |
| 27084 | .@"union", .union_tagged => { | |
| 27133 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 27085 | 27134 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 27086 | 27135 | switch (union_obj.requires_comptime) { |
| 27087 | 27136 | .no, .wip => return false, |
src/Zir.zig+5| ... | ... | @@ -410,6 +410,8 @@ pub const Inst = struct { |
| 410 | 410 | /// to the named field. The field name is stored in string_bytes. Used by a.b syntax. |
| 411 | 411 | /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. |
| 412 | 412 | field_ptr, |
| 413 | /// Same as `field_ptr` but used for struct init. | |
| 414 | field_ptr_init, | |
| 413 | 415 | /// Given a struct or object that contains virtual fields, returns the named field. |
| 414 | 416 | /// The field name is stored in string_bytes. Used by a.b syntax. |
| 415 | 417 | /// This instruction also accepts a pointer. |
| ... | ... | @@ -1070,6 +1072,7 @@ pub const Inst = struct { |
| 1070 | 1072 | .@"export", |
| 1071 | 1073 | .export_value, |
| 1072 | 1074 | .field_ptr, |
| 1075 | .field_ptr_init, | |
| 1073 | 1076 | .field_val, |
| 1074 | 1077 | .field_call_bind, |
| 1075 | 1078 | .field_ptr_named, |
| ... | ... | @@ -1370,6 +1373,7 @@ pub const Inst = struct { |
| 1370 | 1373 | .elem_ptr_imm, |
| 1371 | 1374 | .elem_val_node, |
| 1372 | 1375 | .field_ptr, |
| 1376 | .field_ptr_init, | |
| 1373 | 1377 | .field_val, |
| 1374 | 1378 | .field_call_bind, |
| 1375 | 1379 | .field_ptr_named, |
| ... | ... | @@ -1629,6 +1633,7 @@ pub const Inst = struct { |
| 1629 | 1633 | .@"export" = .pl_node, |
| 1630 | 1634 | .export_value = .pl_node, |
| 1631 | 1635 | .field_ptr = .pl_node, |
| 1636 | .field_ptr_init = .pl_node, | |
| 1632 | 1637 | .field_val = .pl_node, |
| 1633 | 1638 | .field_ptr_named = .pl_node, |
| 1634 | 1639 | .field_val_named = .pl_node, |
src/arch/wasm/abi.zig+2-2| ... | ... | @@ -77,7 +77,7 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 77 | 77 | .Union => { |
| 78 | 78 | const layout = ty.unionGetLayout(target); |
| 79 | 79 | if (layout.payload_size == 0 and layout.tag_size != 0) { |
| 80 | return classifyType(ty.unionTagType().?, target); | |
| 80 | return classifyType(ty.unionTagTypeSafety().?, target); | |
| 81 | 81 | } |
| 82 | 82 | if (ty.unionFields().count() > 1) return memory; |
| 83 | 83 | return classifyType(ty.unionFields().values()[0].ty, target); |
| ... | ... | @@ -111,7 +111,7 @@ pub fn scalarType(ty: Type, target: std.Target) Type { |
| 111 | 111 | .Union => { |
| 112 | 112 | const layout = ty.unionGetLayout(target); |
| 113 | 113 | if (layout.payload_size == 0 and layout.tag_size != 0) { |
| 114 | return scalarType(ty.unionTagType().?, target); | |
| 114 | return scalarType(ty.unionTagTypeSafety().?, target); | |
| 115 | 115 | } |
| 116 | 116 | std.debug.assert(ty.unionFields().count() == 1); |
| 117 | 117 | return scalarType(ty.unionFields().values()[0].ty, target); |
src/codegen/c.zig+9-9| ... | ... | @@ -504,7 +504,7 @@ pub const DeclGen = struct { |
| 504 | 504 | if (field_ty.hasRuntimeBitsIgnoreComptime()) { |
| 505 | 505 | try writer.writeAll("&("); |
| 506 | 506 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); |
| 507 | if (field_ptr.container_ty.tag() == .union_tagged) { | |
| 507 | if (field_ptr.container_ty.tag() == .union_tagged or field_ptr.container_ty.tag() == .union_safety_tagged) { | |
| 508 | 508 | try writer.print(")->payload.{ }", .{fmtIdent(field_name)}); |
| 509 | 509 | } else { |
| 510 | 510 | try writer.print(")->{ }", .{fmtIdent(field_name)}); |
| ... | ... | @@ -842,7 +842,7 @@ pub const DeclGen = struct { |
| 842 | 842 | try dg.renderTypecast(writer, ty); |
| 843 | 843 | try writer.writeAll("){"); |
| 844 | 844 | |
| 845 | if (ty.unionTagType()) |tag_ty| { | |
| 845 | if (ty.unionTagTypeSafety()) |tag_ty| { | |
| 846 | 846 | if (layout.tag_size != 0) { |
| 847 | 847 | try writer.writeAll(".tag = "); |
| 848 | 848 | try dg.renderValue(writer, tag_ty, union_obj.tag, location); |
| ... | ... | @@ -858,7 +858,7 @@ pub const DeclGen = struct { |
| 858 | 858 | try writer.print(".{ } = ", .{fmtIdent(field_name)}); |
| 859 | 859 | try dg.renderValue(writer, field_ty, union_obj.val, location); |
| 860 | 860 | } |
| 861 | if (ty.unionTagType()) |_| { | |
| 861 | if (ty.unionTagTypeSafety()) |_| { | |
| 862 | 862 | try writer.writeAll("}"); |
| 863 | 863 | } |
| 864 | 864 | try writer.writeAll("}"); |
| ... | ... | @@ -1110,7 +1110,7 @@ pub const DeclGen = struct { |
| 1110 | 1110 | defer buffer.deinit(); |
| 1111 | 1111 | |
| 1112 | 1112 | try buffer.appendSlice("typedef "); |
| 1113 | if (t.unionTagType()) |tag_ty| { | |
| 1113 | if (t.unionTagTypeSafety()) |tag_ty| { | |
| 1114 | 1114 | const name: CValue = .{ .bytes = "tag" }; |
| 1115 | 1115 | try buffer.appendSlice("struct {\n "); |
| 1116 | 1116 | if (layout.tag_size != 0) { |
| ... | ... | @@ -1134,7 +1134,7 @@ pub const DeclGen = struct { |
| 1134 | 1134 | } |
| 1135 | 1135 | try buffer.appendSlice("} "); |
| 1136 | 1136 | |
| 1137 | if (t.unionTagType()) |_| { | |
| 1137 | if (t.unionTagTypeSafety()) |_| { | |
| 1138 | 1138 | try buffer.appendSlice("payload;\n} "); |
| 1139 | 1139 | } |
| 1140 | 1140 | |
| ... | ... | @@ -3368,7 +3368,7 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 3368 | 3368 | field_name = fields.keys()[index]; |
| 3369 | 3369 | field_val_ty = fields.values()[index].ty; |
| 3370 | 3370 | }, |
| 3371 | .@"union", .union_tagged => { | |
| 3371 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 3372 | 3372 | const fields = struct_ty.unionFields(); |
| 3373 | 3373 | field_name = fields.keys()[index]; |
| 3374 | 3374 | field_val_ty = fields.values()[index].ty; |
| ... | ... | @@ -3383,7 +3383,7 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 3383 | 3383 | }, |
| 3384 | 3384 | else => unreachable, |
| 3385 | 3385 | } |
| 3386 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; | |
| 3386 | const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; | |
| 3387 | 3387 | |
| 3388 | 3388 | const inst_ty = f.air.typeOfIndex(inst); |
| 3389 | 3389 | const local = try f.allocLocal(inst_ty, .Const); |
| ... | ... | @@ -3415,7 +3415,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3415 | 3415 | defer buf.deinit(); |
| 3416 | 3416 | const field_name = switch (struct_ty.tag()) { |
| 3417 | 3417 | .@"struct" => struct_ty.structFields().keys()[extra.field_index], |
| 3418 | .@"union", .union_tagged => struct_ty.unionFields().keys()[extra.field_index], | |
| 3418 | .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index], | |
| 3419 | 3419 | .tuple, .anon_struct => blk: { |
| 3420 | 3420 | const tuple = struct_ty.tupleFields(); |
| 3421 | 3421 | if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none; |
| ... | ... | @@ -3425,7 +3425,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3425 | 3425 | }, |
| 3426 | 3426 | else => unreachable, |
| 3427 | 3427 | }; |
| 3428 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; | |
| 3428 | const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; | |
| 3429 | 3429 | |
| 3430 | 3430 | const inst_ty = f.air.typeOfIndex(inst); |
| 3431 | 3431 | const local = try f.allocLocal(inst_ty, .Const); |
src/codegen/llvm.zig+2-2| ... | ... | @@ -3404,7 +3404,7 @@ pub const DeclGen = struct { |
| 3404 | 3404 | |
| 3405 | 3405 | if (layout.payload_size == 0) { |
| 3406 | 3406 | return lowerValue(dg, .{ |
| 3407 | .ty = tv.ty.unionTagType().?, | |
| 3407 | .ty = tv.ty.unionTagTypeSafety().?, | |
| 3408 | 3408 | .val = tag_and_val.tag, |
| 3409 | 3409 | }); |
| 3410 | 3410 | } |
| ... | ... | @@ -3446,7 +3446,7 @@ pub const DeclGen = struct { |
| 3446 | 3446 | } |
| 3447 | 3447 | } |
| 3448 | 3448 | const llvm_tag_value = try lowerValue(dg, .{ |
| 3449 | .ty = tv.ty.unionTagType().?, | |
| 3449 | .ty = tv.ty.unionTagTypeSafety().?, | |
| 3450 | 3450 | .val = tag_and_val.tag, |
| 3451 | 3451 | }); |
| 3452 | 3452 | var fields: [3]*const llvm.Value = undefined; |
src/print_zir.zig+1| ... | ... | @@ -390,6 +390,7 @@ const Writer = struct { |
| 390 | 390 | .switch_block => try self.writeSwitchBlock(stream, inst), |
| 391 | 391 | |
| 392 | 392 | .field_ptr, |
| 393 | .field_ptr_init, | |
| 393 | 394 | .field_val, |
| 394 | 395 | .field_call_bind, |
| 395 | 396 | => try self.writePlNodeField(stream, inst), |
src/type.zig+56-27| ... | ... | @@ -149,6 +149,7 @@ pub const Type = extern union { |
| 149 | 149 | => return .Enum, |
| 150 | 150 | |
| 151 | 151 | .@"union", |
| 152 | .union_safety_tagged, | |
| 152 | 153 | .union_tagged, |
| 153 | 154 | .type_info, |
| 154 | 155 | => return .Union, |
| ... | ... | @@ -902,7 +903,7 @@ pub const Type = extern union { |
| 902 | 903 | .reduce_op, |
| 903 | 904 | => unreachable, // needed to resolve the type before now |
| 904 | 905 | |
| 905 | .@"union", .union_tagged => { | |
| 906 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 906 | 907 | const a_union_obj = a.cast(Payload.Union).?.data; |
| 907 | 908 | const b_union_obj = (b.cast(Payload.Union) orelse return false).data; |
| 908 | 909 | return a_union_obj == b_union_obj; |
| ... | ... | @@ -1210,7 +1211,7 @@ pub const Type = extern union { |
| 1210 | 1211 | .reduce_op, |
| 1211 | 1212 | => unreachable, // needed to resolve the type before now |
| 1212 | 1213 | |
| 1213 | .@"union", .union_tagged => { | |
| 1214 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 1214 | 1215 | const union_obj: *const Module.Union = ty.cast(Payload.Union).?.data; |
| 1215 | 1216 | std.hash.autoHash(hasher, std.builtin.TypeId.Union); |
| 1216 | 1217 | std.hash.autoHash(hasher, union_obj); |
| ... | ... | @@ -1479,7 +1480,7 @@ pub const Type = extern union { |
| 1479 | 1480 | .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name), |
| 1480 | 1481 | .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope), |
| 1481 | 1482 | .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct), |
| 1482 | .@"union", .union_tagged => return self.copyPayloadShallow(allocator, Payload.Union), | |
| 1483 | .@"union", .union_safety_tagged, .union_tagged => return self.copyPayloadShallow(allocator, Payload.Union), | |
| 1483 | 1484 | .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple), |
| 1484 | 1485 | .enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered), |
| 1485 | 1486 | .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull), |
| ... | ... | @@ -1603,7 +1604,7 @@ pub const Type = extern union { |
| 1603 | 1604 | @tagName(t), struct_obj.owner_decl, |
| 1604 | 1605 | }); |
| 1605 | 1606 | }, |
| 1606 | .@"union", .union_tagged => { | |
| 1607 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 1607 | 1608 | const union_obj = ty.cast(Payload.Union).?.data; |
| 1608 | 1609 | return writer.print("({s} decl={d})", .{ |
| 1609 | 1610 | @tagName(t), union_obj.owner_decl, |
| ... | ... | @@ -1989,7 +1990,7 @@ pub const Type = extern union { |
| 1989 | 1990 | const decl = mod.declPtr(struct_obj.owner_decl); |
| 1990 | 1991 | try decl.renderFullyQualifiedName(mod, writer); |
| 1991 | 1992 | }, |
| 1992 | .@"union", .union_tagged => { | |
| 1993 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 1993 | 1994 | const union_obj = ty.cast(Payload.Union).?.data; |
| 1994 | 1995 | const decl = mod.declPtr(union_obj.owner_decl); |
| 1995 | 1996 | try decl.renderFullyQualifiedName(mod, writer); |
| ... | ... | @@ -2485,8 +2486,8 @@ pub const Type = extern union { |
| 2485 | 2486 | return false; |
| 2486 | 2487 | } |
| 2487 | 2488 | }, |
| 2488 | .union_tagged => { | |
| 2489 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 2489 | .union_safety_tagged, .union_tagged => { | |
| 2490 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 2490 | 2491 | if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) { |
| 2491 | 2492 | return true; |
| 2492 | 2493 | } |
| ... | ... | @@ -2644,7 +2645,7 @@ pub const Type = extern union { |
| 2644 | 2645 | |
| 2645 | 2646 | .optional => ty.isPtrLikeOptional(), |
| 2646 | 2647 | .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto, |
| 2647 | .@"union" => ty.castTag(.@"union").?.data.layout != .Auto, | |
| 2648 | .@"union", .union_safety_tagged => ty.cast(Payload.Union).?.data.layout != .Auto, | |
| 2648 | 2649 | .union_tagged => false, |
| 2649 | 2650 | }; |
| 2650 | 2651 | } |
| ... | ... | @@ -3050,11 +3051,10 @@ pub const Type = extern union { |
| 3050 | 3051 | }, |
| 3051 | 3052 | .@"union" => { |
| 3052 | 3053 | const union_obj = ty.castTag(.@"union").?.data; |
| 3053 | // TODO pass `true` for have_tag when unions have a safety tag | |
| 3054 | 3054 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, false); |
| 3055 | 3055 | }, |
| 3056 | .union_tagged => { | |
| 3057 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 3056 | .union_safety_tagged, .union_tagged => { | |
| 3057 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 3058 | 3058 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, true); |
| 3059 | 3059 | }, |
| 3060 | 3060 | |
| ... | ... | @@ -3232,11 +3232,10 @@ pub const Type = extern union { |
| 3232 | 3232 | }, |
| 3233 | 3233 | .@"union" => { |
| 3234 | 3234 | const union_obj = ty.castTag(.@"union").?.data; |
| 3235 | // TODO pass `true` for have_tag when unions have a safety tag | |
| 3236 | 3235 | return abiSizeAdvancedUnion(ty, target, strat, union_obj, false); |
| 3237 | 3236 | }, |
| 3238 | .union_tagged => { | |
| 3239 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 3237 | .union_safety_tagged, .union_tagged => { | |
| 3238 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 3240 | 3239 | return abiSizeAdvancedUnion(ty, target, strat, union_obj, true); |
| 3241 | 3240 | }, |
| 3242 | 3241 | |
| ... | ... | @@ -3526,7 +3525,7 @@ pub const Type = extern union { |
| 3526 | 3525 | return try bitSizeAdvanced(int_tag_ty, target, sema_kit); |
| 3527 | 3526 | }, |
| 3528 | 3527 | |
| 3529 | .@"union", .union_tagged => { | |
| 3528 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 3530 | 3529 | if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); |
| 3531 | 3530 | const union_obj = ty.cast(Payload.Union).?.data; |
| 3532 | 3531 | assert(union_obj.haveFieldTypes()); |
| ... | ... | @@ -4194,6 +4193,33 @@ pub const Type = extern union { |
| 4194 | 4193 | }; |
| 4195 | 4194 | } |
| 4196 | 4195 | |
| 4196 | /// Same as `unionTagType` but includes safety tag. | |
| 4197 | /// Codegen should use this version. | |
| 4198 | pub fn unionTagTypeSafety(ty: Type) ?Type { | |
| 4199 | return switch (ty.tag()) { | |
| 4200 | .union_safety_tagged, .union_tagged => { | |
| 4201 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 4202 | assert(union_obj.haveFieldTypes()); | |
| 4203 | return union_obj.tag_ty; | |
| 4204 | }, | |
| 4205 | ||
| 4206 | .atomic_order, | |
| 4207 | .atomic_rmw_op, | |
| 4208 | .calling_convention, | |
| 4209 | .address_space, | |
| 4210 | .float_mode, | |
| 4211 | .reduce_op, | |
| 4212 | .call_options, | |
| 4213 | .prefetch_options, | |
| 4214 | .export_options, | |
| 4215 | .extern_options, | |
| 4216 | .type_info, | |
| 4217 | => unreachable, // needed to call resolveTypeFields first | |
| 4218 | ||
| 4219 | else => null, | |
| 4220 | }; | |
| 4221 | } | |
| 4222 | ||
| 4197 | 4223 | /// Asserts the type is a union; returns the tag type, even if the tag will |
| 4198 | 4224 | /// not be stored at runtime. |
| 4199 | 4225 | pub fn unionTagTypeHypothetical(ty: Type) Type { |
| ... | ... | @@ -4225,8 +4251,8 @@ pub const Type = extern union { |
| 4225 | 4251 | const union_obj = ty.castTag(.@"union").?.data; |
| 4226 | 4252 | return union_obj.getLayout(target, false); |
| 4227 | 4253 | }, |
| 4228 | .union_tagged => { | |
| 4229 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 4254 | .union_safety_tagged, .union_tagged => { | |
| 4255 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 4230 | 4256 | return union_obj.getLayout(target, true); |
| 4231 | 4257 | }, |
| 4232 | 4258 | else => unreachable, |
| ... | ... | @@ -4238,6 +4264,7 @@ pub const Type = extern union { |
| 4238 | 4264 | .tuple, .empty_struct_literal, .anon_struct => .Auto, |
| 4239 | 4265 | .@"struct" => ty.castTag(.@"struct").?.data.layout, |
| 4240 | 4266 | .@"union" => ty.castTag(.@"union").?.data.layout, |
| 4267 | .union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.layout, | |
| 4241 | 4268 | .union_tagged => ty.castTag(.union_tagged).?.data.layout, |
| 4242 | 4269 | else => unreachable, |
| 4243 | 4270 | }; |
| ... | ... | @@ -4936,7 +4963,7 @@ pub const Type = extern union { |
| 4936 | 4963 | return null; |
| 4937 | 4964 | } |
| 4938 | 4965 | }, |
| 4939 | .@"union", .union_tagged => { | |
| 4966 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 4940 | 4967 | const union_obj = ty.cast(Payload.Union).?.data; |
| 4941 | 4968 | const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null; |
| 4942 | 4969 | const only_field = union_obj.fields.values()[0]; |
| ... | ... | @@ -5114,7 +5141,7 @@ pub const Type = extern union { |
| 5114 | 5141 | } |
| 5115 | 5142 | }, |
| 5116 | 5143 | |
| 5117 | .@"union", .union_tagged => { | |
| 5144 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5118 | 5145 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 5119 | 5146 | switch (union_obj.requires_comptime) { |
| 5120 | 5147 | .wip, .unknown => unreachable, // This function asserts types already resolved. |
| ... | ... | @@ -5167,6 +5194,7 @@ pub const Type = extern union { |
| 5167 | 5194 | .empty_struct => self.castTag(.empty_struct).?.data, |
| 5168 | 5195 | .@"opaque" => &self.castTag(.@"opaque").?.data.namespace, |
| 5169 | 5196 | .@"union" => &self.castTag(.@"union").?.data.namespace, |
| 5197 | .union_safety_tagged => &self.castTag(.union_safety_tagged).?.data.namespace, | |
| 5170 | 5198 | .union_tagged => &self.castTag(.union_tagged).?.data.namespace, |
| 5171 | 5199 | |
| 5172 | 5200 | else => null, |
| ... | ... | @@ -5439,7 +5467,7 @@ pub const Type = extern union { |
| 5439 | 5467 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 5440 | 5468 | return struct_obj.fields.values()[index].ty; |
| 5441 | 5469 | }, |
| 5442 | .@"union", .union_tagged => { | |
| 5470 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5443 | 5471 | const union_obj = ty.cast(Payload.Union).?.data; |
| 5444 | 5472 | return union_obj.fields.values()[index].ty; |
| 5445 | 5473 | }, |
| ... | ... | @@ -5456,7 +5484,7 @@ pub const Type = extern union { |
| 5456 | 5484 | assert(struct_obj.layout != .Packed); |
| 5457 | 5485 | return struct_obj.fields.values()[index].normalAlignment(target); |
| 5458 | 5486 | }, |
| 5459 | .@"union", .union_tagged => { | |
| 5487 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5460 | 5488 | const union_obj = ty.cast(Payload.Union).?.data; |
| 5461 | 5489 | return union_obj.fields.values()[index].normalAlignment(target); |
| 5462 | 5490 | }, |
| ... | ... | @@ -5619,8 +5647,8 @@ pub const Type = extern union { |
| 5619 | 5647 | }, |
| 5620 | 5648 | |
| 5621 | 5649 | .@"union" => return 0, |
| 5622 | .union_tagged => { | |
| 5623 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 5650 | .union_safety_tagged, .union_tagged => { | |
| 5651 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 5624 | 5652 | const layout = union_obj.getLayout(target, true); |
| 5625 | 5653 | if (layout.tag_align >= layout.payload_align) { |
| 5626 | 5654 | // {Tag, Payload} |
| ... | ... | @@ -5660,7 +5688,7 @@ pub const Type = extern union { |
| 5660 | 5688 | const error_set = ty.castTag(.error_set).?.data; |
| 5661 | 5689 | return error_set.srcLoc(mod); |
| 5662 | 5690 | }, |
| 5663 | .@"union", .union_tagged => { | |
| 5691 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5664 | 5692 | const union_obj = ty.cast(Payload.Union).?.data; |
| 5665 | 5693 | return union_obj.srcLoc(mod); |
| 5666 | 5694 | }, |
| ... | ... | @@ -5704,7 +5732,7 @@ pub const Type = extern union { |
| 5704 | 5732 | const error_set = ty.castTag(.error_set).?.data; |
| 5705 | 5733 | return error_set.owner_decl; |
| 5706 | 5734 | }, |
| 5707 | .@"union", .union_tagged => { | |
| 5735 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5708 | 5736 | const union_obj = ty.cast(Payload.Union).?.data; |
| 5709 | 5737 | return union_obj.owner_decl; |
| 5710 | 5738 | }, |
| ... | ... | @@ -5748,7 +5776,7 @@ pub const Type = extern union { |
| 5748 | 5776 | const error_set = ty.castTag(.error_set).?.data; |
| 5749 | 5777 | return error_set.node_offset; |
| 5750 | 5778 | }, |
| 5751 | .@"union", .union_tagged => { | |
| 5779 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5752 | 5780 | const union_obj = ty.cast(Payload.Union).?.data; |
| 5753 | 5781 | return union_obj.node_offset; |
| 5754 | 5782 | }, |
| ... | ... | @@ -5893,6 +5921,7 @@ pub const Type = extern union { |
| 5893 | 5921 | @"opaque", |
| 5894 | 5922 | @"struct", |
| 5895 | 5923 | @"union", |
| 5924 | union_safety_tagged, | |
| 5896 | 5925 | union_tagged, |
| 5897 | 5926 | enum_simple, |
| 5898 | 5927 | enum_numbered, |
| ... | ... | @@ -6009,7 +6038,7 @@ pub const Type = extern union { |
| 6009 | 6038 | .error_set_single => Payload.Name, |
| 6010 | 6039 | .@"opaque" => Payload.Opaque, |
| 6011 | 6040 | .@"struct" => Payload.Struct, |
| 6012 | .@"union", .union_tagged => Payload.Union, | |
| 6041 | .@"union", .union_safety_tagged, .union_tagged => Payload.Union, | |
| 6013 | 6042 | .enum_full, .enum_nonexhaustive => Payload.EnumFull, |
| 6014 | 6043 | .enum_simple => Payload.EnumSimple, |
| 6015 | 6044 | .enum_numbered => Payload.EnumNumbered, |
test/behavior/bugs/1381.zig+2| ... | ... | @@ -12,8 +12,10 @@ const A = union(enum) { |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | 14 | test "union that needs padding bytes inside an array" { |
| 15 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 15 | 16 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 16 | 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 18 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 17 | 19 | |
| 18 | 20 | var as = [_]A{ |
| 19 | 21 | A{ .B = B{ .D = 1 } }, |
test/behavior/struct.zig+3| ... | ... | @@ -998,6 +998,9 @@ test "tuple element initialized with fn call" { |
| 998 | 998 | } |
| 999 | 999 | |
| 1000 | 1000 | test "struct with union field" { |
| 1001 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1002 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1003 | ||
| 1001 | 1004 | const Value = struct { |
| 1002 | 1005 | ref: u32 = 2, |
| 1003 | 1006 | kind: union(enum) { |
test/behavior/type.zig+1-1| ... | ... | @@ -412,7 +412,7 @@ test "Type.Union" { |
| 412 | 412 | |
| 413 | 413 | const Untagged = @Type(.{ |
| 414 | 414 | .Union = .{ |
| 415 | .layout = .Auto, | |
| 415 | .layout = .Extern, | |
| 416 | 416 | .tag_type = null, |
| 417 | 417 | .fields = &.{ |
| 418 | 418 | .{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) }, |
test/behavior/union.zig+13| ... | ... | @@ -37,6 +37,7 @@ test "init union with runtime value - floats" { |
| 37 | 37 | |
| 38 | 38 | test "basic unions" { |
| 39 | 39 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 40 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 40 | 41 | |
| 41 | 42 | var foo = Foo{ .int = 1 }; |
| 42 | 43 | try expect(foo.int == 1); |
| ... | ... | @@ -430,9 +431,11 @@ const Foo1 = union(enum) { |
| 430 | 431 | var glbl: Foo1 = undefined; |
| 431 | 432 | |
| 432 | 433 | test "global union with single field is correctly initialized" { |
| 434 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 433 | 435 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 434 | 436 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 435 | 437 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 438 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 436 | 439 | |
| 437 | 440 | glbl = Foo1{ |
| 438 | 441 | .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 }, |
| ... | ... | @@ -473,8 +476,11 @@ test "update the tag value for zero-sized unions" { |
| 473 | 476 | } |
| 474 | 477 | |
| 475 | 478 | test "union initializer generates padding only if needed" { |
| 479 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 476 | 480 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 481 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 477 | 482 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 483 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 478 | 484 | |
| 479 | 485 | const U = union(enum) { |
| 480 | 486 | A: u24, |
| ... | ... | @@ -747,9 +753,11 @@ fn Setter(attr: Attribute) type { |
| 747 | 753 | } |
| 748 | 754 | |
| 749 | 755 | test "return union init with void payload" { |
| 756 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 750 | 757 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 751 | 758 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 752 | 759 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 760 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 753 | 761 | |
| 754 | 762 | const S = struct { |
| 755 | 763 | fn entry() !void { |
| ... | ... | @@ -775,6 +783,7 @@ test "@unionInit stored to a const" { |
| 775 | 783 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 776 | 784 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 777 | 785 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 786 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 778 | 787 | |
| 779 | 788 | const S = struct { |
| 780 | 789 | const U = union(enum) { |
| ... | ... | @@ -937,6 +946,7 @@ test "cast from anonymous struct to union" { |
| 937 | 946 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 938 | 947 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 939 | 948 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 949 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 940 | 950 | |
| 941 | 951 | const S = struct { |
| 942 | 952 | const U = union(enum) { |
| ... | ... | @@ -969,6 +979,7 @@ test "cast from pointer to anonymous struct to pointer to union" { |
| 969 | 979 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 970 | 980 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 971 | 981 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 982 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 972 | 983 | |
| 973 | 984 | const S = struct { |
| 974 | 985 | const U = union(enum) { |
| ... | ... | @@ -1104,6 +1115,8 @@ test "union enum type gets a separate scope" { |
| 1104 | 1115 | |
| 1105 | 1116 | test "global variable struct contains union initialized to non-most-aligned field" { |
| 1106 | 1117 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1118 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1119 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1107 | 1120 | |
| 1108 | 1121 | const T = struct { |
| 1109 | 1122 | const U = union(enum) { |
test/cases/compile_errors/wrong_initializer_for_union_payload_of_type_type.zig+1-2| ... | ... | @@ -13,5 +13,4 @@ export fn entry() void { |
| 13 | 13 | // backend=stage2 |
| 14 | 14 | // target=native |
| 15 | 15 | // |
| 16 | // :9:14: error: expected type 'type', found 'tmp.U' | |
| 17 | // :1:11: note: union declared here | |
| 16 | // :9:8: error: use of undefined value here causes undefined behavior |
test/cases/safety/bad union field access.zig	+6-4| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 4 | _ = stack_trace; |
| 6 | std.process.exit(0); | |
| 5 | if (std.mem.eql(u8, message, "access of inactive union field")) { | |
| 6 | std.process.exit(0); | |
| 7 | } | |
| 8 | std.process.exit(1); | |
| 7 | 9 | } |
| 8 | 10 | |
| 9 | 11 | const Foo = union { |
| ... | ... | @@ -21,5 +23,5 @@ fn bar(f: *Foo) void { |
| 21 | 23 | f.float = 12.34; |
| 22 | 24 | } |
| 23 | 25 | // run |
| 24 | // backend=stage1 | |
| 25 | // target=native | |
| \ No newline at end of file | ||
| 26 | // backend=llvm | |
| 27 | // target=native |