| ... | ... | @@ -9972,11 +9972,16 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9972 | 9972 | const array_ptr = try sema.resolveInst(extra.lhs); |
| 9973 | 9973 | const start = try sema.resolveInst(extra.start); |
| 9974 | 9974 | const len = try sema.resolveInst(extra.len); |
| 9975 | const sentinel = try sema.resolveInst(extra.sentinel); |
| 9975 | 9976 | const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node }; |
| 9976 | 9977 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset }; |
| 9977 | 9978 | const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; |
| 9979 | const sentinel_src: LazySrcLoc = if (sentinel == .none) |
| 9980 | .unneeded |
| 9981 | else |
| 9982 | .{ .node_offset_slice_sentinel = inst_data.src_node }; |
| 9978 | 9983 | |
| 9979 | | return sema.analyzeSlice(block, src, array_ptr, start, len, .none, .unneeded, ptr_src, start_src, end_src, true); |
| 9984 | return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true); |
| 9980 | 9985 | } |
| 9981 | 9986 | |
| 9982 | 9987 | fn zirSwitchCapture( |
| ... | ... | @@ -29283,17 +29288,15 @@ fn analyzeSlice( |
| 29283 | 29288 | // we might learn of the length because it is a comptime-known slice value. |
| 29284 | 29289 | var end_is_len = uncasted_end_opt == .none; |
| 29285 | 29290 | const end = e: { |
| 29286 | | if (by_length and !end_is_len) { |
| 29287 | | if (!block.wantSafety()) break :e undefined; |
| 29288 | | const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29289 | | const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); |
| 29290 | | const end = try sema.coerce(block, Type.usize, uncasted_end, end_src); |
| 29291 | | break :e end; |
| 29292 | | } else if (array_ty.zigTypeTag() == .Array) { |
| 29291 | if (array_ty.zigTypeTag() == .Array) { |
| 29293 | 29292 | const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()); |
| 29294 | 29293 | |
| 29295 | 29294 | if (!end_is_len) { |
| 29296 | | const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29295 | const end = if (by_length) end: { |
| 29296 | const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29297 | const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); |
| 29298 | break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); |
| 29299 | } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29297 | 29300 | if (try sema.resolveMaybeUndefVal(end)) |end_val| { |
| 29298 | 29301 | const len_s_val = try Value.Tag.int_u64.create( |
| 29299 | 29302 | sema.arena, |
| ... | ... | @@ -29330,7 +29333,11 @@ fn analyzeSlice( |
| 29330 | 29333 | break :e try sema.addConstant(Type.usize, len_val); |
| 29331 | 29334 | } else if (slice_ty.isSlice()) { |
| 29332 | 29335 | if (!end_is_len) { |
| 29333 | | const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29336 | const end = if (by_length) end: { |
| 29337 | const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29338 | const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); |
| 29339 | break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); |
| 29340 | } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29334 | 29341 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| 29335 | 29342 | if (try sema.resolveMaybeUndefVal(ptr_or_slice)) |slice_val| { |
| 29336 | 29343 | if (slice_val.isUndef()) { |
| ... | ... | @@ -29399,66 +29406,64 @@ fn analyzeSlice( |
| 29399 | 29406 | const slice_sentinel = if (sentinel_opt != .none) sentinel else null; |
| 29400 | 29407 | |
| 29401 | 29408 | // requirement: start <= end |
| 29402 | | if (!by_length) { |
| 29403 | | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| 29404 | | if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { |
| 29405 | | if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { |
| 29406 | | return sema.fail( |
| 29409 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| 29410 | if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { |
| 29411 | if (!by_length and !(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { |
| 29412 | return sema.fail( |
| 29413 | block, |
| 29414 | start_src, |
| 29415 | "start index {} is larger than end index {}", |
| 29416 | .{ |
| 29417 | start_val.fmtValue(Type.usize, mod), |
| 29418 | end_val.fmtValue(Type.usize, mod), |
| 29419 | }, |
| 29420 | ); |
| 29421 | } |
| 29422 | if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: { |
| 29423 | const expected_sentinel = sentinel orelse break :sentinel_check; |
| 29424 | const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; |
| 29425 | const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; |
| 29426 | const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); |
| 29427 | |
| 29428 | const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); |
| 29429 | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); |
| 29430 | const actual_sentinel = switch (res) { |
| 29431 | .runtime_load => break :sentinel_check, |
| 29432 | .val => |v| v, |
| 29433 | .needed_well_defined => |ty| return sema.fail( |
| 29407 | 29434 | block, |
| 29408 | | start_src, |
| 29409 | | "start index {} is larger than end index {}", |
| 29410 | | .{ |
| 29411 | | start_val.fmtValue(Type.usize, mod), |
| 29412 | | end_val.fmtValue(Type.usize, mod), |
| 29413 | | }, |
| 29414 | | ); |
| 29415 | | } |
| 29416 | | if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: { |
| 29417 | | const expected_sentinel = sentinel orelse break :sentinel_check; |
| 29418 | | const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; |
| 29419 | | const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; |
| 29420 | | const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); |
| 29421 | | |
| 29422 | | const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); |
| 29423 | | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); |
| 29424 | | const actual_sentinel = switch (res) { |
| 29425 | | .runtime_load => break :sentinel_check, |
| 29426 | | .val => |v| v, |
| 29427 | | .needed_well_defined => |ty| return sema.fail( |
| 29428 | | block, |
| 29429 | | src, |
| 29430 | | "comptime dereference requires '{}' to have a well-defined layout, but it does not.", |
| 29431 | | .{ty.fmt(sema.mod)}, |
| 29432 | | ), |
| 29433 | | .out_of_bounds => |ty| return sema.fail( |
| 29434 | | block, |
| 29435 | | end_src, |
| 29436 | | "slice end index {d} exceeds bounds of containing decl of type '{}'", |
| 29437 | | .{ end_int, ty.fmt(sema.mod) }, |
| 29438 | | ), |
| 29439 | | }; |
| 29435 | src, |
| 29436 | "comptime dereference requires '{}' to have a well-defined layout, but it does not.", |
| 29437 | .{ty.fmt(sema.mod)}, |
| 29438 | ), |
| 29439 | .out_of_bounds => |ty| return sema.fail( |
| 29440 | block, |
| 29441 | end_src, |
| 29442 | "slice end index {d} exceeds bounds of containing decl of type '{}'", |
| 29443 | .{ end_int, ty.fmt(sema.mod) }, |
| 29444 | ), |
| 29445 | }; |
| 29440 | 29446 | |
| 29441 | | if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { |
| 29442 | | const msg = msg: { |
| 29443 | | const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); |
| 29444 | | errdefer msg.destroy(sema.gpa); |
| 29445 | | try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ |
| 29446 | | expected_sentinel.fmtValue(elem_ty, sema.mod), |
| 29447 | | actual_sentinel.fmtValue(elem_ty, sema.mod), |
| 29448 | | }); |
| 29447 | if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { |
| 29448 | const msg = msg: { |
| 29449 | const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); |
| 29450 | errdefer msg.destroy(sema.gpa); |
| 29451 | try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ |
| 29452 | expected_sentinel.fmtValue(elem_ty, sema.mod), |
| 29453 | actual_sentinel.fmtValue(elem_ty, sema.mod), |
| 29454 | }); |
| 29449 | 29455 | |
| 29450 | | break :msg msg; |
| 29451 | | }; |
| 29452 | | return sema.failWithOwnedErrorMsg(msg); |
| 29453 | | } |
| 29456 | break :msg msg; |
| 29457 | }; |
| 29458 | return sema.failWithOwnedErrorMsg(msg); |
| 29454 | 29459 | } |
| 29455 | 29460 | } |
| 29456 | 29461 | } |
| 29462 | } |
| 29457 | 29463 | |
| 29458 | | if (block.wantSafety() and !block.is_comptime) { |
| 29459 | | // requirement: start <= end |
| 29460 | | try sema.panicStartLargerThanEnd(block, start, end); |
| 29461 | | } |
| 29464 | if (!by_length and block.wantSafety() and !block.is_comptime) { |
| 29465 | // requirement: start <= end |
| 29466 | try sema.panicStartLargerThanEnd(block, start, end); |
| 29462 | 29467 | } |
| 29463 | 29468 | const new_len = if (by_length) |
| 29464 | 29469 | try sema.coerce(block, Type.usize, uncasted_end_opt, end_src) |