| ... | @@ -3595,7 +3595,20 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, | ... | @@ -3595,7 +3595,20 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, |
| 3595 | }; | 3595 | }; |
| 3596 | break :ptr (try Value.fromInterned(decl_parent_ptr).ptrField(idx, pt)).toIntern(); | 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 | try ptr_mapping.put(air_ptr, new_ptr); | 3613 | try ptr_mapping.put(air_ptr, new_ptr); |
| 3601 | } | 3614 | } |
| ... | @@ -4540,10 +4553,7 @@ fn validateStructInit( | ... | @@ -4540,10 +4553,7 @@ fn validateStructInit( |
| 4540 | }; | 4553 | }; |
| 4541 | | 4554 | |
| 4542 | const field_src = init_src; // TODO better source location | 4555 | const field_src = init_src; // TODO better source location |
| 4543 | const default_field_ptr = if (struct_ty.isTuple(zcu)) | 4556 | const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty); |
| 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); | | |
| 4547 | try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr); | 4557 | try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr); |
| 4548 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, .fromValue(default_val), field_src, .store); | 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,11 +4969,11 @@ pub fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError! |
| 4959 | .ty = array_ty.toIntern(), | 4969 | .ty = array_ty.toIntern(), |
| 4960 | .storage = .{ .bytes = string }, | 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 { | 4975 | fn uavRef(sema: *Sema, val: Value) CompileError!Air.Inst.Ref { |
| 4966 | return Air.internedToRef(try sema.pt.refValue(val)); | 4976 | return .fromValue(try sema.pt.uavValue(val)); |
| 4967 | } | 4977 | } |
| 4968 | | 4978 | |
| 4969 | fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 4979 | fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -6226,7 +6236,7 @@ fn popErrorReturnTrace( | ... | @@ -6226,7 +6236,7 @@ fn popErrorReturnTrace( |
| 6226 | const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); | 6236 | const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); |
| 6227 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); | 6237 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 6228 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); | 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 | try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); | 6240 | try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); |
| 6231 | } else if (is_non_error == null) { | 6241 | } else if (is_non_error == null) { |
| 6232 | // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need | 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,7 +6261,7 @@ fn popErrorReturnTrace( |
| 6251 | const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); | 6261 | const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); |
| 6252 | const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); | 6262 | const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 6253 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); | 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 | try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); | 6265 | try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); |
| 6256 | _ = try then_block.addBr(cond_block_inst, .void_value); | 6266 | _ = try then_block.addBr(cond_block_inst, .void_value); |
| 6257 | | 6267 | |
| ... | @@ -8196,23 +8206,10 @@ fn zirOptionalPayload( | ... | @@ -8196,23 +8206,10 @@ fn zirOptionalPayload( |
| 8196 | const operand_ty = sema.typeOf(operand); | 8206 | const operand_ty = sema.typeOf(operand); |
| 8197 | const result_ty = switch (operand_ty.zigTypeTag(zcu)) { | 8207 | const result_ty = switch (operand_ty.zigTypeTag(zcu)) { |
| 8198 | .optional => operand_ty.optionalChild(zcu), | 8208 | .optional => operand_ty.optionalChild(zcu), |
| 8199 | .pointer => t: { | 8209 | // TODO: https://github.com/ziglang/zig/issues/6597 will eliminate this branch so that we only need to handle optionals. |
| 8200 | if (operand_ty.ptrSize(zcu) != .c) { | 8210 | .pointer => switch (operand_ty.ptrSize(zcu)) { |
| 8201 | return sema.failWithExpectedOptionalType(block, src, operand_ty); | 8211 | .c => operand_ty, // if `ptr` is a `[*c]T`, then `ptr.?` is also a `[*c]T` |
| 8202 | } | 8212 | .one, .many, .slice => return sema.failWithExpectedOptionalType(block, src, operand_ty), |
| 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 | }); | | |
| 8216 | }, | 8213 | }, |
| 8217 | else => return sema.failWithExpectedOptionalType(block, src, operand_ty), | 8214 | else => return sema.failWithExpectedOptionalType(block, src, operand_ty), |
| 8218 | }; | 8215 | }; |
| ... | @@ -10322,10 +10319,10 @@ fn analyzeSwitchBlock( | ... | @@ -10322,10 +10319,10 @@ fn analyzeSwitchBlock( |
| 10322 | const payload_inst: Zir.Inst.Index = if (capture != .none) inst: { | 10319 | const payload_inst: Zir.Inst.Index = if (capture != .none) inst: { |
| 10323 | const payload_inst = zir_switch.payload_capture_placeholder.unwrap() orelse switch_inst; | 10320 | const payload_inst = zir_switch.payload_capture_placeholder.unwrap() orelse switch_inst; |
| 10324 | const payload_ref: Air.Inst.Ref = payload_ref: { | 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 | .@"union" => item_val: { | 10323 | .@"union" => item_val: { |
| 10327 | if (maybe_operand_opv) |operand_opv| { | 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 | assert(union_originally); // operand type must be union, otherwise it would be an OPV type here | 10327 | assert(union_originally); // operand type must be union, otherwise it would be an OPV type here |
| 10331 | assert(zir_switch.any_maybe_runtime_capture); // there's a payload capture | 10328 | assert(zir_switch.any_maybe_runtime_capture); // there's a payload capture |
| ... | @@ -10362,10 +10359,10 @@ fn analyzeSwitchBlock( | ... | @@ -10362,10 +10359,10 @@ fn analyzeSwitchBlock( |
| 10362 | validated_switch.else_err_ty, | 10359 | validated_switch.else_err_ty, |
| 10363 | ); | 10360 | ); |
| 10364 | }, | 10361 | }, |
| 10365 | else => item_opv.toIntern(), | 10362 | else => item_opv, |
| 10366 | }; | 10363 | }; |
| 10367 | break :payload_ref switch (capture) { | 10364 | break :payload_ref switch (capture) { |
| 10368 | .by_val => .fromIntern(item_val), | 10365 | .by_val => .fromValue(item_val), |
| 10369 | .by_ref => try sema.uavRef(item_val), | 10366 | .by_ref => try sema.uavRef(item_val), |
| 10370 | .none => unreachable, | 10367 | .none => unreachable, |
| 10371 | }; | 10368 | }; |
| ... | @@ -12198,7 +12195,7 @@ fn analyzeSwitchPayloadCapture( | ... | @@ -12198,7 +12195,7 @@ fn analyzeSwitchPayloadCapture( |
| 12198 | return case_block.addStructFieldVal(operand_val, field_index, field_ty); | 12195 | return case_block.addStructFieldVal(operand_val, field_index, field_ty); |
| 12199 | } | 12196 | } |
| 12200 | } else if (capture_by_ref) { | 12197 | } else if (capture_by_ref) { |
| 12201 | return sema.uavRef(item_val.toIntern()); | 12198 | return sema.uavRef(item_val); |
| 12202 | } else { | 12199 | } else { |
| 12203 | return kind.inline_ref; | 12200 | return kind.inline_ref; |
| 12204 | } | 12201 | } |
| ... | @@ -12280,37 +12277,14 @@ fn analyzeSwitchPayloadCapture( | ... | @@ -12280,37 +12277,14 @@ fn analyzeSwitchPayloadCapture( |
| 12280 | | 12277 | |
| 12281 | // By-reference captures have some further restrictions which make them easier to emit | 12278 | // By-reference captures have some further restrictions which make them easier to emit |
| 12282 | if (capture_by_ref) { | 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 | const capture_ptr_ty = resolve: { | 12281 | const capture_ptr_ty = resolve: { |
| 12285 | // By-ref captures of hetereogeneous types are only allowed if all field | 12282 | // By-ref captures of hetereogeneous types are only allowed if all field |
| 12286 | // pointer types are peer resolvable to each other. | 12283 | // pointer types are peer resolvable to each other. |
| 12287 | // We need values to run PTR on, so make a bunch of undef constants. | 12284 | // We need values to run PTR on, so make a bunch of undef constants. |
| 12288 | const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len); | 12285 | const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len); |
| 12289 | for (field_indices, dummy_captures) |field_idx, *dummy| { | 12286 | for (field_indices, dummy_captures) |field_index, *dummy| { |
| 12290 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); | 12287 | const field_ptr_ty = try operand_ptr_ty.fieldPtrType(field_index, pt); |
| 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 | }); | | |
| 12314 | dummy.* = try pt.undefRef(field_ptr_ty); | 12288 | dummy.* = try pt.undefRef(field_ptr_ty); |
| 12315 | } | 12289 | } |
| 12316 | const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len); | 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,7 +13670,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13696 | element_vals[elem_i] = coerced_elem_val.toIntern(); | 13670 | element_vals[elem_i] = coerced_elem_val.toIntern(); |
| 13697 | } | 13671 | } |
| 13698 | return sema.addConstantMaybeRef( | 13672 | return sema.addConstantMaybeRef( |
| 13699 | (try pt.aggregateValue(result_ty, element_vals)).toIntern(), | 13673 | try pt.aggregateValue(result_ty, element_vals), |
| 13700 | ptr_addrspace != null, | 13674 | ptr_addrspace != null, |
| 13701 | ); | 13675 | ); |
| 13702 | } else break :rs rhs_src; | 13676 | } else break :rs rhs_src; |
| ... | @@ -14094,7 +14068,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -14094,7 +14068,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14094 | } | 14068 | } |
| 14095 | break :v try pt.aggregateValue(result_ty, element_vals); | 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 | try sema.requireRuntimeBlock(block, src, lhs_src); | 14074 | try sema.requireRuntimeBlock(block, src, lhs_src); |
| ... | @@ -15270,7 +15244,7 @@ fn analyzeArithmetic( | ... | @@ -15270,7 +15244,7 @@ fn analyzeArithmetic( |
| 15270 | }; | 15244 | }; |
| 15271 | | 15245 | |
| 15272 | try sema.ensureLayoutResolved(lhs_ty.childType(zcu), src); | 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,7 +15344,6 @@ fn analyzePtrArithmetic( |
| 15370 | ptr: Air.Inst.Ref, | 15344 | ptr: Air.Inst.Ref, |
| 15371 | uncasted_offset: Air.Inst.Ref, | 15345 | uncasted_offset: Air.Inst.Ref, |
| 15372 | air_tag: Air.Inst.Tag, | 15346 | air_tag: Air.Inst.Tag, |
| 15373 | ptr_src: LazySrcLoc, | | |
| 15374 | offset_src: LazySrcLoc, | 15347 | offset_src: LazySrcLoc, |
| 15375 | ) CompileError!Air.Inst.Ref { | 15348 | ) CompileError!Air.Inst.Ref { |
| 15376 | // TODO if the operand is comptime-known to be negative, or is a negative int, | 15349 | // TODO if the operand is comptime-known to be negative, or is a negative int, |
| ... | @@ -15378,12 +15351,14 @@ fn analyzePtrArithmetic( | ... | @@ -15378,12 +15351,14 @@ fn analyzePtrArithmetic( |
| 15378 | const offset = try sema.coerce(block, .usize, uncasted_offset, offset_src); | 15351 | const offset = try sema.coerce(block, .usize, uncasted_offset, offset_src); |
| 15379 | const pt = sema.pt; | 15352 | const pt = sema.pt; |
| 15380 | const zcu = pt.zcu; | 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 | const ptr_ty = sema.typeOf(ptr); | 15354 | const ptr_ty = sema.typeOf(ptr); |
| 15384 | const ptr_info = ptr_ty.ptrInfo(zcu); | 15355 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 15385 | assert(ptr_info.flags.size == .many or ptr_info.flags.size == .c); | 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 | const elem_ty: Type = .fromInterned(ptr_info.child); | 15362 | const elem_ty: Type = .fromInterned(ptr_info.child); |
| 15388 | elem_ty.assertHasLayout(zcu); | 15363 | elem_ty.assertHasLayout(zcu); |
| 15389 | | 15364 | |
| ... | @@ -15395,70 +15370,36 @@ fn analyzePtrArithmetic( | ... | @@ -15395,70 +15370,36 @@ fn analyzePtrArithmetic( |
| 15395 | else => {}, | 15370 | else => {}, |
| 15396 | } | 15371 | } |
| 15397 | | 15372 | |
| 15398 | const new_ptr_ty = t: { | 15373 | const elem_ptr_ty = try ptr_ty.elemPtrType(maybe_index, pt); |
| 15399 | // Calculate the new pointer alignment. | 15374 | // `elem_ptr_ty` is a single-item pointer, but we want a many-item or C pointer, and to preserve |
| 15400 | // This code is duplicated in `Type.elemPtrType`. | 15375 | // any input sentinel. |
| 15401 | if (ptr_info.flags.alignment == .none) { | 15376 | const new_ptr_ty = try pt.ptrType(info: { |
| 15402 | // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. | 15377 | var info = elem_ptr_ty.ptrInfo(zcu); |
| 15403 | break :t ptr_ty; | 15378 | info.flags.size = ptr_info.flags.size; |
| 15404 | } | 15379 | info.sentinel = ptr_info.sentinel; |
| 15405 | // If the addend is not a comptime-known value we can still count on | 15380 | break :info info; |
| 15406 | // it being a multiple of the type size. | 15381 | }); |
| 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 | }; | | |
| 15435 | | 15382 | |
| 15436 | const runtime_src = rs: { | 15383 | ct: { |
| 15437 | if (opt_ptr_val) |ptr_val| { | 15384 | const ptr_val = sema.resolveValue(ptr) orelse break :ct; |
| 15438 | if (opt_off_val) |offset_val| { | 15385 | if (ptr_val.isUndef(zcu)) return pt.undefRef(new_ptr_ty); |
| 15439 | if (ptr_val.isUndef(zcu)) return pt.undefRef(new_ptr_ty); | 15386 | const index = maybe_index orelse break :ct; |
| 15440 | | 15387 | |
| 15441 | const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(zcu)); | 15388 | if (index == 0) return ptr; |
| 15442 | if (offset_int == 0) return ptr; | 15389 | if (air_tag == .ptr_sub) { |
| 15443 | if (air_tag == .ptr_sub) { | 15390 | const elem_size = elem_ty.abiSize(zcu); |
| 15444 | const elem_size = elem_ty.abiSize(zcu); | 15391 | return .fromValue(try sema.ptrSubtract(block, op_src, ptr_val, index * elem_size, new_ptr_ty)); |
| 15445 | const new_ptr_val = try sema.ptrSubtract(block, op_src, ptr_val, offset_int * elem_size, new_ptr_ty); | 15392 | } else { |
| 15446 | return Air.internedToRef(new_ptr_val.toIntern()); | 15393 | return .fromValue(try pt.getCoerced(try ptr_val.ptrElem(index, pt), new_ptr_ty)); |
| 15447 | } else { | 15394 | } |
| 15448 | const new_ptr_val = try pt.getCoerced(try ptr_val.ptrElem(offset_int, pt), new_ptr_ty); | 15395 | } |
| 15449 | return Air.internedToRef(new_ptr_val.toIntern()); | | |
| 15450 | } | | |
| 15451 | } else break :rs offset_src; | | |
| 15452 | } else break :rs ptr_src; | | |
| 15453 | }; | | |
| 15454 | | 15396 | |
| 15455 | try sema.requireRuntimeBlock(block, op_src, runtime_src); | | |
| 15456 | try sema.checkLogicalPtrOperation(block, op_src, ptr_ty); | 15397 | try sema.checkLogicalPtrOperation(block, op_src, ptr_ty); |
| 15457 | | 15398 | |
| 15458 | return block.addInst(.{ | 15399 | return block.addInst(.{ |
| 15459 | .tag = air_tag, | 15400 | .tag = air_tag, |
| 15460 | .data = .{ .ty_pl = .{ | 15401 | .data = .{ .ty_pl = .{ |
| 15461 | .ty = Air.internedToRef(new_ptr_ty.toIntern()), | 15402 | .ty = .fromType(new_ptr_ty), |
| 15462 | .payload = try sema.addExtra(Air.Bin{ | 15403 | .payload = try sema.addExtra(Air.Bin{ |
| 15463 | .lhs = ptr, | 15404 | .lhs = ptr, |
| 15464 | .rhs = offset, | 15405 | .rhs = offset, |
| ... | @@ -16222,6 +16163,11 @@ fn zirBuiltinSrc( | ... | @@ -16222,6 +16163,11 @@ fn zirBuiltinSrc( |
| 16222 | return Air.internedToRef((try pt.aggregateValue(src_loc_ty, &fields)).toIntern()); | 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 | fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 16171 | fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 16226 | const pt = sema.pt; | 16172 | const pt = sema.pt; |
| 16227 | const zcu = pt.zcu; | 16173 | const zcu = pt.zcu; |
| ... | @@ -16726,17 +16672,21 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -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 | const alignment = switch (layout) { | 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 | .@"packed" => .none, | 16682 | .@"packed" => .none, |
| 16732 | }; | 16683 | }; |
| 16733 | | 16684 | |
| 16734 | const field_ty = union_obj.field_types.get(ip)[field_index]; | | |
| 16735 | const union_field_fields = .{ | 16685 | const union_field_fields = .{ |
| 16736 | // name: [:0]const u8, | 16686 | // name: [:0]const u8, |
| 16737 | name_val, | 16687 | name_val, |
| 16738 | // type: type, | 16688 | // type: type, |
| 16739 | field_ty, | 16689 | field_ty.toIntern(), |
| 16740 | // alignment: comptime_int, | 16690 | // alignment: comptime_int, |
| 16741 | (try pt.intValue(.comptime_int, alignment.toByteUnits() orelse 0)).toIntern(), | 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,7 +16845,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16895 | const opt_default_val: ?Value = if (field_default == .none) null else .fromInterned(field_default); | 16845 | const opt_default_val: ?Value = if (field_default == .none) null else .fromInterned(field_default); |
| 16896 | const default_val_ptr = try sema.optRefValue(opt_default_val); | 16846 | const default_val_ptr = try sema.optRefValue(opt_default_val); |
| 16897 | const alignment = switch (struct_type.layout) { | 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 | .@"packed" => .none, | 16852 | .@"packed" => .none, |
| 16900 | }; | 16853 | }; |
| 16901 | | 16854 | |
| ... | @@ -18425,8 +18378,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is | ... | @@ -18425,8 +18378,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is |
| 18425 | const init_ref = try sema.coerce(block, init_ty, empty_ref, src); | 18378 | const init_ref = try sema.coerce(block, init_ty, empty_ref, src); |
| 18426 | | 18379 | |
| 18427 | if (is_byref) { | 18380 | if (is_byref) { |
| 18428 | const init_val = sema.resolveValue(init_ref).?; | 18381 | return sema.uavRef(sema.resolveValue(init_ref).?); |
| 18429 | return sema.uavRef(init_val.toIntern()); | | |
| 18430 | } else { | 18382 | } else { |
| 18431 | return init_ref; | 18383 | return init_ref; |
| 18432 | } | 18384 | } |
| ... | @@ -18648,7 +18600,7 @@ fn zirStructInit( | ... | @@ -18648,7 +18600,7 @@ fn zirStructInit( |
| 18648 | })); | 18600 | })); |
| 18649 | const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src); | 18601 | const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src); |
| 18650 | const final_val = sema.resolveValue(final_val_inst).?; | 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 | if (resolved_ty.comptimeOnly(zcu)) { | 18606 | if (resolved_ty.comptimeOnly(zcu)) { |
| ... | @@ -18789,7 +18741,7 @@ fn finishStructInit( | ... | @@ -18789,7 +18741,7 @@ fn finishStructInit( |
| 18789 | } | 18741 | } |
| 18790 | const struct_val = try pt.aggregateValue(struct_ty, elems); | 18742 | const struct_val = try pt.aggregateValue(struct_ty, elems); |
| 18791 | const final_val_ref = try sema.coerce(block, result_ty, .fromValue(struct_val), init_src); | 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 | .@"packed" => { | 18746 | .@"packed" => { |
| 18795 | const buf = try sema.arena.alloc(u8, (struct_ty.bitSize(zcu) + 7) / 8); | 18747 | const buf = try sema.arena.alloc(u8, (struct_ty.bitSize(zcu) + 7) / 8); |
| ... | @@ -18808,7 +18760,7 @@ fn finishStructInit( | ... | @@ -18808,7 +18760,7 @@ fn finishStructInit( |
| 18808 | error.OutOfMemory => |e| return e, | 18760 | error.OutOfMemory => |e| return e, |
| 18809 | }; | 18761 | }; |
| 18810 | const final_val_ref = try sema.coerce(block, result_ty, .fromValue(struct_val), init_src); | 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,7 +18952,7 @@ fn structInitAnon( |
| 19000 | | 18952 | |
| 19001 | _ = opt_runtime_index orelse { | 18953 | _ = opt_runtime_index orelse { |
| 19002 | const struct_val = try pt.aggregateValue(struct_ty, values); | 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 | if (is_ref) { | 18958 | if (is_ref) { |
| ... | @@ -19137,7 +19089,7 @@ fn zirArrayInit( | ... | @@ -19137,7 +19089,7 @@ fn zirArrayInit( |
| 19137 | const arr_val = try pt.aggregateValue(array_ty, elem_vals); | 19089 | const arr_val = try pt.aggregateValue(array_ty, elem_vals); |
| 19138 | const result_ref = try sema.coerce(block, result_ty, Air.internedToRef(arr_val.toIntern()), src); | 19090 | const result_ref = try sema.coerce(block, result_ty, Air.internedToRef(arr_val.toIntern()), src); |
| 19139 | const result_val = (sema.resolveValue(result_ref)).?; | 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 | if (is_ref) { | 19095 | if (is_ref) { |
| ... | @@ -19261,7 +19213,7 @@ fn arrayInitAnon( | ... | @@ -19261,7 +19213,7 @@ fn arrayInitAnon( |
| 19261 | | 19213 | |
| 19262 | const runtime_src = opt_runtime_src orelse { | 19214 | const runtime_src = opt_runtime_src orelse { |
| 19263 | const tuple_val = try pt.aggregateValue(tuple_ty, values); | 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 | try sema.requireRuntimeBlock(block, src, runtime_src); | 19219 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | @@ -19304,8 +19256,8 @@ fn arrayInitAnon( | ... | @@ -19304,8 +19256,8 @@ fn arrayInitAnon( |
| 19304 | return block.addAggregateInit(tuple_ty, element_refs); | 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 { | 19259 | fn addConstantMaybeRef(sema: *Sema, val: Value, is_ref: bool) !Air.Inst.Ref { |
| 19308 | return if (is_ref) sema.uavRef(val) else Air.internedToRef(val); | 19260 | return if (is_ref) sema.uavRef(val) else .fromValue(val); |
| 19309 | } | 19261 | } |
| 19310 | | 19262 | |
| 19311 | fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 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,125 +23353,74 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 23401 | const field_ptr = sema.resolveInst(extra.field_ptr); | 23353 | const field_ptr = sema.resolveInst(extra.field_ptr); |
| 23402 | const field_ptr_ty = sema.typeOf(field_ptr); | 23354 | const field_ptr_ty = sema.typeOf(field_ptr); |
| 23403 | try sema.checkPtrOperand(block, field_ptr_src, field_ptr_ty); | 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 = .{ | 23357 | const hypothetical_field_ptr_ty = try parent_ptr_ty.fieldPtrType(field_index, pt); |
| 23407 | .child = parent_ty.toIntern(), | 23358 | const casted_field_ptr = try sema.ptrCastFull( |
| 23408 | .flags = .{ | 23359 | block, |
| 23409 | .alignment = parent_ptr_ty.ptrAlignment(zcu), | 23360 | flags, |
| 23410 | .is_const = field_ptr_info.flags.is_const, | 23361 | inst_src, |
| 23411 | .is_volatile = field_ptr_info.flags.is_volatile, | 23362 | field_ptr, |
| 23412 | .is_allowzero = field_ptr_info.flags.is_allowzero, | 23363 | field_ptr_src, |
| 23413 | .address_space = field_ptr_info.flags.address_space, | 23364 | hypothetical_field_ptr_ty, |
| 23414 | }, | 23365 | "@fieldParentPtr", |
| 23415 | .packed_offset = parent_ptr_info.packed_offset, | 23366 | ); |
| 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 | } | | |
| 23456 | | 23367 | |
| 23457 | const actual_field_ptr_ty = try pt.ptrType(actual_field_ptr_info); | 23368 | const unaligned_parent_ptr_ty = try pt.ptrType(info: { |
| 23458 | const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src); | 23369 | var info = parent_ptr_ty.ptrInfo(zcu); |
| 23459 | const actual_parent_ptr_ty = try pt.ptrType(actual_parent_ptr_info); | 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: { | 23374 | const unaligned_parent_ptr: Air.Inst.Ref = if (try sema.resolveDefinedValue( |
| 23462 | switch (parent_ty.zigTypeTag(zcu)) { | 23375 | block, |
| 23463 | .@"struct" => switch (parent_ty.containerLayout(zcu)) { | 23376 | field_ptr_src, |
| 23464 | .auto => {}, | 23377 | casted_field_ptr, |
| 23465 | .@"extern" => { | 23378 | )) |field_ptr_val| switch (parent_ty.containerLayout(zcu)) { |
| 23466 | const byte_offset = parent_ty.structFieldOffset(field_index, zcu); | 23379 | .@"packed" => .fromValue(try pt.getCoerced(field_ptr_val, unaligned_parent_ptr_ty)), |
| 23467 | const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty); | 23380 | .@"extern" => switch (parent_ty.zigTypeTag(zcu)) { |
| 23468 | break :result Air.internedToRef(parent_ptr_val.toIntern()); | 23381 | .@"struct" => .fromValue(try sema.ptrSubtract( |
| 23469 | }, | 23382 | block, |
| 23470 | .@"packed" => { | 23383 | field_ptr_src, |
| 23471 | // Logic lifted from type computation above - I'm just assuming it's correct. | 23384 | field_ptr_val, |
| 23472 | // `catch unreachable` since error case handled above. | 23385 | parent_ty.structFieldOffset(field_index, zcu), |
| 23473 | const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) + | 23386 | unaligned_parent_ptr_ty, |
| 23474 | zcu.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) - | 23387 | )), |
| 23475 | actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable; | 23388 | .@"union" => .fromValue(try pt.getCoerced(field_ptr_val, unaligned_parent_ptr_ty)), |
| 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 | }, | | |
| 23488 | else => unreachable, | 23389 | else => unreachable, |
| 23489 | } | 23390 | }, |
| 23490 | | 23391 | .auto => result: { |
| 23491 | const opt_field: ?InternPool.Key.Ptr.BaseAddr.BaseIndex = opt_field: { | 23392 | const opt_field: ?InternPool.Key.Ptr.BaseAddr.BaseIndex = opt_field: { |
| 23492 | const ptr = switch (ip.indexToKey(field_ptr_val.toIntern())) { | 23393 | const ptr = switch (ip.indexToKey(field_ptr_val.toIntern())) { |
| 23493 | .ptr => |ptr| ptr, | 23394 | .ptr => |ptr| ptr, |
| 23494 | else => break :opt_field null, | 23395 | else => break :opt_field null, |
| 23495 | }; | 23396 | }; |
| 23496 | if (ptr.byte_offset != 0) break :opt_field null; | 23397 | if (ptr.byte_offset != 0) break :opt_field null; |
| 23497 | break :opt_field switch (ptr.base_addr) { | 23398 | break :opt_field switch (ptr.base_addr) { |
| 23498 | .field => |field| field, | 23399 | .field => |field| field, |
| 23499 | else => null, | 23400 | else => null, |
| | 23401 | }; |
| 23500 | }; | 23402 | }; |
| 23501 | }; | | |
| 23502 | | 23403 | |
| 23503 | const field = opt_field orelse { | 23404 | const field = opt_field orelse { |
| 23504 | return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{}); | 23405 | return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{}); |
| 23505 | }; | 23406 | }; |
| 23506 | | 23407 | |
| 23507 | if (Value.fromInterned(field.base).typeOf(zcu).childType(zcu).toIntern() != parent_ty.toIntern()) { | 23408 | 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", .{}); | 23409 | return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{}); |
| 23509 | } | 23410 | } |
| 23510 | | 23411 | |
| 23511 | if (field.index != field_index) { | 23412 | 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}'", .{ | 23413 | 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), | 23414 | field_name.fmt(ip), field_index, field.index, parent_ty.fmt(pt), |
| 23514 | }); | 23415 | }); |
| 23515 | } | 23416 | } |
| 23516 | break :result try sema.coerce(block, actual_parent_ptr_ty, Air.internedToRef(field.base), inst_src); | 23417 | break :result .fromValue(try pt.getCoerced(.fromInterned(field.base), unaligned_parent_ptr_ty)); |
| | 23418 | }, |
| 23517 | } else result: { | 23419 | } else result: { |
| 23518 | try sema.requireRuntimeBlock(block, inst_src, field_ptr_src); | | |
| 23519 | break :result try block.addInst(.{ | 23420 | break :result try block.addInst(.{ |
| 23520 | .tag = .field_parent_ptr, | 23421 | .tag = .field_parent_ptr, |
| 23521 | .data = .{ .ty_pl = .{ | 23422 | .data = .{ .ty_pl = .{ |
| 23522 | .ty = Air.internedToRef(actual_parent_ptr_ty.toIntern()), | 23423 | .ty = .fromType(unaligned_parent_ptr_ty), |
| 23523 | .payload = try block.sema.addExtra(Air.FieldParentPtr{ | 23424 | .payload = try block.sema.addExtra(Air.FieldParentPtr{ |
| 23524 | .field_ptr = casted_field_ptr, | 23425 | .field_ptr = casted_field_ptr, |
| 23525 | .field_index = @intCast(field_index), | 23426 | .field_index = @intCast(field_index), |
| ... | @@ -23527,14 +23428,61 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins | ... | @@ -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 | fn ptrSubtract(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, byte_subtract: u64, new_ty: Type) !Value { | 23481 | fn ptrSubtract(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, byte_subtract: u64, new_ty: Type) !Value { |
| 23534 | const pt = sema.pt; | 23482 | const pt = sema.pt; |
| 23535 | const zcu = pt.zcu; | 23483 | const zcu = pt.zcu; |
| 23536 | if (byte_subtract == 0) return pt.getCoerced(ptr_val, new_ty); | 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 | .undef => return sema.failWithUseOfUndef(block, src, null), | 23486 | .undef => return sema.failWithUseOfUndef(block, src, null), |
| 23539 | .ptr => |ptr| ptr, | 23487 | .ptr => |ptr| ptr, |
| 23540 | else => unreachable, | 23488 | else => unreachable, |
| ... | @@ -23547,9 +23495,11 @@ fn ptrSubtract(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, byte | ... | @@ -23547,9 +23495,11 @@ fn ptrSubtract(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, byte |
| 23547 | break :msg msg; | 23495 | break :msg msg; |
| 23548 | }); | 23496 | }); |
| 23549 | } | 23497 | } |
| 23550 | ptr.byte_offset -= byte_subtract; | 23498 | return Value.fromInterned(try pt.intern(.{ .ptr = .{ |
| 23551 | ptr.ty = new_ty.toIntern(); | 23499 | .ty = new_ty.toIntern(), |
| 23552 | return Value.fromInterned(try pt.intern(.{ .ptr = ptr })); | 23500 | .base_addr = ptr.base_addr, |
| | 23501 | .byte_offset = ptr.byte_offset - byte_subtract, |
| | 23502 | } })); |
| 23553 | } | 23503 | } |
| 23554 | | 23504 | |
| 23555 | fn zirMinMax( | 23505 | fn zirMinMax( |
| ... | @@ -24186,8 +24136,8 @@ fn zirMemcpy( | ... | @@ -24186,8 +24136,8 @@ fn zirMemcpy( |
| 24186 | | 24136 | |
| 24187 | // ok1: dest >= src + len | 24137 | // ok1: dest >= src + len |
| 24188 | // ok2: src >= dest + len | 24138 | // ok2: src >= dest + len |
| 24189 | const src_plus_len = try sema.analyzePtrArithmetic(block, src, raw_src_ptr, len, .ptr_add, src_src, src); | 24139 | const src_plus_len = try sema.analyzePtrArithmetic(block, src, raw_src_ptr, len, .ptr_add, src); |
| 24190 | const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src); | 24140 | const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, src); |
| 24191 | const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len); | 24141 | const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len); |
| 24192 | const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len); | 24142 | const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len); |
| 24193 | const ok = try block.addBinOp(.bool_or, ok1, ok2); | 24143 | const ok = try block.addBinOp(.bool_or, ok1, ok2); |
| ... | @@ -25402,21 +25352,36 @@ fn addSafetyCheckSentinelMismatch( | ... | @@ -25402,21 +25352,36 @@ fn addSafetyCheckSentinelMismatch( |
| 25402 | const expected_sentinel = Air.internedToRef(expected_sentinel_val.toIntern()); | 25352 | const expected_sentinel = Air.internedToRef(expected_sentinel_val.toIntern()); |
| 25403 | | 25353 | |
| 25404 | const ptr_ty = sema.typeOf(ptr); | 25354 | const ptr_ty = sema.typeOf(ptr); |
| 25405 | const actual_sentinel = if (ptr_ty.isSlice(zcu)) | 25355 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 25406 | try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index) | 25356 | const actual_sentinel: Air.Inst.Ref = switch (ptr_ty.ptrSize(zcu)) { |
| 25407 | else blk: { | 25357 | .slice => try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index), |
| 25408 | const elem_ptr_ty = try ptr_ty.elemPtrType(null, pt); | 25358 | .one => s: { |
| 25409 | const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty); | 25359 | const array_ty: Type = .fromInterned(ptr_info.child); |
| 25410 | break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr); | 25360 | assert(array_ty.zigTypeTag(zcu) == .array); |
| 25411 | }; | 25361 | assert(array_ty.childType(zcu).toIntern() == sentinel_ty.toIntern()); |
| 25412 | | 25362 | const many_ptr_ty = try pt.ptrType(.{ |
| 25413 | const ok = if (sentinel_ty.zigTypeTag(zcu) == .vector) ok: { | 25363 | .child = sentinel_ty.toIntern(), |
| 25414 | const eql = try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq); | 25364 | .flags = .{ |
| 25415 | break :ok try parent_block.addReduce(eql, .And); | 25365 | .size = .many, |
| 25416 | } else ok: { | 25366 | .is_const = ptr_info.flags.is_const, |
| 25417 | assert(sentinel_ty.isSelfComparable(zcu, true)); | 25367 | .is_volatile = ptr_info.flags.is_volatile, |
| 25418 | break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel); | 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 | return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.sentinelMismatch", &.{ | 25386 | return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.sentinelMismatch", &.{ |
| 25422 | expected_sentinel, actual_sentinel, | 25387 | expected_sentinel, actual_sentinel, |
| ... | @@ -25676,7 +25641,7 @@ fn fieldVal( | ... | @@ -25676,7 +25641,7 @@ fn fieldVal( |
| 25676 | .@"struct" => if (is_pointer_to) { | 25641 | .@"struct" => if (is_pointer_to) { |
| 25677 | // Avoid loading the entire struct by fetching a pointer and loading that | 25642 | // Avoid loading the entire struct by fetching a pointer and loading that |
| 25678 | try sema.ensureLayoutResolved(inner_ty, src); | 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 | return sema.analyzeLoad(block, src, field_ptr, object_src); | 25645 | return sema.analyzeLoad(block, src, field_ptr, object_src); |
| 25681 | } else { | 25646 | } else { |
| 25682 | return sema.structFieldVal(block, object, field_name, field_name_src, inner_ty); | 25647 | return sema.structFieldVal(block, object, field_name, field_name_src, inner_ty); |
| ... | @@ -25730,7 +25695,7 @@ fn fieldPtr( | ... | @@ -25730,7 +25695,7 @@ fn fieldPtr( |
| 25730 | .array => { | 25695 | .array => { |
| 25731 | if (field_name.eqlSlice("len", ip)) { | 25696 | if (field_name.eqlSlice("len", ip)) { |
| 25732 | const int_val = try pt.intValue(.usize, inner_ty.arrayLen(zcu)); | 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 | } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) { | 25699 | } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) { |
| 25735 | const ptr_info = object_ty.ptrInfo(zcu); | 25700 | const ptr_info = object_ty.ptrInfo(zcu); |
| 25736 | const new_ptr_ty = try pt.ptrType(.{ | 25701 | const new_ptr_ty = try pt.ptrType(.{ |
| ... | @@ -25752,6 +25717,7 @@ fn fieldPtr( | ... | @@ -25752,6 +25717,7 @@ fn fieldPtr( |
| 25752 | .child = new_ptr_ty.toIntern(), | 25717 | .child = new_ptr_ty.toIntern(), |
| 25753 | .sentinel = if (object_ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none, | 25718 | .sentinel = if (object_ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none, |
| 25754 | .flags = .{ | 25719 | .flags = .{ |
| | 25720 | .size = .one, |
| 25755 | .alignment = ptr_ptr_info.flags.alignment, | 25721 | .alignment = ptr_ptr_info.flags.alignment, |
| 25756 | .is_const = ptr_ptr_info.flags.is_const, | 25722 | .is_const = ptr_ptr_info.flags.is_const, |
| 25757 | .is_volatile = ptr_ptr_info.flags.is_volatile, | 25723 | .is_volatile = ptr_ptr_info.flags.is_volatile, |
| ... | @@ -25857,10 +25823,10 @@ fn fieldPtr( | ... | @@ -25857,10 +25823,10 @@ fn fieldPtr( |
| 25857 | }, | 25823 | }, |
| 25858 | else => unreachable, | 25824 | else => unreachable, |
| 25859 | }; | 25825 | }; |
| 25860 | return uavRef(sema, try pt.intern(.{ .err = .{ | 25826 | return uavRef(sema, .fromInterned(try pt.intern(.{ .err = .{ |
| 25861 | .ty = err_set_ty.toIntern(), | 25827 | .ty = err_set_ty.toIntern(), |
| 25862 | .name = field_name, | 25828 | .name = field_name, |
| 25863 | } })); | 25829 | } }))); |
| 25864 | }, | 25830 | }, |
| 25865 | .@"union" => { | 25831 | .@"union" => { |
| 25866 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { | 25832 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| ... | @@ -25871,7 +25837,7 @@ fn fieldPtr( | ... | @@ -25871,7 +25837,7 @@ fn fieldPtr( |
| 25871 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| { | 25837 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| { |
| 25872 | const field_index_u32: u32 = @intCast(field_index); | 25838 | const field_index_u32: u32 = @intCast(field_index); |
| 25873 | const idx_val = try pt.enumValueFieldIndex(enum_ty, field_index_u32); | 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 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | 25843 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| ... | @@ -25886,7 +25852,7 @@ fn fieldPtr( | ... | @@ -25886,7 +25852,7 @@ fn fieldPtr( |
| 25886 | }; | 25852 | }; |
| 25887 | const field_index_u32: u32 = @intCast(field_index); | 25853 | const field_index_u32: u32 = @intCast(field_index); |
| 25888 | const idx_val = try pt.enumValueFieldIndex(child_type, field_index_u32); | 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 | .@"struct", .@"opaque" => { | 25857 | .@"struct", .@"opaque" => { |
| 25892 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { | 25858 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| ... | @@ -25903,7 +25869,7 @@ fn fieldPtr( | ... | @@ -25903,7 +25869,7 @@ fn fieldPtr( |
| 25903 | else | 25869 | else |
| 25904 | object_ptr; | 25870 | object_ptr; |
| 25905 | try sema.ensureLayoutResolved(inner_ty, src); | 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 | try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); | 25873 | try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); |
| 25908 | return field_ptr; | 25874 | return field_ptr; |
| 25909 | }, | 25875 | }, |
| ... | @@ -26190,7 +26156,6 @@ fn structFieldPtr( | ... | @@ -26190,7 +26156,6 @@ fn structFieldPtr( |
| 26190 | field_name: InternPool.NullTerminatedString, | 26156 | field_name: InternPool.NullTerminatedString, |
| 26191 | field_name_src: LazySrcLoc, | 26157 | field_name_src: LazySrcLoc, |
| 26192 | struct_ty: Type, | 26158 | struct_ty: Type, |
| 26193 | initializing: bool, | | |
| 26194 | ) CompileError!Air.Inst.Ref { | 26159 | ) CompileError!Air.Inst.Ref { |
| 26195 | const pt = sema.pt; | 26160 | const pt = sema.pt; |
| 26196 | const zcu = pt.zcu; | 26161 | const zcu = pt.zcu; |
| ... | @@ -26199,23 +26164,24 @@ fn structFieldPtr( | ... | @@ -26199,23 +26164,24 @@ fn structFieldPtr( |
| 26199 | assert(struct_ty.zigTypeTag(zcu) == .@"struct"); | 26164 | assert(struct_ty.zigTypeTag(zcu) == .@"struct"); |
| 26200 | struct_ty.assertHasLayout(zcu); | 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 | if (field_name.eqlSlice("len", ip)) { | 26168 | if (field_name.eqlSlice("len", ip)) { |
| 26204 | const len_inst = try pt.intRef(.usize, struct_ty.structFieldCount(zcu)); | 26169 | const len_inst = try pt.intRef(.usize, struct_ty.structFieldCount(zcu)); |
| 26205 | return sema.analyzeRef(block, src, len_inst); | 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); | 26172 | break :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); | 26173 | } else field_index: { |
| 26209 | } | 26174 | const struct_type = zcu.typeToStruct(struct_ty).?; |
| 26210 | | 26175 | break :field_index struct_type.nameIndex(ip, field_name) orelse { |
| 26211 | const struct_type = zcu.typeToStruct(struct_ty).?; | 26176 | return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name); |
| 26212 | | 26177 | }; |
| 26213 | const field_index = struct_type.nameIndex(ip, field_name) orelse | 26178 | }; |
| 26214 | return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name); | | |
| 26215 | | 26179 | |
| 26216 | return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, struct_ty); | 26180 | return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, struct_ty); |
| 26217 | } | 26181 | } |
| 26218 | | 26182 | |
| | 26183 | /// Supports both structs and unions. |
| | 26184 | /// |
| 26219 | /// Asserts that the layout of `struct_ty` is already resolved. | 26185 | /// Asserts that the layout of `struct_ty` is already resolved. |
| 26220 | fn structFieldPtrByIndex( | 26186 | fn structFieldPtrByIndex( |
| 26221 | sema: *Sema, | 26187 | sema: *Sema, |
| ... | @@ -26227,82 +26193,23 @@ fn structFieldPtrByIndex( | ... | @@ -26227,82 +26193,23 @@ fn structFieldPtrByIndex( |
| 26227 | ) CompileError!Air.Inst.Ref { | 26193 | ) CompileError!Air.Inst.Ref { |
| 26228 | const pt = sema.pt; | 26194 | const pt = sema.pt; |
| 26229 | const zcu = pt.zcu; | 26195 | const zcu = pt.zcu; |
| 26230 | const ip = &zcu.intern_pool; | | |
| 26231 | | 26196 | |
| 26232 | struct_ty.assertHasLayout(zcu); | 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 | const struct_ptr_ty = sema.typeOf(struct_ptr); | 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) | 26200 | if (struct_ty.structFieldIsComptime(field_index, zcu)) { |
| 26260 | struct_ptr_ty_info.flags.alignment | 26201 | const field_ptr_ty = try struct_ptr_ty.fieldPtrType(field_index, pt); |
| 26261 | else | 26202 | return .fromIntern(try pt.intern(.{ .ptr = .{ |
| 26262 | struct_ty.abiAlignment(zcu); | 26203 | .ty = field_ptr_ty.toIntern(), |
| 26263 | | 26204 | .base_addr = .{ .comptime_field = struct_ty.structFieldDefaultValue(field_index, zcu).?.toIntern() }, |
| 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] }, | | |
| 26300 | .byte_offset = 0, | 26205 | .byte_offset = 0, |
| 26301 | } }); | 26206 | } })); |
| 26302 | return Air.internedToRef(val); | 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 | fn structFieldVal( | 26215 | fn structFieldVal( |
| ... | @@ -26438,29 +26345,11 @@ fn unionFieldPtr( | ... | @@ -26438,29 +26345,11 @@ fn unionFieldPtr( |
| 26438 | assert(union_ty.zigTypeTag(zcu) == .@"union"); | 26345 | assert(union_ty.zigTypeTag(zcu) == .@"union"); |
| 26439 | union_ty.assertHasLayout(zcu); | 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 | const union_obj = zcu.typeToUnion(union_ty).?; | 26348 | const union_obj = zcu.typeToUnion(union_ty).?; |
| | 26349 | const tag_ty: Type = .fromInterned(union_obj.enum_tag_type); |
| | 26350 | |
| 26444 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); | 26351 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 26445 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); | 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 | if (initializing and field_ty.classify(zcu) == .no_possible_value) { | 26354 | if (initializing and field_ty.classify(zcu) == .no_possible_value) { |
| 26466 | const msg = msg: { | 26355 | const msg = msg: { |
| ... | @@ -26484,23 +26373,17 @@ fn unionFieldPtr( | ... | @@ -26484,23 +26373,17 @@ fn unionFieldPtr( |
| 26484 | break :ct; | 26373 | break :ct; |
| 26485 | } | 26374 | } |
| 26486 | // Store to the union to initialize the tag. | 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); | 26376 | const field_tag = try pt.enumValueFieldIndex(tag_ty, field_index); |
| 26488 | const payload_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); | 26377 | const payload_val = try field_ty.onePossibleValue(pt) orelse try pt.undefValue(field_ty); |
| 26489 | const new_union_val = try pt.unionValue(union_ty, field_tag, try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty)); | 26378 | const new_union_val = try pt.unionValue(union_ty, field_tag, payload_val); |
| 26490 | try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty); | 26379 | try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty); |
| 26491 | } else { | 26380 | } else { |
| 26492 | const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse | 26381 | const union_val = try sema.pointerDeref(block, src, union_ptr_val, union_ptr_val.typeOf(zcu)) orelse break :ct; |
| 26493 | break :ct; | 26382 | if (union_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null); |
| 26494 | if (union_val.isUndef(zcu)) { | 26383 | const active_index = tag_ty.enumTagFieldIndex(union_val.unionTag(zcu).?, zcu).?; |
| 26495 | return sema.failWithUseOfUndef(block, src, null); | 26384 | if (active_index != field_index) { |
| 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) { | | |
| 26501 | const msg = msg: { | 26385 | const msg = msg: { |
| 26502 | const active_index = Type.fromInterned(union_obj.enum_tag_type).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?; | 26386 | const active_field_name = tag_ty.enumFieldName(active_index, zcu); |
| 26503 | const active_field_name = Type.fromInterned(union_obj.enum_tag_type).enumFieldName(active_index, zcu); | | |
| 26504 | const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{ | 26387 | const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{ |
| 26505 | field_name.fmt(ip), | 26388 | field_name.fmt(ip), |
| 26506 | active_field_name.fmt(ip), | 26389 | active_field_name.fmt(ip), |
| ... | @@ -26520,11 +26403,10 @@ fn unionFieldPtr( | ... | @@ -26520,11 +26403,10 @@ fn unionFieldPtr( |
| 26520 | // If the union has a tag, we must either set or or safety check it depending on `initializing`. | 26403 | // If the union has a tag, we must either set or or safety check it depending on `initializing`. |
| 26521 | tag: { | 26404 | tag: { |
| 26522 | if (union_ty.containerLayout(zcu) != .auto) break :tag; | 26405 | if (union_ty.containerLayout(zcu) != .auto) break :tag; |
| 26523 | const tag_ty: Type = .fromInterned(union_obj.enum_tag_type); | | |
| 26524 | if (tag_ty.classify(zcu) == .one_possible_value) break :tag; | 26406 | if (tag_ty.classify(zcu) == .one_possible_value) break :tag; |
| 26525 | // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but | 26407 | // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but |
| 26526 | // only emit a safety check if it's available at runtime (i.e. it's safety-tagged). | 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 | if (initializing) { | 26410 | if (initializing) { |
| 26529 | const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag)); | 26411 | const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag)); |
| 26530 | try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store | 26412 | try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store |
| ... | @@ -26540,7 +26422,9 @@ fn unionFieldPtr( | ... | @@ -26540,7 +26422,9 @@ fn unionFieldPtr( |
| 26540 | _ = try block.addNoOp(.unreach); | 26422 | _ = try block.addNoOp(.unreach); |
| 26541 | return .unreachable_value; | 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 | fn unionFieldVal( | 26430 | fn unionFieldVal( |
| ... | @@ -26628,13 +26512,9 @@ fn elemPtr( | ... | @@ -26628,13 +26512,9 @@ fn elemPtr( |
| 26628 | try sema.ensureLayoutResolved(indexable_ty, src); | 26512 | try sema.ensureLayoutResolved(indexable_ty, src); |
| 26629 | | 26513 | |
| 26630 | const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) { | 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), | 26515 | .vector => try sema.elemPtrVector(block, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init), |
| 26632 | .@"struct" => blk: { | 26516 | .array => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), |
| 26633 | // Tuple field access. | 26517 | .@"struct" => try sema.tupleElemPtr(block, src, indexable_ptr, elem_index, elem_index_src), |
| 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 | }, | | |
| 26638 | else => { | 26518 | else => { |
| 26639 | const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); | 26519 | const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); |
| 26640 | try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu), src); | 26520 | try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu), src); |
| ... | @@ -26672,21 +26552,21 @@ fn elemPtrOneLayerOnly( | ... | @@ -26672,21 +26552,21 @@ fn elemPtrOneLayerOnly( |
| 26672 | .many, .c => { | 26552 | .many, .c => { |
| 26673 | const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable); | 26553 | const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable); |
| 26674 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); | 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 | ct: { | 26556 | ct: { |
| 26676 | const ptr_val = maybe_ptr_val orelse break :ct; | 26557 | const ptr_val = maybe_ptr_val orelse break :ct; |
| 26677 | const index_val = maybe_index_val orelse break :ct; | 26558 | const index: usize = @intCast(maybe_index orelse break :ct); |
| 26678 | const index: usize = @intCast(index_val.toUnsignedInt(zcu)); | 26559 | return .fromValue(try ptr_val.ptrElem(index, pt)); |
| 26679 | const elem_ptr = try ptr_val.ptrElem(index, pt); | | |
| 26680 | return Air.internedToRef(elem_ptr.toIntern()); | | |
| 26681 | } | 26560 | } |
| 26682 | | 26561 | |
| 26683 | try sema.checkLogicalPtrOperation(block, src, indexable_ty); | 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 | try sema.validateRuntimeElemAccess(block, elem_index_src, result_ty, indexable_ty, indexable_src); | 26566 | try sema.validateRuntimeElemAccess(block, elem_index_src, result_ty, indexable_ty, indexable_src); |
| 26687 | try sema.validateRuntimeValue(block, indexable_src, indexable); | 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 | // zero-bit child type; just bitcast the pointer | 26570 | // zero-bit child type; just bitcast the pointer |
| 26691 | return block.addBitCast(result_ty, indexable); | 26571 | return block.addBitCast(result_ty, indexable); |
| 26692 | } | 26572 | } |
| ... | @@ -26695,13 +26575,9 @@ fn elemPtrOneLayerOnly( | ... | @@ -26695,13 +26575,9 @@ fn elemPtrOneLayerOnly( |
| 26695 | }, | 26575 | }, |
| 26696 | .one => { | 26576 | .one => { |
| 26697 | const elem_ptr = switch (child_ty.zigTypeTag(zcu)) { | 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), | 26578 | .vector => try sema.elemPtrVector(block, indexable_src, indexable, elem_index_src, elem_index, init), |
| 26699 | .@"struct" => blk: { | 26579 | .array => try sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety), |
| 26700 | assert(child_ty.isTuple(zcu)); | 26580 | .@"struct" => try sema.tupleElemPtr(block, indexable_src, indexable, elem_index, elem_index_src), |
| 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 | }, | | |
| 26705 | else => unreachable, // Guaranteed by checkIndexable | 26581 | else => unreachable, // Guaranteed by checkIndexable |
| 26706 | }; | 26582 | }; |
| 26707 | try sema.checkKnownAllocPtr(block, indexable, elem_ptr); | 26583 | try sema.checkKnownAllocPtr(block, indexable, elem_ptr); |
| ... | @@ -26746,10 +26622,8 @@ fn elemVal( | ... | @@ -26746,10 +26622,8 @@ fn elemVal( |
| 26746 | const index: usize = @intCast(index_val.toUnsignedInt(zcu)); | 26622 | const index: usize = @intCast(index_val.toUnsignedInt(zcu)); |
| 26747 | const many_ptr_ty = try pt.manyConstPtrType(child_ty); | 26623 | const many_ptr_ty = try pt.manyConstPtrType(child_ty); |
| 26748 | const many_ptr_val = try pt.getCoerced(indexable_val, many_ptr_ty); | 26624 | const many_ptr_val = try pt.getCoerced(indexable_val, many_ptr_ty); |
| 26749 | const elem_ptr_ty = try pt.singleConstPtrType(child_ty); | | |
| 26750 | const elem_ptr_val = try many_ptr_val.ptrElem(index, pt); | 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; | 26626 | return sema.analyzeLoad(block, src, .fromValue(elem_ptr_val), indexable_src); |
| 26752 | return Air.internedToRef((try pt.getCoerced(elem_val, child_ty)).toIntern()); | | |
| 26753 | } | 26627 | } |
| 26754 | | 26628 | |
| 26755 | if (try child_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | 26629 | if (try child_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); |
| ... | @@ -26824,70 +26698,38 @@ fn validateRuntimeElemAccess( | ... | @@ -26824,70 +26698,38 @@ fn validateRuntimeElemAccess( |
| 26824 | } | 26698 | } |
| 26825 | } | 26699 | } |
| 26826 | | 26700 | |
| 26827 | /// Asserts that the layout of the tuple type is already resolved. | 26701 | /// Validates `elem_index`, and returns a pointer to that field using `structFieldPtrByIndex`. |
| 26828 | fn tupleFieldPtr( | 26702 | /// |
| | 26703 | /// Asserts that the type of `tuple_ptr` is a single-item pointer whose child type is a tuple. |
| | 26704 | fn tupleElemPtr( |
| 26829 | sema: *Sema, | 26705 | sema: *Sema, |
| 26830 | block: *Block, | 26706 | block: *Block, |
| 26831 | tuple_ptr_src: LazySrcLoc, | 26707 | src: LazySrcLoc, |
| 26832 | tuple_ptr: Air.Inst.Ref, | 26708 | tuple_ptr: Air.Inst.Ref, |
| 26833 | field_index_src: LazySrcLoc, | 26709 | elem_index: Air.Inst.Ref, |
| 26834 | field_index: u32, | 26710 | elem_index_src: LazySrcLoc, |
| 26835 | init: bool, | | |
| 26836 | ) CompileError!Air.Inst.Ref { | 26711 | ) CompileError!Air.Inst.Ref { |
| 26837 | const pt = sema.pt; | 26712 | const pt = sema.pt; |
| 26838 | const zcu = pt.zcu; | 26713 | const zcu = pt.zcu; |
| 26839 | const tuple_ptr_ty = sema.typeOf(tuple_ptr); | 26714 | const tuple_ptr_ty = sema.typeOf(tuple_ptr); |
| 26840 | const tuple_ptr_info = tuple_ptr_ty.ptrInfo(zcu); | 26715 | assert(tuple_ptr_ty.isSinglePointer(zcu)); |
| 26841 | const tuple_ty: Type = .fromInterned(tuple_ptr_info.child); | 26716 | const tuple_ty = tuple_ptr_ty.childType(zcu); |
| 26842 | const field_count = tuple_ty.structFieldCount(zcu); | 26717 | assert(tuple_ty.isTuple(zcu)); |
| 26843 | | | |
| 26844 | tuple_ty.assertHasLayout(zcu); | | |
| 26845 | | 26718 | |
| | 26719 | const field_count = tuple_ty.structFieldCount(zcu); |
| 26846 | if (field_count == 0) { | 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) { | 26724 | const elem_index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index }); |
| 26851 | return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ | 26725 | const index = elem_index_val.getUnsignedInt(zcu); |
| 26852 | field_index, field_count, | 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); | 26732 | return sema.structFieldPtrByIndex(block, src, tuple_ptr, @intCast(index.?), tuple_ty); |
| 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); | | |
| 26891 | } | 26733 | } |
| 26892 | | 26734 | |
| 26893 | fn tupleField( | 26735 | fn tupleField( |
| ... | @@ -26994,7 +26836,102 @@ fn elemValArray( | ... | @@ -26994,7 +26836,102 @@ fn elemValArray( |
| 26994 | return block.addBinOp(.array_elem_val, array, elem_index); | 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 | fn elemPtrArray( | 26935 | fn elemPtrArray( |
| 26999 | sema: *Sema, | 26936 | sema: *Sema, |
| 27000 | block: *Block, | 26937 | block: *Block, |
| ... | @@ -27009,19 +26946,21 @@ fn elemPtrArray( | ... | @@ -27009,19 +26946,21 @@ fn elemPtrArray( |
| 27009 | const pt = sema.pt; | 26946 | const pt = sema.pt; |
| 27010 | const zcu = pt.zcu; | 26947 | const zcu = pt.zcu; |
| 27011 | const array_ptr_ty = sema.typeOf(array_ptr); | 26948 | const array_ptr_ty = sema.typeOf(array_ptr); |
| | 26949 | assert(array_ptr_ty.ptrSize(zcu) == .one); |
| 27012 | const array_ty = array_ptr_ty.childType(zcu); | 26950 | const array_ty = array_ptr_ty.childType(zcu); |
| | 26951 | assert(array_ty.zigTypeTag(zcu) == .array); |
| 27013 | const array_sent = array_ty.sentinel(zcu) != null; | 26952 | const array_sent = array_ty.sentinel(zcu) != null; |
| 27014 | const array_len = array_ty.arrayLen(zcu); | 26953 | const array_len = array_ty.arrayLen(zcu); |
| 27015 | const array_len_s = array_len + @intFromBool(array_sent); | 26954 | const array_len_s = array_len + @intFromBool(array_sent); |
| 27016 | | 26955 | |
| 27017 | if (array_len_s == 0) { | 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 | const maybe_undef_array_ptr_val = sema.resolveValue(array_ptr); | 26960 | const maybe_undef_array_ptr_val = sema.resolveValue(array_ptr); |
| 27022 | // The index must not be undefined since it can be out of bounds. | 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: { | 26962 | const maybe_index: ?u64 = 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)); | 26963 | const index = index_val.toUnsignedInt(zcu); |
| 27025 | if (index >= array_len_s) { | 26964 | if (index >= array_len_s) { |
| 27026 | const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; | 26965 | const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; |
| 27027 | return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); | 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,20 +26968,15 @@ fn elemPtrArray( |
| 27029 | break :o index; | 26968 | break :o index; |
| 27030 | } else null; | 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 | array_ty.assertHasLayout(zcu); | 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 | if (maybe_undef_array_ptr_val) |array_ptr_val| { | 26974 | if (maybe_undef_array_ptr_val) |array_ptr_val| { |
| 27040 | if (array_ptr_val.isUndef(zcu)) { | 26975 | if (array_ptr_val.isUndef(zcu)) { |
| 27041 | return pt.undefRef(elem_ptr_ty); | 26976 | return pt.undefRef(elem_ptr_ty); |
| 27042 | } | 26977 | } |
| 27043 | if (offset) |index| { | 26978 | if (maybe_index) |index| { |
| 27044 | const elem_ptr = try array_ptr_val.ptrElem(index, pt); | 26979 | return .fromValue(try array_ptr_val.ptrElem(index, pt)); |
| 27045 | return Air.internedToRef(elem_ptr.toIntern()); | | |
| 27046 | } | 26980 | } |
| 27047 | } | 26981 | } |
| 27048 | | 26982 | |
| ... | @@ -27052,7 +26986,7 @@ fn elemPtrArray( | ... | @@ -27052,7 +26986,7 @@ fn elemPtrArray( |
| 27052 | } | 26986 | } |
| 27053 | | 26987 | |
| 27054 | // Runtime check is only needed if unable to comptime check. | 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 | const len_inst = try pt.intRef(.usize, array_len); | 26990 | const len_inst = try pt.intRef(.usize, array_len); |
| 27057 | const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; | 26991 | const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; |
| 27058 | try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op); | 26992 | try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op); |
| ... | @@ -27075,9 +27009,9 @@ fn elemValSlice( | ... | @@ -27075,9 +27009,9 @@ fn elemValSlice( |
| 27075 | const pt = sema.pt; | 27009 | const pt = sema.pt; |
| 27076 | const zcu = pt.zcu; | 27010 | const zcu = pt.zcu; |
| 27077 | const slice_ty = sema.typeOf(slice); | 27011 | const slice_ty = sema.typeOf(slice); |
| | 27012 | assert(slice_ty.isSlice(zcu)); |
| 27078 | const slice_sent = slice_ty.sentinel(zcu) != null; | 27013 | const slice_sent = slice_ty.sentinel(zcu) != null; |
| 27079 | const elem_ty = slice_ty.childType(zcu); | 27014 | const elem_ty = slice_ty.childType(zcu); |
| 27080 | var runtime_src = slice_src; | | |
| 27081 | | 27015 | |
| 27082 | elem_ty.assertHasLayout(zcu); | 27016 | elem_ty.assertHasLayout(zcu); |
| 27083 | | 27017 | |
| ... | @@ -27087,7 +27021,6 @@ fn elemValSlice( | ... | @@ -27087,7 +27021,6 @@ fn elemValSlice( |
| 27087 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); | 27021 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 27088 | | 27022 | |
| 27089 | if (maybe_slice_val) |slice_val| { | 27023 | if (maybe_slice_val) |slice_val| { |
| 27090 | runtime_src = elem_index_src; | | |
| 27091 | const slice_len = slice_val.sliceLen(zcu); | 27024 | const slice_len = slice_val.sliceLen(zcu); |
| 27092 | const slice_len_s = slice_len + @intFromBool(slice_sent); | 27025 | const slice_len_s = slice_len + @intFromBool(slice_sent); |
| 27093 | if (slice_len_s == 0) { | 27026 | if (slice_len_s == 0) { |
| ... | @@ -27099,12 +27032,8 @@ fn elemValSlice( | ... | @@ -27099,12 +27032,8 @@ fn elemValSlice( |
| 27099 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; | 27032 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 27100 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); | 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 | const elem_ptr_val = try slice_val.ptrElem(index, pt); | 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| { | 27036 | return sema.analyzeLoad(block, src, .fromValue(elem_ptr_val), slice_src); |
| 27105 | return Air.internedToRef(elem_val.toIntern()); | | |
| 27106 | } | | |
| 27107 | runtime_src = slice_src; | | |
| 27108 | } | 27037 | } |
| 27109 | } | 27038 | } |
| 27110 | | 27039 | |
| ... | @@ -27138,17 +27067,19 @@ fn elemPtrSlice( | ... | @@ -27138,17 +27067,19 @@ fn elemPtrSlice( |
| 27138 | const pt = sema.pt; | 27067 | const pt = sema.pt; |
| 27139 | const zcu = pt.zcu; | 27068 | const zcu = pt.zcu; |
| 27140 | const slice_ty = sema.typeOf(slice); | 27069 | const slice_ty = sema.typeOf(slice); |
| | 27070 | assert(slice_ty.isSlice(zcu)); |
| 27141 | const slice_sent = slice_ty.sentinel(zcu) != null; | 27071 | const slice_sent = slice_ty.sentinel(zcu) != null; |
| 27142 | | 27072 | const elem_ty = slice_ty.childType(zcu); |
| 27143 | slice_ty.childType(zcu).assertHasLayout(zcu); | 27073 | elem_ty.assertHasLayout(zcu); |
| 27144 | | 27074 | |
| 27145 | const maybe_undef_slice_val = sema.resolveValue(slice); | 27075 | const maybe_undef_slice_val = sema.resolveValue(slice); |
| 27146 | // The index must not be undefined since it can be out of bounds. | 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: { | 27077 | const offset: ?u64 = 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)); | 27078 | break :o index_val.toUnsignedInt(zcu); |
| 27149 | } else null; | 27079 | } else null; |
| 27150 | | 27080 | |
| 27151 | const elem_ptr_ty = try slice_ty.elemPtrType(offset, pt); | 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 | if (maybe_undef_slice_val) |slice_val| { | 27084 | if (maybe_undef_slice_val) |slice_val| { |
| 27154 | if (slice_val.isUndef(zcu)) { | 27085 | if (slice_val.isUndef(zcu)) { |
| ... | @@ -27157,15 +27088,14 @@ fn elemPtrSlice( | ... | @@ -27157,15 +27088,14 @@ fn elemPtrSlice( |
| 27157 | const slice_len = slice_val.sliceLen(zcu); | 27088 | const slice_len = slice_val.sliceLen(zcu); |
| 27158 | const slice_len_s = slice_len + @intFromBool(slice_sent); | 27089 | const slice_len_s = slice_len + @intFromBool(slice_sent); |
| 27159 | if (slice_len_s == 0) { | 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 | if (offset) |index| { | 27093 | if (offset) |index| { |
| 27163 | if (index >= slice_len_s) { | 27094 | if (index >= slice_len_s) { |
| 27164 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; | 27095 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 27165 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); | 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); | 27098 | return .fromValue(try slice_val.ptrElem(index, pt)); |
| 27168 | return Air.internedToRef(elem_ptr_val.toIntern()); | | |
| 27169 | } | 27099 | } |
| 27170 | } | 27100 | } |
| 27171 | | 27101 | |
| ... | @@ -27182,7 +27112,7 @@ fn elemPtrSlice( | ... | @@ -27182,7 +27112,7 @@ fn elemPtrSlice( |
| 27182 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; | 27112 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| 27183 | try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op); | 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 | // zero-bit child type; just extract the pointer and bitcast it | 27116 | // zero-bit child type; just extract the pointer and bitcast it |
| 27187 | const slice_ptr = try block.addTyOp(.slice_ptr, slice_ty.slicePtrFieldType(zcu), slice); | 27117 | const slice_ptr = try block.addTyOp(.slice_ptr, slice_ty.slicePtrFieldType(zcu), slice); |
| 27188 | return block.addBitCast(elem_ptr_ty, slice_ptr); | 27118 | return block.addBitCast(elem_ptr_ty, slice_ptr); |
| ... | @@ -27546,7 +27476,7 @@ fn coerceExtra( | ... | @@ -27546,7 +27476,7 @@ fn coerceExtra( |
| 27546 | .sentinel = dest_info.sentinel, | 27476 | .sentinel = dest_info.sentinel, |
| 27547 | }); | 27477 | }); |
| 27548 | const empty_array_val = try pt.aggregateValue(empty_array_ty, &.{}); | 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 | return sema.coerceArrayPtrToSlice(block, dest_ty, empty_array_ptr, inst_src); | 27480 | return sema.coerceArrayPtrToSlice(block, dest_ty, empty_array_ptr, inst_src); |
| 27551 | } | 27481 | } |
| 27552 | | 27482 | |
| ... | @@ -28499,7 +28429,6 @@ pub fn coerceInMemoryAllowed( | ... | @@ -28499,7 +28429,6 @@ pub fn coerceInMemoryAllowed( |
| 28499 | const field_count = dest_ty.structFieldCount(zcu); | 28429 | const field_count = dest_ty.structFieldCount(zcu); |
| 28500 | for (0..field_count) |field_idx| { | 28430 | for (0..field_count) |field_idx| { |
| 28501 | if (dest_ty.structFieldIsComptime(field_idx, zcu) != src_ty.structFieldIsComptime(field_idx, zcu)) break :tuple; | 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 | const dest_field_ty = dest_ty.fieldType(field_idx, zcu); | 28432 | const dest_field_ty = dest_ty.fieldType(field_idx, zcu); |
| 28504 | const src_field_ty = src_ty.fieldType(field_idx, zcu); | 28433 | const src_field_ty = src_ty.fieldType(field_idx, zcu); |
| 28505 | const field = try sema.coerceInMemoryAllowed(block, dest_field_ty, src_field_ty, dest_is_mut, target, dest_src, src_src, null); | 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,12 +29882,14 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: |
| 29953 | fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { | 29882 | fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { |
| 29954 | const pt = sema.pt; | 29883 | const pt = sema.pt; |
| 29955 | const ptr_anyopaque_ty = try pt.singleConstPtrType(.anyopaque); | 29884 | const ptr_anyopaque_ty = try pt.singleConstPtrType(.anyopaque); |
| 29956 | return Value.fromInterned(try pt.intern(.{ .opt = .{ | 29885 | const opt_ptr_anyopaque_ty = try pt.optionalType(ptr_anyopaque_ty.toIntern()); |
| 29957 | .ty = (try pt.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(), | 29886 | return .fromInterned(try pt.intern(.{ .opt = .{ |
| 29958 | .val = if (opt_val) |val| (try pt.getCoerced( | 29887 | .ty = opt_ptr_anyopaque_ty.toIntern(), |
| 29959 | Value.fromInterned(try pt.refValue(val.toIntern())), | 29888 | .val = payload: { |
| 29960 | ptr_anyopaque_ty, | 29889 | const val = opt_val orelse break :payload .none; |
| 29961 | )).toIntern() else .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,7 +30009,7 @@ fn analyzeRef( |
| 30078 | switch (zcu.intern_pool.indexToKey(val.toIntern())) { | 30009 | switch (zcu.intern_pool.indexToKey(val.toIntern())) { |
| 30079 | .@"extern" => |e| return sema.analyzeNavRef(block, src, e.owner_nav), | 30010 | .@"extern" => |e| return sema.analyzeNavRef(block, src, e.owner_nav), |
| 30080 | .func => |f| return sema.analyzeNavRef(block, src, f.owner_nav), | 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,7 +30459,7 @@ fn analyzeSlice( |
| 30528 | } else ptr_or_slice; | 30459 | } else ptr_or_slice; |
| 30529 | | 30460 | |
| 30530 | const start = try sema.coerce(block, .usize, uncasted_start, start_src); | 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 | const new_ptr_ty = sema.typeOf(new_ptr); | 30463 | const new_ptr_ty = sema.typeOf(new_ptr); |
| 30533 | | 30464 | |
| 30534 | // true if and only if the end index of the slice, implicitly or explicitly, equals | 30465 | // true if and only if the end index of the slice, implicitly or explicitly, equals |
| ... | @@ -30666,7 +30597,7 @@ fn analyzeSlice( | ... | @@ -30666,7 +30597,7 @@ fn analyzeSlice( |
| 30666 | break :msg msg; | 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 | const sentinel = s: { | 30603 | const sentinel = s: { |
| ... | @@ -32118,12 +32049,12 @@ fn resolvePeerTypesInner( | ... | @@ -32118,12 +32049,12 @@ fn resolvePeerTypesInner( |
| 32118 | | 32049 | |
| 32119 | ptr_info.flags.alignment = a: { | 32050 | ptr_info.flags.alignment = a: { |
| 32120 | // If both alignments are implicit, the result alignment is implicit. | 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 | if (ptr_info.flags.alignment == .none and peer_info.flags.alignment == .none) { | 32053 | if (ptr_info.flags.alignment == .none and peer_info.flags.alignment == .none) { |
| 32123 | break :a .none; | 32054 | break :a .none; |
| 32124 | } | 32055 | } |
| 32125 | // Otherwise (if either alignment is explicit), the result alignment is explicit. | 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 | const cur_align = switch (ptr_info.flags.alignment) { | 32058 | const cur_align = switch (ptr_info.flags.alignment) { |
| 32128 | .none => Type.fromInterned(ptr_info.child).abiAlignment(zcu), | 32059 | .none => Type.fromInterned(ptr_info.child).abiAlignment(zcu), |
| 32129 | else => ptr_info.flags.alignment, | 32060 | else => ptr_info.flags.alignment, |
| ... | @@ -33583,7 +33514,7 @@ fn notePathToComptimeAllocPtr( | ... | @@ -33583,7 +33514,7 @@ fn notePathToComptimeAllocPtr( |
| 33583 | else => {}, // there will be another stage | 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 | var second_path_aw: std.Io.Writer.Allocating = .init(arena); | 33519 | var second_path_aw: std.Io.Writer.Allocating = .init(arena); |
| 33589 | defer second_path_aw.deinit(); | 33520 | defer second_path_aw.deinit(); |