authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-31 18:14:31+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:09+00:00
logb8997f871fc63cee28d94168330d84f177543f2c
tree5ae9d230d0ca3dc50947ca1fda3c69d68f2172c9
parent38fdced8bb255d3460afefaacce9dc89dab97def
signaturelock-open Commit is signed but in an unrecognized format.

Sema: clean up and fix alignment handling


8 files changed, 743 insertions(+), 901 deletions(-)

src/Sema.zig+433-502
...@@ -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 };
45414554
4542 const field_src = init_src; // TODO better source location4555 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}
49644974
4965fn uavRef(sema: *Sema, val: InternPool.Index) CompileError!Air.Inst.Ref {4975fn 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}
49684978
4969fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {4979fn 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 need6242 // 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);
62576267
...@@ -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 here10327 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 capture10328 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(
1228012277
12281 // By-reference captures have some further restrictions which make them easier to emit12278 // 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 field12282 // 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 }
1409914073
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 };
1527115245
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);
1538615357
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);
1538915364
...@@ -15395,70 +15370,36 @@ fn analyzePtrArithmetic(...@@ -15395,70 +15370,36 @@ fn analyzePtrArithmetic(
15395 else => {},15370 else => {},
15396 }15371 }
1539715372
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 on15380 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 };
1543515382
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;
1544015387
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 };
1545415396
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);
1545715398
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}
1622416165
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.
16225fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {16171fn 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 };
1672816674
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 };
1673316684
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 };
1690116854
...@@ -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);
1842618379
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 }
1865318605
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 };
1881418766
...@@ -19000,7 +18952,7 @@ fn structInitAnon(...@@ -19000,7 +18952,7 @@ fn structInitAnon(
1900018952
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 };
1900518957
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 };
1914219094
19143 if (is_ref) {19095 if (is_ref) {
...@@ -19261,7 +19213,7 @@ fn arrayInitAnon(...@@ -19261,7 +19213,7 @@ fn arrayInitAnon(
1926119213
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 };
1926619218
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}
1930619258
19307fn addConstantMaybeRef(sema: *Sema, val: InternPool.Index, is_ref: bool) !Air.Inst.Ref {19259fn 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}
1931019262
19311fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {19263fn 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);
2340523356
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 }
2345623367
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 });
2346023373
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 },
2349023391 .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 };
2350223403
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 };
2350623407
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 }
2351023411
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}
2353223480
23533fn ptrSubtract(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, byte_subtract: u64, new_ty: Type) !Value {23481fn 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}
2355423504
23555fn zirMinMax(23505fn zirMinMax(
...@@ -24186,8 +24136,8 @@ fn zirMemcpy(...@@ -24186,8 +24136,8 @@ fn zirMemcpy(
2418624136
24187 // ok1: dest >= src + len24137 // ok1: dest >= src + len
24188 // ok2: src >= dest + len24138 // 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());
2540325353
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());
2541225362 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);
2542025385
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 that25642 // 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 else25869 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);
2620126166
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).?;
2621026175 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);
2621226177 };
26213 const field_index = struct_type.nameIndex(ip, field_name) orelse26178 };
26214 return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name);
2621526179
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}
2621826182
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.
26220fn structFieldPtrByIndex(26186fn 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;
2623126196
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 };
2625826199
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.alignment26201 const field_ptr_ty = try struct_ptr_ty.fieldPtrType(field_index, pt);
26261 else26202 return .fromIntern(try pt.intern(.{ .ptr = .{
26262 struct_ty.abiAlignment(zcu);26203 .ty = field_ptr_ty.toIntern(),
2626326204 .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}
2630726214
26308fn structFieldVal(26215fn 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);
2644026347
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).?);
2646426353
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)) orelse26381 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, but26407 // 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" store26412 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}
2654526429
26546fn unionFieldVal(26430fn 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);
2662926513
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 }
2668226561
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);
2668526565
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);
2668826568
26689 if (result_ty.childType(zcu).abiSize(zcu) == 0) {26569 if (child_ty.abiSize(zcu) == 0) {
26690 // zero-bit child type; just bitcast the pointer26570 // 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 checkIndexable26581 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 }
2675426628
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}
2682626700
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`.
26828fn tupleFieldPtr(26702///
26703/// Asserts that the type of `tuple_ptr` is a single-item pointer whose child type is a tuple.
26704fn 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);
2684526718
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 }
2684926723
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 }
2685526731
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}
2689226734
26893fn tupleField(26735fn 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}
2699626838
26997/// Asserts that the layout of the array or vector is already resolved.26839fn 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.
26998fn elemPtrArray(26935fn 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);
2701626955
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 }
2702026959
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;
2703126970
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);
2703826973
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 }
2704826982
...@@ -27052,7 +26986,7 @@ fn elemPtrArray(...@@ -27052,7 +26986,7 @@ fn elemPtrArray(
27052 }26986 }
2705326987
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;
2708127015
27082 elem_ty.assertHasLayout(zcu);27016 elem_ty.assertHasLayout(zcu);
2708327017
...@@ -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);
2708827022
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 }
2711027039
...@@ -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;
2714227072 const elem_ty = slice_ty.childType(zcu);
27143 slice_ty.childType(zcu).assertHasLayout(zcu);27073 elem_ty.assertHasLayout(zcu);
2714427074
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;
2715027080
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());
2715227083
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 }
2717127101
...@@ -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 it27116 // 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 }
2755227482
...@@ -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:
29953fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {29882fn 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}
2996429895
...@@ -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 }
3008430015
...@@ -30528,7 +30459,7 @@ fn analyzeSlice(...@@ -30528,7 +30459,7 @@ fn analyzeSlice(
30528 } else ptr_or_slice;30459 } else ptr_or_slice;
3052930460
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);
3053330464
30534 // true if and only if the end index of the slice, implicitly or explicitly, equals30465 // 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 };
3067130602
30672 const sentinel = s: {30603 const sentinel = s: {
...@@ -32118,12 +32049,12 @@ fn resolvePeerTypesInner(...@@ -32118,12 +32049,12 @@ fn resolvePeerTypesInner(
3211832049
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 stage33514 else => {}, // there will be another stage
33584 }33515 }
3358533516
33586 const derivation = try comptime_ptr.pointerDerivationAdvanced(arena, pt, false, sema);33517 const derivation = try comptime_ptr.pointerDerivation(arena, pt, sema);
3358733518
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();
src/Type.zig+215-138
...@@ -2337,35 +2337,11 @@ pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {...@@ -2337,35 +2337,11 @@ pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {
2337 return .fromInterned(types.get(ip)[index]);2337 return .fromInterned(types.get(ip)[index]);
2338}2338}
23392339
2340// TODO MLUGG: clean up doc comments and usages of `{resolved,explicit}FieldAlignment`2340/// If an alignment was explicitly specified for the given field of the struct or union type `ty`,
23412341/// returns that. Otherwise, returns `.none`. This function also supports tuples, for which it
2342/// Returns the alignment of the given struct, tuple, or union field.2342/// always returns `.none`.
2343/// Asserts that the layout of `ty` is resolved. Asserts that `ty` is not packed.2343///
2344/// Never returns `.none`, even if the field's alignment was not specified.2344/// Asserts that the layout of `ty` is resolved, unless `ty` is a tuple.
2345pub fn resolvedFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment {
2346 switch (ty.explicitFieldAlignment(index, zcu)) {
2347 .none => {},
2348 else => |explicit| return explicit,
2349 }
2350 const ip = &zcu.intern_pool;
2351 return switch (ip.indexToKey(ty.toIntern())) {
2352 .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]).abiAlignment(zcu),
2353 .struct_type => {
2354 assertHasLayout(ty, zcu);
2355 const struct_obj = ip.loadStructType(ty.toIntern());
2356 const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[index]);
2357 return field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);
2358 },
2359 .union_type => {
2360 assertHasLayout(ty, zcu);
2361 const union_obj = ip.loadUnionType(ty.toIntern());
2362 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[index]);
2363 return field_ty.abiAlignment(zcu);
2364 },
2365 else => unreachable,
2366 };
2367}
2368
2369pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment {2345pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment {
2370 const ip = &zcu.intern_pool;2346 const ip = &zcu.intern_pool;
2371 return switch (ip.indexToKey(ty.toIntern())) {2347 return switch (ip.indexToKey(ty.toIntern())) {
...@@ -2388,7 +2364,10 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment...@@ -2388,7 +2364,10 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment
2388 };2364 };
2389}2365}
23902366
2391/// Returns the alignment a struct field will have if not explicitly specified.2367/// Returns the alignment a struct field of type `field_ty` will be given if no alignment is
2368/// explicitly specified. However, in an `extern struct`, a higher alignment may be available due
2369/// to the struct's full layout (i.e. a field might coincidentally be more aligned).
2370///
2392/// Asserts that the layout of `field_ty` is resolved. Asserts that `layout` is not `.@"packed"`.2371/// Asserts that the layout of `field_ty` is resolved. Asserts that `layout` is not `.@"packed"`.
2393pub fn defaultStructFieldAlignment(2372pub fn defaultStructFieldAlignment(
2394 field_ty: Type,2373 field_ty: Type,
...@@ -2664,45 +2643,6 @@ pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } {...@@ -2664,45 +2643,6 @@ pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } {
2664 return .{ cur_ty, cur_len };2643 return .{ cur_ty, cur_len };
2665}2644}
26662645
2667/// Returns a bit-pointer with the same value and a new packed offset.
2668pub fn packedStructFieldPtrInfo(
2669 struct_ty: Type,
2670 parent_ptr_ty: Type,
2671 field_idx: u32,
2672 pt: Zcu.PerThread,
2673) InternPool.Key.PtrType.PackedOffset {
2674 comptime assert(Type.packed_struct_layout_version == 2);
2675
2676 const zcu = pt.zcu;
2677 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
2678
2679 var bit_offset: u16 = 0;
2680 var running_bits: u16 = 0;
2681 for (0..struct_ty.structFieldCount(zcu)) |i| {
2682 const f_ty = struct_ty.fieldType(i, zcu);
2683 if (i == field_idx) {
2684 bit_offset = running_bits;
2685 }
2686 running_bits += @intCast(f_ty.bitSize(zcu));
2687 }
2688
2689 const res_host_size: u16, const res_bit_offset: u16 = if (parent_ptr_info.packed_offset.host_size != 0) .{
2690 parent_ptr_info.packed_offset.host_size,
2691 parent_ptr_info.packed_offset.bit_offset + bit_offset,
2692 } else .{
2693 switch (zcu.comp.getZigBackend()) {
2694 else => (running_bits + 7) / 8,
2695 .stage2_x86_64, .stage2_c => @intCast(struct_ty.abiSize(zcu)),
2696 },
2697 bit_offset,
2698 };
2699
2700 return .{
2701 .host_size = res_host_size,
2702 .bit_offset = res_bit_offset,
2703 };
2704}
2705
2706pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout {2646pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout {
2707 const ip = &zcu.intern_pool;2647 const ip = &zcu.intern_pool;
2708 var most_aligned_field: u32 = 0;2648 var most_aligned_field: u32 = 0;
...@@ -2770,88 +2710,225 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)...@@ -2770,88 +2710,225 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
2770 };2710 };
2771}2711}
27722712
2773/// Returns the type of a pointer to an element.2713/// Asserts that `ptr_ty` is either a many-item pointer, a slice, a C pointer, or a single pointer
2774/// Asserts that the type is a pointer, and that the element type is indexable.2714/// to array (in other words, a pointer which is indexed by pointer arithmetic), and returns the
2775/// If the element index is comptime-known, it must be passed in `offset`.2715/// type of the element pointer at the given index.
2776/// For *@Vector(n, T), return *align(a:b:h:v) T2716///
2777/// For *[N]T, return *T2717/// Asserts that the layout of the pointer element type is resolved.
2778/// For [*]T, returns *T2718///
2779/// For []T, returns *T2719/// If `index` is `null`, the index is an arbitrary runtime-known value.
2780/// Handles const-ness and address spaces in particular.2720pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error!Type {
2781/// This code is duplicated in `Sema.analyzePtrArithmetic`.
2782/// May perform type resolution and return a transitive `error.AnalysisFail`.
2783/// MLUGG TODO audit this shit
2784pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type {
2785 const zcu = pt.zcu;2721 const zcu = pt.zcu;
2786 const ptr_info = ptr_ty.ptrInfo(zcu);2722 const ip = &zcu.intern_pool;
2723 const ptr_info = ip.indexToKey(ptr_ty.toIntern()).ptr_type;
2787 const elem_ty: Type = switch (ptr_info.flags.size) {2724 const elem_ty: Type = switch (ptr_info.flags.size) {
2788 .one => switch (Type.fromInterned(ptr_info.child).zigTypeTag(zcu)) {2725 .slice, .many, .c => .fromInterned(ptr_info.child),
2789 .array, .vector => Type.fromInterned(ptr_info.child).childType(zcu),2726 .one => switch (ip.indexToKey(ptr_info.child)) {
2790 else => .fromInterned(ptr_info.child),2727 .array_type => |array_type| .fromInterned(array_type.child),
2791 },2728 else => unreachable,
2792 .many, .c, .slice => .fromInterned(ptr_info.child),2729 },
2793 };2730 };
2794 const is_allowzero = ptr_info.flags.is_allowzero and (offset orelse 0) == 0;2731 elem_ty.assertHasLayout(zcu);
2795 const parent_ty = ptr_ty.childType(zcu);2732 const elem_align: Alignment = switch (elem_ty.classify(zcu)) {
27962733 .no_possible_value,
2797 const VI = InternPool.Key.PtrType.VectorIndex;2734 .one_possible_value,
27982735 => ptr_info.flags.alignment,
2799 const vector_info: struct {2736
2800 host_size: u16 = 0,2737 .partially_comptime,
2801 alignment: Alignment = .none,2738 .fully_comptime,
2802 vector_index: VI = .none,2739 => switch (ptr_info.flags.alignment) {
2803 } = if (parent_ty.isVector(zcu) and ptr_info.flags.size == .one) blk: {2740 .none => .none,
2804 const elem_bits = elem_ty.bitSize(zcu);2741 else => |array_align| .minStrict(array_align, elem_ty.abiAlignment(zcu)),
2805 if (elem_bits == 0) break :blk .{};2742 },
2806 const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits);2743
2807 if (!is_packed) break :blk .{};2744 .runtime => switch (ptr_info.flags.alignment) {
28082745 .none => .none,
2809 break :blk .{2746 else => |array_align| elem_align: {
2810 .host_size = @intCast(parent_ty.arrayLen(zcu)),2747 // If the index is runtime-known, use 1 as it gives the minimum possible alignment.
2811 .alignment = parent_ty.abiAlignment(zcu),2748 const effective_index = index orelse 1;
2812 .vector_index = @enumFromInt(offset.?),2749 if (effective_index == 0) break :elem_align array_align;
2813 };2750 const byte_offset = effective_index * elem_ty.abiSize(zcu);
2814 } else .{};2751 break :elem_align .minStrict(array_align, .fromLog2Units(@ctz(byte_offset)));
28152752 },
2816 const alignment: Alignment = a: {2753 },
2817 // Calculate the new pointer alignment.
2818 if (ptr_info.flags.alignment == .none) {
2819 // In case of an ABI-aligned pointer, any pointer arithmetic
2820 // maintains the same ABI-alignedness.
2821 break :a vector_info.alignment;
2822 }
2823 // If the addend is not a comptime-known value we can still count on
2824 // it being a multiple of the type size.
2825 const elem_size = elem_ty.abiSize(zcu);
2826 const addend = if (offset) |off| elem_size * off else elem_size;
2827
2828 // The resulting pointer is aligned to the lcd between the offset (an
2829 // arbitrary number) and the alignment factor (always a power of two,
2830 // non zero).
2831 const new_align: Alignment = @enumFromInt(@min(
2832 @ctz(addend),
2833 ptr_info.flags.alignment.toLog2Units(),
2834 ));
2835 assert(new_align != .none);
2836 break :a new_align;
2837 };2754 };
2838 return pt.ptrType(.{2755 return pt.ptrType(.{
2839 .child = elem_ty.toIntern(),2756 .child = elem_ty.toIntern(),
2840 .flags = .{2757 .flags = .{
2841 .alignment = alignment,2758 .size = .one,
2842 .is_const = ptr_info.flags.is_const,2759 .is_const = ptr_info.flags.is_const,
2843 .is_volatile = ptr_info.flags.is_volatile,2760 .is_volatile = ptr_info.flags.is_volatile,
2844 .is_allowzero = is_allowzero,2761 .is_allowzero = ptr_info.flags.is_allowzero and (index == null or index == 0),
2845 .address_space = ptr_info.flags.address_space,2762 .address_space = ptr_info.flags.address_space,
2846 .vector_index = vector_info.vector_index,2763 .alignment = elem_align,
2847 },
2848 .packed_offset = .{
2849 .host_size = vector_info.host_size,
2850 .bit_offset = 0,
2851 },2764 },
2852 });2765 });
2853}2766}
28542767
2768/// Asserts that `ptr_ty` is a pointer (single-item or C) to a struct, union, tuple, or slice, and
2769/// returns the type of a pointer to the field at `field_index`.
2770///
2771/// Asserts that the layout of the pointer child type is resolved.
2772///
2773/// For slices, `Value.slice_ptr_index` and `Value.slice_len_index` are used for the field index.
2774pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator.Error!Type {
2775 const zcu = pt.zcu;
2776 const ip = &zcu.intern_pool;
2777 const ptr_info = ip.indexToKey(ptr_ty.toIntern()).ptr_type;
2778 assert(ptr_info.flags.size == .one or ptr_info.flags.size == .c);
2779 const aggregate_ty: Type = .fromInterned(ptr_info.child);
2780 aggregate_ty.assertHasLayout(zcu);
2781 // We only exit this `switch` for default-layout aggregates, where the field pointer alignment
2782 // is a simple minimum of the aggregate pointer alignment and the field alignment.
2783 // `field_align` is `.none` if there is no explicit alignment annotation.
2784 const field_ty: Type, const field_align: Alignment = switch (aggregate_ty.zigTypeTag(zcu)) {
2785 .@"struct" => switch (aggregate_ty.containerLayout(zcu)) {
2786 .auto => field: {
2787 if (aggregate_ty.isTuple(zcu)) {
2788 break :field .{ aggregate_ty.fieldType(field_index, zcu), .none };
2789 }
2790 const struct_obj = ip.loadStructType(aggregate_ty.toIntern());
2791 break :field .{
2792 .fromInterned(struct_obj.field_types.get(ip)[field_index]),
2793 struct_obj.field_aligns.getOrNone(ip, field_index),
2794 };
2795 },
2796 .@"extern" => {
2797 // Field alignment is determined based on the actual field offset. For instance, in
2798 // `extern struct { x: u32, y: u16 }`, the `y` field is 4-byte aligned.
2799 const field_ty = aggregate_ty.fieldType(field_index, zcu);
2800 const field_offset = aggregate_ty.structFieldOffset(field_index, zcu);
2801 const parent_align = switch (ptr_info.flags.alignment) {
2802 .none => aggregate_ty.abiAlignment(zcu),
2803 else => |a| a,
2804 };
2805 const actual_field_align = switch (field_offset) {
2806 0 => parent_align,
2807 else => parent_align.minStrict(.fromLog2Units(@ctz(field_offset))),
2808 };
2809 const field_ptr_align: Alignment = a: {
2810 if (parent_align == .none and
2811 aggregate_ty.explicitFieldAlignment(field_index, zcu) == .none and
2812 actual_field_align == field_ty.abiAlignment(zcu))
2813 {
2814 // There's no user-specified 'align' in sight, and the alignment from the
2815 // field offset matches the field type's natural alignment, so just use a
2816 // default-aligned pointer.
2817 break :a .none;
2818 }
2819 break :a actual_field_align;
2820 };
2821 var field_ptr_info = ptr_info;
2822 field_ptr_info.child = field_ty.toIntern();
2823 field_ptr_info.flags.alignment = field_ptr_align;
2824 return pt.ptrType(field_ptr_info);
2825 },
2826 .@"packed" => {
2827 var field_ptr_info = ptr_info;
2828 if (field_ptr_info.flags.alignment == .none) {
2829 field_ptr_info.flags.alignment = aggregate_ty.abiAlignment(zcu);
2830 }
2831 field_ptr_info.packed_offset = packed_offset: {
2832 comptime assert(Type.packed_struct_layout_version == 2);
2833 const bit_offset = zcu.structPackedFieldBitOffset(
2834 ip.loadStructType(aggregate_ty.toIntern()),
2835 field_index,
2836 );
2837 break :packed_offset if (ptr_info.packed_offset.host_size != 0) .{
2838 .host_size = ptr_info.packed_offset.host_size,
2839 .bit_offset = ptr_info.packed_offset.bit_offset + bit_offset,
2840 } else .{
2841 .host_size = switch (zcu.comp.getZigBackend()) {
2842 else => @intCast((aggregate_ty.bitSize(zcu) + 7) / 8),
2843 .stage2_x86_64, .stage2_c => @intCast(aggregate_ty.abiSize(zcu)),
2844 },
2845 .bit_offset = ptr_info.packed_offset.bit_offset + bit_offset,
2846 };
2847 };
2848 field_ptr_info.child = aggregate_ty.fieldType(field_index, zcu).toIntern();
2849 return pt.ptrType(field_ptr_info);
2850 },
2851 },
2852 .@"union" => switch (aggregate_ty.containerLayout(zcu)) {
2853 .auto => field: {
2854 const union_obj = ip.loadUnionType(aggregate_ty.toIntern());
2855 break :field .{
2856 .fromInterned(union_obj.field_types.get(ip)[field_index]),
2857 union_obj.field_aligns.getOrNone(ip, field_index),
2858 };
2859 },
2860 .@"extern" => {
2861 // The alignment always matches that of the union pointer. If the union pointer is
2862 // default aligned (`.none`), we may need to explicitly align the result pointer.
2863 const field_ty = aggregate_ty.fieldType(field_index, zcu);
2864 var field_ptr_info = ptr_info;
2865 field_ptr_info.child = field_ty.toIntern();
2866 if (field_ptr_info.flags.alignment == .none and
2867 Alignment.compareStrict(field_ty.abiAlignment(zcu), .neq, aggregate_ty.abiAlignment(zcu)))
2868 {
2869 field_ptr_info.flags.alignment = aggregate_ty.abiAlignment(zcu);
2870 }
2871 return pt.ptrType(field_ptr_info);
2872 },
2873 .@"packed" => {
2874 const field_ty = aggregate_ty.fieldType(field_index, zcu);
2875 var field_ptr_info = ptr_info;
2876 if (field_ptr_info.flags.alignment == .none) {
2877 const resolved_align = aggregate_ty.abiAlignment(zcu);
2878 if (field_ty.abiAlignment(zcu) != resolved_align) {
2879 field_ptr_info.flags.alignment = resolved_align;
2880 }
2881 }
2882 field_ptr_info.child = aggregate_ty.fieldType(field_index, zcu).toIntern();
2883 return pt.ptrType(field_ptr_info);
2884 },
2885 },
2886 .pointer => field: {
2887 assert(aggregate_ty.isSlice(zcu));
2888 break :field switch (field_index) {
2889 Value.slice_ptr_index => .{ aggregate_ty.slicePtrFieldType(zcu), .none },
2890 Value.slice_len_index => .{ .usize, .none },
2891 else => unreachable,
2892 };
2893 },
2894 else => unreachable,
2895 };
2896 const field_ptr_align: Alignment = a: {
2897 if (aggregate_ty.zigTypeTag(zcu) == .@"struct" and aggregate_ty.structFieldIsComptime(field_index, zcu)) {
2898 // For `comptime` fields, just use exactly what was specified, or ABI alignment if nothing was specified.
2899 break :a field_align;
2900 }
2901 const actual_field_align = switch (field_align) {
2902 .none => switch (ip.indexToKey(aggregate_ty.toIntern())) {
2903 .tuple_type, .union_type => field_ty.abiAlignment(zcu),
2904 .struct_type => field_ty.defaultStructFieldAlignment(.auto, zcu),
2905 .ptr_type => Type.usize.abiAlignment(zcu),
2906 else => unreachable,
2907 },
2908 else => |a| a,
2909 };
2910 const actual_aggregate_align = switch (ptr_info.flags.alignment) {
2911 .none => aggregate_ty.abiAlignment(zcu),
2912 else => |a| a,
2913 };
2914 if (actual_aggregate_align.compareStrict(.lt, actual_field_align)) {
2915 // Underaligned aggregate; use that alignment.
2916 assert(ptr_info.flags.alignment != .none);
2917 break :a actual_aggregate_align;
2918 }
2919 if (field_align == .none and actual_field_align == field_ty.abiAlignment(zcu)) {
2920 // No explicit annotation on the field (nor an unusual default), and the aggregate
2921 // alignment is irrelevant to us, so return an un-annotated pointer.
2922 break :a .none;
2923 }
2924 break :a actual_field_align;
2925 };
2926 var field_ptr_info = ptr_info;
2927 field_ptr_info.flags.alignment = field_ptr_align;
2928 field_ptr_info.child = field_ty.toIntern();
2929 return pt.ptrType(field_ptr_info);
2930}
2931
2855pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTerminatedString {2932pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTerminatedString {
2856 return switch (ip.indexToKey(ty.toIntern())) {2933 return switch (ip.indexToKey(ty.toIntern())) {
2857 .struct_type => ip.loadStructType(ty.toIntern()).name,2934 .struct_type => ip.loadStructType(ty.toIntern()).name,
src/Value.zig+73-229
...@@ -1687,9 +1687,6 @@ pub fn makeBool(x: bool) Value {...@@ -1687,9 +1687,6 @@ pub fn makeBool(x: bool) Value {
1687/// `parent_ptr` must be a single-pointer or C pointer to some optional.1687/// `parent_ptr` must be a single-pointer or C pointer to some optional.
1688///1688///
1689/// Returns a pointer to the payload of the optional.1689/// Returns a pointer to the payload of the optional.
1690///
1691/// May perform type resolution.
1692/// MLUGG TODO audit
1693pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {1690pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
1694 const zcu = pt.zcu;1691 const zcu = pt.zcu;
1695 const parent_ptr_ty = parent_ptr.typeOf(zcu);1692 const parent_ptr_ty = parent_ptr.typeOf(zcu);
...@@ -1715,7 +1712,7 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {...@@ -1715,7 +1712,7 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
1715 }1712 }
17161713
1717 const base_ptr = try parent_ptr.canonicalizeBasePtr(.one, opt_ty, pt);1714 const base_ptr = try parent_ptr.canonicalizeBasePtr(.one, opt_ty, pt);
1718 return Value.fromInterned(try pt.intern(.{ .ptr = .{1715 return .fromInterned(try pt.intern(.{ .ptr = .{
1719 .ty = result_ty.toIntern(),1716 .ty = result_ty.toIntern(),
1720 .base_addr = .{ .opt_payload = base_ptr.toIntern() },1717 .base_addr = .{ .opt_payload = base_ptr.toIntern() },
1721 .byte_offset = 0,1718 .byte_offset = 0,
...@@ -1724,8 +1721,6 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {...@@ -1724,8 +1721,6 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
17241721
1725/// `parent_ptr` must be a single-pointer to some error union.1722/// `parent_ptr` must be a single-pointer to some error union.
1726/// Returns a pointer to the payload of the error union.1723/// Returns a pointer to the payload of the error union.
1727/// May perform type resolution.
1728/// MLUGG TODO audit
1729pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {1724pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
1730 const zcu = pt.zcu;1725 const zcu = pt.zcu;
1731 const parent_ptr_ty = parent_ptr.typeOf(zcu);1726 const parent_ptr_ty = parent_ptr.typeOf(zcu);
...@@ -1745,137 +1740,57 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {...@@ -1745,137 +1740,57 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
1745 if (parent_ptr.isUndef(zcu)) return pt.undefValue(result_ty);1740 if (parent_ptr.isUndef(zcu)) return pt.undefValue(result_ty);
17461741
1747 const base_ptr = try parent_ptr.canonicalizeBasePtr(.one, eu_ty, pt);1742 const base_ptr = try parent_ptr.canonicalizeBasePtr(.one, eu_ty, pt);
1748 return Value.fromInterned(try pt.intern(.{ .ptr = .{1743 return .fromInterned(try pt.intern(.{ .ptr = .{
1749 .ty = result_ty.toIntern(),1744 .ty = result_ty.toIntern(),
1750 .base_addr = .{ .eu_payload = base_ptr.toIntern() },1745 .base_addr = .{ .eu_payload = base_ptr.toIntern() },
1751 .byte_offset = 0,1746 .byte_offset = 0,
1752 } }));1747 } }));
1753}1748}
17541749
1755// MLUGG TODO: audit ptrField etc in terms of resolution, and probably move them under sema1750/// `parent_ptr` must be a single-item pointer or C pointer to a struct, union, or slice.
1756
1757/// `parent_ptr` must be a single-pointer or c pointer to a struct, union, or slice.
1758///1751///
1759/// Returns a pointer to the aggregate field at the specified index.1752/// Returns a pointer to the aggregate field at the specified index.
1760///1753///
1761/// For slices, uses `slice_ptr_index` and `slice_len_index`.1754/// For slices, uses `slice_ptr_index` and `slice_len_index`.
1762///1755///
1763/// May perform type resolution.1756/// Asserts that the layout of the aggregate type is resolved.
1764pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {1757pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
1765 const zcu = pt.zcu;1758 const zcu = pt.zcu;
1766 const parent_ptr_ty = parent_ptr.typeOf(zcu);1759 const parent_ptr_ty = parent_ptr.typeOf(zcu);
1767 const aggregate_ty = parent_ptr_ty.childType(zcu);1760 const aggregate_ty = parent_ptr_ty.childType(zcu);
1761 aggregate_ty.assertHasLayout(zcu);
17681762
1769 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);1763 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
1770 assert(parent_ptr_info.flags.size == .one or parent_ptr_info.flags.size == .c);1764 assert(parent_ptr_info.flags.size == .one or parent_ptr_info.flags.size == .c);
17711765
1772 // Exiting this `switch` indicates that the `field` pointer representation should be used.1766 const field_ptr_ty = try parent_ptr_ty.fieldPtrType(field_idx, pt);
1773 const field_ty: Type, const new_align: InternPool.Alignment = switch (aggregate_ty.zigTypeTag(zcu)) {1767
1774 .@"struct" => field: {1768 switch (aggregate_ty.zigTypeTag(zcu)) {
1775 const field_ty = aggregate_ty.fieldType(field_idx, zcu);1769 .pointer => assert(aggregate_ty.isSlice(zcu)),
1776 switch (aggregate_ty.containerLayout(zcu)) {1770 .@"struct" => switch (aggregate_ty.containerLayout(zcu)) {
1777 .auto => break :field .{ field_ty, a: {1771 .auto => {},
1778 if (parent_ptr_info.flags.alignment == .none) {1772 .@"extern" => return parent_ptr.getOffsetPtr(
1779 break :a aggregate_ty.explicitFieldAlignment(field_idx, zcu);1773 aggregate_ty.structFieldOffset(field_idx, zcu),
1780 }1774 field_ptr_ty,
1781 const field_align = aggregate_ty.resolvedFieldAlignment(field_idx, zcu);1775 pt,
1782 break :a field_align.min(parent_ptr_info.flags.alignment);1776 ),
1783 } },1777 .@"packed" => return pt.getCoerced(parent_ptr, field_ptr_ty),
1784 .@"extern" => {
1785 // Well-defined layout, so just offset the pointer appropriately.
1786 const byte_off = aggregate_ty.structFieldOffset(field_idx, zcu);
1787 const field_align: InternPool.Alignment = a: {
1788 if (byte_off == 0) break :a parent_ptr_info.flags.alignment;
1789 const true_field_align: InternPool.Alignment = .fromLog2Units(@ctz(byte_off));
1790 if (parent_ptr_info.flags.alignment == .none and
1791 true_field_align == field_ty.abiAlignment(zcu))
1792 {
1793 break :a .none;
1794 }
1795 const parent_align = if (parent_ptr_info.flags.alignment == .none) pa: {
1796 break :pa aggregate_ty.abiAlignment(zcu);
1797 } else parent_ptr_info.flags.alignment;
1798 break :a .minStrict(true_field_align, parent_align);
1799 };
1800 const result_ty = try pt.ptrType(info: {
1801 var new = parent_ptr_info;
1802 new.child = field_ty.toIntern();
1803 new.flags.alignment = field_align;
1804 break :info new;
1805 });
1806 return parent_ptr.getOffsetPtr(byte_off, result_ty, pt);
1807 },
1808 .@"packed" => {
1809 const packed_offset = aggregate_ty.packedStructFieldPtrInfo(parent_ptr_ty, field_idx, pt);
1810 const result_ty = try pt.ptrType(info: {
1811 var new = parent_ptr_info;
1812 new.packed_offset = packed_offset;
1813 new.child = field_ty.toIntern();
1814 if (new.flags.alignment == .none) {
1815 new.flags.alignment = aggregate_ty.abiAlignment(zcu);
1816 }
1817 break :info new;
1818 });
1819 return pt.getCoerced(parent_ptr, result_ty);
1820 },
1821 }
1822 },
1823 .@"union" => field: {
1824 const union_obj = zcu.typeToUnion(aggregate_ty).?;
1825 const field_ty = Type.fromInterned(union_obj.field_types.get(&zcu.intern_pool)[field_idx]);
1826 switch (aggregate_ty.containerLayout(zcu)) {
1827 .auto => break :field .{ field_ty, a: {
1828 if (parent_ptr_info.flags.alignment == .none) {
1829 break :a aggregate_ty.explicitFieldAlignment(field_idx, zcu);
1830 }
1831 const field_align = aggregate_ty.resolvedFieldAlignment(field_idx, zcu);
1832 break :a field_align.min(parent_ptr_info.flags.alignment);
1833 } },
1834 .@"extern" => {
1835 // Point to the same address.
1836 const result_ty = try pt.ptrType(info: {
1837 var new = parent_ptr_info;
1838 new.child = field_ty.toIntern();
1839 break :info new;
1840 });
1841 return pt.getCoerced(parent_ptr, result_ty);
1842 },
1843 .@"packed" => {
1844 const result_ty = try pt.ptrType(info: {
1845 var new = parent_ptr_info;
1846 new.child = field_ty.toIntern();
1847 break :info new;
1848 });
1849 return pt.getCoerced(parent_ptr, result_ty);
1850 },
1851 }
1852 },1778 },
1853 .pointer => field_ty: {1779 .@"union" => switch (aggregate_ty.containerLayout(zcu)) {
1854 assert(aggregate_ty.isSlice(zcu));1780 .auto => {},
1855 break :field_ty .{ switch (field_idx) {1781 .@"packed", .@"extern" => return pt.getCoerced(parent_ptr, field_ptr_ty),
1856 Value.slice_ptr_index => aggregate_ty.slicePtrFieldType(zcu),
1857 Value.slice_len_index => Type.usize,
1858 else => unreachable,
1859 }, switch (parent_ptr_info.flags.alignment) {
1860 .none => .none,
1861 else => Type.usize.abiAlignment(zcu).min(parent_ptr_info.flags.alignment),
1862 } };
1863 },1782 },
1864 else => unreachable,1783 else => unreachable,
1865 };1784 }
18661785
1867 const result_ty = try pt.ptrType(info: {1786 // If we get here, we need to use the `.field` comptime pointer representation, because the
1868 var new = parent_ptr_info;1787 // aggregate does not have a well-defined layout.
1869 new.child = field_ty.toIntern();
1870 new.flags.alignment = new_align;
1871 break :info new;
1872 });
18731788
1874 if (parent_ptr.isUndef(zcu)) return pt.undefValue(result_ty);1789 if (parent_ptr.isUndef(zcu)) return pt.undefValue(field_ptr_ty);
18751790
1876 const base_ptr = try parent_ptr.canonicalizeBasePtr(.one, aggregate_ty, pt);1791 const base_ptr = try parent_ptr.canonicalizeBasePtr(.one, aggregate_ty, pt);
1877 return Value.fromInterned(try pt.intern(.{ .ptr = .{1792 return .fromInterned(try pt.intern(.{ .ptr = .{
1878 .ty = result_ty.toIntern(),1793 .ty = field_ptr_ty.toIntern(),
1879 .base_addr = .{ .field = .{1794 .base_addr = .{ .field = .{
1880 .base = base_ptr.toIntern(),1795 .base = base_ptr.toIntern(),
1881 .index = field_idx,1796 .index = field_idx,
...@@ -1884,10 +1799,9 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {...@@ -1884,10 +1799,9 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
1884 } }));1799 } }));
1885}1800}
18861801
1887/// `orig_parent_ptr` must be either a single-pointer to an array or vector, or a many-pointer or C-pointer or slice.1802/// `orig_parent_ptr` must be either a single-pointer to an array, a slice, a many-item pointer, or a C pointer.
1888/// Returns a pointer to the element at the specified index.1803/// Returns a pointer to the element at the specified index.
1889/// May perform type resolution.1804/// Asserts that the layout of the pointer element type is resolved.
1890/// MLUGG TODO AUDIT
1891pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value {1805pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value {
1892 const zcu = pt.zcu;1806 const zcu = pt.zcu;
1893 const parent_ptr = switch (orig_parent_ptr.typeOf(zcu).ptrSize(zcu)) {1807 const parent_ptr = switch (orig_parent_ptr.typeOf(zcu).ptrSize(zcu)) {
...@@ -1896,77 +1810,50 @@ pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value...@@ -1896,77 +1810,50 @@ pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value
1896 };1810 };
18971811
1898 const parent_ptr_ty = parent_ptr.typeOf(zcu);1812 const parent_ptr_ty = parent_ptr.typeOf(zcu);
1899 const elem_ty = parent_ptr_ty.childType(zcu);1813 const result_ty = try parent_ptr_ty.elemPtrType(field_idx, pt);
1900 const result_ty = try parent_ptr_ty.elemPtrType(@intCast(field_idx), pt);1814 const elem_ty = result_ty.childType(zcu);
1815 elem_ty.assertHasLayout(zcu);
19011816
1902 if (parent_ptr.isUndef(zcu)) return pt.undefValue(result_ty);1817 if (parent_ptr.isUndef(zcu)) return pt.undefValue(result_ty);
19031818
1904 if (result_ty.ptrInfo(zcu).packed_offset.host_size != 0) {1819 if (!elem_ty.comptimeOnly(zcu)) {
1905 // Since we have a bit-pointer, the pointer address should be unchanged.1820 const byte_offset = field_idx * elem_ty.abiSize(zcu);
1906 assert(elem_ty.zigTypeTag(zcu) == .vector);1821 return parent_ptr.getOffsetPtr(byte_offset, result_ty, pt);
1907 return pt.getCoerced(parent_ptr, result_ty);
1908 }1822 }
19091823
1910 const PtrStrat = union(enum) {1824 // Comptime-only element type.
1911 offset: u64,
1912 elem_ptr: Type, // many-ptr elem ty
1913 };
1914
1915 const strat: PtrStrat = switch (parent_ptr_ty.ptrSize(zcu)) {
1916 .one => switch (elem_ty.zigTypeTag(zcu)) {
1917 .vector => .{ .offset = field_idx * @divExact(elem_ty.childType(zcu).bitSize(zcu), 8) },
1918 .array => strat: {
1919 const arr_elem_ty = elem_ty.childType(zcu);
1920 if (arr_elem_ty.comptimeOnly(zcu)) break :strat .{ .elem_ptr = arr_elem_ty };
1921 break :strat .{ .offset = field_idx * arr_elem_ty.abiSize(zcu) };
1922 },
1923 else => unreachable,
1924 },
1925
1926 .many, .c => if (elem_ty.comptimeOnly(zcu))
1927 .{ .elem_ptr = elem_ty }
1928 else
1929 .{ .offset = field_idx * elem_ty.abiSize(zcu) },
19301825
1931 .slice => unreachable,1826 if (field_idx == 0) {
1932 };1827 return pt.getCoerced(parent_ptr, result_ty);
1828 }
19331829
1934 switch (strat) {1830 const arr_base_ty, const arr_base_len = elem_ty.arrayBase(zcu);
1935 .offset => |byte_offset| {1831 const base_idx = arr_base_len * field_idx;
1936 return parent_ptr.getOffsetPtr(byte_offset, result_ty, pt);1832 const parent_info = zcu.intern_pool.indexToKey(parent_ptr.toIntern()).ptr;
1937 },1833 switch (parent_info.base_addr) {
1938 .elem_ptr => |manyptr_elem_ty| if (field_idx == 0) {1834 .arr_elem => |arr_elem| {
1939 return pt.getCoerced(parent_ptr, result_ty);1835 if (Value.fromInterned(arr_elem.base).typeOf(zcu).childType(zcu).toIntern() == arr_base_ty.toIntern()) {
1940 } else {1836 // We already have a pointer to an element of an array of this type.
1941 const arr_base_ty, const arr_base_len = manyptr_elem_ty.arrayBase(zcu);1837 // Just modify the index.
1942 const base_idx = arr_base_len * field_idx;1838 return .fromInterned(try pt.intern(.{ .ptr = ptr: {
1943 const parent_info = zcu.intern_pool.indexToKey(parent_ptr.toIntern()).ptr;1839 var new = parent_info;
1944 switch (parent_info.base_addr) {1840 new.base_addr.arr_elem.index += base_idx;
1945 .arr_elem => |arr_elem| {1841 new.ty = result_ty.toIntern();
1946 if (Value.fromInterned(arr_elem.base).typeOf(zcu).childType(zcu).toIntern() == arr_base_ty.toIntern()) {1842 break :ptr new;
1947 // We already have a pointer to an element of an array of this type.1843 } }));
1948 // Just modify the index.
1949 return Value.fromInterned(try pt.intern(.{ .ptr = ptr: {
1950 var new = parent_info;
1951 new.base_addr.arr_elem.index += base_idx;
1952 new.ty = result_ty.toIntern();
1953 break :ptr new;
1954 } }));
1955 }
1956 },
1957 else => {},
1958 }1844 }
1959 const base_ptr = try parent_ptr.canonicalizeBasePtr(.many, arr_base_ty, pt);
1960 return Value.fromInterned(try pt.intern(.{ .ptr = .{
1961 .ty = result_ty.toIntern(),
1962 .base_addr = .{ .arr_elem = .{
1963 .base = base_ptr.toIntern(),
1964 .index = base_idx,
1965 } },
1966 .byte_offset = 0,
1967 } }));
1968 },1845 },
1846 else => {},
1969 }1847 }
1848 const base_ptr = try parent_ptr.canonicalizeBasePtr(.many, arr_base_ty, pt);
1849 return .fromInterned(try pt.intern(.{ .ptr = .{
1850 .ty = result_ty.toIntern(),
1851 .base_addr = .{ .arr_elem = .{
1852 .base = base_ptr.toIntern(),
1853 .index = base_idx,
1854 } },
1855 .byte_offset = 0,
1856 } }));
1970}1857}
19711858
1972fn canonicalizeBasePtr(base_ptr: Value, want_size: std.builtin.Type.Pointer.Size, want_child: Type, pt: Zcu.PerThread) !Value {1859fn canonicalizeBasePtr(base_ptr: Value, want_size: std.builtin.Type.Pointer.Size, want_child: Type, pt: Zcu.PerThread) !Value {
...@@ -2062,19 +1949,11 @@ pub const PointerDeriveStep = union(enum) {...@@ -2062,19 +1949,11 @@ pub const PointerDeriveStep = union(enum) {
2062 }1949 }
2063};1950};
20641951
2065pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Allocator.Error!PointerDeriveStep {
2066 return ptr_val.pointerDerivationAdvanced(arena, pt, false, null) catch |err| switch (err) {
2067 error.OutOfMemory => |e| return e,
2068 error.Canceled => @panic("TODO"), // pls remove from error set mlugg
2069 error.AnalysisFail => unreachable,
2070 };
2071}
2072
2073/// Given a pointer value, get the sequence of steps to derive it, ideally by taking1952/// Given a pointer value, get the sequence of steps to derive it, ideally by taking
2074/// only field and element pointers with no casts. This can be used by codegen backends1953/// only field and element pointers with no casts. This can be used by codegen backends
2075/// which prefer field/elem accesses when lowering constant pointer values.1954/// which prefer field/elem accesses when lowering constant pointer values.
2076/// It is also used by the Value printing logic for pointers.1955/// It is also used by the Value printing logic for pointers.
2077pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, comptime resolve_types: bool, opt_sema: ?*Sema) !PointerDeriveStep {1956pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, opt_sema: ?*Sema) Allocator.Error!PointerDeriveStep {
2078 // MLUGG TODO: audit tf outta this code1957 // MLUGG TODO: audit tf outta this code
2079 const zcu = pt.zcu;1958 const zcu = pt.zcu;
2080 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;1959 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
...@@ -2118,7 +1997,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -2118,7 +1997,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
2118 const base_ptr = Value.fromInterned(eu_ptr);1997 const base_ptr = Value.fromInterned(eu_ptr);
2119 const base_ptr_ty = base_ptr.typeOf(zcu);1998 const base_ptr_ty = base_ptr.typeOf(zcu);
2120 const parent_step = try arena.create(PointerDeriveStep);1999 const parent_step = try arena.create(PointerDeriveStep);
2121 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(eu_ptr), arena, pt, resolve_types, opt_sema);2000 parent_step.* = try pointerDerivation(.fromInterned(eu_ptr), arena, pt, opt_sema);
2122 break :base .{ .eu_payload_ptr = .{2001 break :base .{ .eu_payload_ptr = .{
2123 .parent = parent_step,2002 .parent = parent_step,
2124 .result_ptr_ty = try pt.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).errorUnionPayload(zcu)),2003 .result_ptr_ty = try pt.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).errorUnionPayload(zcu)),
...@@ -2128,7 +2007,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -2128,7 +2007,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
2128 const base_ptr = Value.fromInterned(opt_ptr);2007 const base_ptr = Value.fromInterned(opt_ptr);
2129 const base_ptr_ty = base_ptr.typeOf(zcu);2008 const base_ptr_ty = base_ptr.typeOf(zcu);
2130 const parent_step = try arena.create(PointerDeriveStep);2009 const parent_step = try arena.create(PointerDeriveStep);
2131 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(opt_ptr), arena, pt, resolve_types, opt_sema);2010 parent_step.* = try pointerDerivation(.fromInterned(opt_ptr), arena, pt, opt_sema);
2132 break :base .{ .opt_payload_ptr = .{2011 break :base .{ .opt_payload_ptr = .{
2133 .parent = parent_step,2012 .parent = parent_step,
2134 .result_ptr_ty = try pt.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).optionalChild(zcu)),2013 .result_ptr_ty = try pt.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).optionalChild(zcu)),
...@@ -2137,48 +2016,27 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -2137,48 +2016,27 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
2137 .field => |field| base: {2016 .field => |field| base: {
2138 const base_ptr = Value.fromInterned(field.base);2017 const base_ptr = Value.fromInterned(field.base);
2139 const base_ptr_ty = base_ptr.typeOf(zcu);2018 const base_ptr_ty = base_ptr.typeOf(zcu);
2140 const agg_ty = base_ptr_ty.childType(zcu);
2141 if (resolve_types) try opt_sema.?.ensureLayoutResolved(agg_ty, .unneeded); // MLUGG TODO: unneeded is a hack
2142 const field_ty: Type, const field_align: InternPool.Alignment = switch (agg_ty.zigTypeTag(zcu)) {
2143 .@"struct", .@"union" => .{ agg_ty.fieldType(@intCast(field.index), zcu), agg_ty.resolvedFieldAlignment(@intCast(field.index), pt.zcu) },
2144 .pointer => switch (field.index) {
2145 Value.slice_ptr_index => .{ agg_ty.slicePtrFieldType(zcu), Type.ptrAbiAlignment(zcu.getTarget()) },
2146 Value.slice_len_index => .{ .usize, Type.abiAlignment(.usize, zcu) },
2147 else => unreachable,
2148 },
2149 else => unreachable,
2150 };
2151 const base_align = base_ptr_ty.ptrAlignment(zcu);
2152 const result_align = field_align.minStrict(base_align);
2153 const result_ty = try pt.ptrType(.{
2154 .child = field_ty.toIntern(),
2155 .flags = flags: {
2156 var flags = base_ptr_ty.ptrInfo(zcu).flags;
2157 if (result_align == field_ty.abiAlignment(zcu)) {
2158 flags.alignment = .none;
2159 } else {
2160 flags.alignment = result_align;
2161 }
2162 break :flags flags;
2163 },
2164 });
2165 const parent_step = try arena.create(PointerDeriveStep);2019 const parent_step = try arena.create(PointerDeriveStep);
2166 parent_step.* = try pointerDerivationAdvanced(base_ptr, arena, pt, resolve_types, opt_sema);2020 parent_step.* = try pointerDerivation(base_ptr, arena, pt, opt_sema);
2167 break :base .{ .field_ptr = .{2021 break :base .{ .field_ptr = .{
2168 .parent = parent_step,2022 .parent = parent_step,
2169 .field_idx = @intCast(field.index),2023 .field_idx = @intCast(field.index),
2170 .result_ptr_ty = result_ty,2024 .result_ptr_ty = try base_ptr_ty.fieldPtrType(@intCast(field.index), pt),
2171 } };2025 } };
2172 },2026 },
2173 .arr_elem => |arr_elem| base: {2027 .arr_elem => |arr_elem| base: {
2174 const parent_step = try arena.create(PointerDeriveStep);2028 const parent_step = try arena.create(PointerDeriveStep);
2175 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(arr_elem.base), arena, pt, resolve_types, opt_sema);2029 parent_step.* = try pointerDerivation(.fromInterned(arr_elem.base), arena, pt, opt_sema);
2176 const parent_ptr_info = (try parent_step.ptrType(pt)).ptrInfo(zcu);2030 const parent_ptr_info = (try parent_step.ptrType(pt)).ptrInfo(zcu);
2177 const result_ptr_ty = try pt.ptrType(.{2031 const result_ptr_ty = try pt.ptrType(.{
2178 .child = parent_ptr_info.child,2032 .child = parent_ptr_info.child,
2179 .flags = flags: {2033 .flags = flags: {
2180 var flags = parent_ptr_info.flags;2034 var flags = parent_ptr_info.flags;
2181 flags.size = .one;2035 flags.size = .one;
2036 if (flags.alignment != .none) flags.alignment = .minStrict(
2037 flags.alignment,
2038 Type.fromInterned(parent_ptr_info.child).abiAlignment(zcu),
2039 );
2182 break :flags flags;2040 break :flags flags;
2183 },2041 },
2184 });2042 });
...@@ -2299,26 +2157,12 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -2299,26 +2157,12 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
2299 const end_off = start_off + field_ty.abiSize(zcu);2157 const end_off = start_off + field_ty.abiSize(zcu);
2300 if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {2158 if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {
2301 const old_ptr_ty = try cur_derive.ptrType(pt);2159 const old_ptr_ty = try cur_derive.ptrType(pt);
2302 const parent_align = old_ptr_ty.ptrAlignment(zcu);
2303 const field_align = InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(start_off)));
2304 const parent = try arena.create(PointerDeriveStep);2160 const parent = try arena.create(PointerDeriveStep);
2305 parent.* = cur_derive;2161 parent.* = cur_derive;
2306 const new_ptr_ty = try pt.ptrType(.{
2307 .child = field_ty.toIntern(),
2308 .flags = flags: {
2309 var flags = old_ptr_ty.ptrInfo(zcu).flags;
2310 if (field_align == field_ty.abiAlignment(zcu)) {
2311 flags.alignment = .none;
2312 } else {
2313 flags.alignment = field_align;
2314 }
2315 break :flags flags;
2316 },
2317 });
2318 cur_derive = .{ .field_ptr = .{2162 cur_derive = .{ .field_ptr = .{
2319 .parent = parent,2163 .parent = parent,
2320 .field_idx = @intCast(field_idx),2164 .field_idx = @intCast(field_idx),
2321 .result_ptr_ty = new_ptr_ty,2165 .result_ptr_ty = try old_ptr_ty.fieldPtrType(@intCast(field_idx), pt),
2322 } };2166 } };
2323 cur_offset -= start_off;2167 cur_offset -= start_off;
2324 break;2168 break;
src/Zcu.zig+3-3
...@@ -3813,9 +3813,9 @@ pub const AtomicPtrAlignmentDiagnostics = struct {...@@ -3813,9 +3813,9 @@ pub const AtomicPtrAlignmentDiagnostics = struct {
3813 max_bits: u16 = undefined,3813 max_bits: u16 = undefined,
3814};3814};
38153815
3816/// If ABI alignment of `ty` is OK for atomic operations, returns 0.3816/// Returns the alignment required for the target to perform atomic operations on type `ty` (that
3817/// Otherwise returns the alignment required on a pointer for the target3817/// is, the required align attribute on the pointer). If the ABI alignment of `ty` is sufficient,
3818/// to perform atomic operations.3818/// returns `.none`.
3819// TODO this function does not take into account CPU features, which can affect3819// TODO this function does not take into account CPU features, which can affect
3820// this value. Audit this!3820// this value. Audit this!
3821pub fn atomicPtrAlignment(3821pub fn atomicPtrAlignment(
src/Zcu/PerThread.zig+11-13
...@@ -3943,10 +3943,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err...@@ -3943,10 +3943,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err
3943 return pt.ptrType(.{3943 return pt.ptrType(.{
3944 .child = ty,3944 .child = ty,
3945 .flags = .{3945 .flags = .{
3946 .alignment = if (alignment == Type.fromInterned(ty).abiAlignment(zcu))3946 .alignment = alignment,
3947 .none
3948 else
3949 alignment,
3950 .address_space = @"addrspace",3947 .address_space = @"addrspace",
3951 .is_const = is_const,3948 .is_const = is_const,
3952 },3949 },
...@@ -4015,23 +4012,24 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace...@@ -4015,23 +4012,24 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
4015 namespace.generation = zcu.generation;4012 namespace.generation = zcu.generation;
4016}4013}
40174014
4018pub fn refValue(pt: Zcu.PerThread, val: InternPool.Index) Zcu.SemaError!InternPool.Index {4015pub fn uavValue(pt: Zcu.PerThread, val: Value) Zcu.SemaError!Value {
4019 const ptr_ty = (try pt.ptrType(.{4016 const zcu = pt.zcu;
4020 .child = pt.zcu.intern_pool.typeOf(val),4017 const ptr_ty = try pt.ptrType(.{
4018 .child = val.typeOf(zcu).toIntern(),
4021 .flags = .{4019 .flags = .{
4022 .alignment = .none,4020 .alignment = .none,
4023 .is_const = true,4021 .is_const = true,
4024 .address_space = .generic,4022 .address_space = .generic,
4025 },4023 },
4026 })).toIntern();4024 });
4027 return pt.intern(.{ .ptr = .{4025 return .fromInterned(try pt.intern(.{ .ptr = .{
4028 .ty = ptr_ty,4026 .ty = ptr_ty.toIntern(),
4029 .base_addr = .{ .uav = .{4027 .base_addr = .{ .uav = .{
4030 .val = val,4028 .val = val.toIntern(),
4031 .orig_ty = ptr_ty,4029 .orig_ty = ptr_ty.toIntern(),
4032 } },4030 } },
4033 .byte_offset = 0,4031 .byte_offset = 0,
4034 } });4032 } }));
4035}4033}
40364034
4037pub fn addDependency(pt: Zcu.PerThread, unit: AnalUnit, dependee: InternPool.Dependee) Allocator.Error!void {4035pub fn addDependency(pt: Zcu.PerThread, unit: AnalUnit, dependee: InternPool.Dependee) Allocator.Error!void {
src/codegen/c.zig+1-1
...@@ -1215,7 +1215,7 @@ pub const DeclGen = struct {...@@ -1215,7 +1215,7 @@ pub const DeclGen = struct {
1215 .ptr => {1215 .ptr => {
1216 var arena = std.heap.ArenaAllocator.init(zcu.gpa);1216 var arena = std.heap.ArenaAllocator.init(zcu.gpa);
1217 defer arena.deinit();1217 defer arena.deinit();
1218 const derivation = try val.pointerDerivation(arena.allocator(), pt);1218 const derivation = try val.pointerDerivation(arena.allocator(), pt, null);
1219 try dg.renderPointer(w, derivation, location);1219 try dg.renderPointer(w, derivation, location);
1220 },1220 },
1221 .opt => |opt| switch (ctype.info(ctype_pool)) {1221 .opt => |opt| switch (ctype.info(ctype_pool)) {
src/codegen/spirv/CodeGen.zig+1-1
...@@ -1038,7 +1038,7 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {...@@ -1038,7 +1038,7 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
1038 var arena = std.heap.ArenaAllocator.init(gpa);1038 var arena = std.heap.ArenaAllocator.init(gpa);
1039 defer arena.deinit();1039 defer arena.deinit();
10401040
1041 const derivation = try ptr_val.pointerDerivation(arena.allocator(), pt);1041 const derivation = try ptr_val.pointerDerivation(arena.allocator(), pt, null);
1042 return cg.derivePtr(derivation);1042 return cg.derivePtr(derivation);
1043}1043}
10441044
src/print_value.zig+6-14
...@@ -25,10 +25,7 @@ pub fn formatSema(ctx: FormatContext, writer: *Writer) Writer.Error!void {...@@ -25,10 +25,7 @@ pub fn formatSema(ctx: FormatContext, writer: *Writer) Writer.Error!void {
25 const sema = ctx.opt_sema.?;25 const sema = ctx.opt_sema.?;
26 return print(ctx.val, writer, ctx.depth, ctx.pt, sema) catch |err| switch (err) {26 return print(ctx.val, writer, ctx.depth, ctx.pt, sema) catch |err| switch (err) {
27 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function27 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
28 error.ComptimeBreak, error.ComptimeReturn => unreachable,28 error.WriteFailed => |e| return e,
29 error.AnalysisFail => unreachable, // TODO: re-evaluate when we use `sema` more fully
30 error.Canceled => @panic("TODO"), // pls stop returning this error mlugg
31 else => |e| return e,
32 };29 };
33}30}
3431
...@@ -36,9 +33,7 @@ pub fn format(ctx: FormatContext, writer: *Writer) Writer.Error!void {...@@ -36,9 +33,7 @@ pub fn format(ctx: FormatContext, writer: *Writer) Writer.Error!void {
36 std.debug.assert(ctx.opt_sema == null);33 std.debug.assert(ctx.opt_sema == null);
37 return print(ctx.val, writer, ctx.depth, ctx.pt, null) catch |err| switch (err) {34 return print(ctx.val, writer, ctx.depth, ctx.pt, null) catch |err| switch (err) {
38 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function35 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
39 error.ComptimeBreak, error.ComptimeReturn, error.AnalysisFail => unreachable,36 error.WriteFailed => |e| return e,
40 error.Canceled => @panic("TODO"), // pls stop returning this error mlugg
41 else => |e| return e,
42 };37 };
43}38}
4439
...@@ -48,7 +43,7 @@ pub fn print(...@@ -48,7 +43,7 @@ pub fn print(
48 level: u8,43 level: u8,
49 pt: Zcu.PerThread,44 pt: Zcu.PerThread,
50 opt_sema: ?*Sema,45 opt_sema: ?*Sema,
51) (Writer.Error || Zcu.CompileError)!void {46) (Writer.Error || Allocator.Error)!void {
52 const zcu = pt.zcu;47 const zcu = pt.zcu;
53 const ip = &zcu.intern_pool;48 const ip = &zcu.intern_pool;
54 switch (ip.indexToKey(val.toIntern())) {49 switch (ip.indexToKey(val.toIntern())) {
...@@ -212,7 +207,7 @@ fn printAggregate(...@@ -212,7 +207,7 @@ fn printAggregate(
212 level: u8,207 level: u8,
213 pt: Zcu.PerThread,208 pt: Zcu.PerThread,
214 opt_sema: ?*Sema,209 opt_sema: ?*Sema,
215) (Writer.Error || Zcu.CompileError)!void {210) (Writer.Error || Allocator.Error)!void {
216 if (level == 0) {211 if (level == 0) {
217 if (is_ref) try writer.writeByte('&');212 if (is_ref) try writer.writeByte('&');
218 return writer.writeAll(".{ ... }");213 return writer.writeAll(".{ ... }");
...@@ -307,7 +302,7 @@ fn printPtr(...@@ -307,7 +302,7 @@ fn printPtr(
307 level: u8,302 level: u8,
308 pt: Zcu.PerThread,303 pt: Zcu.PerThread,
309 opt_sema: ?*Sema,304 opt_sema: ?*Sema,
310) (Writer.Error || Zcu.CompileError)!void {305) (Writer.Error || Allocator.Error)!void {
311 const ptr = switch (pt.zcu.intern_pool.indexToKey(ptr_val.toIntern())) {306 const ptr = switch (pt.zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
312 .undef => return writer.writeAll("undefined"),307 .undef => return writer.writeAll("undefined"),
313 .ptr => |ptr| ptr,308 .ptr => |ptr| ptr,
...@@ -332,10 +327,7 @@ fn printPtr(...@@ -332,10 +327,7 @@ fn printPtr(
332327
333 var arena = std.heap.ArenaAllocator.init(pt.zcu.gpa);328 var arena = std.heap.ArenaAllocator.init(pt.zcu.gpa);
334 defer arena.deinit();329 defer arena.deinit();
335 const derivation = if (opt_sema) |sema|330 const derivation = try ptr_val.pointerDerivation(arena.allocator(), pt, opt_sema);
336 try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, true, sema)
337 else
338 try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, false, null);
339331
340 _ = try printPtrDerivation(derivation, writer, pt, want_kind, .{ .print_val = .{332 _ = try printPtrDerivation(derivation, writer, pt, want_kind, .{ .print_val = .{
341 .level = level,333 .level = level,