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