From a62b5d84d834757682be9b5a0606ff8168c1d594 Mon Sep 17 00:00:00 2001 From: dweiller <4678790+dweiller@users.noreplay.github.com> Date: Sun, 30 Apr 2023 12:25:13 +1000 Subject: zir: add slice_length tag --- src/Sema.zig | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/Sema.zig') diff --git a/src/Sema.zig b/src/Sema.zig index b2387dfe12..d225a8f7b3 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -985,6 +985,7 @@ fn analyzeBodyInner( .slice_end => try sema.zirSliceEnd(block, inst), .slice_sentinel => try sema.zirSliceSentinel(block, inst), .slice_start => try sema.zirSliceStart(block, inst), + .slice_length => try sema.zirSliceLength(block, inst), .str => try sema.zirStr(block, inst), .switch_block => try sema.zirSwitchBlock(block, inst), .switch_cond => try sema.zirSwitchCond(block, inst, false), @@ -9961,6 +9962,15 @@ fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src); } +fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const tracy = trace(@src()); + defer tracy.end(); + + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.fail(block, src, "TODO: implement .slice_length", .{}); +} + fn zirSwitchCapture( sema: *Sema, block: *Block, -- cgit v1.2.3 From e58a0c5e9e9a6eab7f5efdc60b0f3d5b9c106786 Mon Sep 17 00:00:00 2001 From: dweiller <4678790+dweiller@users.noreplay.github.com> Date: Sun, 30 Apr 2023 15:00:28 +1000 Subject: sema: implement slice_length ZIR instruction --- src/Sema.zig | 133 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 57 deletions(-) (limited to 'src/Sema.zig') diff --git a/src/Sema.zig b/src/Sema.zig index d225a8f7b3..bcb13ec6f0 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9923,7 +9923,7 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; - return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src); + return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src, false); } fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9940,7 +9940,7 @@ fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; - return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src); + return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src, false); } fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9959,7 +9959,7 @@ fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node }; const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; - return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src); + return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src, false); } fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9968,7 +9968,15 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); - return sema.fail(block, src, "TODO: implement .slice_length", .{}); + const extra = sema.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data; + const array_ptr = try sema.resolveInst(extra.lhs); + const start = try sema.resolveInst(extra.start); + const len = try sema.resolveInst(extra.len); + const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node }; + const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset }; + const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; + + return sema.analyzeSlice(block, src, array_ptr, start, len, .none, .unneeded, ptr_src, start_src, end_src, true); } fn zirSwitchCapture( @@ -29200,6 +29208,7 @@ fn analyzeSlice( ptr_src: LazySrcLoc, start_src: LazySrcLoc, end_src: LazySrcLoc, + by_length: bool, ) CompileError!Air.Inst.Ref { // Slice expressions can operate on a variable whose type is an array. This requires // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer. @@ -29274,7 +29283,12 @@ fn analyzeSlice( // we might learn of the length because it is a comptime-known slice value. var end_is_len = uncasted_end_opt == .none; const end = e: { - if (array_ty.zigTypeTag() == .Array) { + if (by_length and !end_is_len) { + const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); + const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); + const end = try sema.coerce(block, Type.usize, uncasted_end, end_src); + break :e end; + } else if (array_ty.zigTypeTag() == .Array) { const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()); if (!end_is_len) { @@ -29384,66 +29398,71 @@ fn analyzeSlice( const slice_sentinel = if (sentinel_opt != .none) sentinel else null; // requirement: start <= end - if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { - if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { - if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { - return sema.fail( - block, - start_src, - "start index {} is larger than end index {}", - .{ - start_val.fmtValue(Type.usize, mod), - end_val.fmtValue(Type.usize, mod), - }, - ); - } - if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: { - const expected_sentinel = sentinel orelse break :sentinel_check; - const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; - const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; - const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); - - const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); - const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); - const actual_sentinel = switch (res) { - .runtime_load => break :sentinel_check, - .val => |v| v, - .needed_well_defined => |ty| return sema.fail( - block, - src, - "comptime dereference requires '{}' to have a well-defined layout, but it does not.", - .{ty.fmt(sema.mod)}, - ), - .out_of_bounds => |ty| return sema.fail( + if (!by_length) { + if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { + if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { + if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { + return sema.fail( block, - end_src, - "slice end index {d} exceeds bounds of containing decl of type '{}'", - .{ end_int, ty.fmt(sema.mod) }, - ), - }; + start_src, + "start index {} is larger than end index {}", + .{ + start_val.fmtValue(Type.usize, mod), + end_val.fmtValue(Type.usize, mod), + }, + ); + } + if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: { + const expected_sentinel = sentinel orelse break :sentinel_check; + const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; + const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; + const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); + + const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); + const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); + const actual_sentinel = switch (res) { + .runtime_load => break :sentinel_check, + .val => |v| v, + .needed_well_defined => |ty| return sema.fail( + block, + src, + "comptime dereference requires '{}' to have a well-defined layout, but it does not.", + .{ty.fmt(sema.mod)}, + ), + .out_of_bounds => |ty| return sema.fail( + block, + end_src, + "slice end index {d} exceeds bounds of containing decl of type '{}'", + .{ end_int, ty.fmt(sema.mod) }, + ), + }; - if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { - const msg = msg: { - const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); - errdefer msg.destroy(sema.gpa); - try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ - expected_sentinel.fmtValue(elem_ty, sema.mod), - actual_sentinel.fmtValue(elem_ty, sema.mod), - }); + if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { + const msg = msg: { + const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); + errdefer msg.destroy(sema.gpa); + try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ + expected_sentinel.fmtValue(elem_ty, sema.mod), + actual_sentinel.fmtValue(elem_ty, sema.mod), + }); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(msg); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + } } } } - } - if (block.wantSafety() and !block.is_comptime) { - // requirement: start <= end - try sema.panicStartLargerThanEnd(block, start, end); + if (block.wantSafety() and !block.is_comptime) { + // requirement: start <= end + try sema.panicStartLargerThanEnd(block, start, end); + } } - const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false); + const new_len = if (by_length) + try sema.coerce(block, Type.usize, uncasted_end_opt, end_src) + else + try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false); const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data; -- cgit v1.2.3 From 8aa70cf6cd88b6103200d558c60295550c7b911d Mon Sep 17 00:00:00 2001 From: dweiller <4678790+dweiller@users.noreplay.github.com> Date: Sun, 30 Apr 2023 14:38:11 +1000 Subject: sema: omit extraneous addition when safety is unwanted --- src/Sema.zig | 1 + 1 file changed, 1 insertion(+) (limited to 'src/Sema.zig') diff --git a/src/Sema.zig b/src/Sema.zig index bcb13ec6f0..17ba89a6e3 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -29284,6 +29284,7 @@ fn analyzeSlice( var end_is_len = uncasted_end_opt == .none; const end = e: { if (by_length and !end_is_len) { + if (!block.wantSafety()) break :e undefined; const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); const end = try sema.coerce(block, Type.usize, uncasted_end, end_src); -- cgit v1.2.3 From 64e319f5555a25dbf4c4d7e65289f7f96d6588b4 Mon Sep 17 00:00:00 2001 From: dweiller <4678790+dweiller@users.noreplay.github.com> Date: Sun, 30 Apr 2023 23:50:08 +1000 Subject: add optional sentinel to slice_length ZIR --- src/AstGen.zig | 42 +++++++++++++++-- src/Autodoc.zig | 17 ++++++- src/Sema.zig | 131 ++++++++++++++++++++++++++++-------------------------- src/Zir.zig | 3 +- src/print_zir.zig | 4 ++ 5 files changed, 129 insertions(+), 68 deletions(-) (limited to 'src/Sema.zig') diff --git a/src/AstGen.zig b/src/AstGen.zig index c8d079f1e1..8df8f0e1cf 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -851,9 +851,18 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE .slice => { const extra = tree.extraData(node_datas[node].rhs, Ast.Node.Slice); const lhs_node = node_datas[node].lhs; - if (node_tags[lhs_node] == .slice_open and nodeIsTriviallyZero(tree, extra.start)) { + const lhs_tag = node_tags[lhs_node]; + const lhs_is_slice_sentinel = lhs_tag == .slice_sentinel; + const lhs_is_open_slice = lhs_tag == .slice_open or + (lhs_is_slice_sentinel and tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel).end == 0); + if (lhs_is_open_slice and nodeIsTriviallyZero(tree, extra.start)) { const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[lhs_node].lhs); - const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[lhs_node].rhs); + + const start = if (lhs_is_slice_sentinel) start: { + const lhs_extra = tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel); + break :start try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, lhs_extra.start); + } else try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[lhs_node].rhs); + const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); const len = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none; try emitDbgStmt(gz, cursor); @@ -862,6 +871,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE .start = start, .len = len, .start_src_node_offset = gz.nodeIndexToRelative(lhs_node), + .sentinel = .none, }); return rvalue(gz, ri, result, node); } @@ -879,10 +889,36 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE return rvalue(gz, ri, result, node); }, .slice_sentinel => { + const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SliceSentinel); + const lhs_node = node_datas[node].lhs; + const lhs_tag = node_tags[lhs_node]; + const lhs_is_slice_sentinel = lhs_tag == .slice_sentinel; + const lhs_is_open_slice = lhs_tag == .slice_open or + (lhs_is_slice_sentinel and tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel).end == 0); + if (lhs_is_open_slice and nodeIsTriviallyZero(tree, extra.start)) { + const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[lhs_node].lhs); + + const start = if (lhs_is_slice_sentinel) start: { + const lhs_extra = tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel); + break :start try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, lhs_extra.start); + } else try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[lhs_node].rhs); + + const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); + const len = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none; + const sentinel = try expr(gz, scope, .{ .rl = .none }, extra.sentinel); + try emitDbgStmt(gz, cursor); + const result = try gz.addPlNode(.slice_length, node, Zir.Inst.SliceLength{ + .lhs = lhs, + .start = start, + .len = len, + .start_src_node_offset = gz.nodeIndexToRelative(lhs_node), + .sentinel = sentinel, + }); + return rvalue(gz, ri, result, node); + } const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); - const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SliceSentinel); const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.start); const end = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none; const sentinel = try expr(gz, scope, .{ .rl = .none }, extra.sentinel); diff --git a/src/Autodoc.zig b/src/Autodoc.zig index b068c260ef..eba53b7e17 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -1315,6 +1315,16 @@ fn walkInstruction( extra.data.len, false, ); + var sentinel_opt: ?DocData.WalkResult = if (extra.data.sentinel != .none) + try self.walkRef( + file, + parent_scope, + parent_src, + extra.data.sentinel, + false, + ) + else + null; const lhs_index = self.exprs.items.len; try self.exprs.append(self.arena, lhs.expr); @@ -1322,7 +1332,12 @@ fn walkInstruction( try self.exprs.append(self.arena, start.expr); const len_index = self.exprs.items.len; try self.exprs.append(self.arena, len.expr); - self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index, .end = len_index } }; + const sentinel_index = if (sentinel_opt) |sentinel| sentinel_index: { + const index = self.exprs.items.len; + try self.exprs.append(self.arena, sentinel.expr); + break :sentinel_index index; + } else null; + self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index, .end = len_index, .sentinel = sentinel_index } }; return DocData.WalkResult{ .typeRef = self.decls.items[lhs.expr.declRef.Analyzed].value.typeRef, diff --git a/src/Sema.zig b/src/Sema.zig index 17ba89a6e3..8deca97505 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9972,11 +9972,16 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const array_ptr = try sema.resolveInst(extra.lhs); const start = try sema.resolveInst(extra.start); const len = try sema.resolveInst(extra.len); + const sentinel = try sema.resolveInst(extra.sentinel); const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node }; const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset }; const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; + const sentinel_src: LazySrcLoc = if (sentinel == .none) + .unneeded + else + .{ .node_offset_slice_sentinel = inst_data.src_node }; - return sema.analyzeSlice(block, src, array_ptr, start, len, .none, .unneeded, ptr_src, start_src, end_src, true); + return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true); } fn zirSwitchCapture( @@ -29283,17 +29288,15 @@ fn analyzeSlice( // we might learn of the length because it is a comptime-known slice value. var end_is_len = uncasted_end_opt == .none; const end = e: { - if (by_length and !end_is_len) { - if (!block.wantSafety()) break :e undefined; - const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); - const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); - const end = try sema.coerce(block, Type.usize, uncasted_end, end_src); - break :e end; - } else if (array_ty.zigTypeTag() == .Array) { + if (array_ty.zigTypeTag() == .Array) { const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()); if (!end_is_len) { - const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); + const end = if (by_length) end: { + const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); + const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); + break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); + } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); if (try sema.resolveMaybeUndefVal(end)) |end_val| { const len_s_val = try Value.Tag.int_u64.create( sema.arena, @@ -29330,7 +29333,11 @@ fn analyzeSlice( break :e try sema.addConstant(Type.usize, len_val); } else if (slice_ty.isSlice()) { if (!end_is_len) { - const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); + const end = if (by_length) end: { + const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); + const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); + break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); + } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { if (try sema.resolveMaybeUndefVal(ptr_or_slice)) |slice_val| { if (slice_val.isUndef()) { @@ -29399,66 +29406,64 @@ fn analyzeSlice( const slice_sentinel = if (sentinel_opt != .none) sentinel else null; // requirement: start <= end - if (!by_length) { - if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { - if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { - if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { - return sema.fail( + if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { + if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { + if (!by_length and !(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { + return sema.fail( + block, + start_src, + "start index {} is larger than end index {}", + .{ + start_val.fmtValue(Type.usize, mod), + end_val.fmtValue(Type.usize, mod), + }, + ); + } + if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: { + const expected_sentinel = sentinel orelse break :sentinel_check; + const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; + const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; + const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); + + const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); + const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); + const actual_sentinel = switch (res) { + .runtime_load => break :sentinel_check, + .val => |v| v, + .needed_well_defined => |ty| return sema.fail( block, - start_src, - "start index {} is larger than end index {}", - .{ - start_val.fmtValue(Type.usize, mod), - end_val.fmtValue(Type.usize, mod), - }, - ); - } - if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: { - const expected_sentinel = sentinel orelse break :sentinel_check; - const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; - const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; - const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); - - const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); - const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); - const actual_sentinel = switch (res) { - .runtime_load => break :sentinel_check, - .val => |v| v, - .needed_well_defined => |ty| return sema.fail( - block, - src, - "comptime dereference requires '{}' to have a well-defined layout, but it does not.", - .{ty.fmt(sema.mod)}, - ), - .out_of_bounds => |ty| return sema.fail( - block, - end_src, - "slice end index {d} exceeds bounds of containing decl of type '{}'", - .{ end_int, ty.fmt(sema.mod) }, - ), - }; + src, + "comptime dereference requires '{}' to have a well-defined layout, but it does not.", + .{ty.fmt(sema.mod)}, + ), + .out_of_bounds => |ty| return sema.fail( + block, + end_src, + "slice end index {d} exceeds bounds of containing decl of type '{}'", + .{ end_int, ty.fmt(sema.mod) }, + ), + }; - if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { - const msg = msg: { - const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); - errdefer msg.destroy(sema.gpa); - try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ - expected_sentinel.fmtValue(elem_ty, sema.mod), - actual_sentinel.fmtValue(elem_ty, sema.mod), - }); + if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { + const msg = msg: { + const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); + errdefer msg.destroy(sema.gpa); + try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ + expected_sentinel.fmtValue(elem_ty, sema.mod), + actual_sentinel.fmtValue(elem_ty, sema.mod), + }); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(msg); - } + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); } } } + } - if (block.wantSafety() and !block.is_comptime) { - // requirement: start <= end - try sema.panicStartLargerThanEnd(block, start, end); - } + if (!by_length and block.wantSafety() and !block.is_comptime) { + // requirement: start <= end + try sema.panicStartLargerThanEnd(block, start, end); } const new_len = if (by_length) try sema.coerce(block, Type.usize, uncasted_end_opt, end_src) diff --git a/src/Zir.zig b/src/Zir.zig index 27ea02e642..ccff32c435 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -570,7 +570,7 @@ pub const Inst = struct { /// Returns a pointer to the subslice. /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceSentinel`. slice_sentinel, - /// Slice operation `array_ptr[start..][0..len]`. No sentinel. + /// Slice operation `array_ptr[start..][0..len]`. Optional sentinel. /// Returns a pointer to the subslice. /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceLength`. slice_length, @@ -2991,6 +2991,7 @@ pub const Inst = struct { lhs: Ref, start: Ref, len: Ref, + sentinel: Ref, start_src_node_offset: i32, }; diff --git a/src/print_zir.zig b/src/print_zir.zig index 6d1a716d3c..f5e84fcf5b 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -765,6 +765,10 @@ const Writer = struct { try self.writeInstRef(stream, extra.start); try stream.writeAll(", "); try self.writeInstRef(stream, extra.len); + if (extra.sentinel != .none) { + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.sentinel); + } try stream.writeAll(") "); try self.writeSrc(stream, inst_data.src()); } -- cgit v1.2.3 From cba9077cc12b953dd00369f9c0340d7667af1611 Mon Sep 17 00:00:00 2001 From: dweiller <4678790+dweiller@users.noreplay.github.com> Date: Wed, 3 May 2023 11:30:30 +1000 Subject: sema: fix slice by length non-array, non-slice case --- src/Sema.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/Sema.zig') diff --git a/src/Sema.zig b/src/Sema.zig index 8deca97505..68fbfe08d1 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -29384,7 +29384,11 @@ fn analyzeSlice( break :e try sema.analyzeSliceLen(block, src, ptr_or_slice); } if (!end_is_len) { - break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); + if (by_length) { + const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); + const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); + break :e try sema.coerce(block, Type.usize, uncasted_end, end_src); + } else break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); } return sema.fail(block, src, "slice of pointer must include end value", .{}); }; -- cgit v1.2.3