authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-21 15:15:38-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-21 15:15:38-04:00
log18a43b61f92ae937e39fc5dbc3de581e26709151
tree5399ae5ccee2b92d278b03aa4f56d32f3c684df2
parent0577069af5f5deb859762725736537d60c324453
parent59668fbe802be744c200ea9fd38fda28f5f951c1
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11253 from Vexu/pretty-print-values

stage2: print values with types

10 files changed, 348 insertions(+), 41 deletions(-)

src/Sema.zig+8-8
......@@ -1867,7 +1867,7 @@ fn createTypeName(
18671867 const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg) catch unreachable;
18681868
18691869 if (arg_i != 0) try buf.appendSlice(",");
1870 try buf.writer().print("{}", .{arg_val});
1870 try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg))});
18711871
18721872 arg_i += 1;
18731873 continue;
......@@ -3673,7 +3673,7 @@ fn zirCompileLog(
36733673 const arg = sema.resolveInst(arg_ref);
36743674 const arg_ty = sema.typeOf(arg);
36753675 if (try sema.resolveMaybeUndefVal(block, src, arg)) |val| {
3676 try writer.print("@as({}, {})", .{ arg_ty, val });
3676 try writer.print("@as({}, {})", .{ arg_ty, val.fmtValue(arg_ty) });
36773677 } else {
36783678 try writer.print("@as({}, [runtime value])", .{arg_ty});
36793679 }
......@@ -5670,7 +5670,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
56705670 block,
56715671 src,
56725672 "enum '{}' has no tag with value {}",
5673 .{ dest_ty, int_val },
5673 .{ dest_ty, int_val.fmtValue(sema.typeOf(operand)) },
56745674 );
56755675 errdefer msg.destroy(sema.gpa);
56765676 try sema.mod.errNoteNonLazy(
......@@ -7900,7 +7900,7 @@ fn validateSwitchItemEnum(
79007900 block,
79017901 src,
79027902 "enum '{}' has no tag with value '{}'",
7903 .{ item_tv.ty, item_tv.val },
7903 .{ item_tv.ty, item_tv.val.fmtValue(item_tv.ty) },
79047904 );
79057905 errdefer msg.destroy(sema.gpa);
79067906 try sema.mod.errNoteNonLazy(
......@@ -17507,7 +17507,7 @@ fn coerce(
1750717507 const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :float;
1750817508
1750917509 if (val.floatHasFraction()) {
17510 return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val, dest_ty });
17510 return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val.fmtValue(inst_ty), dest_ty });
1751117511 }
1751217512 const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) {
1751317513 error.FloatCannotFit => {
......@@ -17521,7 +17521,7 @@ fn coerce(
1752117521 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
1752217522 // comptime known integer to other number
1752317523 if (!val.intFitsInType(dest_ty, target)) {
17524 return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty, val });
17524 return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty, val.fmtValue(inst_ty) });
1752517525 }
1752617526 return try sema.addConstant(dest_ty, val);
1752717527 }
......@@ -17556,7 +17556,7 @@ fn coerce(
1755617556 block,
1755717557 inst_src,
1755817558 "type {} cannot represent float value {}",
17559 .{ dest_ty, val },
17559 .{ dest_ty, val.fmtValue(inst_ty) },
1756017560 );
1756117561 }
1756217562 return try sema.addConstant(dest_ty, result_val);
......@@ -18850,7 +18850,7 @@ fn coerceEnumToUnion(
1885018850 const field_index = union_obj.tag_ty.enumTagFieldIndex(val) orelse {
1885118851 const msg = msg: {
1885218852 const msg = try sema.errMsg(block, inst_src, "union {} has no tag with value {}", .{
18853 union_ty, val,
18853 union_ty, val.fmtValue(tag_ty),
1885418854 });
1885518855 errdefer msg.destroy(sema.gpa);
1885618856 try sema.addDeclaredHereNote(msg, union_ty);
src/TypedValue.zig+281
......@@ -42,3 +42,284 @@ pub fn hash(tv: TypedValue, hasher: *std.hash.Wyhash) void {
4242pub fn enumToInt(tv: TypedValue, buffer: *Value.Payload.U64) Value {
4343 return tv.val.enumToInt(tv.ty, buffer);
4444}
45
46const max_aggregate_items = 100;
47
48pub fn format(
49 tv: TypedValue,
50 comptime fmt: []const u8,
51 options: std.fmt.FormatOptions,
52 writer: anytype,
53) !void {
54 comptime std.debug.assert(fmt.len == 0);
55 return tv.print(options, writer, 3);
56}
57
58pub fn print(
59 tv: TypedValue,
60 options: std.fmt.FormatOptions,
61 writer: anytype,
62 level: u8,
63) @TypeOf(writer).Error!void {
64 var val = tv.val;
65 var ty = tv.ty;
66 while (true) switch (val.tag()) {
67 .u1_type => return writer.writeAll("u1"),
68 .u8_type => return writer.writeAll("u8"),
69 .i8_type => return writer.writeAll("i8"),
70 .u16_type => return writer.writeAll("u16"),
71 .i16_type => return writer.writeAll("i16"),
72 .u32_type => return writer.writeAll("u32"),
73 .i32_type => return writer.writeAll("i32"),
74 .u64_type => return writer.writeAll("u64"),
75 .i64_type => return writer.writeAll("i64"),
76 .u128_type => return writer.writeAll("u128"),
77 .i128_type => return writer.writeAll("i128"),
78 .isize_type => return writer.writeAll("isize"),
79 .usize_type => return writer.writeAll("usize"),
80 .c_short_type => return writer.writeAll("c_short"),
81 .c_ushort_type => return writer.writeAll("c_ushort"),
82 .c_int_type => return writer.writeAll("c_int"),
83 .c_uint_type => return writer.writeAll("c_uint"),
84 .c_long_type => return writer.writeAll("c_long"),
85 .c_ulong_type => return writer.writeAll("c_ulong"),
86 .c_longlong_type => return writer.writeAll("c_longlong"),
87 .c_ulonglong_type => return writer.writeAll("c_ulonglong"),
88 .c_longdouble_type => return writer.writeAll("c_longdouble"),
89 .f16_type => return writer.writeAll("f16"),
90 .f32_type => return writer.writeAll("f32"),
91 .f64_type => return writer.writeAll("f64"),
92 .f80_type => return writer.writeAll("f80"),
93 .f128_type => return writer.writeAll("f128"),
94 .anyopaque_type => return writer.writeAll("anyopaque"),
95 .bool_type => return writer.writeAll("bool"),
96 .void_type => return writer.writeAll("void"),
97 .type_type => return writer.writeAll("type"),
98 .anyerror_type => return writer.writeAll("anyerror"),
99 .comptime_int_type => return writer.writeAll("comptime_int"),
100 .comptime_float_type => return writer.writeAll("comptime_float"),
101 .noreturn_type => return writer.writeAll("noreturn"),
102 .null_type => return writer.writeAll("@Type(.Null)"),
103 .undefined_type => return writer.writeAll("@Type(.Undefined)"),
104 .fn_noreturn_no_args_type => return writer.writeAll("fn() noreturn"),
105 .fn_void_no_args_type => return writer.writeAll("fn() void"),
106 .fn_naked_noreturn_no_args_type => return writer.writeAll("fn() callconv(.Naked) noreturn"),
107 .fn_ccc_void_no_args_type => return writer.writeAll("fn() callconv(.C) void"),
108 .single_const_pointer_to_comptime_int_type => return writer.writeAll("*const comptime_int"),
109 .anyframe_type => return writer.writeAll("anyframe"),
110 .const_slice_u8_type => return writer.writeAll("[]const u8"),
111 .const_slice_u8_sentinel_0_type => return writer.writeAll("[:0]const u8"),
112 .anyerror_void_error_union_type => return writer.writeAll("anyerror!void"),
113
114 .enum_literal_type => return writer.writeAll("@Type(.EnumLiteral)"),
115 .manyptr_u8_type => return writer.writeAll("[*]u8"),
116 .manyptr_const_u8_type => return writer.writeAll("[*]const u8"),
117 .manyptr_const_u8_sentinel_0_type => return writer.writeAll("[*:0]const u8"),
118 .atomic_order_type => return writer.writeAll("std.builtin.AtomicOrder"),
119 .atomic_rmw_op_type => return writer.writeAll("std.builtin.AtomicRmwOp"),
120 .calling_convention_type => return writer.writeAll("std.builtin.CallingConvention"),
121 .address_space_type => return writer.writeAll("std.builtin.AddressSpace"),
122 .float_mode_type => return writer.writeAll("std.builtin.FloatMode"),
123 .reduce_op_type => return writer.writeAll("std.builtin.ReduceOp"),
124 .call_options_type => return writer.writeAll("std.builtin.CallOptions"),
125 .prefetch_options_type => return writer.writeAll("std.builtin.PrefetchOptions"),
126 .export_options_type => return writer.writeAll("std.builtin.ExportOptions"),
127 .extern_options_type => return writer.writeAll("std.builtin.ExternOptions"),
128 .type_info_type => return writer.writeAll("std.builtin.Type"),
129
130 .empty_struct_value => return writer.writeAll(".{}"),
131 .aggregate => {
132 if (level == 0) {
133 return writer.writeAll(".{ ... }");
134 }
135 const vals = val.castTag(.aggregate).?.data;
136 if (ty.zigTypeTag() == .Struct) {
137 try writer.writeAll(".{ ");
138 const struct_fields = ty.structFields();
139 const max_len = std.math.min(struct_fields.count(), max_aggregate_items);
140
141 const field_names = struct_fields.keys();
142 const fields = struct_fields.values();
143
144 var i: u32 = 0;
145 while (i < max_len) : (i += 1) {
146 if (i != 0) try writer.writeAll(", ");
147 try writer.print(".{s} = ", .{field_names[i]});
148 try print(.{
149 .ty = fields[i].ty,
150 .val = vals[i],
151 }, options, writer, level - 1);
152 }
153 return writer.writeAll(" }");
154 } else {
155 try writer.writeAll(".{ ");
156 const elem_ty = ty.elemType2();
157 const max_len = std.math.min(ty.arrayLen(), max_aggregate_items);
158
159 var i: u32 = 0;
160 while (i < max_len) : (i += 1) {
161 if (i != 0) try writer.writeAll(", ");
162 try print(.{
163 .ty = elem_ty,
164 .val = vals[i],
165 }, options, writer, level - 1);
166 }
167 return writer.writeAll(" }");
168 }
169 },
170 .@"union" => {
171 if (level == 0) {
172 return writer.writeAll(".{ ... }");
173 }
174 const union_val = val.castTag(.@"union").?.data;
175 try writer.writeAll(".{ ");
176
177 try print(.{
178 .ty = ty.unionTagType().?,
179 .val = union_val.tag,
180 }, options, writer, level - 1);
181 try writer.writeAll(" = ");
182 try print(.{
183 .ty = ty.unionFieldType(union_val.tag),
184 .val = union_val.val,
185 }, options, writer, level - 1);
186
187 return writer.writeAll(" }");
188 },
189 .null_value => return writer.writeAll("null"),
190 .undef => return writer.writeAll("undefined"),
191 .zero => return writer.writeAll("0"),
192 .one => return writer.writeAll("1"),
193 .void_value => return writer.writeAll("{}"),
194 .unreachable_value => return writer.writeAll("unreachable"),
195 .the_only_possible_value => {
196 val = ty.onePossibleValue().?;
197 },
198 .bool_true => return writer.writeAll("true"),
199 .bool_false => return writer.writeAll("false"),
200 .ty => return val.castTag(.ty).?.data.format("", options, writer),
201 .int_type => {
202 const int_type = val.castTag(.int_type).?.data;
203 return writer.print("{s}{d}", .{
204 if (int_type.signed) "s" else "u",
205 int_type.bits,
206 });
207 },
208 .int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", options, writer),
209 .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, writer),
210 .int_big_positive => return writer.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
211 .int_big_negative => return writer.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
212 .function => return writer.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}),
213 .extern_fn => return writer.writeAll("(extern function)"),
214 .variable => return writer.writeAll("(variable)"),
215 .decl_ref_mut => {
216 const decl = val.castTag(.decl_ref_mut).?.data.decl;
217 if (level == 0) {
218 return writer.print("(decl ref mut '{s}')", .{decl.name});
219 }
220 return print(.{
221 .ty = decl.ty,
222 .val = decl.val,
223 }, options, writer, level - 1);
224 },
225 .decl_ref => {
226 const decl = val.castTag(.decl_ref).?.data;
227 if (level == 0) {
228 return writer.print("(decl ref '{s}')", .{decl.name});
229 }
230 return print(.{
231 .ty = decl.ty,
232 .val = decl.val,
233 }, options, writer, level - 1);
234 },
235 .elem_ptr => {
236 const elem_ptr = val.castTag(.elem_ptr).?.data;
237 try writer.writeAll("&");
238 try print(.{
239 .ty = elem_ptr.elem_ty,
240 .val = elem_ptr.array_ptr,
241 }, options, writer, level - 1);
242 return writer.print("[{}]", .{elem_ptr.index});
243 },
244 .field_ptr => {
245 const field_ptr = val.castTag(.field_ptr).?.data;
246 try writer.writeAll("&");
247 try print(.{
248 .ty = field_ptr.container_ty,
249 .val = field_ptr.container_ptr,
250 }, options, writer, level - 1);
251
252 if (field_ptr.container_ty.zigTypeTag() == .Struct) {
253 const field_name = field_ptr.container_ty.structFields().keys()[field_ptr.field_index];
254 return writer.print(".{s}", .{field_name});
255 } else if (field_ptr.container_ty.zigTypeTag() == .Union) {
256 const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index];
257 return writer.print(".{s}", .{field_name});
258 } else unreachable;
259 },
260 .empty_array => return writer.writeAll(".{}"),
261 .enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),
262 .enum_field_index => {
263 return writer.print(".{s}", .{ty.enumFieldName(val.castTag(.enum_field_index).?.data)});
264 },
265 .bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
266 .repeated => {
267 if (level == 0) {
268 return writer.writeAll(".{ ... }");
269 }
270 var i: u32 = 0;
271 try writer.writeAll(".{ ");
272 const elem_tv = TypedValue{
273 .ty = ty.elemType2(),
274 .val = val.castTag(.repeated).?.data,
275 };
276 while (i < max_aggregate_items) : (i += 1) {
277 if (i != 0) try writer.writeAll(", ");
278 try print(elem_tv, options, writer, level - 1);
279 }
280 return writer.writeAll(" }");
281 },
282 .empty_array_sentinel => {
283 if (level == 0) {
284 return writer.writeAll(".{ (sentinel) }");
285 }
286 try writer.writeAll(".{ ");
287 try print(.{
288 .ty = ty.elemType2(),
289 .val = ty.sentinel().?,
290 }, options, writer, level - 1);
291 return writer.writeAll(" }");
292 },
293 .slice => return writer.writeAll("(slice)"),
294 .float_16 => return writer.print("{}", .{val.castTag(.float_16).?.data}),
295 .float_32 => return writer.print("{}", .{val.castTag(.float_32).?.data}),
296 .float_64 => return writer.print("{}", .{val.castTag(.float_64).?.data}),
297 .float_80 => return writer.print("{}", .{val.castTag(.float_80).?.data}),
298 .float_128 => return writer.print("{}", .{val.castTag(.float_128).?.data}),
299 .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}),
300 .eu_payload => {
301 val = val.castTag(.eu_payload).?.data;
302 },
303 .opt_payload => {
304 val = val.castTag(.opt_payload).?.data;
305 },
306 .eu_payload_ptr => {
307 try writer.writeAll("&");
308 val = val.castTag(.eu_payload_ptr).?.data.container_ptr;
309 },
310 .opt_payload_ptr => {
311 try writer.writeAll("&");
312 val = val.castTag(.opt_payload_ptr).?.data.container_ptr;
313 },
314
315 // TODO these should not appear in this function
316 .inferred_alloc => return writer.writeAll("(inferred allocation value)"),
317 .inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),
318 .bound_fn => {
319 const bound_func = val.castTag(.bound_fn).?.data;
320 return writer.print("(bound_fn %{}(%{})", .{ bound_func.func_inst, bound_func.arg0_inst });
321 },
322 .generic_poison_type => return writer.writeAll("(generic poison type)"),
323 .generic_poison => return writer.writeAll("(generic poison)"),
324 };
325}
src/arch/aarch64/CodeGen.zig+1-1
......@@ -3873,7 +3873,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
38733873}
38743874
38753875fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
3876 log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty, tv.val });
3876 log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty, tv.val.fmtDebug() });
38773877 const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| {
38783878 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
38793879 };
src/arch/x86_64/CodeGen.zig+1-1
......@@ -5735,7 +5735,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
57355735}
57365736
57375737fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
5738 log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty, tv.val });
5738 log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty, tv.val.fmtDebug() });
57395739 const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| {
57405740 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
57415741 };
src/codegen.zig+1-1
......@@ -165,7 +165,7 @@ pub fn generateSymbol(
165165 const target = bin_file.options.target;
166166 const endian = target.cpu.arch.endian();
167167
168 log.debug("generateSymbol: ty = {}, val = {}", .{ typed_value.ty, typed_value.val });
168 log.debug("generateSymbol: ty = {}, val = {}", .{ typed_value.ty, typed_value.val.fmtDebug() });
169169
170170 if (typed_value.val.isUndefDeep()) {
171171 const abi_size = try math.cast(usize, typed_value.ty.abiSize(target));
src/codegen/llvm.zig+1-1
......@@ -1676,7 +1676,7 @@ pub const DeclGen = struct {
16761676 const decl = dg.decl;
16771677 assert(decl.has_tv);
16781678
1679 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val });
1679 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val.fmtDebug() });
16801680
16811681 if (decl.val.castTag(.function)) |func_payload| {
16821682 _ = func_payload;
src/print_air.zig+1-1
......@@ -491,7 +491,7 @@ const Writer = struct {
491491 fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
492492 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
493493 const val = w.air.values[ty_pl.payload];
494 try s.print("{}, {}", .{ w.air.getRefType(ty_pl.ty), val });
494 try s.print("{}, {}", .{ w.air.getRefType(ty_pl.ty), val.fmtDebug() });
495495 }
496496
497497 fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
src/type.zig+5-7
......@@ -1633,7 +1633,7 @@ pub const Type = extern union {
16331633 },
16341634 .array_sentinel => {
16351635 const payload = ty.castTag(.array_sentinel).?.data;
1636 try writer.print("[{d}:{}]", .{ payload.len, payload.sentinel });
1636 try writer.print("[{d}:{}]", .{ payload.len, payload.sentinel.fmtValue(payload.elem_type) });
16371637 ty = payload.elem_type;
16381638 continue;
16391639 },
......@@ -1648,8 +1648,7 @@ pub const Type = extern union {
16481648 }
16491649 try field_ty.format("", .{}, writer);
16501650 if (val.tag() != .unreachable_value) {
1651 try writer.writeAll(" = ");
1652 try val.format("", .{}, writer);
1651 try writer.print(" = {}", .{val.fmtValue(field_ty)});
16531652 }
16541653 }
16551654 try writer.writeAll("}");
......@@ -1668,8 +1667,7 @@ pub const Type = extern union {
16681667 try writer.writeAll(": ");
16691668 try field_ty.format("", .{}, writer);
16701669 if (val.tag() != .unreachable_value) {
1671 try writer.writeAll(" = ");
1672 try val.format("", .{}, writer);
1670 try writer.print(" = {}", .{val.fmtValue(field_ty)});
16731671 }
16741672 }
16751673 try writer.writeAll("}");
......@@ -1754,8 +1752,8 @@ pub const Type = extern union {
17541752 const payload = ty.castTag(.pointer).?.data;
17551753 if (payload.sentinel) |some| switch (payload.size) {
17561754 .One, .C => unreachable,
1757 .Many => try writer.print("[*:{}]", .{some}),
1758 .Slice => try writer.print("[:{}]", .{some}),
1755 .Many => try writer.print("[*:{}]", .{some.fmtValue(payload.pointee_type)}),
1756 .Slice => try writer.print("[:{}]", .{some.fmtValue(payload.pointee_type)}),
17591757 } else switch (payload.size) {
17601758 .One => try writer.writeAll("*"),
17611759 .Many => try writer.writeAll("[*]"),
src/value.zig+19-1
......@@ -600,9 +600,17 @@ pub const Value = extern union {
600600 return Value{ .ptr_otherwise = &new_payload.base };
601601 }
602602
603 pub fn format(val: Value, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
604 _ = val;
605 _ = fmt;
606 _ = options;
607 _ = writer;
608 @compileError("do not use format values directly; use either fmtDebug or fmtValue");
609 }
610
603611 /// TODO this should become a debug dump() function. In order to print values in a meaningful way
604612 /// we also need access to the type.
605 pub fn format(
613 pub fn dump(
606614 start_val: Value,
607615 comptime fmt: []const u8,
608616 options: std.fmt.FormatOptions,
......@@ -766,6 +774,16 @@ pub const Value = extern union {
766774 };
767775 }
768776
777 pub fn fmtDebug(val: Value) std.fmt.Formatter(dump) {
778 return .{ .data = val };
779 }
780
781 const TypedValue = @import("TypedValue.zig");
782
783 pub fn fmtValue(val: Value, ty: Type) std.fmt.Formatter(TypedValue.format) {
784 return .{ .data = .{ .ty = ty, .val = val } };
785 }
786
769787 /// Asserts that the value is representable as an array of bytes.
770788 /// Copies the value into a freshly allocated slice of memory, which is owned by the caller.
771789 pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator) ![]u8 {
test/behavior/comptime_memory.zig+30-20
......@@ -5,10 +5,8 @@ const ptr_size = @sizeOf(usize);
55
66test "type pun signed and unsigned as single pointer" {
77 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
8 if (builtin.zig_backend != .stage1) {
9 // TODO https://github.com/ziglang/zig/issues/9646
10 return error.SkipZigTest;
11 }
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1210
1311 comptime {
1412 var x: u32 = 0;
......@@ -20,10 +18,7 @@ test "type pun signed and unsigned as single pointer" {
2018
2119test "type pun signed and unsigned as many pointer" {
2220 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
23 if (builtin.zig_backend != .stage1) {
24 // TODO https://github.com/ziglang/zig/issues/9646
25 return error.SkipZigTest;
26 }
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2722
2823 comptime {
2924 var x: u32 = 0;
......@@ -35,10 +30,7 @@ test "type pun signed and unsigned as many pointer" {
3530
3631test "type pun signed and unsigned as array pointer" {
3732 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
38 if (builtin.zig_backend != .stage1) {
39 // TODO https://github.com/ziglang/zig/issues/9646
40 return error.SkipZigTest;
41 }
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4234
4335 comptime {
4436 var x: u32 = 0;
......@@ -82,10 +74,7 @@ test "type pun signed and unsigned as array pointer" {
8274
8375test "type pun value and struct" {
8476 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
85 if (builtin.zig_backend != .stage1) {
86 // TODO https://github.com/ziglang/zig/issues/9646
87 return error.SkipZigTest;
88 }
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8978
9079 comptime {
9180 const StructOfU32 = extern struct { x: u32 };
......@@ -102,10 +91,8 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
10291}
10392test "type pun endianness" {
10493 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
105 if (builtin.zig_backend != .stage1) {
106 // TODO https://github.com/ziglang/zig/issues/9646
107 return error.SkipZigTest;
108 }
94 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
95 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10996
11097 comptime {
11198 const StructOfBytes = extern struct { x: [4]u8 };
......@@ -412,3 +399,26 @@ test "offset field ptr by enclosing array element size" {
412399 }
413400 }
414401}
402
403test "accessing reinterpreted memory of parent object" {
404 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
406 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
407 const S = extern struct {
408 a: f32,
409 b: [4]u8,
410 c: f32,
411 };
412 const expected = if (endian == .Little) 102 else 38;
413
414 comptime {
415 const x = S{
416 .a = 1.5,
417 .b = [_]u8{ 1, 2, 3, 4 },
418 .c = 2.6,
419 };
420 const ptr = &x.b[0];
421 const b = @ptrCast([*c]const u8, ptr)[5];
422 try testing.expect(b == expected);
423 }
424}