authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-24 23:47:41-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-24 23:47:41-05:00
log0866fa9d1d46f3c66a4adcaf1d863e762f874c6c
tree0ea2cdfdc44ad2ff4aa0fdd41ab8ea01a4b60e16
parent913d61ebb95567fe67b0bfad99694892aac841e2
parent60e6bf112cf00e96818209cafd36b98546cc4d8b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10688 from topolarity/c-backend-union-support

stage2: Add `union` support to C backend

2 files changed, 197 insertions(+), 58 deletions(-)

src/codegen/c.zig+196-57
...@@ -34,6 +34,8 @@ pub const CValue = union(enum) {...@@ -34,6 +34,8 @@ pub const CValue = union(enum) {
34 /// By-value34 /// By-value
35 decl: *Decl,35 decl: *Decl,
36 decl_ref: *Decl,36 decl_ref: *Decl,
37 /// Render the slice as an identifier (using fmtIdent)
38 identifier: []const u8,
37 /// Render these bytes literally.39 /// Render these bytes literally.
38 /// TODO make this a [*:0]const u8 to save memory40 /// TODO make this a [*:0]const u8 to save memory
39 bytes: []const u8,41 bytes: []const u8,
...@@ -78,6 +80,7 @@ fn formatIdent(...@@ -78,6 +80,7 @@ fn formatIdent(
78) !void {80) !void {
79 _ = fmt;81 _ = fmt;
80 _ = options;82 _ = options;
83 try writer.writeAll("__"); // Add double underscore to avoid conflicting with C's reserved keywords
81 for (ident) |c, i| {84 for (ident) |c, i| {
82 switch (c) {85 switch (c) {
83 'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c),86 'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c),
...@@ -408,6 +411,18 @@ pub const DeclGen = struct {...@@ -408,6 +411,18 @@ pub const DeclGen = struct {
408 try dg.renderValue(writer, Type.usize, slice.len);411 try dg.renderValue(writer, Type.usize, slice.len);
409 try writer.writeAll("}");412 try writer.writeAll("}");
410 },413 },
414 .elem_ptr => {
415 const elem_ptr = val.castTag(.elem_ptr).?.data;
416 var arena = std.heap.ArenaAllocator.init(dg.module.gpa);
417 defer arena.deinit();
418 const elem_ptr_ty = try ty.elemPtrType(arena.allocator());
419
420 try writer.writeAll("(&((");
421 try dg.renderType(writer, ty);
422 try writer.writeByte(')');
423 try dg.renderValue(writer, elem_ptr_ty, elem_ptr.array_ptr);
424 try writer.print(")[{d}])", .{elem_ptr.index});
425 },
411 .function => {426 .function => {
412 const func = val.castTag(.function).?.data;427 const func = val.castTag(.function).?.data;
413 try dg.renderDeclName(func.owner_decl, writer);428 try dg.renderDeclName(func.owner_decl, writer);
...@@ -527,6 +542,15 @@ pub const DeclGen = struct {...@@ -527,6 +542,15 @@ pub const DeclGen = struct {
527 return writer.print("{d}", .{field_index});542 return writer.print("{d}", .{field_index});
528 }543 }
529 },544 },
545 .enum_numbered => {
546 const enum_obj = ty.castTag(.enum_numbered).?.data;
547 if (enum_obj.values.count() != 0) {
548 const tag_val = enum_obj.values.keys()[field_index];
549 return dg.renderValue(writer, enum_obj.tag_ty, tag_val);
550 } else {
551 return writer.print("{d}", .{field_index});
552 }
553 },
530 else => unreachable,554 else => unreachable,
531 }555 }
532 },556 },
...@@ -565,6 +589,37 @@ pub const DeclGen = struct {...@@ -565,6 +589,37 @@ pub const DeclGen = struct {
565589
566 try writer.writeAll("}");590 try writer.writeAll("}");
567 },591 },
592 .Union => {
593 const union_obj = val.castTag(.@"union").?.data;
594 const union_ty = ty.cast(Type.Payload.Union).?.data;
595 const target = dg.module.getTarget();
596 const layout = ty.unionGetLayout(target);
597
598 try writer.writeAll("(");
599 try dg.renderType(writer, ty);
600 try writer.writeAll("){");
601
602 if (ty.unionTagType()) |tag_ty| {
603 if (layout.tag_size != 0) {
604 try writer.writeAll(".tag = ");
605 try dg.renderValue(writer, tag_ty, union_obj.tag);
606 try writer.writeAll(", ");
607 }
608 try writer.writeAll(".payload = {");
609 }
610
611 const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?;
612 const field_ty = ty.unionFields().values()[index].ty;
613 const field_name = ty.unionFields().keys()[index];
614 if (field_ty.hasCodeGenBits()) {
615 try writer.print(".{} = ", .{fmtIdent(field_name)});
616 try dg.renderValue(writer, field_ty, union_obj.val);
617 }
618 if (ty.unionTagType()) |_| {
619 try writer.writeAll("}");
620 }
621 try writer.writeAll("}");
622 },
568623
569 .ComptimeInt => unreachable,624 .ComptimeInt => unreachable,
570 .ComptimeFloat => unreachable,625 .ComptimeFloat => unreachable,
...@@ -577,7 +632,6 @@ pub const DeclGen = struct {...@@ -577,7 +632,6 @@ pub const DeclGen = struct {
577 .BoundFn => unreachable,632 .BoundFn => unreachable,
578 .Opaque => unreachable,633 .Opaque => unreachable,
579634
580 .Union,
581 .Frame,635 .Frame,
582 .AnyFrame,636 .AnyFrame,
583 .Vector,637 .Vector,
...@@ -609,22 +663,24 @@ pub const DeclGen = struct {...@@ -609,22 +663,24 @@ pub const DeclGen = struct {
609 try dg.renderDeclName(dg.decl, w);663 try dg.renderDeclName(dg.decl, w);
610 try w.writeAll("(");664 try w.writeAll("(");
611 const param_len = dg.decl.ty.fnParamLen();665 const param_len = dg.decl.ty.fnParamLen();
612 const is_var_args = dg.decl.ty.fnIsVarArgs();666
613 if (param_len == 0 and !is_var_args)667 var index: usize = 0;
614 try w.writeAll("void")668 var params_written: usize = 0;
615 else {669 while (index < param_len) : (index += 1) {
616 var index: usize = 0;670 if (dg.decl.ty.fnParamType(index).zigTypeTag() == .Void) continue;
617 while (index < param_len) : (index += 1) {671 if (params_written > 0) {
618 if (index > 0) {672 try w.writeAll(", ");
619 try w.writeAll(", ");
620 }
621 try dg.renderType(w, dg.decl.ty.fnParamType(index));
622 try w.print(" a{d}", .{index});
623 }673 }
674 try dg.renderType(w, dg.decl.ty.fnParamType(index));
675 try w.print(" a{d}", .{index});
676 params_written += 1;
624 }677 }
625 if (is_var_args) {678
626 if (param_len != 0) try w.writeAll(", ");679 if (dg.decl.ty.fnIsVarArgs()) {
680 if (params_written != 0) try w.writeAll(", ");
627 try w.writeAll("...");681 try w.writeAll("...");
682 } else if (params_written == 0) {
683 try w.writeAll("void");
628 }684 }
629 try w.writeByte(')');685 try w.writeByte(')');
630 }686 }
...@@ -646,21 +702,23 @@ pub const DeclGen = struct {...@@ -646,21 +702,23 @@ pub const DeclGen = struct {
646 const name_end = buffer.items.len - 2;702 const name_end = buffer.items.len - 2;
647703
648 const param_len = fn_info.param_types.len;704 const param_len = fn_info.param_types.len;
649 const is_var_args = fn_info.is_var_args;705
650 if (param_len == 0 and !is_var_args)706 var params_written: usize = 0;
651 try bw.writeAll("void")707 var index: usize = 0;
652 else {708 while (index < param_len) : (index += 1) {
653 var index: usize = 0;709 if (fn_info.param_types[index].zigTypeTag() == .Void) continue;
654 while (index < param_len) : (index += 1) {710 if (params_written > 0) {
655 if (index > 0) {711 try bw.writeAll(", ");
656 try bw.writeAll(", ");
657 }
658 try dg.renderType(bw, fn_info.param_types[index]);
659 }712 }
713 try dg.renderType(bw, fn_info.param_types[index]);
714 params_written += 1;
660 }715 }
661 if (is_var_args) {716
662 if (param_len != 0) try bw.writeAll(", ");717 if (fn_info.is_var_args) {
718 if (params_written != 0) try bw.writeAll(", ");
663 try bw.writeAll("...");719 try bw.writeAll("...");
720 } else if (params_written == 0) {
721 try bw.writeAll("void");
664 }722 }
665 try bw.writeAll(");\n");723 try bw.writeAll(");\n");
666724
...@@ -729,7 +787,7 @@ pub const DeclGen = struct {...@@ -729,7 +787,7 @@ pub const DeclGen = struct {
729 if (!field_ty.hasCodeGenBits()) continue;787 if (!field_ty.hasCodeGenBits()) continue;
730788
731 const alignment = entry.value_ptr.abi_align;789 const alignment = entry.value_ptr.abi_align;
732 const name: CValue = .{ .bytes = entry.key_ptr.* };790 const name: CValue = .{ .identifier = entry.key_ptr.* };
733 try buffer.append(' ');791 try buffer.append(' ');
734 try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut, alignment);792 try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut, alignment);
735 try buffer.appendSlice(";\n");793 try buffer.appendSlice(";\n");
...@@ -753,6 +811,62 @@ pub const DeclGen = struct {...@@ -753,6 +811,62 @@ pub const DeclGen = struct {
753 return name;811 return name;
754 }812 }
755813
814 fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
815 const union_ty = t.cast(Type.Payload.Union).?.data;
816 const fqn = try union_ty.getFullyQualifiedName(dg.typedefs.allocator);
817 defer dg.typedefs.allocator.free(fqn);
818
819 const target = dg.module.getTarget();
820 const layout = t.unionGetLayout(target);
821
822 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
823 defer buffer.deinit();
824
825 try buffer.appendSlice("typedef ");
826 if (t.unionTagType()) |tag_ty| {
827 const name: CValue = .{ .bytes = "tag" };
828 try buffer.appendSlice("struct {\n ");
829 if (layout.tag_size != 0) {
830 try dg.renderTypeAndName(buffer.writer(), tag_ty, name, .Mut, Value.initTag(.abi_align_default));
831 try buffer.appendSlice(";\n");
832 }
833 }
834
835 try buffer.appendSlice("union {\n");
836 {
837 var it = t.unionFields().iterator();
838 while (it.next()) |entry| {
839 const field_ty = entry.value_ptr.ty;
840 if (!field_ty.hasCodeGenBits()) continue;
841 const alignment = entry.value_ptr.abi_align;
842 const name: CValue = .{ .identifier = entry.key_ptr.* };
843 try buffer.append(' ');
844 try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut, alignment);
845 try buffer.appendSlice(";\n");
846 }
847 }
848 try buffer.appendSlice("} ");
849
850 if (t.unionTagType()) |_| {
851 try buffer.appendSlice("payload;\n} ");
852 }
853
854 const name_start = buffer.items.len;
855 try buffer.writer().print("zig_U_{s};\n", .{fmtIdent(fqn)});
856
857 const rendered = buffer.toOwnedSlice();
858 errdefer dg.typedefs.allocator.free(rendered);
859 const name = rendered[name_start .. rendered.len - 2];
860
861 try dg.typedefs.ensureUnusedCapacity(1);
862 dg.typedefs.putAssumeCapacityNoClobber(
863 try t.copy(dg.typedefs_arena),
864 .{ .name = name, .rendered = rendered },
865 );
866
867 return name;
868 }
869
756 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {870 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
757 const child_type = t.errorUnionPayload();871 const child_type = t.errorUnionPayload();
758 const err_set_type = t.errorUnionSet();872 const err_set_type = t.errorUnionSet();
...@@ -931,6 +1045,12 @@ pub const DeclGen = struct {...@@ -931,6 +1045,12 @@ pub const DeclGen = struct {
9311045
932 return w.writeAll(name);1046 return w.writeAll(name);
933 },1047 },
1048 .Union => {
1049 const name = dg.getTypedefName(t) orelse
1050 try dg.renderUnionTypedef(t);
1051
1052 return w.writeAll(name);
1053 },
934 .Enum => {1054 .Enum => {
935 // For enums, we simply use the integer tag type.1055 // For enums, we simply use the integer tag type.
936 var int_tag_ty_buffer: Type.Payload.Bits = undefined;1056 var int_tag_ty_buffer: Type.Payload.Bits = undefined;
...@@ -939,7 +1059,6 @@ pub const DeclGen = struct {...@@ -939,7 +1059,6 @@ pub const DeclGen = struct {
939 try dg.renderType(w, int_tag_ty);1059 try dg.renderType(w, int_tag_ty);
940 },1060 },
9411061
942 .Union,
943 .Frame,1062 .Frame,
944 .AnyFrame,1063 .AnyFrame,
945 .Vector,1064 .Vector,
...@@ -1021,6 +1140,7 @@ pub const DeclGen = struct {...@@ -1021,6 +1140,7 @@ pub const DeclGen = struct {
1021 try w.writeByte('&');1140 try w.writeByte('&');
1022 return dg.renderDeclName(decl, w);1141 return dg.renderDeclName(decl, w);
1023 },1142 },
1143 .identifier => |ident| return w.print("{}", .{fmtIdent(ident)}),
1024 .bytes => |bytes| return w.writeAll(bytes),1144 .bytes => |bytes| return w.writeAll(bytes),
1025 }1145 }
1026 }1146 }
...@@ -1103,13 +1223,10 @@ pub fn genDecl(o: *Object) !void {...@@ -1103,13 +1223,10 @@ pub fn genDecl(o: *Object) !void {
1103 if (variable.is_threadlocal) {1223 if (variable.is_threadlocal) {
1104 try fwd_decl_writer.writeAll("zig_threadlocal ");1224 try fwd_decl_writer.writeAll("zig_threadlocal ");
1105 }1225 }
1106 try o.dg.renderType(fwd_decl_writer, o.dg.decl.ty);1226
1107 try fwd_decl_writer.writeAll(" ");1227 const decl_c_value: CValue = if (is_global) .{ .bytes = mem.span(o.dg.decl.name) } else .{ .decl = o.dg.decl };
1108 if (is_global) {1228
1109 try fwd_decl_writer.writeAll(mem.span(o.dg.decl.name));1229 try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.align_val);
1110 } else {
1111 try o.dg.renderDeclName(o.dg.decl, fwd_decl_writer);
1112 }
1113 try fwd_decl_writer.writeAll(";\n");1230 try fwd_decl_writer.writeAll(";\n");
11141231
1115 if (variable.init.isUndefDeep()) {1232 if (variable.init.isUndefDeep()) {
...@@ -1118,13 +1235,7 @@ pub fn genDecl(o: *Object) !void {...@@ -1118,13 +1235,7 @@ pub fn genDecl(o: *Object) !void {
11181235
1119 try o.indent_writer.insertNewline();1236 try o.indent_writer.insertNewline();
1120 const w = o.writer();1237 const w = o.writer();
1121 try o.dg.renderType(w, o.dg.decl.ty);1238 try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.align_val);
1122 try w.writeAll(" ");
1123 if (is_global) {
1124 try w.writeAll(mem.span(o.dg.decl.name));
1125 } else {
1126 try o.dg.renderDeclName(o.dg.decl, w);
1127 }
1128 try w.writeAll(" = ");1239 try w.writeAll(" = ");
1129 if (variable.init.tag() != .unreachable_value) {1240 if (variable.init.tag() != .unreachable_value) {
1130 try o.dg.renderValue(w, tv.ty, variable.init);1241 try o.dg.renderValue(w, tv.ty, variable.init);
...@@ -2339,9 +2450,9 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2339,9 +2450,9 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
2339 try f.writeCValue(writer, local);2450 try f.writeCValue(writer, local);
2340 try writer.writeAll(", &");2451 try writer.writeAll(", &");
2341 try f.writeCValue(writer, operand);2452 try f.writeCValue(writer, operand);
2342 try writer.writeAll(", sizeof ");2453 try writer.writeAll(", sizeof(");
2343 try f.writeCValue(writer, local);2454 try f.writeCValue(writer, local);
2344 try writer.writeAll(");\n");2455 try writer.writeAll("));\n");
23452456
2346 return local;2457 return local;
2347}2458}
...@@ -2650,21 +2761,36 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue...@@ -2650,21 +2761,36 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue
26502761
2651fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {2762fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {
2652 const writer = f.object.writer();2763 const writer = f.object.writer();
2653 const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data;2764 const struct_ty = struct_ptr_ty.elemType();
2654 const field_name = struct_obj.fields.keys()[index];2765 var field_name: []const u8 = undefined;
2655 const field_val = struct_obj.fields.values()[index];2766 var field_val_ty: Type = undefined;
2656 const addrof = if (field_val.ty.zigTypeTag() == .Array) "" else "&";2767
2768 switch (struct_ty.tag()) {
2769 .@"struct" => {
2770 const fields = struct_ty.structFields();
2771 field_name = fields.keys()[index];
2772 field_val_ty = fields.values()[index].ty;
2773 },
2774 .@"union", .union_tagged => {
2775 const fields = struct_ty.unionFields();
2776 field_name = fields.keys()[index];
2777 field_val_ty = fields.values()[index].ty;
2778 },
2779 else => unreachable,
2780 }
2781 const addrof = if (field_val_ty.zigTypeTag() == .Array) "" else "&";
2782 const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";
26572783
2658 const inst_ty = f.air.typeOfIndex(inst);2784 const inst_ty = f.air.typeOfIndex(inst);
2659 const local = try f.allocLocal(inst_ty, .Const);2785 const local = try f.allocLocal(inst_ty, .Const);
2660 switch (struct_ptr) {2786 switch (struct_ptr) {
2661 .local_ref => |i| {2787 .local_ref => |i| {
2662 try writer.print(" = {s}t{d}.{};\n", .{ addrof, i, fmtIdent(field_name) });2788 try writer.print(" = {s}t{d}.{s}{};\n", .{ addrof, i, payload, fmtIdent(field_name) });
2663 },2789 },
2664 else => {2790 else => {
2665 try writer.print(" = {s}", .{addrof});2791 try writer.print(" = {s}", .{addrof});
2666 try f.writeCValue(writer, struct_ptr);2792 try f.writeCValue(writer, struct_ptr);
2667 try writer.print("->{};\n", .{fmtIdent(field_name)});2793 try writer.print("->{s}{};\n", .{ payload, fmtIdent(field_name) });
2668 },2794 },
2669 }2795 }
2670 return local;2796 return local;
...@@ -2679,14 +2805,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2679,14 +2805,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
2679 const writer = f.object.writer();2805 const writer = f.object.writer();
2680 const struct_byval = try f.resolveInst(extra.struct_operand);2806 const struct_byval = try f.resolveInst(extra.struct_operand);
2681 const struct_ty = f.air.typeOf(extra.struct_operand);2807 const struct_ty = f.air.typeOf(extra.struct_operand);
2682 const struct_obj = struct_ty.castTag(.@"struct").?.data;2808 const field_name = switch (struct_ty.tag()) {
2683 const field_name = struct_obj.fields.keys()[extra.field_index];2809 .@"struct" => struct_ty.structFields().keys()[extra.field_index],
2810 .@"union", .union_tagged => struct_ty.unionFields().keys()[extra.field_index],
2811 else => unreachable,
2812 };
2813 const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";
26842814
2685 const inst_ty = f.air.typeOfIndex(inst);2815 const inst_ty = f.air.typeOfIndex(inst);
2686 const local = try f.allocLocal(inst_ty, .Const);2816 const local = try f.allocLocal(inst_ty, .Const);
2687 try writer.writeAll(" = ");2817 try writer.writeAll(" = ");
2688 try f.writeCValue(writer, struct_byval);2818 try f.writeCValue(writer, struct_byval);
2689 try writer.print(".{};\n", .{fmtIdent(field_name)});2819 try writer.print(".{s}{};\n", .{ payload, fmtIdent(field_name) });
2690 return local;2820 return local;
2691}2821}
26922822
...@@ -3027,9 +3157,13 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3027,9 +3157,13 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
3027 const new_tag = try f.resolveInst(bin_op.rhs);3157 const new_tag = try f.resolveInst(bin_op.rhs);
3028 const writer = f.object.writer();3158 const writer = f.object.writer();
30293159
3030 try writer.writeAll("*");3160 const union_ty = f.air.typeOf(bin_op.lhs).childType();
3161 const target = f.object.dg.module.getTarget();
3162 const layout = union_ty.unionGetLayout(target);
3163 if (layout.tag_size == 0) return CValue.none;
3164
3031 try f.writeCValue(writer, union_ptr);3165 try f.writeCValue(writer, union_ptr);
3032 try writer.writeAll(" = ");3166 try writer.writeAll("->tag = ");
3033 try f.writeCValue(writer, new_tag);3167 try f.writeCValue(writer, new_tag);
3034 try writer.writeAll(";\n");3168 try writer.writeAll(";\n");
30353169
...@@ -3043,12 +3177,17 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3043,12 +3177,17 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
3043 const inst_ty = f.air.typeOfIndex(inst);3177 const inst_ty = f.air.typeOfIndex(inst);
3044 const local = try f.allocLocal(inst_ty, .Const);3178 const local = try f.allocLocal(inst_ty, .Const);
3045 const ty_op = f.air.instructions.items(.data)[inst].ty_op;3179 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3180 const un_ty = f.air.typeOf(ty_op.operand);
3046 const writer = f.object.writer();3181 const writer = f.object.writer();
3047 const operand = try f.resolveInst(ty_op.operand);3182 const operand = try f.resolveInst(ty_op.operand);
30483183
3049 try writer.writeAll("get_union_tag(");3184 const target = f.object.dg.module.getTarget();
3185 const layout = un_ty.unionGetLayout(target);
3186 if (layout.tag_size == 0) return CValue.none;
3187
3188 try writer.writeAll(" = ");
3050 try f.writeCValue(writer, operand);3189 try f.writeCValue(writer, operand);
3051 try writer.writeAll(");\n");3190 try writer.writeAll(".tag;\n");
3052 return local;3191 return local;
3053}3192}
30543193
test/behavior.zig+1-1
...@@ -67,6 +67,7 @@ test {...@@ -67,6 +67,7 @@ test {
67 // Tests that pass for stage1, llvm backend, C backend67 // Tests that pass for stage1, llvm backend, C backend
68 _ = @import("behavior/cast_int.zig");68 _ = @import("behavior/cast_int.zig");
69 _ = @import("behavior/int128.zig");69 _ = @import("behavior/int128.zig");
70 _ = @import("behavior/union.zig");
70 _ = @import("behavior/translate_c_macros.zig");71 _ = @import("behavior/translate_c_macros.zig");
7172
72 if (builtin.zig_backend != .stage2_c) {73 if (builtin.zig_backend != .stage2_c) {
...@@ -110,7 +111,6 @@ test {...@@ -110,7 +111,6 @@ test {
110 _ = @import("behavior/slice.zig");111 _ = @import("behavior/slice.zig");
111 _ = @import("behavior/struct_llvm.zig");112 _ = @import("behavior/struct_llvm.zig");
112 _ = @import("behavior/switch.zig");113 _ = @import("behavior/switch.zig");
113 _ = @import("behavior/union.zig");
114 _ = @import("behavior/widening.zig");114 _ = @import("behavior/widening.zig");
115115
116 if (builtin.zig_backend != .stage1) {116 if (builtin.zig_backend != .stage1) {