authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-14 00:23:27-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-14 00:23:27-05:00
logec58ddf46c4e1ac060333c6d0780955acae22442
tree16b1f97c8962817dccdcc90ffbd7169bb8171ef7
parent0d45c72d3e4f38029a453443ae6a34c398f5c530
parent336d0c97feabad4c93525ba6ef73a6b6163f49c7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10582 from ziglang/stage2-arrays

stage2: detection of comptime array literals

10 files changed, 329 insertions(+), 110 deletions(-)

src/AstGen.zig+8-1
......@@ -1418,7 +1418,13 @@ fn arrayInitExprRlPtrInner(
14181418 extra_index += 1;
14191419 _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init);
14201420 }
1421 _ = try gz.addPlNodePayloadIndex(.validate_array_init, node, payload_index);
1421
1422 const tag: Zir.Inst.Tag = if (gz.force_comptime)
1423 .validate_array_init_comptime
1424 else
1425 .validate_array_init;
1426
1427 _ = try gz.addPlNodePayloadIndex(tag, node, payload_index);
14221428 return .void_value;
14231429}
14241430
......@@ -2317,6 +2323,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
23172323 .validate_struct_init,
23182324 .validate_struct_init_comptime,
23192325 .validate_array_init,
2326 .validate_array_init_comptime,
23202327 .set_align_stack,
23212328 .set_cold,
23222329 .set_float_mode,
src/Sema.zig+220-84
......@@ -836,7 +836,12 @@ pub fn analyzeBody(
836836 continue;
837837 },
838838 .validate_array_init => {
839 try sema.zirValidateArrayInit(block, inst);
839 try sema.zirValidateArrayInit(block, inst, false);
840 i += 1;
841 continue;
842 },
843 .validate_array_init_comptime => {
844 try sema.zirValidateArrayInit(block, inst, true);
840845 i += 1;
841846 continue;
842847 },
......@@ -2815,13 +2820,18 @@ fn validateStructInit(
28152820 }
28162821}
28172822
2818fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
2823fn zirValidateArrayInit(
2824 sema: *Sema,
2825 block: *Block,
2826 inst: Zir.Inst.Index,
2827 is_comptime: bool,
2828) CompileError!void {
28192829 const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
28202830 const init_src = validate_inst.src();
28212831 const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index);
28222832 const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len];
2823 const elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
2824 const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, elem_ptr_data.payload_index).data;
2833 const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
2834 const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data;
28252835 const array_ptr = sema.resolveInst(elem_ptr_extra.ptr);
28262836 const array_ty = sema.typeOf(array_ptr).childType();
28272837 const array_len = array_ty.arrayLen();
......@@ -2831,6 +2841,82 @@ fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
28312841 array_len, instrs.len,
28322842 });
28332843 }
2844
2845 if (is_comptime or block.is_comptime) {
2846 // In this case the comptime machinery will have evaluated the store instructions
2847 // at comptime and we have nothing to do here.
2848 return;
2849 }
2850
2851 var array_is_comptime = true;
2852 var first_block_index: usize = std.math.maxInt(u32);
2853
2854 // Collect the comptime element values in case the array literal ends up
2855 // being comptime-known.
2856 const element_vals = try sema.arena.alloc(Value, instrs.len);
2857 const opt_opv = try sema.typeHasOnePossibleValue(block, init_src, array_ty);
2858 const air_tags = sema.air_instructions.items(.tag);
2859 const air_datas = sema.air_instructions.items(.data);
2860
2861 for (instrs) |elem_ptr, i| {
2862 const elem_ptr_data = sema.code.instructions.items(.data)[elem_ptr].pl_node;
2863 const elem_src: LazySrcLoc = .{ .node_offset = elem_ptr_data.src_node };
2864
2865 // Determine whether the value stored to this pointer is comptime-known.
2866
2867 if (opt_opv) |opv| {
2868 element_vals[i] = opv;
2869 continue;
2870 }
2871
2872 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
2873 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;
2874 // Find the block index of the elem_ptr so that we can look at the next
2875 // instruction after it within the same block.
2876 // Possible performance enhancement: save the `block_index` between iterations
2877 // of the for loop.
2878 const next_air_inst = inst: {
2879 var block_index = block.instructions.items.len - 1;
2880 while (block.instructions.items[block_index] != elem_ptr_air_inst) {
2881 block_index -= 1;
2882 }
2883 first_block_index = @minimum(first_block_index, block_index);
2884 break :inst block.instructions.items[block_index + 1];
2885 };
2886
2887 // If the next instructon is a store with a comptime operand, this element
2888 // is comptime.
2889 switch (air_tags[next_air_inst]) {
2890 .store => {
2891 const bin_op = air_datas[next_air_inst].bin_op;
2892 if (bin_op.lhs != elem_ptr_air_ref) {
2893 array_is_comptime = false;
2894 continue;
2895 }
2896 if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| {
2897 element_vals[i] = val;
2898 } else {
2899 array_is_comptime = false;
2900 }
2901 continue;
2902 },
2903 else => {
2904 array_is_comptime = false;
2905 continue;
2906 },
2907 }
2908 }
2909
2910 if (array_is_comptime) {
2911 // Our task is to delete all the `elem_ptr` and `store` instructions, and insert
2912 // instead a single `store` to the array_ptr with a comptime struct value.
2913
2914 block.instructions.shrinkRetainingCapacity(first_block_index);
2915
2916 const array_val = try Value.Tag.array.create(sema.arena, element_vals);
2917 const array_init = try sema.addConstant(array_ty, array_val);
2918 try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
2919 }
28342920}
28352921
28362922fn failWithBadMemberAccess(
......@@ -14085,88 +14171,112 @@ fn beginComptimePtrMutation(
1408514171 .elem_ptr => {
1408614172 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
1408714173 var parent = try beginComptimePtrMutation(sema, block, src, elem_ptr.array_ptr);
14088 const elem_ty = parent.ty.childType();
14089 switch (parent.val.tag()) {
14090 .undef => {
14091 // An array has been initialized to undefined at comptime and now we
14092 // are for the first time setting an element. We must change the representation
14093 // of the array from `undef` to `array`.
14094 const arena = parent.beginArena(sema.gpa);
14095 defer parent.finishArena();
14174 switch (parent.ty.zigTypeTag()) {
14175 .Array, .Vector => {
14176 const check_len = parent.ty.arrayLenIncludingSentinel();
14177 if (elem_ptr.index >= check_len) {
14178 // TODO have the parent include the decl so we can say "declared here"
14179 return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{
14180 elem_ptr.index, check_len,
14181 });
14182 }
14183 const elem_ty = parent.ty.childType();
14184 switch (parent.val.tag()) {
14185 .undef => {
14186 // An array has been initialized to undefined at comptime and now we
14187 // are for the first time setting an element. We must change the representation
14188 // of the array from `undef` to `array`.
14189 const arena = parent.beginArena(sema.gpa);
14190 defer parent.finishArena();
14191
14192 const array_len_including_sentinel =
14193 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
14194 const elems = try arena.alloc(Value, array_len_including_sentinel);
14195 mem.set(Value, elems, Value.undef);
14196
14197 parent.val.* = try Value.Tag.array.create(arena, elems);
1409614198
14097 const array_len_including_sentinel =
14098 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
14099 const elems = try arena.alloc(Value, array_len_including_sentinel);
14100 mem.set(Value, elems, Value.undef);
14199 return ComptimePtrMutationKit{
14200 .decl_ref_mut = parent.decl_ref_mut,
14201 .val = &elems[elem_ptr.index],
14202 .ty = elem_ty,
14203 };
14204 },
14205 .bytes => {
14206 // An array is memory-optimized to store a slice of bytes, but we are about
14207 // to modify an individual field and the representation has to change.
14208 // If we wanted to avoid this, there would need to be special detection
14209 // elsewhere to identify when writing a value to an array element that is stored
14210 // using the `bytes` tag, and handle it without making a call to this function.
14211 const arena = parent.beginArena(sema.gpa);
14212 defer parent.finishArena();
14213
14214 const bytes = parent.val.castTag(.bytes).?.data;
14215 const dest_len = parent.ty.arrayLenIncludingSentinel();
14216 // bytes.len may be one greater than dest_len because of the case when
14217 // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted.
14218 assert(bytes.len >= dest_len);
14219 const elems = try arena.alloc(Value, @intCast(usize, dest_len));
14220 for (elems) |*elem, i| {
14221 elem.* = try Value.Tag.int_u64.create(arena, bytes[i]);
14222 }
1410114223
14102 parent.val.* = try Value.Tag.array.create(arena, elems);
14224 parent.val.* = try Value.Tag.array.create(arena, elems);
1410314225
14104 return ComptimePtrMutationKit{
14105 .decl_ref_mut = parent.decl_ref_mut,
14106 .val = &elems[elem_ptr.index],
14107 .ty = elem_ty,
14108 };
14109 },
14110 .bytes => {
14111 // An array is memory-optimized to store a slice of bytes, but we are about
14112 // to modify an individual field and the representation has to change.
14113 // If we wanted to avoid this, there would need to be special detection
14114 // elsewhere to identify when writing a value to an array element that is stored
14115 // using the `bytes` tag, and handle it without making a call to this function.
14116 const arena = parent.beginArena(sema.gpa);
14117 defer parent.finishArena();
14226 return ComptimePtrMutationKit{
14227 .decl_ref_mut = parent.decl_ref_mut,
14228 .val = &elems[elem_ptr.index],
14229 .ty = elem_ty,
14230 };
14231 },
14232 .repeated => {
14233 // An array is memory-optimized to store only a single element value, and
14234 // that value is understood to be the same for the entire length of the array.
14235 // However, now we want to modify an individual field and so the
14236 // representation has to change. If we wanted to avoid this, there would
14237 // need to be special detection elsewhere to identify when writing a value to an
14238 // array element that is stored using the `repeated` tag, and handle it
14239 // without making a call to this function.
14240 const arena = parent.beginArena(sema.gpa);
14241 defer parent.finishArena();
14242
14243 const repeated_val = try parent.val.castTag(.repeated).?.data.copy(arena);
14244 const array_len_including_sentinel =
14245 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
14246 const elems = try arena.alloc(Value, array_len_including_sentinel);
14247 mem.set(Value, elems, repeated_val);
14248
14249 parent.val.* = try Value.Tag.array.create(arena, elems);
1411814250
14119 const bytes = parent.val.castTag(.bytes).?.data;
14120 const dest_len = parent.ty.arrayLenIncludingSentinel();
14121 // bytes.len may be one greater than dest_len because of the case when
14122 // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted.
14123 assert(bytes.len >= dest_len);
14124 const elems = try arena.alloc(Value, @intCast(usize, dest_len));
14125 for (elems) |*elem, i| {
14126 elem.* = try Value.Tag.int_u64.create(arena, bytes[i]);
14127 }
14251 return ComptimePtrMutationKit{
14252 .decl_ref_mut = parent.decl_ref_mut,
14253 .val = &elems[elem_ptr.index],
14254 .ty = elem_ty,
14255 };
14256 },
1412814257
14129 parent.val.* = try Value.Tag.array.create(arena, elems);
14258 .array => return ComptimePtrMutationKit{
14259 .decl_ref_mut = parent.decl_ref_mut,
14260 .val = &parent.val.castTag(.array).?.data[elem_ptr.index],
14261 .ty = elem_ty,
14262 },
1413014263
14131 return ComptimePtrMutationKit{
14132 .decl_ref_mut = parent.decl_ref_mut,
14133 .val = &elems[elem_ptr.index],
14134 .ty = elem_ty,
14135 };
14264 else => unreachable,
14265 }
1413614266 },
14137 .repeated => {
14138 // An array is memory-optimized to store only a single element value, and
14139 // that value is understood to be the same for the entire length of the array.
14140 // However, now we want to modify an individual field and so the
14141 // representation has to change. If we wanted to avoid this, there would
14142 // need to be special detection elsewhere to identify when writing a value to an
14143 // array element that is stored using the `repeated` tag, and handle it
14144 // without making a call to this function.
14145 const arena = parent.beginArena(sema.gpa);
14146 defer parent.finishArena();
14147
14148 const repeated_val = try parent.val.castTag(.repeated).?.data.copy(arena);
14149 const array_len_including_sentinel =
14150 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
14151 const elems = try arena.alloc(Value, array_len_including_sentinel);
14152 mem.set(Value, elems, repeated_val);
14153
14154 parent.val.* = try Value.Tag.array.create(arena, elems);
14155
14267 else => {
14268 if (elem_ptr.index != 0) {
14269 // TODO include a "declared here" note for the decl
14270 return sema.fail(block, src, "out of bounds comptime store of index {d}", .{
14271 elem_ptr.index,
14272 });
14273 }
1415614274 return ComptimePtrMutationKit{
1415714275 .decl_ref_mut = parent.decl_ref_mut,
14158 .val = &elems[elem_ptr.index],
14159 .ty = elem_ty,
14276 .val = parent.val,
14277 .ty = parent.ty,
1416014278 };
1416114279 },
14162
14163 .array => return ComptimePtrMutationKit{
14164 .decl_ref_mut = parent.decl_ref_mut,
14165 .val = &parent.val.castTag(.array).?.data[elem_ptr.index],
14166 .ty = elem_ty,
14167 },
14168
14169 else => unreachable,
1417014280 }
1417114281 },
1417214282 .field_ptr => {
......@@ -14296,15 +14406,41 @@ fn beginComptimePtrLoad(
1429614406 .elem_ptr => {
1429714407 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
1429814408 const parent = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr);
14299 const elem_ty = parent.ty.childType();
14300 const elem_size = elem_ty.abiSize(target);
14301 return ComptimePtrLoadKit{
14302 .root_val = parent.root_val,
14303 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),
14304 .ty = elem_ty,
14305 .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + elem_size * elem_ptr.index),
14306 .is_mutable = parent.is_mutable,
14307 };
14409 switch (parent.ty.zigTypeTag()) {
14410 .Array, .Vector => {
14411 const check_len = parent.ty.arrayLenIncludingSentinel();
14412 if (elem_ptr.index >= check_len) {
14413 // TODO have the parent include the decl so we can say "declared here"
14414 return sema.fail(block, src, "comptime load of index {d} out of bounds of array length {d}", .{
14415 elem_ptr.index, check_len,
14416 });
14417 }
14418 const elem_ty = parent.ty.childType();
14419 const elem_size = elem_ty.abiSize(target);
14420 return ComptimePtrLoadKit{
14421 .root_val = parent.root_val,
14422 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),
14423 .ty = elem_ty,
14424 .byte_offset = try sema.usizeCast(block, src, parent.byte_offset + elem_size * elem_ptr.index),
14425 .is_mutable = parent.is_mutable,
14426 };
14427 },
14428 else => {
14429 if (elem_ptr.index != 0) {
14430 // TODO have the parent include the decl so we can say "declared here"
14431 return sema.fail(block, src, "out of bounds comptime load of index {d}", .{
14432 elem_ptr.index,
14433 });
14434 }
14435 return ComptimePtrLoadKit{
14436 .root_val = parent.root_val,
14437 .val = parent.val,
14438 .ty = parent.ty,
14439 .byte_offset = parent.byte_offset,
14440 .is_mutable = parent.is_mutable,
14441 };
14442 },
14443 }
1430814444 },
1430914445 .field_ptr => {
1431014446 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
src/Zir.zig+5
......@@ -663,6 +663,9 @@ pub const Inst = struct {
663663 /// because it must use one of them to find out the array type.
664664 /// Uses the `pl_node` field. Payload is `Block`.
665665 validate_array_init,
666 /// Same as `validate_array_init` but additionally communicates that the
667 /// resulting array initialization value is within a comptime scope.
668 validate_array_init_comptime,
666669 /// A struct literal with a specified type, with no fields.
667670 /// Uses the `un_node` field.
668671 struct_init_empty,
......@@ -1087,6 +1090,7 @@ pub const Inst = struct {
10871090 .validate_struct_init,
10881091 .validate_struct_init_comptime,
10891092 .validate_array_init,
1093 .validate_array_init_comptime,
10901094 .struct_init_empty,
10911095 .struct_init,
10921096 .struct_init_ref,
......@@ -1341,6 +1345,7 @@ pub const Inst = struct {
13411345 .validate_struct_init = .pl_node,
13421346 .validate_struct_init_comptime = .pl_node,
13431347 .validate_array_init = .pl_node,
1348 .validate_array_init_comptime = .pl_node,
13441349 .struct_init_empty = .un_node,
13451350 .field_type = .pl_node,
13461351 .field_type_ref = .pl_node,
src/codegen/c.zig+64-12
......@@ -44,7 +44,7 @@ const BlockData = struct {
4444 result: CValue,
4545};
4646
47pub const CValueMap = std.AutoHashMap(Air.Inst.Index, CValue);
47pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
4848pub const TypedefMap = std.ArrayHashMap(
4949 Type,
5050 struct { name: []const u8, rendered: []u8 },
......@@ -110,11 +110,29 @@ pub const Function = struct {
110110 func: *Module.Fn,
111111
112112 fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue {
113 if (f.air.value(inst)) |_| {
114 return CValue{ .constant = inst };
113 const gop = try f.value_map.getOrPut(inst);
114 if (gop.found_existing) return gop.value_ptr.*;
115
116 const val = f.air.value(inst).?;
117 const ty = f.air.typeOf(inst);
118 switch (ty.zigTypeTag()) {
119 .Array => {
120 const writer = f.object.code_header.writer();
121 const decl_c_value = f.allocLocalValue();
122 gop.value_ptr.* = decl_c_value;
123 try writer.writeAll("static ");
124 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const);
125 try writer.writeAll(" = ");
126 try f.object.dg.renderValue(writer, ty, val);
127 try writer.writeAll(";\n ");
128 return decl_c_value;
129 },
130 else => {
131 const result = CValue{ .constant = inst };
132 gop.value_ptr.* = result;
133 return result;
134 },
115135 }
116 const index = Air.refToIndex(inst).?;
117 return f.value_map.get(index).?; // Assertion means instruction does not dominate usage.
118136 }
119137
120138 fn allocLocalValue(f: *Function) CValue {
......@@ -154,6 +172,8 @@ pub const Function = struct {
154172pub const Object = struct {
155173 dg: DeclGen,
156174 code: std.ArrayList(u8),
175 /// Goes before code. Initialized and deinitialized in `genFunc`.
176 code_header: std.ArrayList(u8) = undefined,
157177 indent_writer: IndentWriter(std.ArrayList(u8).Writer),
158178
159179 fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer {
......@@ -218,12 +238,18 @@ pub const DeclGen = struct {
218238 // Determine if we must pointer cast.
219239 if (ty.eql(decl.ty)) {
220240 try writer.writeByte('&');
221 } else {
222 try writer.writeAll("(");
223 try dg.renderType(writer, ty);
224 try writer.writeAll(")&");
241 try dg.renderDeclName(decl, writer);
242 return;
225243 }
244
245 try writer.writeAll("((");
246 try dg.renderType(writer, ty);
247 try writer.writeAll(")&");
248 try dg.renderDeclName(decl, writer);
249 try writer.writeByte(')');
250 return;
226251 }
252
227253 try dg.renderDeclName(decl, writer);
228254 }
229255
......@@ -1010,6 +1036,10 @@ pub fn genFunc(f: *Function) !void {
10101036 defer tracy.end();
10111037
10121038 const o = &f.object;
1039
1040 o.code_header = std.ArrayList(u8).init(f.object.dg.gpa);
1041 defer o.code_header.deinit();
1042
10131043 const is_global = o.dg.module.decl_exports.contains(f.func.owner_decl);
10141044 const fwd_decl_writer = o.dg.fwd_decl.writer();
10151045 if (is_global) {
......@@ -1020,12 +1050,26 @@ pub fn genFunc(f: *Function) !void {
10201050
10211051 try o.indent_writer.insertNewline();
10221052 try o.dg.renderFunctionSignature(o.writer(), is_global);
1023
10241053 try o.writer().writeByte(' ');
1054
1055 // In case we need to use the header, populate it with a copy of the function
1056 // signature here. We anticipate a brace, newline, and space.
1057 try o.code_header.ensureUnusedCapacity(o.code.items.len + 3);
1058 o.code_header.appendSliceAssumeCapacity(o.code.items);
1059 o.code_header.appendSliceAssumeCapacity("{\n ");
1060 const empty_header_len = o.code_header.items.len;
1061
10251062 const main_body = f.air.getMainBody();
10261063 try genBody(f, main_body);
10271064
10281065 try o.indent_writer.insertNewline();
1066
1067 // If we have a header to insert, append the body to the header
1068 // and then return the result, freeing the body.
1069 if (o.code_header.items.len > empty_header_len) {
1070 try o.code_header.appendSlice(o.code.items[empty_header_len..]);
1071 mem.swap(std.ArrayList(u8), &o.code, &o.code_header);
1072 }
10291073}
10301074
10311075pub fn genDecl(o: *Object) !void {
......@@ -1289,7 +1333,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
12891333 };
12901334 switch (result_value) {
12911335 .none => {},
1292 else => try f.value_map.putNoClobber(inst, result_value),
1336 else => try f.value_map.putNoClobber(Air.indexToRef(inst), result_value),
12931337 }
12941338 }
12951339
......@@ -2189,7 +2233,15 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
21892233fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
21902234 const dbg_stmt = f.air.instructions.items(.data)[inst].dbg_stmt;
21912235 const writer = f.object.writer();
2192 try writer.print("#line {d}\n", .{dbg_stmt.line + 1});
2236 // TODO re-evaluate whether to emit these or not. If we naively emit
2237 // these directives, the output file will report bogus line numbers because
2238 // every newline after the #line directive adds one to the line.
2239 // We also don't print the filename yet, so the output is strictly unhelpful.
2240 // If we wanted to go this route, we would need to go all the way and not output
2241 // newlines until the next dbg_stmt occurs.
2242 // Perhaps an additional compilation option is in order?
2243 //try writer.print("#line {d}\n", .{dbg_stmt.line + 1});
2244 try writer.print("/* file:{d}:{d} */\n", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
21932245 return CValue.none;
21942246}
21952247
src/print_zir.zig+1
......@@ -369,6 +369,7 @@ const Writer = struct {
369369 .validate_struct_init,
370370 .validate_struct_init_comptime,
371371 .validate_array_init,
372 .validate_array_init_comptime,
372373 .c_import,
373374 => try self.writePlNodeBlock(stream, inst),
374375
src/value.zig+6-1
......@@ -1817,8 +1817,13 @@ pub const Value = extern union {
18171817
18181818 .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer),
18191819 .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.val.elemValueAdvanced(index, arena, buffer),
1820 .elem_ptr => {
1821 const data = val.castTag(.elem_ptr).?.data;
1822 return data.array_ptr.elemValueAdvanced(index + data.index, arena, buffer);
1823 },
18201824
1821 // The child type of arrays which have only one possible value need to have only one possible value itself.
1825 // The child type of arrays which have only one possible value need
1826 // to have only one possible value itself.
18221827 .the_only_possible_value => return val,
18231828
18241829 else => unreachable,
test/behavior/array.zig+7
......@@ -114,6 +114,13 @@ test "void arrays" {
114114}
115115
116116test "nested arrays" {
117 if (builtin.zig_backend == .stage2_wasm) {
118 // TODO this is a recent stage2 test case regression due to an enhancement;
119 // now arrays are properly detected as comptime. This exercised a new code
120 // path in the wasm backend that is not yet implemented.
121 return error.SkipZigTest;
122 }
123
117124 const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
118125 for (array_of_strings) |s, i| {
119126 if (i == 0) try expect(mem.eql(u8, s, "hello"));
test/behavior/array_llvm.zig+12
......@@ -33,3 +33,15 @@ test "read/write through global variable array of struct fields initialized via
3333 };
3434 try S.doTheTest();
3535}
36
37test "implicit cast single-item pointer" {
38 try testImplicitCastSingleItemPtr();
39 comptime try testImplicitCastSingleItemPtr();
40}
41
42fn testImplicitCastSingleItemPtr() !void {
43 var byte: u8 = 100;
44 const slice = @as(*[1]u8, &byte)[0..];
45 slice[0] += 1;
46 try expect(byte == 101);
47}
test/behavior/array_stage1.zig-12
......@@ -4,18 +4,6 @@ const mem = std.mem;
44const expect = testing.expect;
55const expectEqual = testing.expectEqual;
66
7test "implicit cast single-item pointer" {
8 try testImplicitCastSingleItemPtr();
9 comptime try testImplicitCastSingleItemPtr();
10}
11
12fn testImplicitCastSingleItemPtr() !void {
13 var byte: u8 = 100;
14 const slice = @as(*[1]u8, &byte)[0..];
15 slice[0] += 1;
16 try expect(byte == 101);
17}
18
197fn testArrayByValAtComptime(b: [2]u8) u8 {
208 return b[0];
219}
test/behavior/for.zig+6
......@@ -62,6 +62,12 @@ test "ignore lval with underscore (for loop)" {
6262}
6363
6464test "basic for loop" {
65 if (@import("builtin").zig_backend == .stage2_wasm) {
66 // TODO this is a recent stage2 test case regression due to an enhancement;
67 // now arrays are properly detected as comptime. This exercised a new code
68 // path in the wasm backend that is not yet implemented.
69 return error.SkipZigTest;
70 }
6571 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
6672
6773 var buffer: [expected_result.len]u8 = undefined;