diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-02-19 10:20:19 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-02-19 10:20:19 -0700 |
| commit | b5b634e4e8a2a1fe32fba50ccd175257b4213936 (patch) | |
| tree | 4eed625db81dd4d6907e386084df36ec3ac85687 /src/Sema.zig | |
| parent | efdc94c10712f610e7de5e49fd9cd6f88b4bbbae (diff) | |
| parent | 02f5d2673f1bb21e7329acdd664fed565ecd4317 (diff) | |
| download | zig-b5b634e4e8a2a1fe32fba50ccd175257b4213936.tar.gz zig-b5b634e4e8a2a1fe32fba50ccd175257b4213936.zip | |
Merge remote-tracking branch 'origin/master' into llvm16
Diffstat (limited to 'src/Sema.zig')
| -rw-r--r-- | src/Sema.zig | 509 |
1 files changed, 334 insertions, 175 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index cf6350e35f..fcdb1ce518 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1035,6 +1035,7 @@ fn analyzeBodyInner( .@"await" => try sema.zirAwait(block, inst), .array_base_ptr => try sema.zirArrayBasePtr(block, inst), .field_base_ptr => try sema.zirFieldBasePtr(block, inst), + .for_len => try sema.zirForLen(block, inst), .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), @@ -1059,15 +1060,16 @@ fn analyzeBodyInner( .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon), .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func), - .add => try sema.zirArithmetic(block, inst, .add), - .addwrap => try sema.zirArithmetic(block, inst, .addwrap), - .add_sat => try sema.zirArithmetic(block, inst, .add_sat), - .mul => try sema.zirArithmetic(block, inst, .mul), - .mulwrap => try sema.zirArithmetic(block, inst, .mulwrap), - .mul_sat => try sema.zirArithmetic(block, inst, .mul_sat), - .sub => try sema.zirArithmetic(block, inst, .sub), - .subwrap => try sema.zirArithmetic(block, inst, .subwrap), - .sub_sat => try sema.zirArithmetic(block, inst, .sub_sat), + .add => try sema.zirArithmetic(block, inst, .add, true), + .addwrap => try sema.zirArithmetic(block, inst, .addwrap, true), + .add_sat => try sema.zirArithmetic(block, inst, .add_sat, true), + .add_unsafe=> try sema.zirArithmetic(block, inst, .add_unsafe, false), + .mul => try sema.zirArithmetic(block, inst, .mul, true), + .mulwrap => try sema.zirArithmetic(block, inst, .mulwrap, true), + .mul_sat => try sema.zirArithmetic(block, inst, .mul_sat, true), + .sub => try sema.zirArithmetic(block, inst, .sub, true), + .subwrap => try sema.zirArithmetic(block, inst, .subwrap, true), + .sub_sat => try sema.zirArithmetic(block, inst, .sub_sat, true), .div => try sema.zirDiv(block, inst), .div_exact => try sema.zirDivExact(block, inst), @@ -3377,26 +3379,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE else object_ty; - if (!array_ty.isIndexable()) { - const msg = msg: { - const msg = try sema.errMsg( - block, - src, - "type '{}' does not support indexing", - .{array_ty.fmt(sema.mod)}, - ); - errdefer msg.destroy(sema.gpa); - try sema.errNote( - block, - src, - msg, - "for loop operand must be an array, slice, tuple, or vector", - .{}, - ); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(msg); - } + try checkIndexable(sema, block, src, array_ty); return sema.fieldVal(block, src, object, "len", src); } @@ -3819,7 +3802,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty); const empty_trash_count = trash_block.instructions.items.len; - for (placeholders) |bitcast_inst, i| { + for (placeholders, 0..) |bitcast_inst, i| { const sub_ptr_ty = sema.typeOf(Air.indexToRef(bitcast_inst)); if (mut_final_ptr_ty.eql(sub_ptr_ty, sema.mod)) { @@ -3919,6 +3902,121 @@ fn zirFieldBasePtr( return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType()); } +fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const gpa = sema.gpa; + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); + const args = sema.code.refSlice(extra.end, extra.data.operands_len); + const src = inst_data.src(); + + var len: Air.Inst.Ref = .none; + var len_val: ?Value = null; + var len_idx: u32 = undefined; + var any_runtime = false; + + const runtime_arg_lens = try gpa.alloc(Air.Inst.Ref, args.len); + defer gpa.free(runtime_arg_lens); + + // First pass to look for comptime values. + for (args, 0..) |zir_arg, i_usize| { + const i = @intCast(u32, i_usize); + runtime_arg_lens[i] = .none; + if (zir_arg == .none) continue; + const object = try sema.resolveInst(zir_arg); + const object_ty = sema.typeOf(object); + // Each arg could be an indexable, or a range, in which case the length + // is passed directly as an integer. + const is_int = switch (object_ty.zigTypeTag()) { + .Int, .ComptimeInt => true, + else => false, + }; + const arg_src: LazySrcLoc = .{ .for_input = .{ + .for_node_offset = inst_data.src_node, + .input_index = i, + } }; + const arg_len_uncoerced = if (is_int) object else l: { + try checkIndexable(sema, block, arg_src, object_ty); + if (!object_ty.indexableHasLen()) continue; + + break :l try sema.fieldVal(block, arg_src, object, "len", arg_src); + }; + const arg_len = try sema.coerce(block, Type.usize, arg_len_uncoerced, arg_src); + if (len == .none) { + len = arg_len; + len_idx = i; + } + if (try sema.resolveDefinedValue(block, src, arg_len)) |arg_val| { + if (len_val) |v| { + if (!(try sema.valuesEqual(arg_val, v, Type.usize))) { + const msg = msg: { + const msg = try sema.errMsg(block, src, "non-matching for loop lengths", .{}); + errdefer msg.destroy(gpa); + const a_src: LazySrcLoc = .{ .for_input = .{ + .for_node_offset = inst_data.src_node, + .input_index = len_idx, + } }; + try sema.errNote(block, a_src, msg, "length {} here", .{ + v.fmtValue(Type.usize, sema.mod), + }); + try sema.errNote(block, arg_src, msg, "length {} here", .{ + arg_val.fmtValue(Type.usize, sema.mod), + }); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + } + } else { + len = arg_len; + len_val = arg_val; + len_idx = i; + } + continue; + } + runtime_arg_lens[i] = arg_len; + any_runtime = true; + } + + if (len == .none) { + const msg = msg: { + const msg = try sema.errMsg(block, src, "unbounded for loop", .{}); + errdefer msg.destroy(gpa); + for (args, 0..) |zir_arg, i_usize| { + const i = @intCast(u32, i_usize); + if (zir_arg == .none) continue; + const object = try sema.resolveInst(zir_arg); + const object_ty = sema.typeOf(object); + // Each arg could be an indexable, or a range, in which case the length + // is passed directly as an integer. + switch (object_ty.zigTypeTag()) { + .Int, .ComptimeInt => continue, + else => {}, + } + const arg_src: LazySrcLoc = .{ .for_input = .{ + .for_node_offset = inst_data.src_node, + .input_index = i, + } }; + try sema.errNote(block, arg_src, msg, "type '{}' has no upper bound", .{ + object_ty.fmt(sema.mod), + }); + } + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + } + + // Now for the runtime checks. + if (any_runtime and block.wantSafety()) { + for (runtime_arg_lens, 0..) |arg_len, i| { + if (arg_len == .none) continue; + if (i == len_idx) continue; + const ok = try block.addBinOp(.cmp_eq, len, arg_len); + try sema.addSafetyCheck(block, ok, .for_len_mismatch); + } + } + + return len; +} + fn validateArrayInitTy( sema: *Sema, block: *Block, @@ -4198,7 +4296,7 @@ fn validateStructInit( // In this case the only thing we need to do is evaluate the implicit // store instructions for default field values, and report any missing fields. // Avoid the cost of the extra machinery for detecting a comptime struct init value. - for (found_fields) |field_ptr, i| { + for (found_fields, 0..) |field_ptr, i| { if (field_ptr != 0) continue; const default_val = struct_ty.structFieldDefaultValue(i); @@ -4264,7 +4362,7 @@ fn validateStructInit( // ends up being comptime-known. const field_values = try sema.arena.alloc(Value, struct_ty.structFieldCount()); - field: for (found_fields) |field_ptr, i| { + field: for (found_fields, 0..) |field_ptr, i| { if (field_ptr != 0) { // Determine whether the value stored to this pointer is comptime-known. const field_ty = struct_ty.structFieldType(i); @@ -4397,7 +4495,7 @@ fn validateStructInit( try sema.resolveStructLayout(struct_ty); // Our task is to insert `store` instructions for all the default field values. - for (found_fields) |field_ptr, i| { + for (found_fields, 0..) |field_ptr, i| { if (field_ptr != 0) continue; const field_src = init_src; // TODO better source location @@ -4472,7 +4570,7 @@ fn zirValidateArrayInit( // any ZIR instructions at comptime; we need to do that here. if (array_ty.sentinel()) |sentinel_val| { const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len); - const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true); + const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true); const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val); try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store); } @@ -4491,7 +4589,7 @@ fn zirValidateArrayInit( const air_tags = sema.air_instructions.items(.tag); const air_datas = sema.air_instructions.items(.data); - outer: for (instrs) |elem_ptr, i| { + outer: for (instrs, 0..) |elem_ptr, i| { // Determine whether the value stored to this pointer is comptime-known. if (array_ty.isTuple()) { @@ -5010,7 +5108,7 @@ fn zirCompileLog( const src_node = extra.data.src_node; const args = sema.code.refSlice(extra.end, extended.small); - for (args) |arg_ref, i| { + for (args, 0..) |arg_ref, i| { if (i != 0) try writer.print(", ", .{}); const arg = try sema.resolveInst(arg_ref); @@ -6228,7 +6326,7 @@ const GenericCallAdapter = struct { if (ctx.generic_fn.owner_decl != other_key.generic_owner_decl.unwrap().?) return false; const other_comptime_args = other_key.comptime_args.?; - for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| { + for (other_comptime_args[0..ctx.func_ty_info.param_types.len], 0..) |other_arg, i| { const this_arg = ctx.args[i]; const this_is_comptime = this_arg.val.tag() != .generic_poison; const other_is_comptime = other_arg.val.tag() != .generic_poison; @@ -6744,7 +6842,7 @@ fn analyzeCall( assert(!func_ty_info.is_generic); const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); - for (uncasted_args) |uncasted_arg, i| { + for (uncasted_args, 0..) |uncasted_arg, i| { if (i < fn_params_len) { const opts: CoerceOpts = .{ .param_src = .{ .func_inst = func, @@ -7519,7 +7617,7 @@ fn resolveGenericInstantiationType( fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { if (!ty.isSimpleTupleOrAnonStruct()) return; const tuple = ty.tupleFields(); - for (tuple.values) |field_val, i| { + for (tuple.values, 0..) |field_val, i| { try sema.resolveTupleLazyValues(block, src, tuple.types[i]); if (field_val.tag() == .unreachable_value) continue; try sema.resolveLazyValue(field_val); @@ -8593,7 +8691,7 @@ fn funcCommon( const cc_resolved = cc orelse .Unspecified; const param_types = try sema.arena.alloc(Type, block.params.items.len); const comptime_params = try sema.arena.alloc(bool, block.params.items.len); - for (block.params.items) |param, i| { + for (block.params.items, 0..) |param, i| { const is_noalias = blk: { const index = std.math.cast(u5, i) orelse break :blk false; break :blk @truncate(u1, noalias_bits >> index) != 0; @@ -8702,7 +8800,7 @@ fn funcCommon( const tags = sema.code.instructions.items(.tag); const data = sema.code.instructions.items(.data); const param_body = sema.code.getParamBody(func_inst); - for (block.params.items) |param, i| { + for (block.params.items, 0..) |param, i| { if (!param.is_comptime) { const param_index = param_body[i]; const param_src = switch (tags[param_index]) { @@ -9619,7 +9717,7 @@ fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const array = try sema.resolveInst(extra.lhs); const elem_index = try sema.resolveInst(extra.rhs); - return sema.elemVal(block, src, array, elem_index, src); + return sema.elemVal(block, src, array, elem_index, src, false); } fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9632,7 +9730,7 @@ fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const array = try sema.resolveInst(extra.lhs); const elem_index = try sema.resolveInst(extra.rhs); - return sema.elemVal(block, src, array, elem_index, elem_index_src); + return sema.elemVal(block, src, array, elem_index, elem_index_src, true); } fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9644,7 +9742,22 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const array_ptr = try sema.resolveInst(extra.lhs); const elem_index = try sema.resolveInst(extra.rhs); - return sema.elemPtr(block, src, array_ptr, elem_index, src, false); + const indexable_ty = sema.typeOf(array_ptr); + if (indexable_ty.zigTypeTag() != .Pointer) { + const capture_src: LazySrcLoc = .{ .for_capture_from_input = inst_data.src_node }; + const msg = msg: { + const msg = try sema.errMsg(block, capture_src, "pointer capture of non pointer type '{}'", .{ + indexable_ty.fmt(sema.mod), + }); + errdefer msg.destroy(sema.gpa); + if (indexable_ty.zigTypeTag() == .Array) { + try sema.errNote(block, src, msg, "consider using '&' here", .{}); + } + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + } + return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false); } fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9657,7 +9770,7 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const array_ptr = try sema.resolveInst(extra.lhs); const elem_index = try sema.resolveInst(extra.rhs); - return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false); + return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, true); } fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9669,7 +9782,7 @@ fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; const array_ptr = try sema.resolveInst(extra.ptr); const elem_index = try sema.addIntUnsigned(Type.usize, extra.index); - return sema.elemPtr(block, src, array_ptr, elem_index, src, true); + return sema.elemPtr(block, src, array_ptr, elem_index, src, true, true); } fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9801,7 +9914,7 @@ fn zirSwitchCapture( const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, sema.mod).?); const first_field = union_obj.fields.values()[first_field_index]; - for (items[1..]) |item, i| { + for (items[1..], 0..) |item, i| { const item_ref = try sema.resolveInst(item); // Previous switch validation ensured this will succeed const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; @@ -10131,7 +10244,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const items = sema.code.refSlice(extra_index, items_len); extra_index += items_len + body_len; - for (items) |item_ref, item_i| { + for (items, 0..) |item_ref, item_i| { try sema.validateSwitchItemEnum( block, seen_enum_fields, @@ -10165,7 +10278,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError .{}, ); errdefer msg.destroy(sema.gpa); - for (seen_enum_fields) |seen_src, i| { + for (seen_enum_fields, 0..) |seen_src, i| { if (seen_src != null) continue; const field_name = operand_ty.enumFieldName(i); @@ -10227,7 +10340,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const items = sema.code.refSlice(extra_index, items_len); extra_index += items_len + body_len; - for (items) |item_ref, item_i| { + for (items, 0..) |item_ref, item_i| { try sema.validateSwitchItemError( block, &seen_errors, @@ -10369,7 +10482,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const items = sema.code.refSlice(extra_index, items_len); extra_index += items_len; - for (items) |item_ref, item_i| { + for (items, 0..) |item_ref, item_i| { try sema.validateSwitchItem( block, &range_set, @@ -10464,7 +10577,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const items = sema.code.refSlice(extra_index, items_len); extra_index += items_len + body_len; - for (items) |item_ref, item_i| { + for (items, 0..) |item_ref, item_i| { try sema.validateSwitchItemBool( block, &true_count, @@ -10548,7 +10661,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const items = sema.code.refSlice(extra_index, items_len); extra_index += items_len + body_len; - for (items) |item_ref, item_i| { + for (items, 0..) |item_ref, item_i| { try sema.validateSwitchItemSparse( block, &seen_values, @@ -10859,7 +10972,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } } - for (items) |item_ref, item_i| { + for (items, 0..) |item_ref, item_i| { cases_len += 1; const item = try sema.resolveInst(item_ref); @@ -11045,7 +11158,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError operand_ty.fmt(sema.mod), }); } - for (seen_enum_fields) |f, i| { + for (seen_enum_fields, 0..) |f, i| { if (f != null) continue; cases_len += 1; @@ -11188,7 +11301,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } const analyze_body = if (union_originally and !special.is_inline) - for (seen_enum_fields) |seen_field, index| { + for (seen_enum_fields, 0..) |seen_field, index| { if (seen_field != null) continue; const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data; const field_ty = union_obj.fields.values()[index].ty; @@ -12168,7 +12281,7 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen()); var elem_val_buf: Value.ElemValueBuffer = undefined; const elems = try sema.arena.alloc(Value, vec_len); - for (elems) |*elem, i| { + for (elems, 0..) |*elem, i| { const elem_val = val.elemValueBuffer(sema.mod, i, &elem_val_buf); elem.* = try elem_val.bitwiseNot(scalar_type, sema.arena, sema.mod); } @@ -12434,14 +12547,14 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai while (elem_i < lhs_len) : (elem_i += 1) { const elem_index = try sema.addIntUnsigned(Type.usize, elem_i); const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); - const init = try sema.elemVal(block, lhs_src, lhs, elem_index, src); + const init = try sema.elemVal(block, lhs_src, lhs, elem_index, src, true); try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); } while (elem_i < result_len) : (elem_i += 1) { const elem_index = try sema.addIntUnsigned(Type.usize, elem_i); const rhs_index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len); const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); - const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src); + const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src, true); try sema.storePtr2(block, src, elem_ptr, src, init, rhs_src, .store); } if (res_sent_val) |sent_val| { @@ -12459,12 +12572,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai var elem_i: usize = 0; while (elem_i < lhs_len) : (elem_i += 1) { const index = try sema.addIntUnsigned(Type.usize, elem_i); - const init = try sema.elemVal(block, lhs_src, lhs, index, src); + const init = try sema.elemVal(block, lhs_src, lhs, index, src, true); element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, lhs_src); } while (elem_i < result_len) : (elem_i += 1) { const index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len); - const init = try sema.elemVal(block, rhs_src, rhs, index, src); + const init = try sema.elemVal(block, rhs_src, rhs, index, src, true); element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, rhs_src); } } @@ -12684,7 +12797,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai elem_i += 1; const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i); const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); - const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src); + const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src, true); try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); } } @@ -12704,7 +12817,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai var lhs_i: usize = 0; while (lhs_i < lhs_len) : (lhs_i += 1) { const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i); - const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src); + const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src, true); element_refs[elem_i] = init; elem_i += 1; } @@ -12776,6 +12889,7 @@ fn zirArithmetic( block: *Block, inst: Zir.Inst.Index, zir_tag: Zir.Inst.Tag, + safety: bool, ) CompileError!Air.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); @@ -12788,7 +12902,7 @@ fn zirArithmetic( const lhs = try sema.resolveInst(extra.lhs); const rhs = try sema.resolveInst(extra.rhs); - return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src, true); + return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src, safety); } fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -13612,7 +13726,7 @@ fn intRem( ) CompileError!Value { if (ty.zigTypeTag() == .Vector) { const result_data = try sema.arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { + for (result_data, 0..) |*scalar, i| { var lhs_buf: Value.ElemValueBuffer = undefined; var rhs_buf: Value.ElemValueBuffer = undefined; const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); @@ -14139,7 +14253,7 @@ fn analyzeArithmetic( const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: { switch (zir_tag) { - .add => { + .add, .add_unsafe => { // For integers:intAddSat // If either of the operands are zero, then the other operand is // returned, even if it is undefined. @@ -14722,7 +14836,7 @@ fn zirAsm( const outputs = try sema.arena.alloc(ConstraintName, outputs_len); var expr_ty = Air.Inst.Ref.void_type; - for (out_args) |*arg, out_i| { + for (out_args, 0..) |*arg, out_i| { const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i); extra_i = output.end; @@ -14749,7 +14863,7 @@ fn zirAsm( const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len); const inputs = try sema.arena.alloc(ConstraintName, inputs_len); - for (args) |*arg, arg_i| { + for (args, 0..) |*arg, arg_i| { const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i); extra_i = input.end; @@ -15473,7 +15587,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai defer params_anon_decl.deinit(); const param_vals = try params_anon_decl.arena().alloc(Value, info.param_types.len); - for (param_vals) |*param_val, i| { + for (param_vals, 0..) |*param_val, i| { const param_ty = info.param_types[i]; const is_generic = param_ty.tag() == .generic_poison; const param_ty_val = if (is_generic) @@ -15717,7 +15831,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const error_field_vals: ?[]Value = if (ty.isAnyError()) null else blk: { const names = ty.errorSetNames(); const vals = try fields_anon_decl.arena().alloc(Value, names.len); - for (vals) |*field_val, i| { + for (vals, 0..) |*field_val, i| { const name = names[i]; const name_val = v: { var anon_decl = try block.startAnonDecl(); @@ -15819,7 +15933,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const enum_fields = ty.enumFields(); const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_fields.count()); - for (enum_field_vals) |*field_val, i| { + for (enum_field_vals, 0..) |*field_val, i| { var tag_val_payload: Value.Payload.U32 = .{ .base = .{ .tag = .enum_field_index }, .data = @intCast(u32, i), @@ -15916,7 +16030,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const union_fields = union_ty.unionFields(); const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count()); - for (union_field_vals) |*field_val, i| { + for (union_field_vals, 0..) |*field_val, i| { const field = union_fields.values()[i]; const name = union_fields.keys()[i]; const name_val = v: { @@ -16025,7 +16139,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const tuple = struct_ty.tupleFields(); const field_types = tuple.types; const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len); - for (struct_field_vals) |*struct_field_val, i| { + for (struct_field_vals, 0..) |*struct_field_val, i| { const field_ty = field_types[i]; const name_val = v: { var anon_decl = try block.startAnonDecl(); @@ -16069,7 +16183,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const struct_fields = struct_ty.structFields(); const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_fields.count()); - for (struct_field_vals) |*field_val, i| { + for (struct_field_vals, 0..) |*field_val, i| { const field = struct_fields.values()[i]; const name = struct_fields.keys()[i]; const name_val = v: { @@ -16408,7 +16522,7 @@ fn zirTypeofPeer( const inst_list = try sema.gpa.alloc(Air.Inst.Ref, args.len); defer sema.gpa.free(inst_list); - for (args) |arg_ref, i| { + for (args, 0..) |arg_ref, i| { inst_list[i] = try sema.resolveInst(arg_ref); } @@ -17519,7 +17633,7 @@ fn finishStructInit( if (struct_ty.isAnonStruct()) { const struct_obj = struct_ty.castTag(.anon_struct).?.data; - for (struct_obj.values) |default_val, i| { + for (struct_obj.values, 0..) |default_val, i| { if (field_inits[i] != .none) continue; if (default_val.tag() == .unreachable_value) { @@ -17555,7 +17669,7 @@ fn finishStructInit( } } else { const struct_obj = struct_ty.castTag(.@"struct").?.data; - for (struct_obj.fields.values()) |field, i| { + for (struct_obj.fields.values(), 0..) |field, i| { if (field_inits[i] != .none) continue; if (field.default_val.tag() == .unreachable_value) { @@ -17596,7 +17710,7 @@ fn finishStructInit( if (is_comptime) { const values = try sema.arena.alloc(Value, field_inits.len); - for (field_inits) |field_init, i| { + for (field_inits, 0..) |field_init, i| { values[i] = (sema.resolveMaybeUndefVal(field_init) catch unreachable).?; } const struct_val = try Value.Tag.aggregate.create(sema.arena, values); @@ -17611,7 +17725,7 @@ fn finishStructInit( .@"addrspace" = target_util.defaultAddressSpace(target, .local), }); const alloc = try block.addTy(.alloc, alloc_ty); - for (field_inits) |field_init, i_usize| { + for (field_inits, 0..) |field_init, i_usize| { const i = @intCast(u32, i_usize); const field_src = dest_src; const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty, true); @@ -17644,7 +17758,7 @@ fn zirStructInitAnon( const opt_runtime_index = rs: { var runtime_index: ?usize = null; var extra_index = extra.end; - for (types) |*field_ty, i| { + for (types, 0..) |*field_ty, i| { const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); extra_index = item.end; @@ -17718,7 +17832,7 @@ fn zirStructInitAnon( }); const alloc = try block.addTy(.alloc, alloc_ty); var extra_index = extra.end; - for (types) |field_ty, i_usize| { + for (types, 0..) |field_ty, i_usize| { const i = @intCast(u32, i_usize); const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); extra_index = item.end; @@ -17740,7 +17854,7 @@ fn zirStructInitAnon( const element_refs = try sema.arena.alloc(Air.Inst.Ref, types.len); var extra_index = extra.end; - for (types) |_, i| { + for (types, 0..) |_, i| { const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); extra_index = item.end; element_refs[i] = try sema.resolveInst(item.data.init); @@ -17768,7 +17882,7 @@ fn zirArrayInit( const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null)); defer gpa.free(resolved_args); - for (args[1..]) |arg, i| { + for (args[1..], 0..) |arg, i| { const resolved_arg = try sema.resolveInst(arg); const elem_ty = if (array_ty.zigTypeTag() == .Struct) array_ty.structFieldType(i) @@ -17789,7 +17903,7 @@ fn zirArrayInit( resolved_args[resolved_args.len - 1] = try sema.addConstant(array_ty.elemType2(), some); } - const opt_runtime_index: ?u32 = for (resolved_args) |arg, i| { + const opt_runtime_index: ?u32 = for (resolved_args, 0..) |arg, i| { const comptime_known = try sema.isComptimeKnown(arg); if (!comptime_known) break @intCast(u32, i); } else null; @@ -17797,7 +17911,7 @@ fn zirArrayInit( const runtime_index = opt_runtime_index orelse { const elem_vals = try sema.arena.alloc(Value, resolved_args.len); - for (resolved_args) |arg, i| { + for (resolved_args, 0..) |arg, i| { // We checked that all args are comptime above. elem_vals[i] = (sema.resolveMaybeUndefVal(arg) catch unreachable).?; } @@ -17826,7 +17940,7 @@ fn zirArrayInit( const alloc = try block.addTy(.alloc, alloc_ty); if (array_ty.isTuple()) { - for (resolved_args) |arg, i| { + for (resolved_args, 0..) |arg, i| { const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ .mutable = true, .@"addrspace" = target_util.defaultAddressSpace(target, .local), @@ -17848,7 +17962,7 @@ fn zirArrayInit( }); const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); - for (resolved_args) |arg, i| { + for (resolved_args, 0..) |arg, i| { const index = try sema.addIntUnsigned(Type.usize, i); const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref); _ = try block.addBinOp(.store, elem_ptr, arg); @@ -17875,7 +17989,7 @@ fn zirArrayInitAnon( const opt_runtime_src = rs: { var runtime_src: ?LazySrcLoc = null; - for (operands) |operand, i| { + for (operands, 0..) |operand, i| { const operand_src = src; // TODO better source location const elem = try sema.resolveInst(operand); types[i] = sema.typeOf(elem); @@ -17918,7 +18032,7 @@ fn zirArrayInitAnon( .@"addrspace" = target_util.defaultAddressSpace(target, .local), }); const alloc = try block.addTy(.alloc, alloc_ty); - for (operands) |operand, i_usize| { + for (operands, 0..) |operand, i_usize| { const i = @intCast(u32, i_usize); const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ .mutable = true, @@ -17935,7 +18049,7 @@ fn zirArrayInitAnon( } const element_refs = try sema.arena.alloc(Air.Inst.Ref, operands.len); - for (operands) |operand, i| { + for (operands, 0..) |operand, i| { element_refs[i] = try sema.resolveInst(operand); } @@ -18138,7 +18252,7 @@ fn zirUnaryMath( var elem_buf: Value.ElemValueBuffer = undefined; const elems = try sema.arena.alloc(Value, vec_len); - for (elems) |*elem, i| { + for (elems, 0..) |*elem, i| { const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); elem.* = try eval(elem_val, scalar_ty, sema.arena, sema.mod); } @@ -19142,7 +19256,7 @@ fn reifyStruct( if (layout == .Packed) { struct_obj.status = .layout_wip; - for (struct_obj.fields.values()) |field, index| { + for (struct_obj.fields.values(), 0..) |field, index| { sema.resolveTypeLayout(field.ty) catch |err| switch (err) { error.AnalysisFail => { const msg = sema.err orelse return err; @@ -19771,7 +19885,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } var elem_buf: Value.ElemValueBuffer = undefined; const elems = try sema.arena.alloc(Value, operand_ty.vectorLen()); - for (elems) |*elem, i| { + for (elems, 0..) |*elem, i| { const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); elem.* = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, sema.mod); } @@ -19873,7 +19987,7 @@ fn zirBitCount( var elem_buf: Value.ElemValueBuffer = undefined; const elems = try sema.arena.alloc(Value, vec_len); const scalar_ty = operand_ty.scalarType(); - for (elems) |*elem, i| { + for (elems, 0..) |*elem, i| { const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); const count = comptimeOp(elem_val, scalar_ty, target); elem.* = try Value.Tag.int_u64.create(sema.arena, count); @@ -19942,7 +20056,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const vec_len = operand_ty.vectorLen(); var elem_buf: Value.ElemValueBuffer = undefined; const elems = try sema.arena.alloc(Value, vec_len); - for (elems) |*elem, i| { + for (elems, 0..) |*elem, i| { const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); elem.* = try elem_val.byteSwap(operand_ty, target, sema.arena); } @@ -19991,7 +20105,7 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const vec_len = operand_ty.vectorLen(); var elem_buf: Value.ElemValueBuffer = undefined; const elems = try sema.arena.alloc(Value, vec_len); - for (elems) |*elem, i| { + for (elems, 0..) |*elem, i| { const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); elem.* = try elem_val.bitReverse(scalar_ty, target, sema.arena); } @@ -20060,7 +20174,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 .Packed => { var bit_sum: u64 = 0; const fields = ty.structFields(); - for (fields.values()) |field, i| { + for (fields.values(), 0..) |field, i| { if (i == field_index) { return bit_sum; } @@ -20997,7 +21111,7 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C var buf: Value.ElemValueBuffer = undefined; const elems = try sema.gpa.alloc(Value, vec_len); - for (elems) |*elem, i| { + for (elems, 0..) |*elem, i| { const pred_elem_val = pred_val.elemValueBuffer(sema.mod, i, &buf); const should_choose_a = pred_elem_val.toBool(); if (should_choose_a) { @@ -21347,12 +21461,12 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError func = bound_data.func_inst; resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount() + 1); resolved_args[0] = bound_data.arg0_inst; - for (resolved_args[1..]) |*resolved, i| { + for (resolved_args[1..], 0..) |*resolved, i| { resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); } } else { resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount()); - for (resolved_args) |*resolved, i| { + for (resolved_args, 0..) |*resolved, i| { resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); } } @@ -21507,7 +21621,7 @@ fn analyzeMinMax( var lhs_buf: Value.ElemValueBuffer = undefined; var rhs_buf: Value.ElemValueBuffer = undefined; const elems = try sema.arena.alloc(Value, vec_len); - for (elems) |*elem, i| { + for (elems, 0..) |*elem, i| { const lhs_elem_val = lhs_val.elemValueBuffer(sema.mod, i, &lhs_buf); const rhs_elem_val = rhs_val.elemValueBuffer(sema.mod, i, &rhs_buf); elem.* = opFunc(lhs_elem_val, rhs_elem_val, target); @@ -22404,7 +22518,7 @@ fn explainWhyTypeIsComptimeInner( if (ty.castTag(.@"struct")) |payload| { const struct_obj = payload.data; - for (struct_obj.fields.values()) |field, i| { + for (struct_obj.fields.values(), 0..) |field, i| { const field_src_loc = struct_obj.fieldSrcLoc(sema.mod, .{ .index = i, .range = .type, @@ -22424,7 +22538,7 @@ fn explainWhyTypeIsComptimeInner( if (ty.cast(Type.Payload.Union)) |payload| { const union_obj = payload.data; - for (union_obj.fields.values()) |field, i| { + for (union_obj.fields.values(), 0..) |field, i| { const field_src_loc = union_obj.fieldSrcLoc(sema.mod, .{ .index = i, .range = .type, @@ -22676,6 +22790,7 @@ pub const PanicId = enum { unwrap_error, index_out_of_bounds, start_index_greater_than_end, + for_len_mismatch, }; fn addSafetyCheck( @@ -23694,7 +23809,7 @@ fn structFieldPtrByIndex( comptime assert(Type.packed_struct_layout_version == 2); var running_bits: u16 = 0; - for (struct_obj.fields.values()) |f, i| { + for (struct_obj.fields.values(), 0..) |f, i| { if (!(try sema.typeHasRuntimeBits(f.ty))) continue; if (i == field_index) { @@ -24057,6 +24172,7 @@ fn elemPtr( elem_index: Air.Inst.Ref, elem_index_src: LazySrcLoc, init: bool, + oob_safety: bool, ) CompileError!Air.Inst.Ref { const indexable_ptr_src = src; // TODO better source location const indexable_ptr_ty = sema.typeOf(indexable_ptr); @@ -24065,46 +24181,61 @@ fn elemPtr( .Pointer => indexable_ptr_ty.elemType(), else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(sema.mod)}), }; - if (!indexable_ty.isIndexable()) { - return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)}); - } - switch (indexable_ty.zigTypeTag()) { - .Pointer => { - // In all below cases, we have to deref the ptr operand to get the actual indexable pointer. - const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); - switch (indexable_ty.ptrSize()) { - .Slice => return sema.elemPtrSlice(block, src, indexable_ptr_src, indexable, elem_index_src, elem_index), - .Many, .C => { - const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_ptr_src, indexable); - const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); - const runtime_src = rs: { - const ptr_val = maybe_ptr_val orelse break :rs indexable_ptr_src; - const index_val = maybe_index_val orelse break :rs elem_index_src; - const index = @intCast(usize, index_val.toUnsignedInt(target)); - const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); - const result_ty = try sema.elemPtrType(indexable_ty, index); - return sema.addConstant(result_ty, elem_ptr); - }; - const result_ty = try sema.elemPtrType(indexable_ty, null); - - try sema.requireRuntimeBlock(block, src, runtime_src); - return block.addPtrElemPtr(indexable, elem_index, result_ty); - }, - .One => { - assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable - return sema.elemPtrArray(block, src, indexable_ptr_src, indexable, elem_index_src, elem_index, init); - }, - } - }, - .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init), + .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), .Struct => { // Tuple field access. const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known"); const index = @intCast(u32, index_val.toUnsignedInt(target)); return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); }, - else => unreachable, + else => { + const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); + return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety); + }, + } +} + +/// Asserts that the type of indexable is pointer. +fn elemPtrOneLayerOnly( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + indexable: Air.Inst.Ref, + elem_index: Air.Inst.Ref, + elem_index_src: LazySrcLoc, + init: bool, + oob_safety: bool, +) CompileError!Air.Inst.Ref { + const indexable_src = src; // TODO better source location + const indexable_ty = sema.typeOf(indexable); + if (!indexable_ty.isIndexable()) { + return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)}); + } + const target = sema.mod.getTarget(); + + switch (indexable_ty.ptrSize()) { + .Slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), + .Many, .C => { + const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable); + const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); + const runtime_src = rs: { + const ptr_val = maybe_ptr_val orelse break :rs indexable_src; + const index_val = maybe_index_val orelse break :rs elem_index_src; + const index = @intCast(usize, index_val.toUnsignedInt(target)); + const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); + const result_ty = try sema.elemPtrType(indexable_ty, index); + return sema.addConstant(result_ty, elem_ptr); + }; + const result_ty = try sema.elemPtrType(indexable_ty, null); + + try sema.requireRuntimeBlock(block, src, runtime_src); + return block.addPtrElemPtr(indexable, elem_index, result_ty); + }, + .One => { + assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable + return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety); + }, } } @@ -24115,6 +24246,7 @@ fn elemVal( indexable: Air.Inst.Ref, elem_index_uncasted: Air.Inst.Ref, elem_index_src: LazySrcLoc, + oob_safety: bool, ) CompileError!Air.Inst.Ref { const indexable_src = src; // TODO better source location const indexable_ty = sema.typeOf(indexable); @@ -24130,7 +24262,7 @@ fn elemVal( switch (indexable_ty.zigTypeTag()) { .Pointer => switch (indexable_ty.ptrSize()) { - .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index), + .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), .Many, .C => { const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable); const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); @@ -24151,14 +24283,14 @@ fn elemVal( }, .One => { assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable - const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false); + const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety); return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src); }, }, - .Array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index), + .Array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), .Vector => { // TODO: If the index is a vector, the result should be a vector. - return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index); + return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety); }, .Struct => { // Tuple field access. @@ -24303,6 +24435,7 @@ fn elemValArray( array: Air.Inst.Ref, elem_index_src: LazySrcLoc, elem_index: Air.Inst.Ref, + oob_safety: bool, ) CompileError!Air.Inst.Ref { const array_ty = sema.typeOf(array); const array_sent = array_ty.sentinel(); @@ -24346,7 +24479,7 @@ fn elemValArray( const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src; try sema.requireRuntimeBlock(block, src, runtime_src); - if (block.wantSafety()) { + if (oob_safety and block.wantSafety()) { // Runtime check is only needed if unable to comptime check if (maybe_index_val == null) { const len_inst = try sema.addIntUnsigned(Type.usize, array_len); @@ -24366,6 +24499,7 @@ fn elemPtrArray( elem_index_src: LazySrcLoc, elem_index: Air.Inst.Ref, init: bool, + oob_safety: bool, ) CompileError!Air.Inst.Ref { const target = sema.mod.getTarget(); const array_ptr_ty = sema.typeOf(array_ptr); @@ -24409,7 +24543,7 @@ fn elemPtrArray( try sema.requireRuntimeBlock(block, src, runtime_src); // Runtime check is only needed if unable to comptime check. - if (block.wantSafety() and offset == null) { + if (oob_safety and block.wantSafety() and offset == null) { const len_inst = try sema.addIntUnsigned(Type.usize, array_len); const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op); @@ -24426,6 +24560,7 @@ fn elemValSlice( slice: Air.Inst.Ref, elem_index_src: LazySrcLoc, elem_index: Air.Inst.Ref, + oob_safety: bool, ) CompileError!Air.Inst.Ref { const slice_ty = sema.typeOf(slice); const slice_sent = slice_ty.sentinel() != null; @@ -24462,7 +24597,7 @@ fn elemValSlice( try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src); try sema.requireRuntimeBlock(block, src, runtime_src); - if (block.wantSafety()) { + if (oob_safety and block.wantSafety()) { const len_inst = if (maybe_slice_val) |slice_val| try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)) else @@ -24482,6 +24617,7 @@ fn elemPtrSlice( slice: Air.Inst.Ref, elem_index_src: LazySrcLoc, elem_index: Air.Inst.Ref, + oob_safety: bool, ) CompileError!Air.Inst.Ref { const target = sema.mod.getTarget(); const slice_ty = sema.typeOf(slice); @@ -24519,7 +24655,7 @@ fn elemPtrSlice( const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src; try sema.requireRuntimeBlock(block, src, runtime_src); - if (block.wantSafety()) { + if (oob_safety and block.wantSafety()) { const len_inst = len: { if (maybe_undef_slice_val) |slice_val| if (!slice_val.isUndef()) @@ -25980,7 +26116,7 @@ fn coerceInMemoryAllowedFns( } }; } - for (dest_info.param_types) |dest_param_ty, i| { + for (dest_info.param_types, 0..) |dest_param_ty, i| { const src_param_ty = src_info.param_types[i]; if (dest_info.comptime_params[i] != src_info.comptime_params[i]) { @@ -26224,7 +26360,7 @@ fn storePtr2( const elem_src = operand_src; // TODO better source location const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i); const elem_index = try sema.addIntUnsigned(Type.usize, i); - const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false); + const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false, true); try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store); } return; @@ -26510,7 +26646,7 @@ fn beginComptimePtrMutation( // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. assert(bytes.len >= dest_len); const elems = try arena.alloc(Value, @intCast(usize, dest_len)); - for (elems) |*elem, i| { + for (elems, 0..) |*elem, i| { elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); } @@ -26539,7 +26675,7 @@ fn beginComptimePtrMutation( const dest_len = parent.ty.arrayLenIncludingSentinel(); const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; const elems = try arena.alloc(Value, @intCast(usize, dest_len)); - for (bytes) |byte, i| { + for (bytes, 0..) |byte, i| { elems[i] = try Value.Tag.int_u64.create(arena, byte); } if (parent.ty.sentinel()) |sent_val| { @@ -27510,7 +27646,7 @@ fn coerceEnumToUnion( var msg: ?*Module.ErrorMsg = null; errdefer if (msg) |some| some.destroy(sema.gpa); - for (union_obj.fields.values()) |field, i| { + for (union_obj.fields.values(), 0..) |field, i| { if (field.ty.zigTypeTag() == .NoReturn) { const err_msg = msg orelse try sema.errMsg( block, @@ -27669,14 +27805,14 @@ fn coerceArrayLike( const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_len); var runtime_src: ?LazySrcLoc = null; - for (element_vals) |*elem, i| { + for (element_vals, 0..) |*elem, i| { const index_ref = try sema.addConstant( Type.usize, try Value.Tag.int_u64.create(sema.arena, i), ); const src = inst_src; // TODO better source location const elem_src = inst_src; // TODO better source location - const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref); + const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref, true); const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); element_refs[i] = coerced; if (runtime_src == null) { @@ -27731,7 +27867,7 @@ fn coerceTupleToArray( const dest_elem_ty = dest_ty.childType(); var runtime_src: ?LazySrcLoc = null; - for (element_vals) |*elem, i_usize| { + for (element_vals, 0..) |*elem, i_usize| { const i = @intCast(u32, i_usize); if (i_usize == inst_len) { elem.* = dest_ty.sentinel().?; @@ -27860,7 +27996,7 @@ fn coerceTupleToStruct( var root_msg: ?*Module.ErrorMsg = null; errdefer if (root_msg) |msg| msg.destroy(sema.gpa); - for (field_refs) |*field_ref, i| { + for (field_refs, 0..) |*field_ref, i| { if (field_ref.* != .none) continue; const field_name = fields.keys()[i]; @@ -27958,7 +28094,7 @@ fn coerceTupleToTuple( var root_msg: ?*Module.ErrorMsg = null; errdefer if (root_msg) |msg| msg.destroy(sema.gpa); - for (field_refs) |*field_ref, i| { + for (field_refs, 0..) |*field_ref, i| { if (field_ref.* != .none) continue; const default_val = tuple_ty.structFieldDefaultValue(i); @@ -29334,7 +29470,7 @@ fn resolvePeerTypes( var seen_const = false; var convert_to_slice = false; var chosen_i: usize = 0; - for (instructions[1..]) |candidate, candidate_i| { + for (instructions[1..], 0..) |candidate, candidate_i| { const candidate_ty = sema.typeOf(candidate); const chosen_ty = sema.typeOf(chosen); @@ -29993,7 +30129,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { }; struct_obj.status = .layout_wip; - for (struct_obj.fields.values()) |field, i| { + for (struct_obj.fields.values(), 0..) |field, i| { sema.resolveTypeLayout(field.ty) catch |err| switch (err) { error.AnalysisFail => { const msg = sema.err orelse return err; @@ -30031,7 +30167,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count()); }; - for (struct_obj.fields.values()) |field, i| { + for (struct_obj.fields.values(), 0..) |field, i| { optimized_order[i] = if (field.ty.hasRuntimeBits()) @intCast(u32, i) else @@ -30191,6 +30327,29 @@ fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ } } +fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, array_ty: Type) !void { + if (!array_ty.isIndexable()) { + const msg = msg: { + const msg = try sema.errMsg( + block, + src, + "type '{}' does not support indexing", + .{array_ty.fmt(sema.mod)}, + ); + errdefer msg.destroy(sema.gpa); + try sema.errNote( + block, + src, + msg, + "for loop operand must be an array, slice, tuple, or vector", + .{}, + ); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + } +} + fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { const resolved_ty = try sema.resolveTypeFields(ty); const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; @@ -30213,7 +30372,7 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { }; union_obj.status = .layout_wip; - for (union_obj.fields.values()) |field, i| { + for (union_obj.fields.values(), 0..) |field, i| { sema.resolveTypeLayout(field.ty) catch |err| switch (err) { error.AnalysisFail => { const msg = sema.err orelse return err; @@ -30361,7 +30520,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { .tuple, .anon_struct => { const tuple = ty.tupleFields(); - for (tuple.types) |field_ty, i| { + for (tuple.types, 0..) |field_ty, i| { const have_comptime_val = tuple.values[i].tag() != .unreachable_value; if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty)) { return true; @@ -30876,7 +31035,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void // so that init values may depend on type layout. const bodies_index = extra_index; - for (fields) |zir_field, field_i| { + for (fields, 0..) |zir_field, field_i| { const field_ty: Type = ty: { if (zir_field.type_ref != .none) { break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) { @@ -30998,7 +31157,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void if (any_inits) { extra_index = bodies_index; - for (fields) |zir_field, field_i| { + for (fields, 0..) |zir_field, field_i| { extra_index += zir_field.type_body_len; extra_index += zir_field.align_body_len; if (zir_field.init_body_len > 0) { @@ -31718,7 +31877,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .@"struct" => { const resolved_ty = try sema.resolveTypeFields(ty); const s = resolved_ty.castTag(.@"struct").?.data; - for (s.fields.values()) |field, i| { + for (s.fields.values(), 0..) |field, i| { if (field.is_comptime) continue; if (field.ty.eql(resolved_ty, sema.mod)) { const msg = try Module.ErrorMsg.create( @@ -31739,7 +31898,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .tuple, .anon_struct => { const tuple = ty.tupleFields(); - for (tuple.values) |val, i| { + for (tuple.values, 0..) |val, i| { const is_comptime = val.tag() != .unreachable_value; if (is_comptime) continue; if ((try sema.typeHasOnePossibleValue(tuple.types[i])) != null) continue; @@ -32379,7 +32538,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { .tuple, .anon_struct => { const tuple = ty.tupleFields(); - for (tuple.types) |field_ty, i| { + for (tuple.types, 0..) |field_ty, i| { const have_comptime_val = tuple.values[i].tag() != .unreachable_value; if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) { return true; @@ -32539,7 +32698,7 @@ fn anonStructFieldIndex( field_src: LazySrcLoc, ) !u32 { const anon_struct = struct_ty.castTag(.anon_struct).?.data; - for (anon_struct.names) |name, i| { + for (anon_struct.names, 0..) |name, i| { if (mem.eql(u8, name, field_name)) { return @intCast(u32, i); } @@ -32557,7 +32716,7 @@ fn queueFullTypeResolution(sema: *Sema, ty: Type) !void { fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try sema.arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { + for (result_data, 0..) |*scalar, i| { var lhs_buf: Value.ElemValueBuffer = undefined; var rhs_buf: Value.ElemValueBuffer = undefined; const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); @@ -32615,7 +32774,7 @@ fn intSub( ) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try sema.arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { + for (result_data, 0..) |*scalar, i| { var lhs_buf: Value.ElemValueBuffer = undefined; var rhs_buf: Value.ElemValueBuffer = undefined; const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); @@ -32673,7 +32832,7 @@ fn floatAdd( ) !Value { if (float_type.zigTypeTag() == .Vector) { const result_data = try sema.arena.alloc(Value, float_type.vectorLen()); - for (result_data) |*scalar, i| { + for (result_data, 0..) |*scalar, i| { var lhs_buf: Value.ElemValueBuffer = undefined; var rhs_buf: Value.ElemValueBuffer = undefined; const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); @@ -32730,7 +32889,7 @@ fn floatSub( ) !Value { if (float_type.zigTypeTag() == .Vector) { const result_data = try sema.arena.alloc(Value, float_type.vectorLen()); - for (result_data) |*scalar, i| { + for (result_data, 0..) |*scalar, i| { var lhs_buf: Value.ElemValueBuffer = undefined; var rhs_buf: Value.ElemValueBuffer = undefined; const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); @@ -32788,7 +32947,7 @@ fn intSubWithOverflow( if (ty.zigTypeTag() == .Vector) { const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen()); const result_data = try sema.arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { + for (result_data, 0..) |*scalar, i| { var lhs_buf: Value.ElemValueBuffer = undefined; var rhs_buf: Value.ElemValueBuffer = undefined; const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); @@ -32842,7 +33001,7 @@ fn floatToInt( if (float_ty.zigTypeTag() == .Vector) { const elem_ty = float_ty.childType(); const result_data = try sema.arena.alloc(Value, float_ty.vectorLen()); - for (result_data) |*scalar, i| { + for (result_data, 0..) |*scalar, i| { var buf: Value.ElemValueBuffer = undefined; const elem_val = val.elemValueBuffer(sema.mod, i, &buf); scalar.* = try sema.floatToIntScalar(block, src, elem_val, elem_ty, int_ty.scalarType()); @@ -33042,7 +33201,7 @@ fn intFitsInType( .aggregate => { assert(ty.zigTypeTag() == .Vector); - for (val.castTag(.aggregate).?.data) |elem, i| { + for (val.castTag(.aggregate).?.data, 0..) |elem, i| { if (!(try sema.intFitsInType(elem, ty.scalarType(), null))) { if (vector_index) |some| some.* = i; return false; @@ -33139,7 +33298,7 @@ fn intAddWithOverflow( if (ty.zigTypeTag() == .Vector) { const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen()); const result_data = try sema.arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { + for (result_data, 0..) |*scalar, i| { var lhs_buf: Value.ElemValueBuffer = undefined; var rhs_buf: Value.ElemValueBuffer = undefined; const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); @@ -33243,7 +33402,7 @@ fn compareVector( ) !Value { assert(ty.zigTypeTag() == .Vector); const result_data = try sema.arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { + for (result_data, 0..) |*scalar, i| { var lhs_buf: Value.ElemValueBuffer = undefined; var rhs_buf: Value.ElemValueBuffer = undefined; const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); |
