authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-04-22 15:46:18-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:28-07:00
logcf28736f0d9f70c801a3cc30293a98067bc96fa0
tree791ca0f4f1c726ccc900532580024ae49a3dbd6b
parent045c1c15576bdc283be40e0ce22ce0b7379e1bb7

cbe: pass behavior tests


5 files changed, 92 insertions(+), 62 deletions(-)

src/codegen/c.zig+62-55
...@@ -698,17 +698,27 @@ pub const Object = struct {...@@ -698,17 +698,27 @@ pub const Object = struct {
698 indent_counter: usize,698 indent_counter: usize,
699699
700 const indent_width = 1;700 const indent_width = 1;
701 const indent_char = ' ';
701702
702 fn newline(o: *Object) !void {703 fn newline(o: *Object) !void {
703 const bw = &o.code.buffered_writer;704 const bw = &o.code.buffered_writer;
704 try bw.writeByte('\n');705 try bw.writeByte('\n');
705 try bw.splatByteAll(' ', o.indent_counter);706 try bw.splatByteAll(indent_char, o.indent_counter);
706 }707 }
707 fn indent(o: *Object) void {708 fn indent(o: *Object) void {
708 o.indent_counter += indent_width;709 o.indent_counter += indent_width;
709 }710 }
710 fn outdent(o: *Object) void {711 fn outdent(o: *Object) !void {
711 o.indent_counter -= indent_width;712 o.indent_counter -= indent_width;
713 const written = o.code.getWritten();
714 switch (written[written.len - 1]) {
715 indent_char => o.code.shrinkRetainingCapacity(written.len - indent_width),
716 '\n' => try o.code.buffered_writer.splatByteAll(indent_char, o.indent_counter),
717 else => {
718 std.debug.print("\"{f}\"\n", .{std.zig.fmtEscapes(written[written.len -| 100..])});
719 unreachable;
720 },
721 }
712 }722 }
713};723};
714724
...@@ -1041,7 +1051,7 @@ pub const DeclGen = struct {...@@ -1041,7 +1051,7 @@ pub const DeclGen = struct {
1041 .error_union => |error_union| switch (ctype.info(ctype_pool)) {1051 .error_union => |error_union| switch (ctype.info(ctype_pool)) {
1042 .basic => switch (error_union.val) {1052 .basic => switch (error_union.val) {
1043 .err_name => |err_name| try dg.renderErrorName(writer, err_name),1053 .err_name => |err_name| try dg.renderErrorName(writer, err_name),
1044 .payload => try writer.writeAll("0"),1054 .payload => try writer.writeByte('0'),
1045 },1055 },
1046 .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,1056 .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
1047 .aggregate => |aggregate| {1057 .aggregate => |aggregate| {
...@@ -1197,7 +1207,7 @@ pub const DeclGen = struct {...@@ -1197,7 +1207,7 @@ pub const DeclGen = struct {
1197 .none => "true",1207 .none => "true",
1198 else => "false",1208 else => "false",
1199 }) else switch (opt.val) {1209 }) else switch (opt.val) {
1200 .none => try writer.writeAll("0"),1210 .none => try writer.writeByte('0'),
1201 else => |payload| switch (ip.indexToKey(payload)) {1211 else => |payload| switch (ip.indexToKey(payload)) {
1202 .undef => |err_ty| try dg.renderUndefValue(1212 .undef => |err_ty| try dg.renderUndefValue(
1203 writer,1213 writer,
...@@ -1528,7 +1538,7 @@ pub const DeclGen = struct {...@@ -1528,7 +1538,7 @@ pub const DeclGen = struct {
1528 try writer.writeByte(')');1538 try writer.writeByte(')');
1529 }1539 }
1530 try dg.renderValue(writer, Value.fromInterned(un.val), location);1540 try dg.renderValue(writer, Value.fromInterned(un.val), location);
1531 } else try writer.writeAll("0");1541 } else try writer.writeByte('0');
1532 return;1542 return;
1533 }1543 }
15341544
...@@ -2786,7 +2796,7 @@ pub fn genErrDecls(o: *Object) Error!void {...@@ -2786,7 +2796,7 @@ pub fn genErrDecls(o: *Object) Error!void {
2786 try bw.print(" = {d}u,", .{value});2796 try bw.print(" = {d}u,", .{value});
2787 try o.newline();2797 try o.newline();
2788 }2798 }
2789 o.outdent();2799 try o.outdent();
2790 try bw.writeAll("};");2800 try bw.writeAll("};");
2791 try o.newline();2801 try o.newline();
2792 }2802 }
...@@ -2895,6 +2905,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn...@@ -2895,6 +2905,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
2895 try bw.print("case {f}: {{", .{2905 try bw.print("case {f}: {{", .{
2896 try o.dg.fmtIntLiteral(try tag_val.intFromEnum(enum_ty, pt), .Other),2906 try o.dg.fmtIntLiteral(try tag_val.intFromEnum(enum_ty, pt), .Other),
2897 });2907 });
2908 o.indent();
2898 try o.newline();2909 try o.newline();
2899 try bw.writeAll("static ");2910 try bw.writeAll("static ");
2900 try o.dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, Const, .none, .complete);2911 try o.dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, Const, .none, .complete);
...@@ -2909,16 +2920,15 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn...@@ -2909,16 +2920,15 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
2909 try o.dg.fmtIntLiteral(try pt.intValue(.usize, tag_name_len), .Other),2920 try o.dg.fmtIntLiteral(try pt.intValue(.usize, tag_name_len), .Other),
2910 });2921 });
2911 try o.newline();2922 try o.newline();
29122923 try o.outdent();
2913 try bw.writeByte('}');2924 try bw.writeByte('}');
2914 try o.newline();2925 try o.newline();
2915 }2926 }
2927 try o.outdent();
2916 try bw.writeByte('}');2928 try bw.writeByte('}');
2917 try o.newline();2929 try o.newline();
2918 try bw.writeAll("while (");2930 try airUnreach(o);
2919 try o.dg.renderValue(bw, Value.true, .Other);2931 try o.outdent();
2920 try bw.writeAll(") ");
2921 _ = try airBreakpoint(o, bw);
2922 try bw.writeByte('}');2932 try bw.writeByte('}');
2923 try o.newline();2933 try o.newline();
2924 },2934 },
...@@ -2940,6 +2950,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn...@@ -2940,6 +2950,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
2940 .fmt_ctype_pool_string = fn_name,2950 .fmt_ctype_pool_string = fn_name,
2941 });2951 });
2942 try bw.writeAll(" {");2952 try bw.writeAll(" {");
2953 o.indent();
2943 try o.newline();2954 try o.newline();
2944 try bw.writeAll("return ");2955 try bw.writeAll("return ");
2945 try o.dg.renderNavName(bw, fn_nav_index);2956 try o.dg.renderNavName(bw, fn_nav_index);
...@@ -2950,6 +2961,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn...@@ -2950,6 +2961,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
2950 }2961 }
2951 try bw.writeAll(");");2962 try bw.writeAll(");");
2952 try o.newline();2963 try o.newline();
2964 try o.outdent();
2953 try bw.writeByte('}');2965 try bw.writeByte('}');
2954 try o.newline();2966 try o.newline();
2955 },2967 },
...@@ -3066,7 +3078,10 @@ fn genFunc(f: *Function) !void {...@@ -3066,7 +3078,10 @@ fn genFunc(f: *Function) !void {
3066 f.free_locals_map.clearRetainingCapacity();3078 f.free_locals_map.clearRetainingCapacity();
30673079
3068 const main_body = f.air.getMainBody();3080 const main_body = f.air.getMainBody();
3069 try genBodyResolveState(f, undefined, &.{}, main_body, false);3081 o.indent();
3082 try genBodyResolveState(f, undefined, &.{}, main_body, true);
3083 try o.outdent();
3084 try o.code.buffered_writer.writeByte('}');
3070 try o.newline();3085 try o.newline();
3071 if (o.dg.expected_block) |_|3086 if (o.dg.expected_block) |_|
3072 return f.fail("runtime code not allowed in naked function", .{});3087 return f.fail("runtime code not allowed in naked function", .{});
...@@ -3285,11 +3300,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) Error!void {...@@ -3285,11 +3300,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) Error!void {
3285 if (body.len == 0) {3300 if (body.len == 0) {
3286 try bw.writeAll("{}");3301 try bw.writeAll("{}");
3287 } else {3302 } else {
3288 try bw.writeAll("{");3303 try bw.writeByte('{');
3289 f.object.indent();3304 f.object.indent();
3290 try f.object.newline();3305 try f.object.newline();
3291 try genBodyInner(f, body);3306 try genBodyInner(f, body);
3292 f.object.outdent();3307 try f.object.outdent();
3293 try bw.writeByte('}');3308 try bw.writeByte('}');
3294 }3309 }
3295}3310}
...@@ -3367,7 +3382,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {...@@ -3367,7 +3382,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {
33673382
3368 .arg => try airArg(f, inst),3383 .arg => try airArg(f, inst),
33693384
3370 .breakpoint => try airBreakpoint(&f.object, &f.object.code.buffered_writer),3385 .breakpoint => try airBreakpoint(f),
3371 .ret_addr => try airRetAddr(f, inst),3386 .ret_addr => try airRetAddr(f, inst),
3372 .frame_addr => try airFrameAddress(f, inst),3387 .frame_addr => try airFrameAddress(f, inst),
33733388
...@@ -3621,7 +3636,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {...@@ -3621,7 +3636,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {
3621 .ret_safe => return airRet(f, inst, false), // TODO3636 .ret_safe => return airRet(f, inst, false), // TODO
3622 .ret_load => return airRet(f, inst, true),3637 .ret_load => return airRet(f, inst, true),
3623 .trap => return airTrap(f, &f.object.code.buffered_writer),3638 .trap => return airTrap(f, &f.object.code.buffered_writer),
3624 .unreach => return airUnreach(f),3639 .unreach => return airUnreach(&f.object),
36253640
3626 // Instructions which may be `noreturn`.3641 // Instructions which may be `noreturn`.
3627 .block => res: {3642 .block => res: {
...@@ -4017,18 +4032,14 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {...@@ -4017,18 +4032,14 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {
4017 try f.writeCValueDeref(bw, ret_val)4032 try f.writeCValueDeref(bw, ret_val)
4018 else4033 else
4019 try f.writeCValue(bw, ret_val, .Other);4034 try f.writeCValue(bw, ret_val, .Other);
4020 try bw.writeByte(';');4035 try bw.writeAll(";\n");
4021 try f.object.newline();
4022 if (is_array) {4036 if (is_array) {
4023 try freeLocal(f, inst, ret_val.new_local, null);4037 try freeLocal(f, inst, ret_val.new_local, null);
4024 }4038 }
4025 } else {4039 } else {
4026 try reap(f, inst, &.{un_op});4040 try reap(f, inst, &.{un_op});
4027 // Not even allowed to return void in a naked function.4041 // Not even allowed to return void in a naked function.
4028 if (!f.object.dg.is_naked_fn) {4042 if (!f.object.dg.is_naked_fn) try bw.writeAll("return;\n");
4029 try bw.writeAll("return;");
4030 try f.object.newline();
4031 }
4032 }4043 }
4033}4044}
40344045
...@@ -4817,7 +4828,10 @@ fn airCall(...@@ -4817,7 +4828,10 @@ fn airCall(
4817 try f.freeCValue(inst, resolved_arg);4828 try f.freeCValue(inst, resolved_arg);
4818 }4829 }
4819 try bw.writeAll(");");4830 try bw.writeAll(");");
4820 try f.object.newline();4831 switch (modifier) {
4832 .always_tail => try bw.writeByte('\n'),
4833 else => try f.object.newline(),
4834 }
48214835
4822 const result = result: {4836 const result = result: {
4823 if (result_local == .none or !lowersToArray(ret_ty, pt))4837 if (result_local == .none or !lowersToArray(ret_ty, pt))
...@@ -4925,8 +4939,6 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -4925,8 +4939,6 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index)
4925 try die(f, inst, death.toRef());4939 try die(f, inst, death.toRef());
4926 }4940 }
49274941
4928 try f.object.newline();
4929
4930 // noreturn blocks have no `br` instructions reaching them, so we don't want a label4942 // noreturn blocks have no `br` instructions reaching them, so we don't want a label
4931 if (f.object.dg.is_naked_fn) {4943 if (f.object.dg.is_naked_fn) {
4932 if (f.object.dg.expected_block) |expected_block| {4944 if (f.object.dg.expected_block) |expected_block| {
...@@ -4936,7 +4948,7 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -4936,7 +4948,7 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index)
4936 }4948 }
4937 } else if (!f.typeOfIndex(inst).isNoReturn(zcu)) {4949 } else if (!f.typeOfIndex(inst).isNoReturn(zcu)) {
4938 // label must be followed by an expression, include an empty one.4950 // label must be followed by an expression, include an empty one.
4939 try bw.print("zig_block_{d}:;", .{block_id});4951 try bw.print("\nzig_block_{d}:;", .{block_id});
4940 try f.object.newline();4952 try f.object.newline();
4941 }4953 }
49424954
...@@ -5057,14 +5069,12 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !void {...@@ -5057,14 +5069,12 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !void {
5057 try a.end(f, bw);5069 try a.end(f, bw);
5058 }5070 }
50595071
5060 try bw.print("goto zig_block_{d};", .{block.block_id});5072 try bw.print("goto zig_block_{d};\n", .{block.block_id});
5061 try f.object.newline();
5062}5073}
50635074
5064fn airRepeat(f: *Function, inst: Air.Inst.Index) !void {5075fn airRepeat(f: *Function, inst: Air.Inst.Index) !void {
5065 const repeat = f.air.instructions.items(.data)[@intFromEnum(inst)].repeat;5076 const repeat = f.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
5066 try f.object.code.buffered_writer.print("goto zig_loop_{d};", .{@intFromEnum(repeat.loop_inst)});5077 try f.object.code.buffered_writer.print("goto zig_loop_{d};\n", .{@intFromEnum(repeat.loop_inst)});
5067 try f.object.newline();
5068}5078}
50695079
5070fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {5080fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {
...@@ -5093,8 +5103,7 @@ fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {...@@ -5093,8 +5103,7 @@ fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {
5093 }5103 }
5094 }5104 }
5095 } else switch_br.cases_len;5105 } else switch_br.cases_len;
5096 try bw.print("goto zig_switch_{d}_dispatch_{d};", .{ @intFromEnum(br.block_inst), target_case_idx });5106 try bw.print("goto zig_switch_{d}_dispatch_{d};\n", .{ @intFromEnum(br.block_inst), target_case_idx });
5097 try f.object.newline();
5098 return;5107 return;
5099 }5108 }
51005109
...@@ -5106,7 +5115,7 @@ fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {...@@ -5106,7 +5115,7 @@ fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {
5106 try f.writeCValue(bw, cond, .Other);5115 try f.writeCValue(bw, cond, .Other);
5107 try bw.writeByte(';');5116 try bw.writeByte(';');
5108 try f.object.newline();5117 try f.object.newline();
5109 try bw.print("goto zig_switch_{d}_loop;", .{@intFromEnum(br.block_inst)});5118 try bw.print("goto zig_switch_{d}_loop;\n", .{@intFromEnum(br.block_inst)});
5110}5119}
51115120
5112fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {5121fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -5241,13 +5250,13 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal...@@ -5241,13 +5250,13 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
5241fn airTrap(f: *Function, bw: *std.io.BufferedWriter) !void {5250fn airTrap(f: *Function, bw: *std.io.BufferedWriter) !void {
5242 // Not even allowed to call trap in a naked function.5251 // Not even allowed to call trap in a naked function.
5243 if (f.object.dg.is_naked_fn) return;5252 if (f.object.dg.is_naked_fn) return;
5244 try bw.writeAll("zig_trap();");5253 try bw.writeAll("zig_trap();\n");
5245 try f.object.newline();
5246}5254}
52475255
5248fn airBreakpoint(o: *Object, bw: *std.io.BufferedWriter) !CValue {5256fn airBreakpoint(f: *Function) !CValue {
5257 const bw = &f.object.code.buffered_writer;
5249 try bw.writeAll("zig_breakpoint();");5258 try bw.writeAll("zig_breakpoint();");
5250 try o.newline();5259 try f.object.newline();
5251 return .none;5260 return .none;
5252}5261}
52535262
...@@ -5273,11 +5282,10 @@ fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5273,11 +5282,10 @@ fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
5273 return local;5282 return local;
5274}5283}
52755284
5276fn airUnreach(f: *Function) !void {5285fn airUnreach(o: *Object) !void {
5277 // Not even allowed to call unreachable in a naked function.5286 // Not even allowed to call unreachable in a naked function.
5278 if (f.object.dg.is_naked_fn) return;5287 if (o.dg.is_naked_fn) return;
5279 try f.object.code.buffered_writer.writeAll("zig_unreachable();");5288 try o.code.buffered_writer.writeAll("zig_unreachable();\n");
5280 try f.object.newline();
5281}5289}
52825290
5283fn airLoop(f: *Function, inst: Air.Inst.Index) !void {5291fn airLoop(f: *Function, inst: Air.Inst.Index) !void {
...@@ -5407,10 +5415,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void...@@ -5407,10 +5415,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
5407 f.object.indent();5415 f.object.indent();
5408 try f.object.newline();5416 try f.object.newline();
5409 if (is_dispatch_loop) {5417 if (is_dispatch_loop) {
5410 try bw.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx });5418 try bw.print("zig_switch_{d}_dispatch_{d}:;", .{ @intFromEnum(inst), case.idx });
5419 try f.object.newline();
5411 }5420 }
5412 try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true);5421 try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true);
5413 f.object.outdent();5422 try f.object.outdent();
5414 try bw.writeByte('}');5423 try bw.writeByte('}');
5415 if (f.object.dg.expected_block) |_|5424 if (f.object.dg.expected_block) |_|
5416 return f.fail("runtime code not allowed in naked function", .{});5425 return f.fail("runtime code not allowed in naked function", .{});
...@@ -5456,7 +5465,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void...@@ -5456,7 +5465,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
5456 try bw.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx });5465 try bw.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx });
5457 }5466 }
5458 try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true);5467 try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true);
5459 f.object.outdent();5468 try f.object.outdent();
5460 try bw.writeByte('}');5469 try bw.writeByte('}');
5461 if (f.object.dg.expected_block) |_|5470 if (f.object.dg.expected_block) |_|
5462 return f.fail("runtime code not allowed in naked function", .{});5471 return f.fail("runtime code not allowed in naked function", .{});
...@@ -5474,14 +5483,10 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void...@@ -5474,14 +5483,10 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
5474 try genBody(f, else_body);5483 try genBody(f, else_body);
5475 if (f.object.dg.expected_block) |_|5484 if (f.object.dg.expected_block) |_|
5476 return f.fail("runtime code not allowed in naked function", .{});5485 return f.fail("runtime code not allowed in naked function", .{});
5477 } else {5486 } else try airUnreach(&f.object);
5478 try bw.writeAll("zig_unreachable();");
5479 }
5480 try f.object.newline();
5481
5482 f.object.outdent();
5483 try bw.writeByte('}');
5484 try f.object.newline();5487 try f.object.newline();
5488 try f.object.outdent();
5489 try bw.writeAll("}\n");
5485}5490}
54865491
5487fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool {5492fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool {
...@@ -6868,7 +6873,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -6868,7 +6873,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
6868 try bw.writeAll("NULL");6873 try bw.writeAll("NULL");
6869 try a.end(f, bw);6874 try a.end(f, bw);
6870 }6875 }
6871 f.object.outdent();6876 try f.object.outdent();
6872 try bw.writeByte('}');6877 try bw.writeByte('}');
6873 try f.object.newline();6878 try f.object.newline();
6874 } else {6879 } else {
...@@ -8119,6 +8124,7 @@ fn compareOperatorC(operator: std.math.CompareOperator) []const u8 {...@@ -8119,6 +8124,7 @@ fn compareOperatorC(operator: std.math.CompareOperator) []const u8 {
8119const StringLiteral = struct {8124const StringLiteral = struct {
8120 len: usize,8125 len: usize,
8121 cur_len: usize,8126 cur_len: usize,
8127 start_count: usize,
8122 bw: *std.io.BufferedWriter,8128 bw: *std.io.BufferedWriter,
81238129
8124 // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal,8130 // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal,
...@@ -8136,6 +8142,7 @@ const StringLiteral = struct {...@@ -8136,6 +8142,7 @@ const StringLiteral = struct {
8136 return .{8142 return .{
8137 .cur_len = 0,8143 .cur_len = 0,
8138 .len = len,8144 .len = len,
8145 .start_count = bw.count,
8139 .bw = bw,8146 .bw = bw,
8140 };8147 };
8141 }8148 }
...@@ -8175,7 +8182,7 @@ const StringLiteral = struct {...@@ -8175,7 +8182,7 @@ const StringLiteral = struct {
81758182
8176 pub fn writeChar(sl: *StringLiteral, c: u8) std.io.Writer.Error!void {8183 pub fn writeChar(sl: *StringLiteral, c: u8) std.io.Writer.Error!void {
8177 if (sl.len <= max_string_initializer_len) {8184 if (sl.len <= max_string_initializer_len) {
8178 if (sl.cur_len == 0 and sl.bw.count > 1)8185 if (sl.cur_len == 0 and sl.bw.count - sl.start_count > 1)
8179 try sl.bw.writeAll("\"\"");8186 try sl.bw.writeAll("\"\"");
81808187
8181 const count = sl.bw.count;8188 const count = sl.bw.count;
...@@ -8186,7 +8193,7 @@ const StringLiteral = struct {...@@ -8186,7 +8193,7 @@ const StringLiteral = struct {
81868193
8187 if (sl.cur_len >= max_literal_len) sl.cur_len = 0;8194 if (sl.cur_len >= max_literal_len) sl.cur_len = 0;
8188 } else {8195 } else {
8189 if (sl.bw.count > 1) try sl.bw.writeByte(',');8196 if (sl.bw.count - sl.start_count > 1) try sl.bw.writeByte(',');
8190 try sl.bw.print("'\\x{x}'", .{c});8197 try sl.bw.print("'\\x{x}'", .{c});
8191 }8198 }
8192 }8199 }
...@@ -8502,7 +8509,7 @@ const Vectorize = struct {...@@ -8502,7 +8509,7 @@ const Vectorize = struct {
85028509
8503 pub fn end(self: Vectorize, f: *Function, inst: Air.Inst.Index, bw: *std.io.BufferedWriter) !void {8510 pub fn end(self: Vectorize, f: *Function, inst: Air.Inst.Index, bw: *std.io.BufferedWriter) !void {
8504 if (self.index != .none) {8511 if (self.index != .none) {
8505 f.object.outdent();8512 try f.object.outdent();
8506 try bw.writeByte('}');8513 try bw.writeByte('}');
8507 try f.object.newline();8514 try f.object.newline();
8508 try freeLocal(f, inst, self.index.new_local, null);8515 try freeLocal(f, inst, self.index.new_local, null);
test/behavior/error.zig+22-2
...@@ -1042,12 +1042,32 @@ test "generic type constructed from inferred error set of unresolved function" {...@@ -1042,12 +1042,32 @@ test "generic type constructed from inferred error set of unresolved function" {
1042 _ = bytes;1042 _ = bytes;
1043 return 0;1043 return 0;
1044 }1044 }
1045 const T = std.io.Writer(void, @typeInfo(@typeInfo(@TypeOf(write)).@"fn".return_type.?).error_union.error_set, write);1045 fn Writer(
1046 comptime Context: type,
1047 comptime WriteError: type,
1048 comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize,
1049 ) type {
1050 return struct {
1051 context: Context,
1052 comptime {
1053 _ = writeFn;
1054 }
1055 };
1056 }
1057 const T = Writer(void, @typeInfo(@typeInfo(@TypeOf(write)).@"fn".return_type.?).error_union.error_set, write);
1046 fn writer() T {1058 fn writer() T {
1047 return .{ .context = {} };1059 return .{ .context = {} };
1048 }1060 }
1061 fn multiWriter(streams: anytype) MultiWriter(@TypeOf(streams)) {
1062 return .{ .streams = streams };
1063 }
1064 fn MultiWriter(comptime Writers: type) type {
1065 return struct {
1066 streams: Writers,
1067 };
1068 }
1049 };1069 };
1050 _ = std.io.multiWriter(.{S.writer()});1070 _ = S.multiWriter(.{S.writer()});
1051}1071}
10521072
1053test "errorCast to adhoc inferred error set" {1073test "errorCast to adhoc inferred error set" {
test/behavior/packed-struct.zig+4-1
...@@ -1086,7 +1086,10 @@ test "packed struct used as part of anon decl name" {...@@ -1086,7 +1086,10 @@ test "packed struct used as part of anon decl name" {
1086 const S = packed struct { a: u0 = 0 };1086 const S = packed struct { a: u0 = 0 };
1087 var a: u8 = 0;1087 var a: u8 = 0;
1088 _ = &a;1088 _ = &a;
1089 try std.io.null_writer.print("\n{} {}\n", .{ a, S{} });1089 var buffer: [std.atomic.cache_line]u8 = undefined;
1090 var nw: std.io.Writer.Null = undefined;
1091 var bw = nw.writer().buffered(&buffer);
1092 try bw.print("\n{} {}\n", .{ a, S{} });
1090}1093}
10911094
1092test "packed struct acts as a namespace" {1095test "packed struct acts as a namespace" {
test/behavior/union_with_members.zig+2-2
...@@ -10,8 +10,8 @@ const ET = union(enum) {...@@ -10,8 +10,8 @@ const ET = union(enum) {
1010
11 pub fn print(a: *const ET, buf: []u8) anyerror!usize {11 pub fn print(a: *const ET, buf: []u8) anyerror!usize {
12 return switch (a.*) {12 return switch (a.*) {
13 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, .lower, fmt.FormatOptions{}),13 ET.SINT => |x| fmt.printInt(buf, x, 10, .lower, fmt.FormatOptions{}),
14 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, .lower, fmt.FormatOptions{}),14 ET.UINT => |x| fmt.printInt(buf, x, 10, .lower, fmt.FormatOptions{}),
15 };15 };
16 }16 }
17};17};
test/behavior/var_args.zig+2-2
...@@ -218,11 +218,11 @@ test "variadic functions" {...@@ -218,11 +218,11 @@ test "variadic functions" {
218 for (std.mem.span(format)) |c| switch (c) {218 for (std.mem.span(format)) |c| switch (c) {
219 's' => {219 's' => {
220 const arg = @cVaArg(ap, [*:0]const u8);220 const arg = @cVaArg(ap, [*:0]const u8);
221 list.writer().print("{s}", .{arg}) catch return;221 list.print("{s}", .{arg}) catch return;
222 },222 },
223 'd' => {223 'd' => {
224 const arg = @cVaArg(ap, c_int);224 const arg = @cVaArg(ap, c_int);
225 list.writer().print("{d}", .{arg}) catch return;225 list.print("{d}", .{arg}) catch return;
226 },226 },
227 else => unreachable,227 else => unreachable,
228 };228 };