| ... | ... | @@ -3595,7 +3595,20 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, |
| 3595 | 3595 | }; |
| 3596 | 3596 | break :ptr (try Value.fromInterned(decl_parent_ptr).ptrField(idx, pt)).toIntern(); |
| 3597 | 3597 | }, |
| 3598 | | .elem => |idx| (try Value.fromInterned(decl_parent_ptr).ptrElem(idx, pt)).toIntern(), |
| 3598 | .elem => |idx| ptr: { |
| 3599 | const parent_ptr_val: Value = .fromInterned(decl_parent_ptr); |
| 3600 | if (parent_ptr_val.typeOf(zcu).childType(zcu).zigTypeTag(zcu) == .vector) { |
| 3601 | const elem_ptr_ty: Type = .fromInterned(new_ptr_ty); |
| 3602 | // Vectors are a bit weird; see logic in `elemPtrVector`. |
| 3603 | if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) { |
| 3604 | break :ptr (try pt.getCoerced(parent_ptr_val, elem_ptr_ty)).toIntern(); |
| 3605 | } else { |
| 3606 | const bit_offset = idx * @divExact(elem_ptr_ty.childType(zcu).bitSize(zcu), 8); |
| 3607 | break :ptr (try parent_ptr_val.getOffsetPtr(bit_offset, elem_ptr_ty, pt)).toIntern(); |
| 3608 | } |
| 3609 | } |
| 3610 | break :ptr (try parent_ptr_val.ptrElem(idx, pt)).toIntern(); |
| 3611 | }, |
| 3599 | 3612 | }; |
| 3600 | 3613 | try ptr_mapping.put(air_ptr, new_ptr); |
| 3601 | 3614 | } |
| ... | ... | @@ -4540,10 +4553,7 @@ fn validateStructInit( |
| 4540 | 4553 | }; |
| 4541 | 4554 | |
| 4542 | 4555 | const field_src = init_src; // TODO better source location |
| 4543 | | const default_field_ptr = if (struct_ty.isTuple(zcu)) |
| 4544 | | try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(i), true) |
| 4545 | | else |
| 4546 | | try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty); |
| 4556 | const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty); |
| 4547 | 4557 | try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr); |
| 4548 | 4558 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, .fromValue(default_val), field_src, .store); |
| 4549 | 4559 | } |
| ... | ... | @@ -4959,11 +4969,11 @@ pub fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError! |
| 4959 | 4969 | .ty = array_ty.toIntern(), |
| 4960 | 4970 | .storage = .{ .bytes = string }, |
| 4961 | 4971 | } }); |
| 4962 | | return sema.uavRef(val); |
| 4972 | return sema.uavRef(.fromInterned(val)); |
| 4963 | 4973 | } |
| 4964 | 4974 | |
| 4965 | | fn uavRef(sema: *Sema, val: InternPool.Index) CompileError!Air.Inst.Ref { |
| 4966 | | return Air.internedToRef(try sema.pt.refValue(val)); |
| 4975 | fn uavRef(sema: *Sema, val: Value) CompileError!Air.Inst.Ref { |
| 4976 | return .fromValue(try sema.pt.uavValue(val)); |
| 4967 | 4977 | } |
| 4968 | 4978 | |
| 4969 | 4979 | fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -6226,7 +6236,7 @@ fn popErrorReturnTrace( |
| 6226 | 6236 | const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); |
| 6227 | 6237 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 6228 | 6238 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); |
| 6229 | | const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty, true); |
| 6239 | const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty); |
| 6230 | 6240 | try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); |
| 6231 | 6241 | } else if (is_non_error == null) { |
| 6232 | 6242 | // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need |
| ... | ... | @@ -6251,7 +6261,7 @@ fn popErrorReturnTrace( |
| 6251 | 6261 | const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); |
| 6252 | 6262 | const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 6253 | 6263 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); |
| 6254 | | const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty, true); |
| 6264 | const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty); |
| 6255 | 6265 | try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); |
| 6256 | 6266 | _ = try then_block.addBr(cond_block_inst, .void_value); |
| 6257 | 6267 | |
| ... | ... | @@ -8196,23 +8206,10 @@ fn zirOptionalPayload( |
| 8196 | 8206 | const operand_ty = sema.typeOf(operand); |
| 8197 | 8207 | const result_ty = switch (operand_ty.zigTypeTag(zcu)) { |
| 8198 | 8208 | .optional => operand_ty.optionalChild(zcu), |
| 8199 | | .pointer => t: { |
| 8200 | | if (operand_ty.ptrSize(zcu) != .c) { |
| 8201 | | return sema.failWithExpectedOptionalType(block, src, operand_ty); |
| 8202 | | } |
| 8203 | | // TODO https://github.com/ziglang/zig/issues/6597 |
| 8204 | | if (true) break :t operand_ty; |
| 8205 | | const ptr_info = operand_ty.ptrInfo(zcu); |
| 8206 | | break :t try pt.ptrType(.{ |
| 8207 | | .child = ptr_info.child, |
| 8208 | | .flags = .{ |
| 8209 | | .alignment = ptr_info.flags.alignment, |
| 8210 | | .is_const = ptr_info.flags.is_const, |
| 8211 | | .is_volatile = ptr_info.flags.is_volatile, |
| 8212 | | .is_allowzero = ptr_info.flags.is_allowzero, |
| 8213 | | .address_space = ptr_info.flags.address_space, |
| 8214 | | }, |
| 8215 | | }); |
| 8209 | // TODO: https://github.com/ziglang/zig/issues/6597 will eliminate this branch so that we only need to handle optionals. |
| 8210 | .pointer => switch (operand_ty.ptrSize(zcu)) { |
| 8211 | .c => operand_ty, // if `ptr` is a `[*c]T`, then `ptr.?` is also a `[*c]T` |
| 8212 | .one, .many, .slice => return sema.failWithExpectedOptionalType(block, src, operand_ty), |
| 8216 | 8213 | }, |
| 8217 | 8214 | else => return sema.failWithExpectedOptionalType(block, src, operand_ty), |
| 8218 | 8215 | }; |
| ... | ... | @@ -10322,10 +10319,10 @@ fn analyzeSwitchBlock( |
| 10322 | 10319 | const payload_inst: Zir.Inst.Index = if (capture != .none) inst: { |
| 10323 | 10320 | const payload_inst = zir_switch.payload_capture_placeholder.unwrap() orelse switch_inst; |
| 10324 | 10321 | const payload_ref: Air.Inst.Ref = payload_ref: { |
| 10325 | | const item_val: InternPool.Index = switch (operand_ty.zigTypeTag(zcu)) { |
| 10322 | const item_val: Value = switch (operand_ty.zigTypeTag(zcu)) { |
| 10326 | 10323 | .@"union" => item_val: { |
| 10327 | 10324 | if (maybe_operand_opv) |operand_opv| { |
| 10328 | | break :item_val zcu.intern_pool.indexToKey(operand_opv.toIntern()).un.val; |
| 10325 | break :item_val .fromInterned(zcu.intern_pool.indexToKey(operand_opv.toIntern()).un.val); |
| 10329 | 10326 | } |
| 10330 | 10327 | assert(union_originally); // operand type must be union, otherwise it would be an OPV type here |
| 10331 | 10328 | assert(zir_switch.any_maybe_runtime_capture); // there's a payload capture |
| ... | ... | @@ -10362,10 +10359,10 @@ fn analyzeSwitchBlock( |
| 10362 | 10359 | validated_switch.else_err_ty, |
| 10363 | 10360 | ); |
| 10364 | 10361 | }, |
| 10365 | | else => item_opv.toIntern(), |
| 10362 | else => item_opv, |
| 10366 | 10363 | }; |
| 10367 | 10364 | break :payload_ref switch (capture) { |
| 10368 | | .by_val => .fromIntern(item_val), |
| 10365 | .by_val => .fromValue(item_val), |
| 10369 | 10366 | .by_ref => try sema.uavRef(item_val), |
| 10370 | 10367 | .none => unreachable, |
| 10371 | 10368 | }; |
| ... | ... | @@ -12198,7 +12195,7 @@ fn analyzeSwitchPayloadCapture( |
| 12198 | 12195 | return case_block.addStructFieldVal(operand_val, field_index, field_ty); |
| 12199 | 12196 | } |
| 12200 | 12197 | } else if (capture_by_ref) { |
| 12201 | | return sema.uavRef(item_val.toIntern()); |
| 12198 | return sema.uavRef(item_val); |
| 12202 | 12199 | } else { |
| 12203 | 12200 | return kind.inline_ref; |
| 12204 | 12201 | } |
| ... | ... | @@ -12280,37 +12277,14 @@ fn analyzeSwitchPayloadCapture( |
| 12280 | 12277 | |
| 12281 | 12278 | // By-reference captures have some further restrictions which make them easier to emit |
| 12282 | 12279 | if (capture_by_ref) { |
| 12283 | | const operand_ptr_info = sema.typeOf(operand_ptr).ptrInfo(zcu); |
| 12280 | const operand_ptr_ty = sema.typeOf(operand_ptr); |
| 12284 | 12281 | const capture_ptr_ty = resolve: { |
| 12285 | 12282 | // By-ref captures of hetereogeneous types are only allowed if all field |
| 12286 | 12283 | // pointer types are peer resolvable to each other. |
| 12287 | 12284 | // We need values to run PTR on, so make a bunch of undef constants. |
| 12288 | 12285 | const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len); |
| 12289 | | for (field_indices, dummy_captures) |field_idx, *dummy| { |
| 12290 | | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); |
| 12291 | | const field_ptr_ty = try pt.ptrType(.{ |
| 12292 | | .child = field_ty.toIntern(), |
| 12293 | | .flags = .{ |
| 12294 | | .is_const = operand_ptr_info.flags.is_const, |
| 12295 | | .is_volatile = operand_ptr_info.flags.is_volatile, |
| 12296 | | .address_space = operand_ptr_info.flags.address_space, |
| 12297 | | // TODO MLUGG: double-check this. and, um, EVERYWHERE we do ptr alignment... |
| 12298 | | .alignment = a: { |
| 12299 | | if (operand_ty.explicitFieldAlignment(field_idx, zcu) == .none and |
| 12300 | | operand_ptr_info.flags.alignment == .none) |
| 12301 | | { |
| 12302 | | break :a .none; |
| 12303 | | } |
| 12304 | | |
| 12305 | | const union_align = switch (operand_ptr_info.flags.alignment) { |
| 12306 | | .none => operand_ty.abiAlignment(zcu), |
| 12307 | | else => |a| a, |
| 12308 | | }; |
| 12309 | | const field_align = operand_ty.resolvedFieldAlignment(field_idx, zcu); |
| 12310 | | break :a .minStrict(union_align, field_align); |
| 12311 | | }, |
| 12312 | | }, |
| 12313 | | }); |
| 12286 | for (field_indices, dummy_captures) |field_index, *dummy| { |
| 12287 | const field_ptr_ty = try operand_ptr_ty.fieldPtrType(field_index, pt); |
| 12314 | 12288 | dummy.* = try pt.undefRef(field_ptr_ty); |
| 12315 | 12289 | } |
| 12316 | 12290 | const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len); |
| ... | ... | @@ -13696,7 +13670,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13696 | 13670 | element_vals[elem_i] = coerced_elem_val.toIntern(); |
| 13697 | 13671 | } |
| 13698 | 13672 | return sema.addConstantMaybeRef( |
| 13699 | | (try pt.aggregateValue(result_ty, element_vals)).toIntern(), |
| 13673 | try pt.aggregateValue(result_ty, element_vals), |
| 13700 | 13674 | ptr_addrspace != null, |
| 13701 | 13675 | ); |
| 13702 | 13676 | } else break :rs rhs_src; |
| ... | ... | @@ -14094,7 +14068,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14094 | 14068 | } |
| 14095 | 14069 | break :v try pt.aggregateValue(result_ty, element_vals); |
| 14096 | 14070 | }; |
| 14097 | | return sema.addConstantMaybeRef(val.toIntern(), ptr_addrspace != null); |
| 14071 | return sema.addConstantMaybeRef(val, ptr_addrspace != null); |
| 14098 | 14072 | } |
| 14099 | 14073 | |
| 14100 | 14074 | try sema.requireRuntimeBlock(block, src, lhs_src); |
| ... | ... | @@ -15270,7 +15244,7 @@ fn analyzeArithmetic( |
| 15270 | 15244 | }; |
| 15271 | 15245 | |
| 15272 | 15246 | try sema.ensureLayoutResolved(lhs_ty.childType(zcu), src); |
| 15273 | | return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, lhs_src, rhs_src); |
| 15247 | return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, rhs_src); |
| 15274 | 15248 | }, |
| 15275 | 15249 | } |
| 15276 | 15250 | } |
| ... | ... | @@ -15370,7 +15344,6 @@ fn analyzePtrArithmetic( |
| 15370 | 15344 | ptr: Air.Inst.Ref, |
| 15371 | 15345 | uncasted_offset: Air.Inst.Ref, |
| 15372 | 15346 | air_tag: Air.Inst.Tag, |
| 15373 | | ptr_src: LazySrcLoc, |
| 15374 | 15347 | offset_src: LazySrcLoc, |
| 15375 | 15348 | ) CompileError!Air.Inst.Ref { |
| 15376 | 15349 | // TODO if the operand is comptime-known to be negative, or is a negative int, |
| ... | ... | @@ -15378,12 +15351,14 @@ fn analyzePtrArithmetic( |
| 15378 | 15351 | const offset = try sema.coerce(block, .usize, uncasted_offset, offset_src); |
| 15379 | 15352 | const pt = sema.pt; |
| 15380 | 15353 | const zcu = pt.zcu; |
| 15381 | | const opt_ptr_val = sema.resolveValue(ptr); |
| 15382 | | const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset); |
| 15383 | 15354 | const ptr_ty = sema.typeOf(ptr); |
| 15384 | 15355 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 15385 | 15356 | assert(ptr_info.flags.size == .many or ptr_info.flags.size == .c); |
| 15386 | 15357 | |
| 15358 | const maybe_index: ?u64 = if (try sema.resolveDefinedValue(block, offset_src, offset)) |val| off: { |
| 15359 | break :off val.toUnsignedInt(zcu); |
| 15360 | } else null; |
| 15361 | |
| 15387 | 15362 | const elem_ty: Type = .fromInterned(ptr_info.child); |
| 15388 | 15363 | elem_ty.assertHasLayout(zcu); |
| 15389 | 15364 | |
| ... | ... | @@ -15395,70 +15370,36 @@ fn analyzePtrArithmetic( |
| 15395 | 15370 | else => {}, |
| 15396 | 15371 | } |
| 15397 | 15372 | |
| 15398 | | const new_ptr_ty = t: { |
| 15399 | | // Calculate the new pointer alignment. |
| 15400 | | // This code is duplicated in `Type.elemPtrType`. |
| 15401 | | if (ptr_info.flags.alignment == .none) { |
| 15402 | | // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. |
| 15403 | | break :t ptr_ty; |
| 15404 | | } |
| 15405 | | // If the addend is not a comptime-known value we can still count on |
| 15406 | | // it being a multiple of the type size. |
| 15407 | | const elem_size = elem_ty.abiSize(zcu); |
| 15408 | | const addend = if (opt_off_val) |off_val| a: { |
| 15409 | | const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(zcu)); |
| 15410 | | break :a elem_size * off_int; |
| 15411 | | } else elem_size; |
| 15412 | | |
| 15413 | | // The resulting pointer is aligned to the lcd between the offset (an |
| 15414 | | // arbitrary number) and the alignment factor (always a power of two, |
| 15415 | | // non zero). |
| 15416 | | const new_align: Alignment = @enumFromInt(@min( |
| 15417 | | @ctz(addend), |
| 15418 | | @intFromEnum(ptr_info.flags.alignment), |
| 15419 | | )); |
| 15420 | | assert(new_align != .none); |
| 15421 | | |
| 15422 | | break :t try pt.ptrType(.{ |
| 15423 | | .child = ptr_info.child, |
| 15424 | | .sentinel = ptr_info.sentinel, |
| 15425 | | .flags = .{ |
| 15426 | | .size = ptr_info.flags.size, |
| 15427 | | .alignment = new_align, |
| 15428 | | .is_const = ptr_info.flags.is_const, |
| 15429 | | .is_volatile = ptr_info.flags.is_volatile, |
| 15430 | | .is_allowzero = ptr_info.flags.is_allowzero, |
| 15431 | | .address_space = ptr_info.flags.address_space, |
| 15432 | | }, |
| 15433 | | }); |
| 15434 | | }; |
| 15373 | const elem_ptr_ty = try ptr_ty.elemPtrType(maybe_index, pt); |
| 15374 | // `elem_ptr_ty` is a single-item pointer, but we want a many-item or C pointer, and to preserve |
| 15375 | // any input sentinel. |
| 15376 | const new_ptr_ty = try pt.ptrType(info: { |
| 15377 | var info = elem_ptr_ty.ptrInfo(zcu); |
| 15378 | info.flags.size = ptr_info.flags.size; |
| 15379 | info.sentinel = ptr_info.sentinel; |
| 15380 | break :info info; |
| 15381 | }); |
| 15435 | 15382 | |
| 15436 | | const runtime_src = rs: { |
| 15437 | | if (opt_ptr_val) |ptr_val| { |
| 15438 | | if (opt_off_val) |offset_val| { |
| 15439 | | if (ptr_val.isUndef(zcu)) return pt.undefRef(new_ptr_ty); |
| 15440 | | |
| 15441 | | const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(zcu)); |
| 15442 | | if (offset_int == 0) return ptr; |
| 15443 | | if (air_tag == .ptr_sub) { |
| 15444 | | const elem_size = elem_ty.abiSize(zcu); |
| 15445 | | const new_ptr_val = try sema.ptrSubtract(block, op_src, ptr_val, offset_int * elem_size, new_ptr_ty); |
| 15446 | | return Air.internedToRef(new_ptr_val.toIntern()); |
| 15447 | | } else { |
| 15448 | | const new_ptr_val = try pt.getCoerced(try ptr_val.ptrElem(offset_int, pt), new_ptr_ty); |
| 15449 | | return Air.internedToRef(new_ptr_val.toIntern()); |
| 15450 | | } |
| 15451 | | } else break :rs offset_src; |
| 15452 | | } else break :rs ptr_src; |
| 15453 | | }; |
| 15383 | ct: { |
| 15384 | const ptr_val = sema.resolveValue(ptr) orelse break :ct; |
| 15385 | if (ptr_val.isUndef(zcu)) return pt.undefRef(new_ptr_ty); |
| 15386 | const index = maybe_index orelse break :ct; |
| 15387 | |
| 15388 | if (index == 0) return ptr; |
| 15389 | if (air_tag == .ptr_sub) { |
| 15390 | const elem_size = elem_ty.abiSize(zcu); |
| 15391 | return .fromValue(try sema.ptrSubtract(block, op_src, ptr_val, index * elem_size, new_ptr_ty)); |
| 15392 | } else { |
| 15393 | return .fromValue(try pt.getCoerced(try ptr_val.ptrElem(index, pt), new_ptr_ty)); |
| 15394 | } |
| 15395 | } |
| 15454 | 15396 | |
| 15455 | | try sema.requireRuntimeBlock(block, op_src, runtime_src); |
| 15456 | 15397 | try sema.checkLogicalPtrOperation(block, op_src, ptr_ty); |
| 15457 | 15398 | |
| 15458 | 15399 | return block.addInst(.{ |
| 15459 | 15400 | .tag = air_tag, |
| 15460 | 15401 | .data = .{ .ty_pl = .{ |
| 15461 | | .ty = Air.internedToRef(new_ptr_ty.toIntern()), |
| 15402 | .ty = .fromType(new_ptr_ty), |
| 15462 | 15403 | .payload = try sema.addExtra(Air.Bin{ |
| 15463 | 15404 | .lhs = ptr, |
| 15464 | 15405 | .rhs = offset, |
| ... | ... | @@ -16222,6 +16163,11 @@ fn zirBuiltinSrc( |
| 16222 | 16163 | return Air.internedToRef((try pt.aggregateValue(src_loc_ty, &fields)).toIntern()); |
| 16223 | 16164 | } |
| 16224 | 16165 | |
| 16166 | /// MLUGG TODO: once this branch is in a more stable state, I need to make a language change so that |
| 16167 | /// `std.builtin.Type` makes all `alignment` fields `?usize` instead of `comptime_int`, to prevent |
| 16168 | /// explicit alignment annotations from sneaking in without the user requesting any; but doing that |
| 16169 | /// right now would be really annoying because it would break the base compiler. I need to have the |
| 16170 | /// compiler more-or-less fully migrated first. |
| 16225 | 16171 | fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 16226 | 16172 | const pt = sema.pt; |
| 16227 | 16173 | const zcu = pt.zcu; |
| ... | ... | @@ -16726,17 +16672,21 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16726 | 16672 | } }); |
| 16727 | 16673 | }; |
| 16728 | 16674 | |
| 16675 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 16676 | |
| 16729 | 16677 | const alignment = switch (layout) { |
| 16730 | | .auto, .@"extern" => ty.resolvedFieldAlignment(field_index, zcu), |
| 16678 | .auto, .@"extern" => switch (ty.explicitFieldAlignment(field_index, zcu)) { |
| 16679 | .none => field_ty.abiAlignment(zcu), |
| 16680 | else => |a| a, |
| 16681 | }, |
| 16731 | 16682 | .@"packed" => .none, |
| 16732 | 16683 | }; |
| 16733 | 16684 | |
| 16734 | | const field_ty = union_obj.field_types.get(ip)[field_index]; |
| 16735 | 16685 | const union_field_fields = .{ |
| 16736 | 16686 | // name: [:0]const u8, |
| 16737 | 16687 | name_val, |
| 16738 | 16688 | // type: type, |
| 16739 | | field_ty, |
| 16689 | field_ty.toIntern(), |
| 16740 | 16690 | // alignment: comptime_int, |
| 16741 | 16691 | (try pt.intValue(.comptime_int, alignment.toByteUnits() orelse 0)).toIntern(), |
| 16742 | 16692 | }; |
| ... | ... | @@ -16895,7 +16845,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16895 | 16845 | const opt_default_val: ?Value = if (field_default == .none) null else .fromInterned(field_default); |
| 16896 | 16846 | const default_val_ptr = try sema.optRefValue(opt_default_val); |
| 16897 | 16847 | const alignment = switch (struct_type.layout) { |
| 16898 | | .auto, .@"extern" => ty.resolvedFieldAlignment(field_index, zcu), |
| 16848 | .auto, .@"extern" => switch (ty.explicitFieldAlignment(field_index, zcu)) { |
| 16849 | .none => field_ty.defaultStructFieldAlignment(struct_type.layout, zcu), |
| 16850 | else => |a| a, |
| 16851 | }, |
| 16899 | 16852 | .@"packed" => .none, |
| 16900 | 16853 | }; |
| 16901 | 16854 | |
| ... | ... | @@ -18425,8 +18378,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is |
| 18425 | 18378 | const init_ref = try sema.coerce(block, init_ty, empty_ref, src); |
| 18426 | 18379 | |
| 18427 | 18380 | if (is_byref) { |
| 18428 | | const init_val = sema.resolveValue(init_ref).?; |
| 18429 | | return sema.uavRef(init_val.toIntern()); |
| 18381 | return sema.uavRef(sema.resolveValue(init_ref).?); |
| 18430 | 18382 | } else { |
| 18431 | 18383 | return init_ref; |
| 18432 | 18384 | } |
| ... | ... | @@ -18648,7 +18600,7 @@ fn zirStructInit( |
| 18648 | 18600 | })); |
| 18649 | 18601 | const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src); |
| 18650 | 18602 | const final_val = sema.resolveValue(final_val_inst).?; |
| 18651 | | return sema.addConstantMaybeRef(final_val.toIntern(), is_ref); |
| 18603 | return sema.addConstantMaybeRef(final_val, is_ref); |
| 18652 | 18604 | } |
| 18653 | 18605 | |
| 18654 | 18606 | if (resolved_ty.comptimeOnly(zcu)) { |
| ... | ... | @@ -18789,7 +18741,7 @@ fn finishStructInit( |
| 18789 | 18741 | } |
| 18790 | 18742 | const struct_val = try pt.aggregateValue(struct_ty, elems); |
| 18791 | 18743 | const final_val_ref = try sema.coerce(block, result_ty, .fromValue(struct_val), init_src); |
| 18792 | | return sema.addConstantMaybeRef(final_val_ref.toInterned().?, is_ref); |
| 18744 | return sema.addConstantMaybeRef(sema.resolveValue(final_val_ref).?, is_ref); |
| 18793 | 18745 | }, |
| 18794 | 18746 | .@"packed" => { |
| 18795 | 18747 | const buf = try sema.arena.alloc(u8, (struct_ty.bitSize(zcu) + 7) / 8); |
| ... | ... | @@ -18808,7 +18760,7 @@ fn finishStructInit( |
| 18808 | 18760 | error.OutOfMemory => |e| return e, |
| 18809 | 18761 | }; |
| 18810 | 18762 | const final_val_ref = try sema.coerce(block, result_ty, .fromValue(struct_val), init_src); |
| 18811 | | return sema.addConstantMaybeRef(final_val_ref.toInterned().?, is_ref); |
| 18763 | return sema.addConstantMaybeRef(sema.resolveValue(final_val_ref).?, is_ref); |
| 18812 | 18764 | }, |
| 18813 | 18765 | }; |
| 18814 | 18766 | |
| ... | ... | @@ -19000,7 +18952,7 @@ fn structInitAnon( |
| 19000 | 18952 | |
| 19001 | 18953 | _ = opt_runtime_index orelse { |
| 19002 | 18954 | const struct_val = try pt.aggregateValue(struct_ty, values); |
| 19003 | | return sema.addConstantMaybeRef(struct_val.toIntern(), is_ref); |
| 18955 | return sema.addConstantMaybeRef(struct_val, is_ref); |
| 19004 | 18956 | }; |
| 19005 | 18957 | |
| 19006 | 18958 | if (is_ref) { |
| ... | ... | @@ -19137,7 +19089,7 @@ fn zirArrayInit( |
| 19137 | 19089 | const arr_val = try pt.aggregateValue(array_ty, elem_vals); |
| 19138 | 19090 | const result_ref = try sema.coerce(block, result_ty, Air.internedToRef(arr_val.toIntern()), src); |
| 19139 | 19091 | const result_val = (sema.resolveValue(result_ref)).?; |
| 19140 | | return sema.addConstantMaybeRef(result_val.toIntern(), is_ref); |
| 19092 | return sema.addConstantMaybeRef(result_val, is_ref); |
| 19141 | 19093 | }; |
| 19142 | 19094 | |
| 19143 | 19095 | if (is_ref) { |
| ... | ... | @@ -19261,7 +19213,7 @@ fn arrayInitAnon( |
| 19261 | 19213 | |
| 19262 | 19214 | const runtime_src = opt_runtime_src orelse { |
| 19263 | 19215 | const tuple_val = try pt.aggregateValue(tuple_ty, values); |
| 19264 | | return sema.addConstantMaybeRef(tuple_val.toIntern(), is_ref); |
| 19216 | return sema.addConstantMaybeRef(tuple_val, is_ref); |
| 19265 | 19217 | }; |
| 19266 | 19218 | |
| 19267 | 19219 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | ... | @@ -19304,8 +19256,8 @@ fn arrayInitAnon( |
| 19304 | 19256 | return block.addAggregateInit(tuple_ty, element_refs); |
| 19305 | 19257 | } |
| 19306 | 19258 | |
| 19307 | | fn addConstantMaybeRef(sema: *Sema, val: InternPool.Index, is_ref: bool) !Air.Inst.Ref { |
| 19308 | | return if (is_ref) sema.uavRef(val) else Air.internedToRef(val); |
| 19259 | fn addConstantMaybeRef(sema: *Sema, val: Value, is_ref: bool) !Air.Inst.Ref { |
| 19260 | return if (is_ref) sema.uavRef(val) else .fromValue(val); |
| 19309 | 19261 | } |
| 19310 | 19262 | |
| 19311 | 19263 | fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -23401,125 +23353,74 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 23401 | 23353 | const field_ptr = sema.resolveInst(extra.field_ptr); |
| 23402 | 23354 | const field_ptr_ty = sema.typeOf(field_ptr); |
| 23403 | 23355 | try sema.checkPtrOperand(block, field_ptr_src, field_ptr_ty); |
| 23404 | | const field_ptr_info = field_ptr_ty.ptrInfo(zcu); |
| 23405 | 23356 | |
| 23406 | | var actual_parent_ptr_info: InternPool.Key.PtrType = .{ |
| 23407 | | .child = parent_ty.toIntern(), |
| 23408 | | .flags = .{ |
| 23409 | | .alignment = parent_ptr_ty.ptrAlignment(zcu), |
| 23410 | | .is_const = field_ptr_info.flags.is_const, |
| 23411 | | .is_volatile = field_ptr_info.flags.is_volatile, |
| 23412 | | .is_allowzero = field_ptr_info.flags.is_allowzero, |
| 23413 | | .address_space = field_ptr_info.flags.address_space, |
| 23414 | | }, |
| 23415 | | .packed_offset = parent_ptr_info.packed_offset, |
| 23416 | | }; |
| 23417 | | const field_ty = parent_ty.fieldType(field_index, zcu); |
| 23418 | | var actual_field_ptr_info: InternPool.Key.PtrType = .{ |
| 23419 | | .child = field_ty.toIntern(), |
| 23420 | | .flags = .{ |
| 23421 | | .alignment = field_ptr_ty.ptrAlignment(zcu), |
| 23422 | | .is_const = field_ptr_info.flags.is_const, |
| 23423 | | .is_volatile = field_ptr_info.flags.is_volatile, |
| 23424 | | .is_allowzero = field_ptr_info.flags.is_allowzero, |
| 23425 | | .address_space = field_ptr_info.flags.address_space, |
| 23426 | | }, |
| 23427 | | .packed_offset = field_ptr_info.packed_offset, |
| 23428 | | }; |
| 23429 | | switch (parent_ty.containerLayout(zcu)) { |
| 23430 | | .auto => { |
| 23431 | | actual_parent_ptr_info.flags.alignment = parent_ty.resolvedFieldAlignment(field_index, zcu); |
| 23432 | | actual_parent_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 }; |
| 23433 | | actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 }; |
| 23434 | | }, |
| 23435 | | .@"extern" => { |
| 23436 | | const field_offset = parent_ty.structFieldOffset(field_index, zcu); |
| 23437 | | actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (field_offset > 0) |
| 23438 | | Alignment.fromLog2Units(@ctz(field_offset)) |
| 23439 | | else |
| 23440 | | actual_field_ptr_info.flags.alignment); |
| 23441 | | |
| 23442 | | actual_parent_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 }; |
| 23443 | | actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 }; |
| 23444 | | }, |
| 23445 | | .@"packed" => { |
| 23446 | | const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) + |
| 23447 | | (if (zcu.typeToStruct(parent_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, field_index) else 0) - |
| 23448 | | actual_field_ptr_info.packed_offset.bit_offset), 8) catch |
| 23449 | | return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{}); |
| 23450 | | actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (byte_offset > 0) |
| 23451 | | Alignment.fromLog2Units(@ctz(byte_offset)) |
| 23452 | | else |
| 23453 | | actual_field_ptr_info.flags.alignment); |
| 23454 | | }, |
| 23455 | | } |
| 23357 | const hypothetical_field_ptr_ty = try parent_ptr_ty.fieldPtrType(field_index, pt); |
| 23358 | const casted_field_ptr = try sema.ptrCastFull( |
| 23359 | block, |
| 23360 | flags, |
| 23361 | inst_src, |
| 23362 | field_ptr, |
| 23363 | field_ptr_src, |
| 23364 | hypothetical_field_ptr_ty, |
| 23365 | "@fieldParentPtr", |
| 23366 | ); |
| 23456 | 23367 | |
| 23457 | | const actual_field_ptr_ty = try pt.ptrType(actual_field_ptr_info); |
| 23458 | | const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src); |
| 23459 | | const actual_parent_ptr_ty = try pt.ptrType(actual_parent_ptr_info); |
| 23368 | const unaligned_parent_ptr_ty = try pt.ptrType(info: { |
| 23369 | var info = parent_ptr_ty.ptrInfo(zcu); |
| 23370 | info.flags.alignment = hypothetical_field_ptr_ty.ptrAlignment(zcu); |
| 23371 | break :info info; |
| 23372 | }); |
| 23460 | 23373 | |
| 23461 | | const result = if (try sema.resolveDefinedValue(block, field_ptr_src, casted_field_ptr)) |field_ptr_val| result: { |
| 23462 | | switch (parent_ty.zigTypeTag(zcu)) { |
| 23463 | | .@"struct" => switch (parent_ty.containerLayout(zcu)) { |
| 23464 | | .auto => {}, |
| 23465 | | .@"extern" => { |
| 23466 | | const byte_offset = parent_ty.structFieldOffset(field_index, zcu); |
| 23467 | | const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty); |
| 23468 | | break :result Air.internedToRef(parent_ptr_val.toIntern()); |
| 23469 | | }, |
| 23470 | | .@"packed" => { |
| 23471 | | // Logic lifted from type computation above - I'm just assuming it's correct. |
| 23472 | | // `catch unreachable` since error case handled above. |
| 23473 | | const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) + |
| 23474 | | zcu.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) - |
| 23475 | | actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable; |
| 23476 | | const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty); |
| 23477 | | break :result Air.internedToRef(parent_ptr_val.toIntern()); |
| 23478 | | }, |
| 23479 | | }, |
| 23480 | | .@"union" => switch (parent_ty.containerLayout(zcu)) { |
| 23481 | | .auto => {}, |
| 23482 | | .@"extern", .@"packed" => { |
| 23483 | | // For an extern or packed union, just coerce the pointer. |
| 23484 | | const parent_ptr_val = try pt.getCoerced(field_ptr_val, actual_parent_ptr_ty); |
| 23485 | | break :result Air.internedToRef(parent_ptr_val.toIntern()); |
| 23486 | | }, |
| 23487 | | }, |
| 23374 | const unaligned_parent_ptr: Air.Inst.Ref = if (try sema.resolveDefinedValue( |
| 23375 | block, |
| 23376 | field_ptr_src, |
| 23377 | casted_field_ptr, |
| 23378 | )) |field_ptr_val| switch (parent_ty.containerLayout(zcu)) { |
| 23379 | .@"packed" => .fromValue(try pt.getCoerced(field_ptr_val, unaligned_parent_ptr_ty)), |
| 23380 | .@"extern" => switch (parent_ty.zigTypeTag(zcu)) { |
| 23381 | .@"struct" => .fromValue(try sema.ptrSubtract( |
| 23382 | block, |
| 23383 | field_ptr_src, |
| 23384 | field_ptr_val, |
| 23385 | parent_ty.structFieldOffset(field_index, zcu), |
| 23386 | unaligned_parent_ptr_ty, |
| 23387 | )), |
| 23388 | .@"union" => .fromValue(try pt.getCoerced(field_ptr_val, unaligned_parent_ptr_ty)), |
| 23488 | 23389 | else => unreachable, |
| 23489 | | } |
| 23490 | | |
| 23491 | | const opt_field: ?InternPool.Key.Ptr.BaseAddr.BaseIndex = opt_field: { |
| 23492 | | const ptr = switch (ip.indexToKey(field_ptr_val.toIntern())) { |
| 23493 | | .ptr => |ptr| ptr, |
| 23494 | | else => break :opt_field null, |
| 23495 | | }; |
| 23496 | | if (ptr.byte_offset != 0) break :opt_field null; |
| 23497 | | break :opt_field switch (ptr.base_addr) { |
| 23498 | | .field => |field| field, |
| 23499 | | else => null, |
| 23390 | }, |
| 23391 | .auto => result: { |
| 23392 | const opt_field: ?InternPool.Key.Ptr.BaseAddr.BaseIndex = opt_field: { |
| 23393 | const ptr = switch (ip.indexToKey(field_ptr_val.toIntern())) { |
| 23394 | .ptr => |ptr| ptr, |
| 23395 | else => break :opt_field null, |
| 23396 | }; |
| 23397 | if (ptr.byte_offset != 0) break :opt_field null; |
| 23398 | break :opt_field switch (ptr.base_addr) { |
| 23399 | .field => |field| field, |
| 23400 | else => null, |
| 23401 | }; |
| 23500 | 23402 | }; |
| 23501 | | }; |
| 23502 | 23403 | |
| 23503 | | const field = opt_field orelse { |
| 23504 | | return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{}); |
| 23505 | | }; |
| 23404 | const field = opt_field orelse { |
| 23405 | return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{}); |
| 23406 | }; |
| 23506 | 23407 | |
| 23507 | | if (Value.fromInterned(field.base).typeOf(zcu).childType(zcu).toIntern() != parent_ty.toIntern()) { |
| 23508 | | return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{}); |
| 23509 | | } |
| 23408 | if (Value.fromInterned(field.base).typeOf(zcu).childType(zcu).toIntern() != parent_ty.toIntern()) { |
| 23409 | return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{}); |
| 23410 | } |
| 23510 | 23411 | |
| 23511 | | if (field.index != field_index) { |
| 23512 | | return sema.fail(block, inst_src, "field '{f}' has index '{d}' but pointer value is index '{d}' of struct '{f}'", .{ |
| 23513 | | field_name.fmt(ip), field_index, field.index, parent_ty.fmt(pt), |
| 23514 | | }); |
| 23515 | | } |
| 23516 | | break :result try sema.coerce(block, actual_parent_ptr_ty, Air.internedToRef(field.base), inst_src); |
| 23412 | if (field.index != field_index) { |
| 23413 | return sema.fail(block, inst_src, "field '{f}' has index '{d}' but pointer value is index '{d}' of struct '{f}'", .{ |
| 23414 | field_name.fmt(ip), field_index, field.index, parent_ty.fmt(pt), |
| 23415 | }); |
| 23416 | } |
| 23417 | break :result .fromValue(try pt.getCoerced(.fromInterned(field.base), unaligned_parent_ptr_ty)); |
| 23418 | }, |
| 23517 | 23419 | } else result: { |
| 23518 | | try sema.requireRuntimeBlock(block, inst_src, field_ptr_src); |
| 23519 | 23420 | break :result try block.addInst(.{ |
| 23520 | 23421 | .tag = .field_parent_ptr, |
| 23521 | 23422 | .data = .{ .ty_pl = .{ |
| 23522 | | .ty = Air.internedToRef(actual_parent_ptr_ty.toIntern()), |
| 23423 | .ty = .fromType(unaligned_parent_ptr_ty), |
| 23523 | 23424 | .payload = try block.sema.addExtra(Air.FieldParentPtr{ |
| 23524 | 23425 | .field_ptr = casted_field_ptr, |
| 23525 | 23426 | .field_index = @intCast(field_index), |
| ... | ... | @@ -23527,14 +23428,61 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 23527 | 23428 | } }, |
| 23528 | 23429 | }); |
| 23529 | 23430 | }; |
| 23530 | | return sema.ptrCastFull(block, flags, inst_src, result, inst_src, parent_ptr_ty, "@fieldParentPtr"); |
| 23431 | |
| 23432 | // There's one more error condition: if the hypothetical field pointer type has a lower |
| 23433 | // alignment than the parent pointer type, then we need an `@alignCast`. Note that the earlier |
| 23434 | // `ptrCastFull` may *also* have "used" the `@alignCast`; that would be a case where the field |
| 23435 | // is naturally less aligned than the rest of the struct, *and* the field pointer is itself |
| 23436 | // underaligned compared to the field alignment. For example, `struct { a: u32, b: u16 }` with |
| 23437 | // a field pointer of type `*align(1) u16`. |
| 23438 | switch (hypothetical_field_ptr_ty.ptrAlignment(zcu).order(parent_ptr_ty.ptrAlignment(zcu))) { |
| 23439 | .gt => unreachable, // getting a field pointer can never increase alignment |
| 23440 | .eq => return unaligned_parent_ptr, |
| 23441 | .lt => if (flags.align_cast) { |
| 23442 | // Go through `ptrCastFull` for the safety check. |
| 23443 | return sema.ptrCastFull( |
| 23444 | block, |
| 23445 | flags, |
| 23446 | inst_src, |
| 23447 | unaligned_parent_ptr, |
| 23448 | inst_src, |
| 23449 | parent_ptr_ty, |
| 23450 | "@fieldParentPtr", |
| 23451 | ); |
| 23452 | } else return sema.failWithOwnedErrorMsg(block, msg: { |
| 23453 | const msg = try sema.errMsg(inst_src, "@fieldParentPtr increases pointer alignment", .{}); |
| 23454 | errdefer msg.destroy(sema.gpa); |
| 23455 | try sema.errNote(inst_src, msg, "parent pointer type '{f}' has alignment '{d}'", .{ |
| 23456 | parent_ptr_ty.fmt(pt), |
| 23457 | parent_ptr_ty.abiAlignment(zcu), |
| 23458 | }); |
| 23459 | if (parent_ty.isTuple(zcu)) { |
| 23460 | try sema.errNote(field_ptr_src, msg, "tuple field '{d}' limits alignment to '{d}'", .{ |
| 23461 | field_index, |
| 23462 | field_ptr_ty.ptrAlignment(zcu), |
| 23463 | }); |
| 23464 | } else { |
| 23465 | try sema.errNote(parent_ty.srcLoc(zcu), msg, "{t} field '{f}' limits alignment to '{d}'", .{ |
| 23466 | parent_ty.zigTypeTag(zcu), |
| 23467 | switch (parent_ty.zigTypeTag(zcu)) { |
| 23468 | .@"struct" => parent_ty.structFieldName(field_index, zcu).unwrap().?.fmt(ip), |
| 23469 | .@"union" => parent_ty.unionTagTypeHypothetical(zcu).enumFieldName(field_index, zcu).fmt(ip), |
| 23470 | else => unreachable, |
| 23471 | }, |
| 23472 | field_ptr_ty.ptrAlignment(zcu), |
| 23473 | }); |
| 23474 | } |
| 23475 | try sema.errNote(inst_src, msg, "use @alignCast to assert pointer alignment", .{}); |
| 23476 | break :msg msg; |
| 23477 | }), |
| 23478 | } |
| 23531 | 23479 | } |
| 23532 | 23480 | |
| 23533 | 23481 | fn ptrSubtract(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, byte_subtract: u64, new_ty: Type) !Value { |
| 23534 | 23482 | const pt = sema.pt; |
| 23535 | 23483 | const zcu = pt.zcu; |
| 23536 | 23484 | if (byte_subtract == 0) return pt.getCoerced(ptr_val, new_ty); |
| 23537 | | var ptr = switch (zcu.intern_pool.indexToKey(ptr_val.toIntern())) { |
| 23485 | const ptr = switch (zcu.intern_pool.indexToKey(ptr_val.toIntern())) { |
| 23538 | 23486 | .undef => return sema.failWithUseOfUndef(block, src, null), |
| 23539 | 23487 | .ptr => |ptr| ptr, |
| 23540 | 23488 | else => unreachable, |
| ... | ... | @@ -23547,9 +23495,11 @@ fn ptrSubtract(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, byte |
| 23547 | 23495 | break :msg msg; |
| 23548 | 23496 | }); |
| 23549 | 23497 | } |
| 23550 | | ptr.byte_offset -= byte_subtract; |
| 23551 | | ptr.ty = new_ty.toIntern(); |
| 23552 | | return Value.fromInterned(try pt.intern(.{ .ptr = ptr })); |
| 23498 | return Value.fromInterned(try pt.intern(.{ .ptr = .{ |
| 23499 | .ty = new_ty.toIntern(), |
| 23500 | .base_addr = ptr.base_addr, |
| 23501 | .byte_offset = ptr.byte_offset - byte_subtract, |
| 23502 | } })); |
| 23553 | 23503 | } |
| 23554 | 23504 | |
| 23555 | 23505 | fn zirMinMax( |
| ... | ... | @@ -24186,8 +24136,8 @@ fn zirMemcpy( |
| 24186 | 24136 | |
| 24187 | 24137 | // ok1: dest >= src + len |
| 24188 | 24138 | // ok2: src >= dest + len |
| 24189 | | const src_plus_len = try sema.analyzePtrArithmetic(block, src, raw_src_ptr, len, .ptr_add, src_src, src); |
| 24190 | | const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src); |
| 24139 | const src_plus_len = try sema.analyzePtrArithmetic(block, src, raw_src_ptr, len, .ptr_add, src); |
| 24140 | const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, src); |
| 24191 | 24141 | const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len); |
| 24192 | 24142 | const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len); |
| 24193 | 24143 | const ok = try block.addBinOp(.bool_or, ok1, ok2); |
| ... | ... | @@ -25402,21 +25352,36 @@ fn addSafetyCheckSentinelMismatch( |
| 25402 | 25352 | const expected_sentinel = Air.internedToRef(expected_sentinel_val.toIntern()); |
| 25403 | 25353 | |
| 25404 | 25354 | const ptr_ty = sema.typeOf(ptr); |
| 25405 | | const actual_sentinel = if (ptr_ty.isSlice(zcu)) |
| 25406 | | try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index) |
| 25407 | | else blk: { |
| 25408 | | const elem_ptr_ty = try ptr_ty.elemPtrType(null, pt); |
| 25409 | | const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty); |
| 25410 | | break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr); |
| 25411 | | }; |
| 25412 | | |
| 25413 | | const ok = if (sentinel_ty.zigTypeTag(zcu) == .vector) ok: { |
| 25414 | | const eql = try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq); |
| 25415 | | break :ok try parent_block.addReduce(eql, .And); |
| 25416 | | } else ok: { |
| 25417 | | assert(sentinel_ty.isSelfComparable(zcu, true)); |
| 25418 | | break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel); |
| 25355 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 25356 | const actual_sentinel: Air.Inst.Ref = switch (ptr_ty.ptrSize(zcu)) { |
| 25357 | .slice => try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index), |
| 25358 | .one => s: { |
| 25359 | const array_ty: Type = .fromInterned(ptr_info.child); |
| 25360 | assert(array_ty.zigTypeTag(zcu) == .array); |
| 25361 | assert(array_ty.childType(zcu).toIntern() == sentinel_ty.toIntern()); |
| 25362 | const many_ptr_ty = try pt.ptrType(.{ |
| 25363 | .child = sentinel_ty.toIntern(), |
| 25364 | .flags = .{ |
| 25365 | .size = .many, |
| 25366 | .is_const = ptr_info.flags.is_const, |
| 25367 | .is_volatile = ptr_info.flags.is_volatile, |
| 25368 | .is_allowzero = ptr_info.flags.is_allowzero, |
| 25369 | .alignment = switch (ptr_info.flags.alignment) { |
| 25370 | .none => .none, |
| 25371 | else => |ptr_align| .minStrict(ptr_align, sentinel_ty.abiAlignment(zcu)), |
| 25372 | }, |
| 25373 | .address_space = ptr_info.flags.address_space, |
| 25374 | }, |
| 25375 | }); |
| 25376 | const many_ptr = try parent_block.addBitCast(many_ptr_ty, ptr); |
| 25377 | break :s try parent_block.addBinOp(.ptr_elem_val, many_ptr, sentinel_index); |
| 25378 | }, |
| 25379 | .many => unreachable, |
| 25380 | .c => unreachable, |
| 25419 | 25381 | }; |
| 25382 | assert(sema.typeOf(actual_sentinel).toIntern() == sentinel_ty.toIntern()); |
| 25383 | assert(sentinel_ty.isSelfComparable(zcu, true)); |
| 25384 | const ok = try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel); |
| 25420 | 25385 | |
| 25421 | 25386 | return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.sentinelMismatch", &.{ |
| 25422 | 25387 | expected_sentinel, actual_sentinel, |
| ... | ... | @@ -25676,7 +25641,7 @@ fn fieldVal( |
| 25676 | 25641 | .@"struct" => if (is_pointer_to) { |
| 25677 | 25642 | // Avoid loading the entire struct by fetching a pointer and loading that |
| 25678 | 25643 | try sema.ensureLayoutResolved(inner_ty, src); |
| 25679 | | const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); |
| 25644 | const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty); |
| 25680 | 25645 | return sema.analyzeLoad(block, src, field_ptr, object_src); |
| 25681 | 25646 | } else { |
| 25682 | 25647 | return sema.structFieldVal(block, object, field_name, field_name_src, inner_ty); |
| ... | ... | @@ -25730,7 +25695,7 @@ fn fieldPtr( |
| 25730 | 25695 | .array => { |
| 25731 | 25696 | if (field_name.eqlSlice("len", ip)) { |
| 25732 | 25697 | const int_val = try pt.intValue(.usize, inner_ty.arrayLen(zcu)); |
| 25733 | | return uavRef(sema, int_val.toIntern()); |
| 25698 | return uavRef(sema, int_val); |
| 25734 | 25699 | } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) { |
| 25735 | 25700 | const ptr_info = object_ty.ptrInfo(zcu); |
| 25736 | 25701 | const new_ptr_ty = try pt.ptrType(.{ |
| ... | ... | @@ -25752,6 +25717,7 @@ fn fieldPtr( |
| 25752 | 25717 | .child = new_ptr_ty.toIntern(), |
| 25753 | 25718 | .sentinel = if (object_ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none, |
| 25754 | 25719 | .flags = .{ |
| 25720 | .size = .one, |
| 25755 | 25721 | .alignment = ptr_ptr_info.flags.alignment, |
| 25756 | 25722 | .is_const = ptr_ptr_info.flags.is_const, |
| 25757 | 25723 | .is_volatile = ptr_ptr_info.flags.is_volatile, |
| ... | ... | @@ -25857,10 +25823,10 @@ fn fieldPtr( |
| 25857 | 25823 | }, |
| 25858 | 25824 | else => unreachable, |
| 25859 | 25825 | }; |
| 25860 | | return uavRef(sema, try pt.intern(.{ .err = .{ |
| 25826 | return uavRef(sema, .fromInterned(try pt.intern(.{ .err = .{ |
| 25861 | 25827 | .ty = err_set_ty.toIntern(), |
| 25862 | 25828 | .name = field_name, |
| 25863 | | } })); |
| 25829 | } }))); |
| 25864 | 25830 | }, |
| 25865 | 25831 | .@"union" => { |
| 25866 | 25832 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| ... | ... | @@ -25871,7 +25837,7 @@ fn fieldPtr( |
| 25871 | 25837 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| { |
| 25872 | 25838 | const field_index_u32: u32 = @intCast(field_index); |
| 25873 | 25839 | const idx_val = try pt.enumValueFieldIndex(enum_ty, field_index_u32); |
| 25874 | | return uavRef(sema, idx_val.toIntern()); |
| 25840 | return uavRef(sema, idx_val); |
| 25875 | 25841 | } |
| 25876 | 25842 | } |
| 25877 | 25843 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| ... | ... | @@ -25886,7 +25852,7 @@ fn fieldPtr( |
| 25886 | 25852 | }; |
| 25887 | 25853 | const field_index_u32: u32 = @intCast(field_index); |
| 25888 | 25854 | const idx_val = try pt.enumValueFieldIndex(child_type, field_index_u32); |
| 25889 | | return uavRef(sema, idx_val.toIntern()); |
| 25855 | return uavRef(sema, idx_val); |
| 25890 | 25856 | }, |
| 25891 | 25857 | .@"struct", .@"opaque" => { |
| 25892 | 25858 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| ... | ... | @@ -25903,7 +25869,7 @@ fn fieldPtr( |
| 25903 | 25869 | else |
| 25904 | 25870 | object_ptr; |
| 25905 | 25871 | try sema.ensureLayoutResolved(inner_ty, src); |
| 25906 | | const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); |
| 25872 | const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty); |
| 25907 | 25873 | try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); |
| 25908 | 25874 | return field_ptr; |
| 25909 | 25875 | }, |
| ... | ... | @@ -26190,7 +26156,6 @@ fn structFieldPtr( |
| 26190 | 26156 | field_name: InternPool.NullTerminatedString, |
| 26191 | 26157 | field_name_src: LazySrcLoc, |
| 26192 | 26158 | struct_ty: Type, |
| 26193 | | initializing: bool, |
| 26194 | 26159 | ) CompileError!Air.Inst.Ref { |
| 26195 | 26160 | const pt = sema.pt; |
| 26196 | 26161 | const zcu = pt.zcu; |
| ... | ... | @@ -26199,23 +26164,24 @@ fn structFieldPtr( |
| 26199 | 26164 | assert(struct_ty.zigTypeTag(zcu) == .@"struct"); |
| 26200 | 26165 | struct_ty.assertHasLayout(zcu); |
| 26201 | 26166 | |
| 26202 | | if (struct_ty.isTuple(zcu)) { |
| 26167 | const field_index: u32 = if (struct_ty.isTuple(zcu)) field_index: { |
| 26203 | 26168 | if (field_name.eqlSlice("len", ip)) { |
| 26204 | 26169 | const len_inst = try pt.intRef(.usize, struct_ty.structFieldCount(zcu)); |
| 26205 | 26170 | return sema.analyzeRef(block, src, len_inst); |
| 26206 | 26171 | } |
| 26207 | | const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); |
| 26208 | | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); |
| 26209 | | } |
| 26210 | | |
| 26211 | | const struct_type = zcu.typeToStruct(struct_ty).?; |
| 26212 | | |
| 26213 | | const field_index = struct_type.nameIndex(ip, field_name) orelse |
| 26214 | | return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name); |
| 26172 | break :field_index try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); |
| 26173 | } else field_index: { |
| 26174 | const struct_type = zcu.typeToStruct(struct_ty).?; |
| 26175 | break :field_index struct_type.nameIndex(ip, field_name) orelse { |
| 26176 | return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name); |
| 26177 | }; |
| 26178 | }; |
| 26215 | 26179 | |
| 26216 | 26180 | return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, struct_ty); |
| 26217 | 26181 | } |
| 26218 | 26182 | |
| 26183 | /// Supports both structs and unions. |
| 26184 | /// |
| 26219 | 26185 | /// Asserts that the layout of `struct_ty` is already resolved. |
| 26220 | 26186 | fn structFieldPtrByIndex( |
| 26221 | 26187 | sema: *Sema, |
| ... | ... | @@ -26227,82 +26193,23 @@ fn structFieldPtrByIndex( |
| 26227 | 26193 | ) CompileError!Air.Inst.Ref { |
| 26228 | 26194 | const pt = sema.pt; |
| 26229 | 26195 | const zcu = pt.zcu; |
| 26230 | | const ip = &zcu.intern_pool; |
| 26231 | 26196 | |
| 26232 | 26197 | struct_ty.assertHasLayout(zcu); |
| 26233 | | |
| 26234 | | const struct_type = zcu.typeToStruct(struct_ty).?; |
| 26235 | | const field_is_comptime = struct_type.field_is_comptime_bits.get(ip, field_index); |
| 26236 | | |
| 26237 | | // Comptime fields are handled later |
| 26238 | | if (!field_is_comptime) { |
| 26239 | | if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { |
| 26240 | | const val = try struct_ptr_val.ptrField(field_index, pt); |
| 26241 | | return Air.internedToRef(val.toIntern()); |
| 26242 | | } |
| 26243 | | } |
| 26244 | | |
| 26245 | | const field_ty = struct_type.field_types.get(ip)[field_index]; |
| 26246 | 26198 | const struct_ptr_ty = sema.typeOf(struct_ptr); |
| 26247 | | const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu); |
| 26248 | | assert(struct_ptr_ty_info.child == struct_ty.toIntern()); |
| 26249 | | |
| 26250 | | var ptr_ty_data: InternPool.Key.PtrType = .{ |
| 26251 | | .child = field_ty, |
| 26252 | | .flags = .{ |
| 26253 | | .is_const = struct_ptr_ty_info.flags.is_const, |
| 26254 | | .is_volatile = struct_ptr_ty_info.flags.is_volatile, |
| 26255 | | .address_space = struct_ptr_ty_info.flags.address_space, |
| 26256 | | }, |
| 26257 | | }; |
| 26258 | 26199 | |
| 26259 | | const parent_align = if (struct_ptr_ty_info.flags.alignment != .none) |
| 26260 | | struct_ptr_ty_info.flags.alignment |
| 26261 | | else |
| 26262 | | struct_ty.abiAlignment(zcu); |
| 26263 | | |
| 26264 | | if (struct_type.layout == .@"packed") { |
| 26265 | | assert(!field_is_comptime); |
| 26266 | | const packed_offset = struct_ty.packedStructFieldPtrInfo(struct_ptr_ty, field_index, pt); |
| 26267 | | ptr_ty_data.flags.alignment = parent_align; |
| 26268 | | ptr_ty_data.packed_offset = packed_offset; |
| 26269 | | } else if (struct_type.layout == .@"extern") { |
| 26270 | | assert(!field_is_comptime); |
| 26271 | | // For extern structs, field alignment might be bigger than type's |
| 26272 | | // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the |
| 26273 | | // second field is aligned as u32. |
| 26274 | | ptr_ty_data.flags.alignment = a: { |
| 26275 | | const field_off = struct_ty.structFieldOffset(field_index, zcu); |
| 26276 | | if (field_off == 0) break :a struct_ptr_ty_info.flags.alignment; |
| 26277 | | const true_field_align: Alignment = .fromLog2Units(@ctz(field_off)); |
| 26278 | | if (struct_ptr_ty_info.flags.alignment == .none and |
| 26279 | | true_field_align == Type.fromInterned(field_ty).abiAlignment(zcu)) |
| 26280 | | { |
| 26281 | | break :a .none; |
| 26282 | | } |
| 26283 | | break :a .minStrict(true_field_align, parent_align); |
| 26284 | | }; |
| 26285 | | } else { |
| 26286 | | // Our alignment is capped at the field alignment. |
| 26287 | | ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none) |
| 26288 | | struct_ty.explicitFieldAlignment(field_index, zcu) |
| 26289 | | else |
| 26290 | | struct_ty.resolvedFieldAlignment(field_index, zcu).min(parent_align); |
| 26291 | | } |
| 26292 | | |
| 26293 | | const ptr_field_ty = try pt.ptrType(ptr_ty_data); |
| 26294 | | |
| 26295 | | if (field_is_comptime) { |
| 26296 | | assert(struct_type.field_defaults.get(ip)[field_index] != .none); |
| 26297 | | const val = try pt.intern(.{ .ptr = .{ |
| 26298 | | .ty = ptr_field_ty.toIntern(), |
| 26299 | | .base_addr = .{ .comptime_field = struct_type.field_defaults.get(ip)[field_index] }, |
| 26200 | if (struct_ty.structFieldIsComptime(field_index, zcu)) { |
| 26201 | const field_ptr_ty = try struct_ptr_ty.fieldPtrType(field_index, pt); |
| 26202 | return .fromIntern(try pt.intern(.{ .ptr = .{ |
| 26203 | .ty = field_ptr_ty.toIntern(), |
| 26204 | .base_addr = .{ .comptime_field = struct_ty.structFieldDefaultValue(field_index, zcu).?.toIntern() }, |
| 26300 | 26205 | .byte_offset = 0, |
| 26301 | | } }); |
| 26302 | | return Air.internedToRef(val); |
| 26206 | } })); |
| 26207 | } else if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { |
| 26208 | return .fromValue(try struct_ptr_val.ptrField(field_index, pt)); |
| 26209 | } else { |
| 26210 | const field_ptr_ty = try struct_ptr_ty.fieldPtrType(field_index, pt); |
| 26211 | return block.addStructFieldPtr(struct_ptr, field_index, field_ptr_ty); |
| 26303 | 26212 | } |
| 26304 | | |
| 26305 | | return block.addStructFieldPtr(struct_ptr, field_index, ptr_field_ty); |
| 26306 | 26213 | } |
| 26307 | 26214 | |
| 26308 | 26215 | fn structFieldVal( |
| ... | ... | @@ -26438,29 +26345,11 @@ fn unionFieldPtr( |
| 26438 | 26345 | assert(union_ty.zigTypeTag(zcu) == .@"union"); |
| 26439 | 26346 | union_ty.assertHasLayout(zcu); |
| 26440 | 26347 | |
| 26441 | | const union_ptr_ty = sema.typeOf(union_ptr); |
| 26442 | | const union_ptr_info = union_ptr_ty.ptrInfo(zcu); |
| 26443 | 26348 | const union_obj = zcu.typeToUnion(union_ty).?; |
| 26349 | const tag_ty: Type = .fromInterned(union_obj.enum_tag_type); |
| 26350 | |
| 26444 | 26351 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 26445 | 26352 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 26446 | | const ptr_field_ty = try pt.ptrType(.{ |
| 26447 | | .child = field_ty.toIntern(), |
| 26448 | | .flags = .{ |
| 26449 | | .is_const = union_ptr_info.flags.is_const, |
| 26450 | | .is_volatile = union_ptr_info.flags.is_volatile, |
| 26451 | | .address_space = union_ptr_info.flags.address_space, |
| 26452 | | .alignment = a: { |
| 26453 | | if (union_obj.layout != .auto) break :a union_ptr_info.flags.alignment; |
| 26454 | | if (union_ptr_info.flags.alignment == .none) { |
| 26455 | | break :a union_ty.explicitFieldAlignment(field_index, zcu); |
| 26456 | | } |
| 26457 | | const field_align = union_ty.resolvedFieldAlignment(field_index, zcu); |
| 26458 | | break :a union_ptr_info.flags.alignment.min(field_align); |
| 26459 | | }, |
| 26460 | | }, |
| 26461 | | .packed_offset = union_ptr_info.packed_offset, |
| 26462 | | }); |
| 26463 | | const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_type).enumFieldIndex(field_name, zcu).?); |
| 26464 | 26353 | |
| 26465 | 26354 | if (initializing and field_ty.classify(zcu) == .no_possible_value) { |
| 26466 | 26355 | const msg = msg: { |
| ... | ... | @@ -26484,23 +26373,17 @@ fn unionFieldPtr( |
| 26484 | 26373 | break :ct; |
| 26485 | 26374 | } |
| 26486 | 26375 | // Store to the union to initialize the tag. |
| 26487 | | const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index); |
| 26488 | | const payload_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 26489 | | const new_union_val = try pt.unionValue(union_ty, field_tag, try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty)); |
| 26376 | const field_tag = try pt.enumValueFieldIndex(tag_ty, field_index); |
| 26377 | const payload_val = try field_ty.onePossibleValue(pt) orelse try pt.undefValue(field_ty); |
| 26378 | const new_union_val = try pt.unionValue(union_ty, field_tag, payload_val); |
| 26490 | 26379 | try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty); |
| 26491 | 26380 | } else { |
| 26492 | | const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse |
| 26493 | | break :ct; |
| 26494 | | if (union_val.isUndef(zcu)) { |
| 26495 | | return sema.failWithUseOfUndef(block, src, null); |
| 26496 | | } |
| 26497 | | const un = ip.indexToKey(union_val.toIntern()).un; |
| 26498 | | const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index); |
| 26499 | | const tag_matches = un.tag == field_tag.toIntern(); |
| 26500 | | if (!tag_matches) { |
| 26381 | const union_val = try sema.pointerDeref(block, src, union_ptr_val, union_ptr_val.typeOf(zcu)) orelse break :ct; |
| 26382 | if (union_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null); |
| 26383 | const active_index = tag_ty.enumTagFieldIndex(union_val.unionTag(zcu).?, zcu).?; |
| 26384 | if (active_index != field_index) { |
| 26501 | 26385 | const msg = msg: { |
| 26502 | | const active_index = Type.fromInterned(union_obj.enum_tag_type).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?; |
| 26503 | | const active_field_name = Type.fromInterned(union_obj.enum_tag_type).enumFieldName(active_index, zcu); |
| 26386 | const active_field_name = tag_ty.enumFieldName(active_index, zcu); |
| 26504 | 26387 | const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{ |
| 26505 | 26388 | field_name.fmt(ip), |
| 26506 | 26389 | active_field_name.fmt(ip), |
| ... | ... | @@ -26520,11 +26403,10 @@ fn unionFieldPtr( |
| 26520 | 26403 | // If the union has a tag, we must either set or or safety check it depending on `initializing`. |
| 26521 | 26404 | tag: { |
| 26522 | 26405 | if (union_ty.containerLayout(zcu) != .auto) break :tag; |
| 26523 | | const tag_ty: Type = .fromInterned(union_obj.enum_tag_type); |
| 26524 | 26406 | if (tag_ty.classify(zcu) == .one_possible_value) break :tag; |
| 26525 | 26407 | // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but |
| 26526 | 26408 | // only emit a safety check if it's available at runtime (i.e. it's safety-tagged). |
| 26527 | | const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index); |
| 26409 | const want_tag = try pt.enumValueFieldIndex(tag_ty, field_index); |
| 26528 | 26410 | if (initializing) { |
| 26529 | 26411 | const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag)); |
| 26530 | 26412 | try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store |
| ... | ... | @@ -26540,7 +26422,9 @@ fn unionFieldPtr( |
| 26540 | 26422 | _ = try block.addNoOp(.unreach); |
| 26541 | 26423 | return .unreachable_value; |
| 26542 | 26424 | } |
| 26543 | | return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty); |
| 26425 | |
| 26426 | const field_ptr_ty = try sema.typeOf(union_ptr).fieldPtrType(field_index, pt); |
| 26427 | return block.addStructFieldPtr(union_ptr, field_index, field_ptr_ty); |
| 26544 | 26428 | } |
| 26545 | 26429 | |
| 26546 | 26430 | fn unionFieldVal( |
| ... | ... | @@ -26628,13 +26512,9 @@ fn elemPtr( |
| 26628 | 26512 | try sema.ensureLayoutResolved(indexable_ty, src); |
| 26629 | 26513 | |
| 26630 | 26514 | const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) { |
| 26631 | | .array, .vector => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), |
| 26632 | | .@"struct" => blk: { |
| 26633 | | // Tuple field access. |
| 26634 | | const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index }); |
| 26635 | | const index: u32 = @intCast(index_val.toUnsignedInt(zcu)); |
| 26636 | | break :blk try sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); |
| 26637 | | }, |
| 26515 | .vector => try sema.elemPtrVector(block, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init), |
| 26516 | .array => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), |
| 26517 | .@"struct" => try sema.tupleElemPtr(block, src, indexable_ptr, elem_index, elem_index_src), |
| 26638 | 26518 | else => { |
| 26639 | 26519 | const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); |
| 26640 | 26520 | try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu), src); |
| ... | ... | @@ -26672,21 +26552,21 @@ fn elemPtrOneLayerOnly( |
| 26672 | 26552 | .many, .c => { |
| 26673 | 26553 | const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable); |
| 26674 | 26554 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 26555 | const maybe_index: ?u64 = if (maybe_index_val) |val| val.toUnsignedInt(zcu) else null; |
| 26675 | 26556 | ct: { |
| 26676 | 26557 | const ptr_val = maybe_ptr_val orelse break :ct; |
| 26677 | | const index_val = maybe_index_val orelse break :ct; |
| 26678 | | const index: usize = @intCast(index_val.toUnsignedInt(zcu)); |
| 26679 | | const elem_ptr = try ptr_val.ptrElem(index, pt); |
| 26680 | | return Air.internedToRef(elem_ptr.toIntern()); |
| 26558 | const index: usize = @intCast(maybe_index orelse break :ct); |
| 26559 | return .fromValue(try ptr_val.ptrElem(index, pt)); |
| 26681 | 26560 | } |
| 26682 | 26561 | |
| 26683 | 26562 | try sema.checkLogicalPtrOperation(block, src, indexable_ty); |
| 26684 | | const result_ty = try indexable_ty.elemPtrType(null, pt); |
| 26563 | |
| 26564 | const result_ty = try indexable_ty.elemPtrType(maybe_index, pt); |
| 26685 | 26565 | |
| 26686 | 26566 | try sema.validateRuntimeElemAccess(block, elem_index_src, result_ty, indexable_ty, indexable_src); |
| 26687 | 26567 | try sema.validateRuntimeValue(block, indexable_src, indexable); |
| 26688 | 26568 | |
| 26689 | | if (result_ty.childType(zcu).abiSize(zcu) == 0) { |
| 26569 | if (child_ty.abiSize(zcu) == 0) { |
| 26690 | 26570 | // zero-bit child type; just bitcast the pointer |
| 26691 | 26571 | return block.addBitCast(result_ty, indexable); |
| 26692 | 26572 | } |
| ... | ... | @@ -26695,13 +26575,9 @@ fn elemPtrOneLayerOnly( |
| 26695 | 26575 | }, |
| 26696 | 26576 | .one => { |
| 26697 | 26577 | const elem_ptr = switch (child_ty.zigTypeTag(zcu)) { |
| 26698 | | .array, .vector => try sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety), |
| 26699 | | .@"struct" => blk: { |
| 26700 | | assert(child_ty.isTuple(zcu)); |
| 26701 | | const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index }); |
| 26702 | | const index: u32 = @intCast(index_val.toUnsignedInt(zcu)); |
| 26703 | | break :blk try sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false); |
| 26704 | | }, |
| 26578 | .vector => try sema.elemPtrVector(block, indexable_src, indexable, elem_index_src, elem_index, init), |
| 26579 | .array => try sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety), |
| 26580 | .@"struct" => try sema.tupleElemPtr(block, indexable_src, indexable, elem_index, elem_index_src), |
| 26705 | 26581 | else => unreachable, // Guaranteed by checkIndexable |
| 26706 | 26582 | }; |
| 26707 | 26583 | try sema.checkKnownAllocPtr(block, indexable, elem_ptr); |
| ... | ... | @@ -26746,10 +26622,8 @@ fn elemVal( |
| 26746 | 26622 | const index: usize = @intCast(index_val.toUnsignedInt(zcu)); |
| 26747 | 26623 | const many_ptr_ty = try pt.manyConstPtrType(child_ty); |
| 26748 | 26624 | const many_ptr_val = try pt.getCoerced(indexable_val, many_ptr_ty); |
| 26749 | | const elem_ptr_ty = try pt.singleConstPtrType(child_ty); |
| 26750 | 26625 | const elem_ptr_val = try many_ptr_val.ptrElem(index, pt); |
| 26751 | | const elem_val = try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty) orelse break :ct; |
| 26752 | | return Air.internedToRef((try pt.getCoerced(elem_val, child_ty)).toIntern()); |
| 26626 | return sema.analyzeLoad(block, src, .fromValue(elem_ptr_val), indexable_src); |
| 26753 | 26627 | } |
| 26754 | 26628 | |
| 26755 | 26629 | if (try child_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); |
| ... | ... | @@ -26824,70 +26698,38 @@ fn validateRuntimeElemAccess( |
| 26824 | 26698 | } |
| 26825 | 26699 | } |
| 26826 | 26700 | |
| 26827 | | /// Asserts that the layout of the tuple type is already resolved. |
| 26828 | | fn tupleFieldPtr( |
| 26701 | /// Validates `elem_index`, and returns a pointer to that field using `structFieldPtrByIndex`. |
| 26702 | /// |
| 26703 | /// Asserts that the type of `tuple_ptr` is a single-item pointer whose child type is a tuple. |
| 26704 | fn tupleElemPtr( |
| 26829 | 26705 | sema: *Sema, |
| 26830 | 26706 | block: *Block, |
| 26831 | | tuple_ptr_src: LazySrcLoc, |
| 26707 | src: LazySrcLoc, |
| 26832 | 26708 | tuple_ptr: Air.Inst.Ref, |
| 26833 | | field_index_src: LazySrcLoc, |
| 26834 | | field_index: u32, |
| 26835 | | init: bool, |
| 26709 | elem_index: Air.Inst.Ref, |
| 26710 | elem_index_src: LazySrcLoc, |
| 26836 | 26711 | ) CompileError!Air.Inst.Ref { |
| 26837 | 26712 | const pt = sema.pt; |
| 26838 | 26713 | const zcu = pt.zcu; |
| 26839 | 26714 | const tuple_ptr_ty = sema.typeOf(tuple_ptr); |
| 26840 | | const tuple_ptr_info = tuple_ptr_ty.ptrInfo(zcu); |
| 26841 | | const tuple_ty: Type = .fromInterned(tuple_ptr_info.child); |
| 26842 | | const field_count = tuple_ty.structFieldCount(zcu); |
| 26843 | | |
| 26844 | | tuple_ty.assertHasLayout(zcu); |
| 26715 | assert(tuple_ptr_ty.isSinglePointer(zcu)); |
| 26716 | const tuple_ty = tuple_ptr_ty.childType(zcu); |
| 26717 | assert(tuple_ty.isTuple(zcu)); |
| 26845 | 26718 | |
| 26719 | const field_count = tuple_ty.structFieldCount(zcu); |
| 26846 | 26720 | if (field_count == 0) { |
| 26847 | | return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{}); |
| 26721 | return sema.fail(block, src, "indexing into empty tuple is not allowed", .{}); |
| 26848 | 26722 | } |
| 26849 | 26723 | |
| 26850 | | if (field_index >= field_count) { |
| 26851 | | return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ |
| 26852 | | field_index, field_count, |
| 26724 | const elem_index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index }); |
| 26725 | const index = elem_index_val.getUnsignedInt(zcu); |
| 26726 | if (index == null or index.? >= field_count) { |
| 26727 | return sema.fail(block, elem_index_src, "index '{f}' out of bounds of tuple '{f}'", .{ |
| 26728 | elem_index_val.fmtValueSema(pt, sema), tuple_ty.fmt(pt), |
| 26853 | 26729 | }); |
| 26854 | 26730 | } |
| 26855 | 26731 | |
| 26856 | | const field_ty = tuple_ty.fieldType(field_index, zcu); |
| 26857 | | const ptr_field_ty = try pt.ptrType(.{ |
| 26858 | | .child = field_ty.toIntern(), |
| 26859 | | .flags = .{ |
| 26860 | | .is_const = tuple_ptr_info.flags.is_const, |
| 26861 | | .is_volatile = tuple_ptr_info.flags.is_volatile, |
| 26862 | | .address_space = tuple_ptr_info.flags.address_space, |
| 26863 | | .alignment = a: { |
| 26864 | | if (tuple_ptr_info.flags.alignment == .none) break :a .none; |
| 26865 | | // The tuple pointer isn't naturally aligned, so the field pointer might be underaligned. |
| 26866 | | const tuple_align = tuple_ptr_info.flags.alignment; |
| 26867 | | const field_align = field_ty.abiAlignment(zcu); |
| 26868 | | break :a tuple_align.min(field_align); |
| 26869 | | }, |
| 26870 | | }, |
| 26871 | | }); |
| 26872 | | |
| 26873 | | if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_val| { |
| 26874 | | return Air.internedToRef((try pt.intern(.{ .ptr = .{ |
| 26875 | | .ty = ptr_field_ty.toIntern(), |
| 26876 | | .base_addr = .{ .comptime_field = default_val.toIntern() }, |
| 26877 | | .byte_offset = 0, |
| 26878 | | } }))); |
| 26879 | | } |
| 26880 | | |
| 26881 | | if (sema.resolveValue(tuple_ptr)) |tuple_ptr_val| { |
| 26882 | | const field_ptr_val = try tuple_ptr_val.ptrField(field_index, pt); |
| 26883 | | return Air.internedToRef(field_ptr_val.toIntern()); |
| 26884 | | } |
| 26885 | | |
| 26886 | | if (!init) { |
| 26887 | | try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src); |
| 26888 | | } |
| 26889 | | |
| 26890 | | return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty); |
| 26732 | return sema.structFieldPtrByIndex(block, src, tuple_ptr, @intCast(index.?), tuple_ty); |
| 26891 | 26733 | } |
| 26892 | 26734 | |
| 26893 | 26735 | fn tupleField( |
| ... | ... | @@ -26994,7 +26836,102 @@ fn elemValArray( |
| 26994 | 26836 | return block.addBinOp(.array_elem_val, array, elem_index); |
| 26995 | 26837 | } |
| 26996 | 26838 | |
| 26997 | | /// Asserts that the layout of the array or vector is already resolved. |
| 26839 | fn elemPtrVector( |
| 26840 | sema: *Sema, |
| 26841 | block: *Block, |
| 26842 | vector_ptr_src: LazySrcLoc, |
| 26843 | vector_ptr: Air.Inst.Ref, |
| 26844 | elem_index_src: LazySrcLoc, |
| 26845 | elem_index: Air.Inst.Ref, |
| 26846 | init: bool, |
| 26847 | ) CompileError!Air.Inst.Ref { |
| 26848 | const pt = sema.pt; |
| 26849 | const zcu = pt.zcu; |
| 26850 | const vector_ptr_ty = sema.typeOf(vector_ptr); |
| 26851 | const vector_ty = vector_ptr_ty.childType(zcu); |
| 26852 | assert(vector_ty.zigTypeTag(zcu) == .vector); |
| 26853 | const vector_len = vector_ty.vectorLen(zcu); |
| 26854 | |
| 26855 | if (vector_len == 0) { |
| 26856 | return sema.fail(block, vector_ptr_src, "cannot index into empty vector", .{}); |
| 26857 | } |
| 26858 | |
| 26859 | const maybe_vector_ptr_val = sema.resolveValue(vector_ptr); |
| 26860 | // The index must not be undefined since it can be out of bounds. |
| 26861 | const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse { |
| 26862 | return sema.fail(block, elem_index_src, "vector index not comptime known", .{}); |
| 26863 | }; |
| 26864 | const index = index_val.toUnsignedInt(zcu); |
| 26865 | if (index >= vector_len) { |
| 26866 | return sema.fail(block, elem_index_src, "index {d} outside vector of length {d}", .{ index, vector_len }); |
| 26867 | } |
| 26868 | |
| 26869 | const elem_ty = vector_ty.childType(zcu); |
| 26870 | const elem_bits = elem_ty.bitSize(zcu); |
| 26871 | // Exiting this block means the operation is a runtime one. |
| 26872 | const elem_ptr_ty: Type = if (elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits)) elem_ptr_ty: { |
| 26873 | // Use a packed pointer (i.e. vector_index != 0) |
| 26874 | const vector_ptr_info = vector_ptr_ty.ptrInfo(zcu); |
| 26875 | const elem_ptr_ty = try pt.ptrType(.{ |
| 26876 | .child = elem_ty.toIntern(), |
| 26877 | .flags = .{ |
| 26878 | .size = .one, |
| 26879 | .alignment = vector_ptr_info.flags.alignment, |
| 26880 | .is_const = vector_ptr_info.flags.is_const, |
| 26881 | .is_volatile = vector_ptr_info.flags.is_volatile, |
| 26882 | .is_allowzero = vector_ptr_info.flags.is_allowzero, |
| 26883 | .address_space = vector_ptr_info.flags.address_space, |
| 26884 | .vector_index = @enumFromInt(index), |
| 26885 | }, |
| 26886 | .packed_offset = .{ |
| 26887 | .host_size = @intCast(vector_len), |
| 26888 | .bit_offset = 0, |
| 26889 | }, |
| 26890 | }); |
| 26891 | if (maybe_vector_ptr_val) |ptr_val| { |
| 26892 | if (ptr_val.isUndef(zcu)) return pt.undefRef(elem_ptr_ty); |
| 26893 | return .fromValue(try pt.getCoerced(ptr_val, elem_ptr_ty)); |
| 26894 | } |
| 26895 | break :elem_ptr_ty elem_ptr_ty; |
| 26896 | } else elem_ptr_ty: { |
| 26897 | // Use a normal pointer (i.e. vector_index == 0) |
| 26898 | const vector_ptr_info = vector_ptr_ty.ptrInfo(zcu); |
| 26899 | const elem_ptr_ty = try pt.ptrType(.{ |
| 26900 | .child = elem_ty.toIntern(), |
| 26901 | .flags = .{ |
| 26902 | .size = .one, |
| 26903 | // TODO: this logic was ported from old code, but it's bogus. This entire block will |
| 26904 | // go away when https://github.com/ziglang/zig/issues/24061 is implemented anyway. |
| 26905 | .alignment = switch (vector_ptr_info.flags.alignment) { |
| 26906 | .none => .none, |
| 26907 | else => |vec_align| switch (index * elem_ty.abiSize(zcu)) { |
| 26908 | 0 => vec_align, |
| 26909 | else => |byte_offset| .minStrict(vec_align, .fromLog2Units(@ctz(byte_offset))), |
| 26910 | }, |
| 26911 | }, |
| 26912 | .is_const = vector_ptr_info.flags.is_const, |
| 26913 | .is_volatile = vector_ptr_info.flags.is_volatile, |
| 26914 | .is_allowzero = vector_ptr_info.flags.is_allowzero, |
| 26915 | .address_space = vector_ptr_info.flags.address_space, |
| 26916 | }, |
| 26917 | }); |
| 26918 | if (maybe_vector_ptr_val) |ptr_val| { |
| 26919 | if (ptr_val.isUndef(zcu)) return pt.undefRef(elem_ptr_ty); |
| 26920 | const bit_offset = index * @divExact(elem_ty.bitSize(zcu), 8); |
| 26921 | return .fromValue(try ptr_val.getOffsetPtr(bit_offset, elem_ptr_ty, pt)); |
| 26922 | } |
| 26923 | break :elem_ptr_ty elem_ptr_ty; |
| 26924 | }; |
| 26925 | |
| 26926 | if (!init) { |
| 26927 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, vector_ty, vector_ptr_src); |
| 26928 | try sema.validateRuntimeValue(block, vector_ptr_src, vector_ptr); |
| 26929 | } |
| 26930 | |
| 26931 | return block.addPtrElemPtr(vector_ptr, elem_index, elem_ptr_ty); |
| 26932 | } |
| 26933 | |
| 26934 | /// Asserts that the layout of the array is already resolved. |
| 26998 | 26935 | fn elemPtrArray( |
| 26999 | 26936 | sema: *Sema, |
| 27000 | 26937 | block: *Block, |
| ... | ... | @@ -27009,19 +26946,21 @@ fn elemPtrArray( |
| 27009 | 26946 | const pt = sema.pt; |
| 27010 | 26947 | const zcu = pt.zcu; |
| 27011 | 26948 | const array_ptr_ty = sema.typeOf(array_ptr); |
| 26949 | assert(array_ptr_ty.ptrSize(zcu) == .one); |
| 27012 | 26950 | const array_ty = array_ptr_ty.childType(zcu); |
| 26951 | assert(array_ty.zigTypeTag(zcu) == .array); |
| 27013 | 26952 | const array_sent = array_ty.sentinel(zcu) != null; |
| 27014 | 26953 | const array_len = array_ty.arrayLen(zcu); |
| 27015 | 26954 | const array_len_s = array_len + @intFromBool(array_sent); |
| 27016 | 26955 | |
| 27017 | 26956 | if (array_len_s == 0) { |
| 27018 | | return sema.fail(block, array_ptr_src, "indexing into empty array is not allowed", .{}); |
| 26957 | return sema.fail(block, array_ptr_src, "cannot index into empty array", .{}); |
| 27019 | 26958 | } |
| 27020 | 26959 | |
| 27021 | 26960 | const maybe_undef_array_ptr_val = sema.resolveValue(array_ptr); |
| 27022 | 26961 | // The index must not be undefined since it can be out of bounds. |
| 27023 | | const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { |
| 27024 | | const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(zcu)); |
| 26962 | const maybe_index: ?u64 = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { |
| 26963 | const index = index_val.toUnsignedInt(zcu); |
| 27025 | 26964 | if (index >= array_len_s) { |
| 27026 | 26965 | const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; |
| 27027 | 26966 | return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); |
| ... | ... | @@ -27029,20 +26968,15 @@ fn elemPtrArray( |
| 27029 | 26968 | break :o index; |
| 27030 | 26969 | } else null; |
| 27031 | 26970 | |
| 27032 | | if (offset == null and array_ty.zigTypeTag(zcu) == .vector) { |
| 27033 | | return sema.fail(block, elem_index_src, "vector index not comptime known", .{}); |
| 27034 | | } |
| 27035 | | |
| 27036 | 26971 | array_ty.assertHasLayout(zcu); |
| 27037 | | const elem_ptr_ty = try array_ptr_ty.elemPtrType(offset, pt); |
| 26972 | const elem_ptr_ty = try array_ptr_ty.elemPtrType(maybe_index, pt); |
| 27038 | 26973 | |
| 27039 | 26974 | if (maybe_undef_array_ptr_val) |array_ptr_val| { |
| 27040 | 26975 | if (array_ptr_val.isUndef(zcu)) { |
| 27041 | 26976 | return pt.undefRef(elem_ptr_ty); |
| 27042 | 26977 | } |
| 27043 | | if (offset) |index| { |
| 27044 | | const elem_ptr = try array_ptr_val.ptrElem(index, pt); |
| 27045 | | return Air.internedToRef(elem_ptr.toIntern()); |
| 26978 | if (maybe_index) |index| { |
| 26979 | return .fromValue(try array_ptr_val.ptrElem(index, pt)); |
| 27046 | 26980 | } |
| 27047 | 26981 | } |
| 27048 | 26982 | |
| ... | ... | @@ -27052,7 +26986,7 @@ fn elemPtrArray( |
| 27052 | 26986 | } |
| 27053 | 26987 | |
| 27054 | 26988 | // Runtime check is only needed if unable to comptime check. |
| 27055 | | if (oob_safety and block.wantSafety() and offset == null) { |
| 26989 | if (oob_safety and block.wantSafety() and maybe_index == null) { |
| 27056 | 26990 | const len_inst = try pt.intRef(.usize, array_len); |
| 27057 | 26991 | const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; |
| 27058 | 26992 | try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op); |
| ... | ... | @@ -27075,9 +27009,9 @@ fn elemValSlice( |
| 27075 | 27009 | const pt = sema.pt; |
| 27076 | 27010 | const zcu = pt.zcu; |
| 27077 | 27011 | const slice_ty = sema.typeOf(slice); |
| 27012 | assert(slice_ty.isSlice(zcu)); |
| 27078 | 27013 | const slice_sent = slice_ty.sentinel(zcu) != null; |
| 27079 | 27014 | const elem_ty = slice_ty.childType(zcu); |
| 27080 | | var runtime_src = slice_src; |
| 27081 | 27015 | |
| 27082 | 27016 | elem_ty.assertHasLayout(zcu); |
| 27083 | 27017 | |
| ... | ... | @@ -27087,7 +27021,6 @@ fn elemValSlice( |
| 27087 | 27021 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 27088 | 27022 | |
| 27089 | 27023 | if (maybe_slice_val) |slice_val| { |
| 27090 | | runtime_src = elem_index_src; |
| 27091 | 27024 | const slice_len = slice_val.sliceLen(zcu); |
| 27092 | 27025 | const slice_len_s = slice_len + @intFromBool(slice_sent); |
| 27093 | 27026 | if (slice_len_s == 0) { |
| ... | ... | @@ -27099,12 +27032,8 @@ fn elemValSlice( |
| 27099 | 27032 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 27100 | 27033 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| 27101 | 27034 | } |
| 27102 | | const elem_ptr_ty = try slice_ty.elemPtrType(index, pt); |
| 27103 | 27035 | const elem_ptr_val = try slice_val.ptrElem(index, pt); |
| 27104 | | if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { |
| 27105 | | return Air.internedToRef(elem_val.toIntern()); |
| 27106 | | } |
| 27107 | | runtime_src = slice_src; |
| 27036 | return sema.analyzeLoad(block, src, .fromValue(elem_ptr_val), slice_src); |
| 27108 | 27037 | } |
| 27109 | 27038 | } |
| 27110 | 27039 | |
| ... | ... | @@ -27138,17 +27067,19 @@ fn elemPtrSlice( |
| 27138 | 27067 | const pt = sema.pt; |
| 27139 | 27068 | const zcu = pt.zcu; |
| 27140 | 27069 | const slice_ty = sema.typeOf(slice); |
| 27070 | assert(slice_ty.isSlice(zcu)); |
| 27141 | 27071 | const slice_sent = slice_ty.sentinel(zcu) != null; |
| 27142 | | |
| 27143 | | slice_ty.childType(zcu).assertHasLayout(zcu); |
| 27072 | const elem_ty = slice_ty.childType(zcu); |
| 27073 | elem_ty.assertHasLayout(zcu); |
| 27144 | 27074 | |
| 27145 | 27075 | const maybe_undef_slice_val = sema.resolveValue(slice); |
| 27146 | 27076 | // The index must not be undefined since it can be out of bounds. |
| 27147 | | const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { |
| 27148 | | break :o try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(zcu)); |
| 27077 | const offset: ?u64 = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { |
| 27078 | break :o index_val.toUnsignedInt(zcu); |
| 27149 | 27079 | } else null; |
| 27150 | 27080 | |
| 27151 | 27081 | const elem_ptr_ty = try slice_ty.elemPtrType(offset, pt); |
| 27082 | assert(elem_ptr_ty.childType(zcu).toIntern() == elem_ty.toIntern()); |
| 27152 | 27083 | |
| 27153 | 27084 | if (maybe_undef_slice_val) |slice_val| { |
| 27154 | 27085 | if (slice_val.isUndef(zcu)) { |
| ... | ... | @@ -27157,15 +27088,14 @@ fn elemPtrSlice( |
| 27157 | 27088 | const slice_len = slice_val.sliceLen(zcu); |
| 27158 | 27089 | const slice_len_s = slice_len + @intFromBool(slice_sent); |
| 27159 | 27090 | if (slice_len_s == 0) { |
| 27160 | | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| 27091 | return sema.fail(block, slice_src, "cannot index into empty slice", .{}); |
| 27161 | 27092 | } |
| 27162 | 27093 | if (offset) |index| { |
| 27163 | 27094 | if (index >= slice_len_s) { |
| 27164 | 27095 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 27165 | 27096 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| 27166 | 27097 | } |
| 27167 | | const elem_ptr_val = try slice_val.ptrElem(index, pt); |
| 27168 | | return Air.internedToRef(elem_ptr_val.toIntern()); |
| 27098 | return .fromValue(try slice_val.ptrElem(index, pt)); |
| 27169 | 27099 | } |
| 27170 | 27100 | } |
| 27171 | 27101 | |
| ... | ... | @@ -27182,7 +27112,7 @@ fn elemPtrSlice( |
| 27182 | 27112 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| 27183 | 27113 | try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op); |
| 27184 | 27114 | } |
| 27185 | | if (slice_ty.childType(zcu).abiSize(zcu) == 0) { |
| 27115 | if (elem_ty.abiSize(zcu) == 0) { |
| 27186 | 27116 | // zero-bit child type; just extract the pointer and bitcast it |
| 27187 | 27117 | const slice_ptr = try block.addTyOp(.slice_ptr, slice_ty.slicePtrFieldType(zcu), slice); |
| 27188 | 27118 | return block.addBitCast(elem_ptr_ty, slice_ptr); |
| ... | ... | @@ -27546,7 +27476,7 @@ fn coerceExtra( |
| 27546 | 27476 | .sentinel = dest_info.sentinel, |
| 27547 | 27477 | }); |
| 27548 | 27478 | const empty_array_val = try pt.aggregateValue(empty_array_ty, &.{}); |
| 27549 | | const empty_array_ptr = try sema.uavRef(empty_array_val.toIntern()); |
| 27479 | const empty_array_ptr = try sema.uavRef(empty_array_val); |
| 27550 | 27480 | return sema.coerceArrayPtrToSlice(block, dest_ty, empty_array_ptr, inst_src); |
| 27551 | 27481 | } |
| 27552 | 27482 | |
| ... | ... | @@ -28499,7 +28429,6 @@ pub fn coerceInMemoryAllowed( |
| 28499 | 28429 | const field_count = dest_ty.structFieldCount(zcu); |
| 28500 | 28430 | for (0..field_count) |field_idx| { |
| 28501 | 28431 | if (dest_ty.structFieldIsComptime(field_idx, zcu) != src_ty.structFieldIsComptime(field_idx, zcu)) break :tuple; |
| 28502 | | if (dest_ty.resolvedFieldAlignment(field_idx, zcu) != src_ty.resolvedFieldAlignment(field_idx, zcu)) break :tuple; |
| 28503 | 28432 | const dest_field_ty = dest_ty.fieldType(field_idx, zcu); |
| 28504 | 28433 | const src_field_ty = src_ty.fieldType(field_idx, zcu); |
| 28505 | 28434 | const field = try sema.coerceInMemoryAllowed(block, dest_field_ty, src_field_ty, dest_is_mut, target, dest_src, src_src, null); |
| ... | ... | @@ -29953,12 +29882,14 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: |
| 29953 | 29882 | fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { |
| 29954 | 29883 | const pt = sema.pt; |
| 29955 | 29884 | const ptr_anyopaque_ty = try pt.singleConstPtrType(.anyopaque); |
| 29956 | | return Value.fromInterned(try pt.intern(.{ .opt = .{ |
| 29957 | | .ty = (try pt.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(), |
| 29958 | | .val = if (opt_val) |val| (try pt.getCoerced( |
| 29959 | | Value.fromInterned(try pt.refValue(val.toIntern())), |
| 29960 | | ptr_anyopaque_ty, |
| 29961 | | )).toIntern() else .none, |
| 29885 | const opt_ptr_anyopaque_ty = try pt.optionalType(ptr_anyopaque_ty.toIntern()); |
| 29886 | return .fromInterned(try pt.intern(.{ .opt = .{ |
| 29887 | .ty = opt_ptr_anyopaque_ty.toIntern(), |
| 29888 | .val = payload: { |
| 29889 | const val = opt_val orelse break :payload .none; |
| 29890 | const ptr_val = try pt.getCoerced(try pt.uavValue(val), ptr_anyopaque_ty); |
| 29891 | break :payload ptr_val.toIntern(); |
| 29892 | }, |
| 29962 | 29893 | } })); |
| 29963 | 29894 | } |
| 29964 | 29895 | |
| ... | ... | @@ -30078,7 +30009,7 @@ fn analyzeRef( |
| 30078 | 30009 | switch (zcu.intern_pool.indexToKey(val.toIntern())) { |
| 30079 | 30010 | .@"extern" => |e| return sema.analyzeNavRef(block, src, e.owner_nav), |
| 30080 | 30011 | .func => |f| return sema.analyzeNavRef(block, src, f.owner_nav), |
| 30081 | | else => return uavRef(sema, val.toIntern()), |
| 30012 | else => return uavRef(sema, val), |
| 30082 | 30013 | } |
| 30083 | 30014 | } |
| 30084 | 30015 | |
| ... | ... | @@ -30528,7 +30459,7 @@ fn analyzeSlice( |
| 30528 | 30459 | } else ptr_or_slice; |
| 30529 | 30460 | |
| 30530 | 30461 | const start = try sema.coerce(block, .usize, uncasted_start, start_src); |
| 30531 | | const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src); |
| 30462 | const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, start_src); |
| 30532 | 30463 | const new_ptr_ty = sema.typeOf(new_ptr); |
| 30533 | 30464 | |
| 30534 | 30465 | // true if and only if the end index of the slice, implicitly or explicitly, equals |
| ... | ... | @@ -30666,7 +30597,7 @@ fn analyzeSlice( |
| 30666 | 30597 | break :msg msg; |
| 30667 | 30598 | }); |
| 30668 | 30599 | } |
| 30669 | | return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src); |
| 30600 | return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, start_src); |
| 30670 | 30601 | }; |
| 30671 | 30602 | |
| 30672 | 30603 | const sentinel = s: { |
| ... | ... | @@ -32118,12 +32049,12 @@ fn resolvePeerTypesInner( |
| 32118 | 32049 | |
| 32119 | 32050 | ptr_info.flags.alignment = a: { |
| 32120 | 32051 | // If both alignments are implicit, the result alignment is implicit. |
| 32121 | | // e.g. '[*c]u32' + '[*c]c_uint' -> '[*c]u32' |
| 32052 | // e.g. '*u32' + '*c_uint' -> '*u32' |
| 32122 | 32053 | if (ptr_info.flags.alignment == .none and peer_info.flags.alignment == .none) { |
| 32123 | 32054 | break :a .none; |
| 32124 | 32055 | } |
| 32125 | 32056 | // Otherwise (if either alignment is explicit), the result alignment is explicit. |
| 32126 | | // e.g. '[*c]u32' + '[*c]align(4) c_uint' -> '[*c]align(4) u32' |
| 32057 | // e.g. '*u32' + '*align(4) c_uint' -> '*align(4) u32' |
| 32127 | 32058 | const cur_align = switch (ptr_info.flags.alignment) { |
| 32128 | 32059 | .none => Type.fromInterned(ptr_info.child).abiAlignment(zcu), |
| 32129 | 32060 | else => ptr_info.flags.alignment, |
| ... | ... | @@ -33583,7 +33514,7 @@ fn notePathToComptimeAllocPtr( |
| 33583 | 33514 | else => {}, // there will be another stage |
| 33584 | 33515 | } |
| 33585 | 33516 | |
| 33586 | | const derivation = try comptime_ptr.pointerDerivationAdvanced(arena, pt, false, sema); |
| 33517 | const derivation = try comptime_ptr.pointerDerivation(arena, pt, sema); |
| 33587 | 33518 | |
| 33588 | 33519 | var second_path_aw: std.Io.Writer.Allocating = .init(arena); |
| 33589 | 33520 | defer second_path_aw.deinit(); |