authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-04-17 12:35:35-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-04-17 12:35:35-07:00
log1fb23813166e768a59bc7468d09bcb2e8e0f8f03
treeea6746763647264d62389f73768662184d32c82e
parent77abd3a96aa8c8c1277cdbb33d88149d4674d389
parent23062a5bed285f72e35651dd1e8b4a125b83dba0
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19630 from mlugg/comptime-ptr-access-5

compiler: rework comptime pointer representation and access

46 files changed, 4843 insertions(+), 2534 deletions(-)

lib/compiler/resinator/ico.zig+2-2
......@@ -232,7 +232,7 @@ test "icon data size too small" {
232232 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));
233233}
234234
235pub const ImageFormat = enum {
235pub const ImageFormat = enum(u2) {
236236 dib,
237237 png,
238238 riff,
......@@ -272,7 +272,7 @@ pub const BitmapHeader = extern struct {
272272 }
273273
274274 /// https://en.wikipedia.org/wiki/BMP_file_format#DIB_header_(bitmap_information_header)
275 pub const Version = enum {
275 pub const Version = enum(u3) {
276276 unknown,
277277 @"win2.0", // Windows 2.0 or later
278278 @"nt3.1", // Windows NT, 3.1x or later
lib/docs/wasm/markdown/Document.zig+1-1
......@@ -131,7 +131,7 @@ pub const Node = struct {
131131 }
132132 };
133133
134 pub const TableCellAlignment = enum {
134 pub const TableCellAlignment = enum(u2) {
135135 unset,
136136 left,
137137 center,
lib/std/net.zig+1-1
......@@ -271,7 +271,7 @@ pub const Ip4Address = extern struct {
271271 sa: posix.sockaddr.in,
272272
273273 pub fn parse(buf: []const u8, port: u16) IPv4ParseError!Ip4Address {
274 var result = Ip4Address{
274 var result: Ip4Address = .{
275275 .sa = .{
276276 .port = mem.nativeToBig(u16, port),
277277 .addr = undefined,
src/InternPool.zig+312-140
......@@ -565,7 +565,7 @@ pub const OptionalNullTerminatedString = enum(u32) {
565565/// * decl val (so that we can analyze the value lazily)
566566/// * decl ref (so that we can analyze the reference lazily)
567567pub const CaptureValue = packed struct(u32) {
568 tag: enum { @"comptime", runtime, decl_val, decl_ref },
568 tag: enum(u2) { @"comptime", runtime, decl_val, decl_ref },
569569 idx: u30,
570570
571571 pub fn wrap(val: Unwrapped) CaptureValue {
......@@ -1026,22 +1026,76 @@ pub const Key = union(enum) {
10261026 pub const Ptr = struct {
10271027 /// This is the pointer type, not the element type.
10281028 ty: Index,
1029 /// The value of the address that the pointer points to.
1030 addr: Addr,
1029 /// The base address which this pointer is offset from.
1030 base_addr: BaseAddr,
1031 /// The offset of this pointer from `base_addr` in bytes.
1032 byte_offset: u64,
10311033
1032 pub const Addr = union(enum) {
1033 const Tag = @typeInfo(Addr).Union.tag_type.?;
1034 pub const BaseAddr = union(enum) {
1035 const Tag = @typeInfo(BaseAddr).Union.tag_type.?;
10341036
1037 /// Points to the value of a single `Decl`, which may be constant or a `variable`.
10351038 decl: DeclIndex,
1039
1040 /// Points to the value of a single comptime alloc stored in `Sema`.
10361041 comptime_alloc: ComptimeAllocIndex,
1042
1043 /// Points to a single unnamed constant value.
10371044 anon_decl: AnonDecl,
1045
1046 /// Points to a comptime field of a struct. Index is the field's value.
1047 ///
1048 /// TODO: this exists because these fields are semantically mutable. We
1049 /// should probably change the language so that this isn't the case.
10381050 comptime_field: Index,
1039 int: Index,
1051
1052 /// A pointer with a fixed integer address, usually from `@ptrFromInt`.
1053 ///
1054 /// The address is stored entirely by `byte_offset`, which will be positive
1055 /// and in-range of a `usize`. The base address is, for all intents and purposes, 0.
1056 int,
1057
1058 /// A pointer to the payload of an error union. Index is the error union pointer.
1059 /// To ensure a canonical representation, the type of the base pointer must:
1060 /// * be a one-pointer
1061 /// * be `const`, `volatile` and `allowzero`
1062 /// * have alignment 1
1063 /// * have the same address space as this pointer
1064 /// * have a host size, bit offset, and vector index of 0
1065 /// See `Value.canonicalizeBasePtr` which enforces these properties.
10401066 eu_payload: Index,
1067
1068 /// A pointer to the payload of a non-pointer-like optional. Index is the
1069 /// optional pointer. To ensure a canonical representation, the base
1070 /// pointer is subject to the same restrictions as in `eu_payload`.
10411071 opt_payload: Index,
1042 elem: BaseIndex,
1072
1073 /// A pointer to a field of a slice, or of an auto-layout struct or union. Slice fields
1074 /// are referenced according to `Value.slice_ptr_index` and `Value.slice_len_index`.
1075 /// Base is the aggregate pointer, which is subject to the same restrictions as
1076 /// in `eu_payload`.
10431077 field: BaseIndex,
10441078
1079 /// A pointer to an element of a comptime-only array. Base is the
1080 /// many-pointer we are indexing into. It is subject to the same restrictions
1081 /// as in `eu_payload`, except it must be a many-pointer rather than a one-pointer.
1082 ///
1083 /// The element type of the base pointer must NOT be an array. Additionally, the
1084 /// base pointer is guaranteed to not be an `arr_elem` into a pointer with the
1085 /// same child type. Thus, since there are no two comptime-only types which are
1086 /// IMC to one another, the only case where the base pointer may also be an
1087 /// `arr_elem` is when this pointer is semantically invalid (e.g. it reinterprets
1088 /// a `type` as a `comptime_int`). These restrictions are in place to ensure
1089 /// a canonical representation.
1090 ///
1091 /// This kind of base address differs from others in that it may refer to any
1092 /// sequence of values; for instance, an `arr_elem` at index 2 may refer to
1093 /// any number of elements starting from index 2.
1094 ///
1095 /// Index must not be 0. To refer to the element at index 0, simply reinterpret
1096 /// the aggregate pointer.
1097 arr_elem: BaseIndex,
1098
10451099 pub const MutDecl = struct {
10461100 decl: DeclIndex,
10471101 runtime_index: RuntimeIndex,
......@@ -1222,10 +1276,11 @@ pub const Key = union(enum) {
12221276 .ptr => |ptr| {
12231277 // Int-to-ptr pointers are hashed separately than decl-referencing pointers.
12241278 // This is sound due to pointer provenance rules.
1225 const addr: @typeInfo(Key.Ptr.Addr).Union.tag_type.? = ptr.addr;
1226 const seed2 = seed + @intFromEnum(addr);
1227 const common = asBytes(&ptr.ty);
1228 return switch (ptr.addr) {
1279 const addr_tag: Key.Ptr.BaseAddr.Tag = ptr.base_addr;
1280 const seed2 = seed + @intFromEnum(addr_tag);
1281 const big_offset: i128 = ptr.byte_offset;
1282 const common = asBytes(&ptr.ty) ++ asBytes(&big_offset);
1283 return switch (ptr.base_addr) {
12291284 inline .decl,
12301285 .comptime_alloc,
12311286 .anon_decl,
......@@ -1235,7 +1290,7 @@ pub const Key = union(enum) {
12351290 .comptime_field,
12361291 => |x| Hash.hash(seed2, common ++ asBytes(&x)),
12371292
1238 .elem, .field => |x| Hash.hash(
1293 .arr_elem, .field => |x| Hash.hash(
12391294 seed2,
12401295 common ++ asBytes(&x.base) ++ asBytes(&x.index),
12411296 ),
......@@ -1494,21 +1549,21 @@ pub const Key = union(enum) {
14941549 .ptr => |a_info| {
14951550 const b_info = b.ptr;
14961551 if (a_info.ty != b_info.ty) return false;
1497
1498 const AddrTag = @typeInfo(Key.Ptr.Addr).Union.tag_type.?;
1499 if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false;
1500
1501 return switch (a_info.addr) {
1502 .decl => |a_decl| a_decl == b_info.addr.decl,
1503 .comptime_alloc => |a_alloc| a_alloc == b_info.addr.comptime_alloc,
1504 .anon_decl => |ad| ad.val == b_info.addr.anon_decl.val and
1505 ad.orig_ty == b_info.addr.anon_decl.orig_ty,
1506 .int => |a_int| a_int == b_info.addr.int,
1507 .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload,
1508 .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload,
1509 .comptime_field => |a_comptime_field| a_comptime_field == b_info.addr.comptime_field,
1510 .elem => |a_elem| std.meta.eql(a_elem, b_info.addr.elem),
1511 .field => |a_field| std.meta.eql(a_field, b_info.addr.field),
1552 if (a_info.byte_offset != b_info.byte_offset) return false;
1553
1554 if (@as(Key.Ptr.BaseAddr.Tag, a_info.base_addr) != @as(Key.Ptr.BaseAddr.Tag, b_info.base_addr)) return false;
1555
1556 return switch (a_info.base_addr) {
1557 .decl => |a_decl| a_decl == b_info.base_addr.decl,
1558 .comptime_alloc => |a_alloc| a_alloc == b_info.base_addr.comptime_alloc,
1559 .anon_decl => |ad| ad.val == b_info.base_addr.anon_decl.val and
1560 ad.orig_ty == b_info.base_addr.anon_decl.orig_ty,
1561 .int => true,
1562 .eu_payload => |a_eu_payload| a_eu_payload == b_info.base_addr.eu_payload,
1563 .opt_payload => |a_opt_payload| a_opt_payload == b_info.base_addr.opt_payload,
1564 .comptime_field => |a_comptime_field| a_comptime_field == b_info.base_addr.comptime_field,
1565 .arr_elem => |a_elem| std.meta.eql(a_elem, b_info.base_addr.arr_elem),
1566 .field => |a_field| std.meta.eql(a_field, b_info.base_addr.field),
15121567 };
15131568 },
15141569
......@@ -2271,6 +2326,46 @@ pub const LoadedStructType = struct {
22712326 .struct_type = s,
22722327 };
22732328 }
2329
2330 pub const ReverseRuntimeOrderIterator = struct {
2331 ip: *InternPool,
2332 last_index: u32,
2333 struct_type: InternPool.LoadedStructType,
2334
2335 pub fn next(it: *@This()) ?u32 {
2336 if (it.last_index == 0)
2337 return null;
2338
2339 if (it.struct_type.hasReorderedFields()) {
2340 it.last_index -= 1;
2341 const order = it.struct_type.runtime_order.get(it.ip);
2342 while (order[it.last_index] == .omitted) {
2343 it.last_index -= 1;
2344 if (it.last_index == 0)
2345 return null;
2346 }
2347 return order[it.last_index].toInt();
2348 }
2349
2350 it.last_index -= 1;
2351 while (it.struct_type.fieldIsComptime(it.ip, it.last_index)) {
2352 it.last_index -= 1;
2353 if (it.last_index == 0)
2354 return null;
2355 }
2356
2357 return it.last_index;
2358 }
2359 };
2360
2361 pub fn iterateRuntimeOrderReverse(s: @This(), ip: *InternPool) ReverseRuntimeOrderIterator {
2362 assert(s.layout != .@"packed");
2363 return .{
2364 .ip = ip,
2365 .last_index = s.field_types.len,
2366 .struct_type = s,
2367 };
2368 }
22742369};
22752370
22762371pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
......@@ -2836,7 +2931,7 @@ pub const Index = enum(u32) {
28362931 ptr_anon_decl: struct { data: *PtrAnonDecl },
28372932 ptr_anon_decl_aligned: struct { data: *PtrAnonDeclAligned },
28382933 ptr_comptime_field: struct { data: *PtrComptimeField },
2839 ptr_int: struct { data: *PtrBase },
2934 ptr_int: struct { data: *PtrInt },
28402935 ptr_eu_payload: struct { data: *PtrBase },
28412936 ptr_opt_payload: struct { data: *PtrBase },
28422937 ptr_elem: struct { data: *PtrBaseIndex },
......@@ -3304,7 +3399,7 @@ pub const Tag = enum(u8) {
33043399 /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value.
33053400 ptr_comptime_field,
33063401 /// A pointer with an integer value.
3307 /// data is extra index of `PtrBase`, which contains the type and address.
3402 /// data is extra index of `PtrInt`, which contains the type and address (byte offset from 0).
33083403 /// Only pointer types are allowed to have this encoding. Optional types must use
33093404 /// `opt_payload` or `opt_null`.
33103405 ptr_int,
......@@ -3497,7 +3592,7 @@ pub const Tag = enum(u8) {
34973592 .ptr_anon_decl => PtrAnonDecl,
34983593 .ptr_anon_decl_aligned => PtrAnonDeclAligned,
34993594 .ptr_comptime_field => PtrComptimeField,
3500 .ptr_int => PtrBase,
3595 .ptr_int => PtrInt,
35013596 .ptr_eu_payload => PtrBase,
35023597 .ptr_opt_payload => PtrBase,
35033598 .ptr_elem => PtrBaseIndex,
......@@ -4153,11 +4248,37 @@ pub const PackedU64 = packed struct(u64) {
41534248pub const PtrDecl = struct {
41544249 ty: Index,
41554250 decl: DeclIndex,
4251 byte_offset_a: u32,
4252 byte_offset_b: u32,
4253 fn init(ty: Index, decl: DeclIndex, byte_offset: u64) @This() {
4254 return .{
4255 .ty = ty,
4256 .decl = decl,
4257 .byte_offset_a = @intCast(byte_offset >> 32),
4258 .byte_offset_b = @truncate(byte_offset),
4259 };
4260 }
4261 fn byteOffset(data: @This()) u64 {
4262 return @as(u64, data.byte_offset_a) << 32 | data.byte_offset_b;
4263 }
41564264};
41574265
41584266pub const PtrAnonDecl = struct {
41594267 ty: Index,
41604268 val: Index,
4269 byte_offset_a: u32,
4270 byte_offset_b: u32,
4271 fn init(ty: Index, val: Index, byte_offset: u64) @This() {
4272 return .{
4273 .ty = ty,
4274 .val = val,
4275 .byte_offset_a = @intCast(byte_offset >> 32),
4276 .byte_offset_b = @truncate(byte_offset),
4277 };
4278 }
4279 fn byteOffset(data: @This()) u64 {
4280 return @as(u64, data.byte_offset_a) << 32 | data.byte_offset_b;
4281 }
41614282};
41624283
41634284pub const PtrAnonDeclAligned = struct {
......@@ -4165,27 +4286,110 @@ pub const PtrAnonDeclAligned = struct {
41654286 val: Index,
41664287 /// Must be nonequal to `ty`. Only the alignment from this value is important.
41674288 orig_ty: Index,
4289 byte_offset_a: u32,
4290 byte_offset_b: u32,
4291 fn init(ty: Index, val: Index, orig_ty: Index, byte_offset: u64) @This() {
4292 return .{
4293 .ty = ty,
4294 .val = val,
4295 .orig_ty = orig_ty,
4296 .byte_offset_a = @intCast(byte_offset >> 32),
4297 .byte_offset_b = @truncate(byte_offset),
4298 };
4299 }
4300 fn byteOffset(data: @This()) u64 {
4301 return @as(u64, data.byte_offset_a) << 32 | data.byte_offset_b;
4302 }
41684303};
41694304
41704305pub const PtrComptimeAlloc = struct {
41714306 ty: Index,
41724307 index: ComptimeAllocIndex,
4308 byte_offset_a: u32,
4309 byte_offset_b: u32,
4310 fn init(ty: Index, index: ComptimeAllocIndex, byte_offset: u64) @This() {
4311 return .{
4312 .ty = ty,
4313 .index = index,
4314 .byte_offset_a = @intCast(byte_offset >> 32),
4315 .byte_offset_b = @truncate(byte_offset),
4316 };
4317 }
4318 fn byteOffset(data: @This()) u64 {
4319 return @as(u64, data.byte_offset_a) << 32 | data.byte_offset_b;
4320 }
41734321};
41744322
41754323pub const PtrComptimeField = struct {
41764324 ty: Index,
41774325 field_val: Index,
4326 byte_offset_a: u32,
4327 byte_offset_b: u32,
4328 fn init(ty: Index, field_val: Index, byte_offset: u64) @This() {
4329 return .{
4330 .ty = ty,
4331 .field_val = field_val,
4332 .byte_offset_a = @intCast(byte_offset >> 32),
4333 .byte_offset_b = @truncate(byte_offset),
4334 };
4335 }
4336 fn byteOffset(data: @This()) u64 {
4337 return @as(u64, data.byte_offset_a) << 32 | data.byte_offset_b;
4338 }
41784339};
41794340
41804341pub const PtrBase = struct {
41814342 ty: Index,
41824343 base: Index,
4344 byte_offset_a: u32,
4345 byte_offset_b: u32,
4346 fn init(ty: Index, base: Index, byte_offset: u64) @This() {
4347 return .{
4348 .ty = ty,
4349 .base = base,
4350 .byte_offset_a = @intCast(byte_offset >> 32),
4351 .byte_offset_b = @truncate(byte_offset),
4352 };
4353 }
4354 fn byteOffset(data: @This()) u64 {
4355 return @as(u64, data.byte_offset_a) << 32 | data.byte_offset_b;
4356 }
41834357};
41844358
41854359pub const PtrBaseIndex = struct {
41864360 ty: Index,
41874361 base: Index,
41884362 index: Index,
4363 byte_offset_a: u32,
4364 byte_offset_b: u32,
4365 fn init(ty: Index, base: Index, index: Index, byte_offset: u64) @This() {
4366 return .{
4367 .ty = ty,
4368 .base = base,
4369 .index = index,
4370 .byte_offset_a = @intCast(byte_offset >> 32),
4371 .byte_offset_b = @truncate(byte_offset),
4372 };
4373 }
4374 fn byteOffset(data: @This()) u64 {
4375 return @as(u64, data.byte_offset_a) << 32 | data.byte_offset_b;
4376 }
4377};
4378
4379pub const PtrInt = struct {
4380 ty: Index,
4381 byte_offset_a: u32,
4382 byte_offset_b: u32,
4383 fn init(ty: Index, byte_offset: u64) @This() {
4384 return .{
4385 .ty = ty,
4386 .byte_offset_a = @intCast(byte_offset >> 32),
4387 .byte_offset_b = @truncate(byte_offset),
4388 };
4389 }
4390 fn byteOffset(data: @This()) u64 {
4391 return @as(u64, data.byte_offset_a) << 32 | data.byte_offset_b;
4392 }
41894393};
41904394
41914395pub const PtrSlice = struct {
......@@ -4569,78 +4773,55 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
45694773 },
45704774 .ptr_decl => {
45714775 const info = ip.extraData(PtrDecl, data);
4572 return .{ .ptr = .{
4573 .ty = info.ty,
4574 .addr = .{ .decl = info.decl },
4575 } };
4776 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .decl = info.decl }, .byte_offset = info.byteOffset() } };
45764777 },
45774778 .ptr_comptime_alloc => {
45784779 const info = ip.extraData(PtrComptimeAlloc, data);
4579 return .{ .ptr = .{
4580 .ty = info.ty,
4581 .addr = .{ .comptime_alloc = info.index },
4582 } };
4780 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .comptime_alloc = info.index }, .byte_offset = info.byteOffset() } };
45834781 },
45844782 .ptr_anon_decl => {
45854783 const info = ip.extraData(PtrAnonDecl, data);
4586 return .{ .ptr = .{
4587 .ty = info.ty,
4588 .addr = .{ .anon_decl = .{
4589 .val = info.val,
4590 .orig_ty = info.ty,
4591 } },
4592 } };
4784 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .anon_decl = .{
4785 .val = info.val,
4786 .orig_ty = info.ty,
4787 } }, .byte_offset = info.byteOffset() } };
45934788 },
45944789 .ptr_anon_decl_aligned => {
45954790 const info = ip.extraData(PtrAnonDeclAligned, data);
4596 return .{ .ptr = .{
4597 .ty = info.ty,
4598 .addr = .{ .anon_decl = .{
4599 .val = info.val,
4600 .orig_ty = info.orig_ty,
4601 } },
4602 } };
4791 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .anon_decl = .{
4792 .val = info.val,
4793 .orig_ty = info.orig_ty,
4794 } }, .byte_offset = info.byteOffset() } };
46034795 },
46044796 .ptr_comptime_field => {
46054797 const info = ip.extraData(PtrComptimeField, data);
4606 return .{ .ptr = .{
4607 .ty = info.ty,
4608 .addr = .{ .comptime_field = info.field_val },
4609 } };
4798 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .comptime_field = info.field_val }, .byte_offset = info.byteOffset() } };
46104799 },
46114800 .ptr_int => {
4612 const info = ip.extraData(PtrBase, data);
4801 const info = ip.extraData(PtrInt, data);
46134802 return .{ .ptr = .{
46144803 .ty = info.ty,
4615 .addr = .{ .int = info.base },
4804 .base_addr = .int,
4805 .byte_offset = info.byteOffset(),
46164806 } };
46174807 },
46184808 .ptr_eu_payload => {
46194809 const info = ip.extraData(PtrBase, data);
4620 return .{ .ptr = .{
4621 .ty = info.ty,
4622 .addr = .{ .eu_payload = info.base },
4623 } };
4810 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .eu_payload = info.base }, .byte_offset = info.byteOffset() } };
46244811 },
46254812 .ptr_opt_payload => {
46264813 const info = ip.extraData(PtrBase, data);
4627 return .{ .ptr = .{
4628 .ty = info.ty,
4629 .addr = .{ .opt_payload = info.base },
4630 } };
4814 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .opt_payload = info.base }, .byte_offset = info.byteOffset() } };
46314815 },
46324816 .ptr_elem => {
46334817 // Avoid `indexToKey` recursion by asserting the tag encoding.
46344818 const info = ip.extraData(PtrBaseIndex, data);
46354819 const index_item = ip.items.get(@intFromEnum(info.index));
46364820 return switch (index_item.tag) {
4637 .int_usize => .{ .ptr = .{
4638 .ty = info.ty,
4639 .addr = .{ .elem = .{
4640 .base = info.base,
4641 .index = index_item.data,
4642 } },
4643 } },
4821 .int_usize => .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .arr_elem = .{
4822 .base = info.base,
4823 .index = index_item.data,
4824 } }, .byte_offset = info.byteOffset() } },
46444825 .int_positive => @panic("TODO"), // implement along with behavior test coverage
46454826 else => unreachable,
46464827 };
......@@ -4650,13 +4831,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
46504831 const info = ip.extraData(PtrBaseIndex, data);
46514832 const index_item = ip.items.get(@intFromEnum(info.index));
46524833 return switch (index_item.tag) {
4653 .int_usize => .{ .ptr = .{
4654 .ty = info.ty,
4655 .addr = .{ .field = .{
4656 .base = info.base,
4657 .index = index_item.data,
4658 } },
4659 } },
4834 .int_usize => .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .field = .{
4835 .base = info.base,
4836 .index = index_item.data,
4837 } }, .byte_offset = info.byteOffset() } },
46604838 .int_positive => @panic("TODO"), // implement along with behavior test coverage
46614839 else => unreachable,
46624840 };
......@@ -5211,57 +5389,40 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
52115389 .ptr => |ptr| {
52125390 const ptr_type = ip.indexToKey(ptr.ty).ptr_type;
52135391 assert(ptr_type.flags.size != .Slice);
5214 ip.items.appendAssumeCapacity(switch (ptr.addr) {
5392 ip.items.appendAssumeCapacity(switch (ptr.base_addr) {
52155393 .decl => |decl| .{
52165394 .tag = .ptr_decl,
5217 .data = try ip.addExtra(gpa, PtrDecl{
5218 .ty = ptr.ty,
5219 .decl = decl,
5220 }),
5395 .data = try ip.addExtra(gpa, PtrDecl.init(ptr.ty, decl, ptr.byte_offset)),
52215396 },
52225397 .comptime_alloc => |alloc_index| .{
52235398 .tag = .ptr_comptime_alloc,
5224 .data = try ip.addExtra(gpa, PtrComptimeAlloc{
5225 .ty = ptr.ty,
5226 .index = alloc_index,
5227 }),
5399 .data = try ip.addExtra(gpa, PtrComptimeAlloc.init(ptr.ty, alloc_index, ptr.byte_offset)),
52285400 },
52295401 .anon_decl => |anon_decl| if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) item: {
52305402 if (ptr.ty != anon_decl.orig_ty) {
52315403 _ = ip.map.pop();
52325404 var new_key = key;
5233 new_key.ptr.addr.anon_decl.orig_ty = ptr.ty;
5405 new_key.ptr.base_addr.anon_decl.orig_ty = ptr.ty;
52345406 const new_gop = try ip.map.getOrPutAdapted(gpa, new_key, adapter);
52355407 if (new_gop.found_existing) return @enumFromInt(new_gop.index);
52365408 }
52375409 break :item .{
52385410 .tag = .ptr_anon_decl,
5239 .data = try ip.addExtra(gpa, PtrAnonDecl{
5240 .ty = ptr.ty,
5241 .val = anon_decl.val,
5242 }),
5411 .data = try ip.addExtra(gpa, PtrAnonDecl.init(ptr.ty, anon_decl.val, ptr.byte_offset)),
52435412 };
52445413 } else .{
52455414 .tag = .ptr_anon_decl_aligned,
5246 .data = try ip.addExtra(gpa, PtrAnonDeclAligned{
5247 .ty = ptr.ty,
5248 .val = anon_decl.val,
5249 .orig_ty = anon_decl.orig_ty,
5250 }),
5415 .data = try ip.addExtra(gpa, PtrAnonDeclAligned.init(ptr.ty, anon_decl.val, anon_decl.orig_ty, ptr.byte_offset)),
52515416 },
52525417 .comptime_field => |field_val| item: {
52535418 assert(field_val != .none);
52545419 break :item .{
52555420 .tag = .ptr_comptime_field,
5256 .data = try ip.addExtra(gpa, PtrComptimeField{
5257 .ty = ptr.ty,
5258 .field_val = field_val,
5259 }),
5421 .data = try ip.addExtra(gpa, PtrComptimeField.init(ptr.ty, field_val, ptr.byte_offset)),
52605422 };
52615423 },
5262 .int, .eu_payload, .opt_payload => |base| item: {
5263 switch (ptr.addr) {
5264 .int => assert(ip.typeOf(base) == .usize_type),
5424 .eu_payload, .opt_payload => |base| item: {
5425 switch (ptr.base_addr) {
52655426 .eu_payload => assert(ip.indexToKey(
52665427 ip.indexToKey(ip.typeOf(base)).ptr_type.child,
52675428 ) == .error_union_type),
......@@ -5271,40 +5432,40 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
52715432 else => unreachable,
52725433 }
52735434 break :item .{
5274 .tag = switch (ptr.addr) {
5275 .int => .ptr_int,
5435 .tag = switch (ptr.base_addr) {
52765436 .eu_payload => .ptr_eu_payload,
52775437 .opt_payload => .ptr_opt_payload,
52785438 else => unreachable,
52795439 },
5280 .data = try ip.addExtra(gpa, PtrBase{
5281 .ty = ptr.ty,
5282 .base = base,
5283 }),
5440 .data = try ip.addExtra(gpa, PtrBase.init(ptr.ty, base, ptr.byte_offset)),
52845441 };
52855442 },
5286 .elem, .field => |base_index| item: {
5443 .int => .{
5444 .tag = .ptr_int,
5445 .data = try ip.addExtra(gpa, PtrInt.init(ptr.ty, ptr.byte_offset)),
5446 },
5447 .arr_elem, .field => |base_index| item: {
52875448 const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type;
5288 switch (ptr.addr) {
5289 .elem => assert(base_ptr_type.flags.size == .Many),
5449 switch (ptr.base_addr) {
5450 .arr_elem => assert(base_ptr_type.flags.size == .Many),
52905451 .field => {
52915452 assert(base_ptr_type.flags.size == .One);
52925453 switch (ip.indexToKey(base_ptr_type.child)) {
52935454 .anon_struct_type => |anon_struct_type| {
5294 assert(ptr.addr == .field);
5455 assert(ptr.base_addr == .field);
52955456 assert(base_index.index < anon_struct_type.types.len);
52965457 },
52975458 .struct_type => {
5298 assert(ptr.addr == .field);
5459 assert(ptr.base_addr == .field);
52995460 assert(base_index.index < ip.loadStructType(base_ptr_type.child).field_types.len);
53005461 },
53015462 .union_type => {
53025463 const union_type = ip.loadUnionType(base_ptr_type.child);
5303 assert(ptr.addr == .field);
5464 assert(ptr.base_addr == .field);
53045465 assert(base_index.index < union_type.field_types.len);
53055466 },
53065467 .ptr_type => |slice_type| {
5307 assert(ptr.addr == .field);
5468 assert(ptr.base_addr == .field);
53085469 assert(slice_type.flags.size == .Slice);
53095470 assert(base_index.index < 2);
53105471 },
......@@ -5321,16 +5482,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
53215482 assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);
53225483 try ip.items.ensureUnusedCapacity(gpa, 1);
53235484 break :item .{
5324 .tag = switch (ptr.addr) {
5325 .elem => .ptr_elem,
5485 .tag = switch (ptr.base_addr) {
5486 .arr_elem => .ptr_elem,
53265487 .field => .ptr_field,
53275488 else => unreachable,
53285489 },
5329 .data = try ip.addExtra(gpa, PtrBaseIndex{
5330 .ty = ptr.ty,
5331 .base = base_index.base,
5332 .index = index_index,
5333 }),
5490 .data = try ip.addExtra(gpa, PtrBaseIndex.init(ptr.ty, base_index.base, index_index, ptr.byte_offset)),
53345491 };
53355492 },
53365493 });
......@@ -7584,13 +7741,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
75847741 if (ip.isPointerType(new_ty)) switch (ip.indexToKey(new_ty).ptr_type.flags.size) {
75857742 .One, .Many, .C => return ip.get(gpa, .{ .ptr = .{
75867743 .ty = new_ty,
7587 .addr = .{ .int = .zero_usize },
7744 .base_addr = .int,
7745 .byte_offset = 0,
75887746 } }),
75897747 .Slice => return ip.get(gpa, .{ .slice = .{
75907748 .ty = new_ty,
75917749 .ptr = try ip.get(gpa, .{ .ptr = .{
75927750 .ty = ip.slicePtrType(new_ty),
7593 .addr = .{ .int = .zero_usize },
7751 .base_addr = .int,
7752 .byte_offset = 0,
75947753 } }),
75957754 .len = try ip.get(gpa, .{ .undef = .usize_type }),
75967755 } }),
......@@ -7630,10 +7789,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
76307789 .ty = new_ty,
76317790 .int = try ip.getCoerced(gpa, val, ip.loadEnumType(new_ty).tag_ty),
76327791 } }),
7633 .ptr_type => return ip.get(gpa, .{ .ptr = .{
7634 .ty = new_ty,
7635 .addr = .{ .int = try ip.getCoerced(gpa, val, .usize_type) },
7636 } }),
7792 .ptr_type => switch (int.storage) {
7793 inline .u64, .i64 => |int_val| return ip.get(gpa, .{ .ptr = .{
7794 .ty = new_ty,
7795 .base_addr = .int,
7796 .byte_offset = @intCast(int_val),
7797 } }),
7798 .big_int => unreachable, // must be a usize
7799 .lazy_align, .lazy_size => {},
7800 },
76377801 else => if (ip.isIntegerType(new_ty))
76387802 return getCoercedInts(ip, gpa, int, new_ty),
76397803 },
......@@ -7684,11 +7848,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
76847848 .ptr => |ptr| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size != .Slice)
76857849 return ip.get(gpa, .{ .ptr = .{
76867850 .ty = new_ty,
7687 .addr = ptr.addr,
7851 .base_addr = ptr.base_addr,
7852 .byte_offset = ptr.byte_offset,
76887853 } })
76897854 else if (ip.isIntegerType(new_ty))
7690 switch (ptr.addr) {
7691 .int => |int| return ip.getCoerced(gpa, int, new_ty),
7855 switch (ptr.base_addr) {
7856 .int => return ip.get(gpa, .{ .int = .{
7857 .ty = .usize_type,
7858 .storage = .{ .u64 = @intCast(ptr.byte_offset) },
7859 } }),
76927860 else => {},
76937861 },
76947862 .opt => |opt| switch (ip.indexToKey(new_ty)) {
......@@ -7696,13 +7864,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
76967864 .none => switch (ptr_type.flags.size) {
76977865 .One, .Many, .C => try ip.get(gpa, .{ .ptr = .{
76987866 .ty = new_ty,
7699 .addr = .{ .int = .zero_usize },
7867 .base_addr = .int,
7868 .byte_offset = 0,
77007869 } }),
77017870 .Slice => try ip.get(gpa, .{ .slice = .{
77027871 .ty = new_ty,
77037872 .ptr = try ip.get(gpa, .{ .ptr = .{
77047873 .ty = ip.slicePtrType(new_ty),
7705 .addr = .{ .int = .zero_usize },
7874 .base_addr = .int,
7875 .byte_offset = 0,
77067876 } }),
77077877 .len = try ip.get(gpa, .{ .undef = .usize_type }),
77087878 } }),
......@@ -8181,7 +8351,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
81818351 .ptr_anon_decl => @sizeOf(PtrAnonDecl),
81828352 .ptr_anon_decl_aligned => @sizeOf(PtrAnonDeclAligned),
81838353 .ptr_comptime_field => @sizeOf(PtrComptimeField),
8184 .ptr_int => @sizeOf(PtrBase),
8354 .ptr_int => @sizeOf(PtrInt),
81858355 .ptr_eu_payload => @sizeOf(PtrBase),
81868356 .ptr_opt_payload => @sizeOf(PtrBase),
81878357 .ptr_elem => @sizeOf(PtrBaseIndex),
......@@ -8854,13 +9024,15 @@ pub fn getBackingDecl(ip: *const InternPool, val: Index) OptionalDeclIndex {
88549024 }
88559025}
88569026
8857pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag {
9027pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.BaseAddr.Tag {
88589028 var base = @intFromEnum(val);
88599029 while (true) {
88609030 switch (ip.items.items(.tag)[base]) {
88619031 .ptr_decl => return .decl,
88629032 .ptr_comptime_alloc => return .comptime_alloc,
8863 .ptr_anon_decl, .ptr_anon_decl_aligned => return .anon_decl,
9033 .ptr_anon_decl,
9034 .ptr_anon_decl_aligned,
9035 => return .anon_decl,
88649036 .ptr_comptime_field => return .comptime_field,
88659037 .ptr_int => return .int,
88669038 inline .ptr_eu_payload,
src/Module.zig+38-22
......@@ -528,21 +528,6 @@ pub const Decl = struct {
528528 return zcu.namespacePtrUnwrap(decl.getInnerNamespaceIndex(zcu));
529529 }
530530
531 pub fn dump(decl: *Decl) void {
532 const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src);
533 std.debug.print("{s}:{d}:{d} name={d} status={s}", .{
534 decl.scope.sub_file_path,
535 loc.line + 1,
536 loc.column + 1,
537 @intFromEnum(decl.name),
538 @tagName(decl.analysis),
539 });
540 if (decl.has_tv) {
541 std.debug.print(" val={}", .{decl.val});
542 }
543 std.debug.print("\n", .{});
544 }
545
546531 pub fn getFileScope(decl: Decl, zcu: *Zcu) *File {
547532 return zcu.namespacePtr(decl.src_namespace).file_scope;
548533 }
......@@ -660,6 +645,22 @@ pub const Decl = struct {
660645 },
661646 };
662647 }
648
649 pub fn declPtrType(decl: Decl, zcu: *Zcu) !Type {
650 assert(decl.has_tv);
651 const decl_ty = decl.typeOf(zcu);
652 return zcu.ptrType(.{
653 .child = decl_ty.toIntern(),
654 .flags = .{
655 .alignment = if (decl.alignment == decl_ty.abiAlignment(zcu))
656 .none
657 else
658 decl.alignment,
659 .address_space = decl.@"addrspace",
660 .is_const = decl.getOwnedVariable(zcu) == null,
661 },
662 });
663 }
663664};
664665
665666/// This state is attached to every Decl when Module emit_h is non-null.
......@@ -3535,6 +3536,10 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
35353536 }
35363537
35373538 log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)});
3539 log.debug("decl name '{}'", .{(try decl.fullyQualifiedName(mod)).fmt(ip)});
3540 defer blk: {
3541 log.debug("finish decl name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)});
3542 }
35383543
35393544 const old_has_tv = decl.has_tv;
35403545 // The following values are ignored if `!old_has_tv`
......@@ -4122,10 +4127,11 @@ fn newEmbedFile(
41224127 })).toIntern();
41234128 const ptr_val = try ip.get(gpa, .{ .ptr = .{
41244129 .ty = ptr_ty,
4125 .addr = .{ .anon_decl = .{
4130 .base_addr = .{ .anon_decl = .{
41264131 .val = array_val,
41274132 .orig_ty = ptr_ty,
41284133 } },
4134 .byte_offset = 0,
41294135 } });
41304136
41314137 result.* = new_file;
......@@ -4489,6 +4495,11 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
44894495 const decl_index = func.owner_decl;
44904496 const decl = mod.declPtr(decl_index);
44914497
4498 log.debug("func name '{}'", .{(try decl.fullyQualifiedName(mod)).fmt(ip)});
4499 defer blk: {
4500 log.debug("finish func name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)});
4501 }
4502
44924503 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
44934504
44944505 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
......@@ -5332,7 +5343,7 @@ pub fn populateTestFunctions(
53325343 const decl = mod.declPtr(decl_index);
53335344 const test_fn_ty = decl.typeOf(mod).slicePtrFieldType(mod).childType(mod);
53345345
5335 const array_anon_decl: InternPool.Key.Ptr.Addr.AnonDecl = array: {
5346 const array_anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl = array: {
53365347 // Add mod.test_functions to an array decl then make the test_functions
53375348 // decl reference it as a slice.
53385349 const test_fn_vals = try gpa.alloc(InternPool.Index, mod.test_functions.count());
......@@ -5342,7 +5353,7 @@ pub fn populateTestFunctions(
53425353 const test_decl = mod.declPtr(test_decl_index);
53435354 const test_decl_name = try test_decl.fullyQualifiedName(mod);
53445355 const test_decl_name_len = test_decl_name.length(ip);
5345 const test_name_anon_decl: InternPool.Key.Ptr.Addr.AnonDecl = n: {
5356 const test_name_anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl = n: {
53465357 const test_name_ty = try mod.arrayType(.{
53475358 .len = test_decl_name_len,
53485359 .child = .u8_type,
......@@ -5363,7 +5374,8 @@ pub fn populateTestFunctions(
53635374 .ty = .slice_const_u8_type,
53645375 .ptr = try mod.intern(.{ .ptr = .{
53655376 .ty = .manyptr_const_u8_type,
5366 .addr = .{ .anon_decl = test_name_anon_decl },
5377 .base_addr = .{ .anon_decl = test_name_anon_decl },
5378 .byte_offset = 0,
53675379 } }),
53685380 .len = try mod.intern(.{ .int = .{
53695381 .ty = .usize_type,
......@@ -5378,7 +5390,8 @@ pub fn populateTestFunctions(
53785390 .is_const = true,
53795391 },
53805392 } }),
5381 .addr = .{ .decl = test_decl_index },
5393 .base_addr = .{ .decl = test_decl_index },
5394 .byte_offset = 0,
53825395 } }),
53835396 };
53845397 test_fn_val.* = try mod.intern(.{ .aggregate = .{
......@@ -5415,7 +5428,8 @@ pub fn populateTestFunctions(
54155428 .ty = new_ty.toIntern(),
54165429 .ptr = try mod.intern(.{ .ptr = .{
54175430 .ty = new_ty.slicePtrFieldType(mod).toIntern(),
5418 .addr = .{ .anon_decl = array_anon_decl },
5431 .base_addr = .{ .anon_decl = array_anon_decl },
5432 .byte_offset = 0,
54195433 } }),
54205434 .len = (try mod.intValue(Type.usize, mod.test_functions.count())).toIntern(),
54215435 } });
......@@ -5680,9 +5694,11 @@ pub fn errorSetFromUnsortedNames(
56805694/// Supports only pointers, not pointer-like optionals.
56815695pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
56825696 assert(ty.zigTypeTag(mod) == .Pointer and !ty.isSlice(mod));
5697 assert(x != 0 or ty.isAllowzeroPtr(mod));
56835698 const i = try intern(mod, .{ .ptr = .{
56845699 .ty = ty.toIntern(),
5685 .addr = .{ .int = (try mod.intValue_u64(Type.usize, x)).toIntern() },
5700 .base_addr = .int,
5701 .byte_offset = x,
56865702 } });
56875703 return Value.fromInterned(i);
56885704}
src/Sema.zig+841-1569
......@@ -126,16 +126,14 @@ const MaybeComptimeAlloc = struct {
126126 runtime_index: Value.RuntimeIndex,
127127 /// Backed by sema.arena. Tracks all comptime-known stores to this `alloc`. Due to
128128 /// RLS, a single comptime-known allocation may have arbitrarily many stores.
129 /// This may also contain `set_union_tag` instructions.
129 /// This list also contains `set_union_tag`, `optional_payload_ptr_set`, and
130 /// `errunion_payload_ptr_set` instructions.
131 /// If the instruction is one of these three tags, `src` may be `.unneeded`.
130132 stores: std.MultiArrayList(struct {
131133 inst: Air.Inst.Index,
132134 src_decl: InternPool.DeclIndex,
133135 src: LazySrcLoc,
134136 }) = .{},
135 /// Backed by sema.arena. Contains instructions such as `optional_payload_ptr_set`
136 /// which have side effects so will not be elided by Liveness: we must rewrite these
137 /// instructions to be nops instead of relying on Liveness.
138 non_elideable_pointers: std.ArrayListUnmanaged(Air.Inst.Index) = .{},
139137};
140138
141139const ComptimeAlloc = struct {
......@@ -177,7 +175,8 @@ const MutableValue = @import("mutable_value.zig").MutableValue;
177175const Type = @import("type.zig").Type;
178176const Air = @import("Air.zig");
179177const Zir = std.zig.Zir;
180const Module = @import("Module.zig");
178const Zcu = @import("Module.zig");
179const Module = Zcu;
181180const trace = @import("tracy.zig").trace;
182181const Namespace = Module.Namespace;
183182const CompileError = Module.CompileError;
......@@ -2138,7 +2137,7 @@ fn resolveValueIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
21382137 if (sema.mod.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) {
21392138 .decl, .anon_decl, .comptime_alloc, .comptime_field => return null,
21402139 .int => {},
2141 .eu_payload, .opt_payload, .elem, .field => unreachable,
2140 .eu_payload, .opt_payload, .arr_elem, .field => unreachable,
21422141 };
21432142 return try sema.resolveLazyValue(val);
21442143}
......@@ -2268,11 +2267,11 @@ fn failWithErrorSetCodeMissing(
22682267}
22692268
22702269fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError {
2271 const mod = sema.mod;
2272 if (int_ty.zigTypeTag(mod) == .Vector) {
2270 const zcu = sema.mod;
2271 if (int_ty.zigTypeTag(zcu) == .Vector) {
22732272 const msg = msg: {
22742273 const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{
2275 int_ty.fmt(sema.mod), val.fmtValue(sema.mod),
2274 int_ty.fmt(zcu), val.fmtValue(zcu, sema),
22762275 });
22772276 errdefer msg.destroy(sema.gpa);
22782277 try sema.errNote(block, src, msg, "when computing vector element at index '{d}'", .{vector_index});
......@@ -2281,7 +2280,7 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty:
22812280 return sema.failWithOwnedErrorMsg(block, msg);
22822281 }
22832282 return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{
2284 int_ty.fmt(sema.mod), val.fmtValue(sema.mod),
2283 int_ty.fmt(zcu), val.fmtValue(zcu, sema),
22852284 });
22862285}
22872286
......@@ -2440,7 +2439,7 @@ fn addFieldErrNote(
24402439 try mod.errNoteNonLazy(field_src, parent, format, args);
24412440}
24422441
2443fn errMsg(
2442pub fn errMsg(
24442443 sema: *Sema,
24452444 block: *Block,
24462445 src: LazySrcLoc,
......@@ -2469,7 +2468,7 @@ pub fn fail(
24692468 return sema.failWithOwnedErrorMsg(block, err_msg);
24702469}
24712470
2472fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.ErrorMsg) error{ AnalysisFail, OutOfMemory } {
2471pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.ErrorMsg) error{ AnalysisFail, OutOfMemory } {
24732472 @setCold(true);
24742473 const gpa = sema.gpa;
24752474 const mod = sema.mod;
......@@ -2922,7 +2921,7 @@ fn createAnonymousDeclTypeNamed(
29222921 return sema.createAnonymousDeclTypeNamed(block, src, val, .anon, anon_prefix, null);
29232922
29242923 if (arg_i != 0) try writer.writeByte(',');
2925 try writer.print("{}", .{arg_val.fmtValue(sema.mod)});
2924 try writer.print("{}", .{arg_val.fmtValue(sema.mod, sema)});
29262925
29272926 arg_i += 1;
29282927 continue;
......@@ -3193,7 +3192,7 @@ fn zirEnumDecl(
31933192 }).lazy;
31943193 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
31953194 const msg = msg: {
3196 const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(sema.mod)});
3195 const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(sema.mod, sema)});
31973196 errdefer msg.destroy(gpa);
31983197 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
31993198 break :msg msg;
......@@ -3213,7 +3212,7 @@ fn zirEnumDecl(
32133212 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
32143213 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
32153214 const msg = msg: {
3216 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(sema.mod)});
3215 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(sema.mod, sema)});
32173216 errdefer msg.destroy(gpa);
32183217 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
32193218 break :msg msg;
......@@ -3235,7 +3234,7 @@ fn zirEnumDecl(
32353234 .range = if (has_tag_value) .value else .name,
32363235 }).lazy;
32373236 const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{
3238 last_tag_val.?.fmtValue(mod), int_tag_ty.fmt(mod),
3237 last_tag_val.?.fmtValue(mod, sema), int_tag_ty.fmt(mod),
32393238 });
32403239 return sema.failWithOwnedErrorMsg(block, msg);
32413240 }
......@@ -3766,7 +3765,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
37663765 // If this was a comptime inferred alloc, then `storeToInferredAllocComptime`
37673766 // might have already done our job and created an anon decl ref.
37683767 switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
3769 .ptr => |ptr| switch (ptr.addr) {
3768 .ptr => |ptr| switch (ptr.base_addr) {
37703769 .anon_decl => {
37713770 // The comptime-ification was already done for us.
37723771 // Just make sure the pointer is const.
......@@ -3778,22 +3777,25 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
37783777 }
37793778
37803779 if (!sema.isComptimeMutablePtr(ptr_val)) break :already_ct;
3781 const alloc_index = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr.comptime_alloc;
3780 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
3781 assert(ptr.byte_offset == 0);
3782 const alloc_index = ptr.base_addr.comptime_alloc;
37823783 const ct_alloc = sema.getComptimeAlloc(alloc_index);
37833784 const interned = try ct_alloc.val.intern(mod, sema.arena);
3784 if (Value.fromInterned(interned).canMutateComptimeVarState(mod)) {
3785 if (interned.canMutateComptimeVarState(mod)) {
37853786 // Preserve the comptime alloc, just make the pointer const.
3786 ct_alloc.val = .{ .interned = interned };
3787 ct_alloc.val = .{ .interned = interned.toIntern() };
37873788 ct_alloc.is_const = true;
37883789 return sema.makePtrConst(block, alloc);
37893790 } else {
37903791 // Promote the constant to an anon decl.
37913792 const new_mut_ptr = Air.internedToRef(try mod.intern(.{ .ptr = .{
37923793 .ty = alloc_ty.toIntern(),
3793 .addr = .{ .anon_decl = .{
3794 .val = interned,
3794 .base_addr = .{ .anon_decl = .{
3795 .val = interned.toIntern(),
37953796 .orig_ty = alloc_ty.toIntern(),
37963797 } },
3798 .byte_offset = 0,
37973799 } }));
37983800 return sema.makePtrConst(block, new_mut_ptr);
37993801 }
......@@ -3818,10 +3820,10 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
38183820/// If `alloc` is an inferred allocation, `resolved_inferred_ty` is taken to be its resolved
38193821/// type. Otherwise, it may be `null`, and the type will be inferred from `alloc`.
38203822fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, resolved_alloc_ty: ?Type) CompileError!?InternPool.Index {
3821 const mod = sema.mod;
3823 const zcu = sema.mod;
38223824
38233825 const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc);
3824 const ptr_info = alloc_ty.ptrInfo(mod);
3826 const ptr_info = alloc_ty.ptrInfo(zcu);
38253827 const elem_ty = Type.fromInterned(ptr_info.child);
38263828
38273829 const alloc_inst = alloc.toIndex() orelse return null;
......@@ -3843,12 +3845,16 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
38433845
38443846 simple: {
38453847 if (stores.len != 1) break :simple;
3846 const store_inst = stores[0];
3847 const store_data = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;
3848 if (store_data.lhs != alloc) break :simple;
3848 const store_inst = sema.air_instructions.get(@intFromEnum(stores[0]));
3849 switch (store_inst.tag) {
3850 .store, .store_safe => {},
3851 .set_union_tag, .optional_payload_ptr_set, .errunion_payload_ptr_set => break :simple, // there's OPV stuff going on!
3852 else => unreachable,
3853 }
3854 if (store_inst.data.bin_op.lhs != alloc) break :simple;
38493855
3850 const val = store_data.rhs.toInterned().?;
3851 assert(mod.intern_pool.typeOf(val) == elem_ty.toIntern());
3856 const val = store_inst.data.bin_op.rhs.toInterned().?;
3857 assert(zcu.intern_pool.typeOf(val) == elem_ty.toIntern());
38523858 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value);
38533859 }
38543860
......@@ -3857,9 +3863,10 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
38573863
38583864 const ct_alloc = try sema.newComptimeAlloc(block, elem_ty, ptr_info.flags.alignment);
38593865
3860 const alloc_ptr = try mod.intern(.{ .ptr = .{
3866 const alloc_ptr = try zcu.intern(.{ .ptr = .{
38613867 .ty = alloc_ty.toIntern(),
3862 .addr = .{ .comptime_alloc = ct_alloc },
3868 .base_addr = .{ .comptime_alloc = ct_alloc },
3869 .byte_offset = 0,
38633870 } });
38643871
38653872 // Maps from pointers into the runtime allocs, to comptime-mutable pointers into the comptime alloc
......@@ -3867,10 +3874,18 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
38673874 try ptr_mapping.ensureTotalCapacity(@intCast(stores.len));
38683875 ptr_mapping.putAssumeCapacity(alloc_inst, alloc_ptr);
38693876
3877 // Whilst constructing our mapping, we will also initialize optional and error union payloads when
3878 // we encounter the corresponding pointers. For this reason, the ordering of `to_map` matters.
38703879 var to_map = try std.ArrayList(Air.Inst.Index).initCapacity(sema.arena, stores.len);
3871 for (stores) |store_inst| {
3872 const bin_op = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;
3873 to_map.appendAssumeCapacity(bin_op.lhs.toIndex().?);
3880 for (stores) |store_inst_idx| {
3881 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
3882 const ptr_to_map = switch (store_inst.tag) {
3883 .store, .store_safe => store_inst.data.bin_op.lhs.toIndex().?, // Map the pointer being stored to.
3884 .set_union_tag => continue, // We can completely ignore these: we'll do it implicitly when we get the field pointer.
3885 .optional_payload_ptr_set, .errunion_payload_ptr_set => store_inst_idx, // Map the generated pointer itself.
3886 else => unreachable,
3887 };
3888 to_map.appendAssumeCapacity(ptr_to_map);
38743889 }
38753890
38763891 const tmp_air = sema.getTmpAir();
......@@ -3950,53 +3965,68 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
39503965 try to_map.appendSlice(&.{ air_ptr, air_parent_ptr.toIndex().? });
39513966 continue;
39523967 };
3953 const new_ptr_ty = tmp_air.typeOfIndex(air_ptr, &mod.intern_pool).toIntern();
3968 const new_ptr_ty = tmp_air.typeOfIndex(air_ptr, &zcu.intern_pool).toIntern();
39543969 const new_ptr = switch (method) {
3955 .same_addr => try mod.intern_pool.getCoerced(sema.gpa, decl_parent_ptr, new_ptr_ty),
3956 .opt_payload => try mod.intern(.{ .ptr = .{
3957 .ty = new_ptr_ty,
3958 .addr = .{ .opt_payload = decl_parent_ptr },
3959 } }),
3960 .eu_payload => try mod.intern(.{ .ptr = .{
3961 .ty = new_ptr_ty,
3962 .addr = .{ .eu_payload = decl_parent_ptr },
3963 } }),
3964 .field => |field_idx| try mod.intern(.{ .ptr = .{
3965 .ty = new_ptr_ty,
3966 .addr = .{ .field = .{
3967 .base = decl_parent_ptr,
3968 .index = field_idx,
3969 } },
3970 } }),
3971 .elem => |elem_idx| (try Value.fromInterned(decl_parent_ptr).elemPtr(Type.fromInterned(new_ptr_ty), @intCast(elem_idx), mod)).toIntern(),
3970 .same_addr => try zcu.intern_pool.getCoerced(sema.gpa, decl_parent_ptr, new_ptr_ty),
3971 .opt_payload => ptr: {
3972 // Set the optional to non-null at comptime.
3973 // If the payload is OPV, we must use that value instead of undef.
3974 const opt_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);
3975 const payload_ty = opt_ty.optionalChild(zcu);
3976 const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try zcu.undefValue(payload_ty);
3977 const opt_val = try zcu.intern(.{ .opt = .{
3978 .ty = opt_ty.toIntern(),
3979 .val = payload_val.toIntern(),
3980 } });
3981 try sema.storePtrVal(block, .unneeded, Value.fromInterned(decl_parent_ptr), Value.fromInterned(opt_val), opt_ty);
3982 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrOptPayload(sema)).toIntern();
3983 },
3984 .eu_payload => ptr: {
3985 // Set the error union to non-error at comptime.
3986 // If the payload is OPV, we must use that value instead of undef.
3987 const eu_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);
3988 const payload_ty = eu_ty.errorUnionPayload(zcu);
3989 const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try zcu.undefValue(payload_ty);
3990 const eu_val = try zcu.intern(.{ .error_union = .{
3991 .ty = eu_ty.toIntern(),
3992 .val = .{ .payload = payload_val.toIntern() },
3993 } });
3994 try sema.storePtrVal(block, .unneeded, Value.fromInterned(decl_parent_ptr), Value.fromInterned(eu_val), eu_ty);
3995 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrEuPayload(sema)).toIntern();
3996 },
3997 .field => |idx| ptr: {
3998 const maybe_union_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);
3999 if (zcu.typeToUnion(maybe_union_ty)) |union_obj| {
4000 // As this is a union field, we must store to the pointer now to set the tag.
4001 // If the payload is OPV, there will not be a payload store, so we store that value.
4002 // Otherwise, there will be a payload store to process later, so undef will suffice.
4003 const payload_ty = Type.fromInterned(union_obj.field_types.get(&zcu.intern_pool)[idx]);
4004 const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try zcu.undefValue(payload_ty);
4005 const tag_val = try zcu.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), idx);
4006 const store_val = try zcu.unionValue(maybe_union_ty, tag_val, payload_val);
4007 try sema.storePtrVal(block, .unneeded, Value.fromInterned(decl_parent_ptr), store_val, maybe_union_ty);
4008 }
4009 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrField(idx, sema)).toIntern();
4010 },
4011 .elem => |idx| (try Value.fromInterned(decl_parent_ptr).ptrElem(idx, sema)).toIntern(),
39724012 };
39734013 try ptr_mapping.put(air_ptr, new_ptr);
39744014 }
39754015
39764016 // We have a correlation between AIR pointers and decl pointers. Perform all stores at comptime.
3977
3978 for (stores) |store_inst| {
3979 switch (sema.air_instructions.items(.tag)[@intFromEnum(store_inst)]) {
3980 .set_union_tag => {
3981 // If this tag has an OPV payload, there won't be a corresponding
3982 // store instruction, so we must set the union payload now.
3983 const bin_op = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;
3984 const air_ptr_inst = bin_op.lhs.toIndex().?;
3985 const tag_val = (try sema.resolveValue(bin_op.rhs)).?;
3986 const union_ty = sema.typeOf(bin_op.lhs).childType(mod);
3987 const payload_ty = union_ty.unionFieldType(tag_val, mod).?;
3988 if (try sema.typeHasOnePossibleValue(payload_ty)) |payload_val| {
3989 const new_ptr = ptr_mapping.get(air_ptr_inst).?;
3990 const store_val = try mod.unionValue(union_ty, tag_val, payload_val);
3991 try sema.storePtrVal(block, .unneeded, Value.fromInterned(new_ptr), store_val, union_ty);
3992 }
3993 },
4017 // Any implicit stores performed by `optional_payload_ptr_set`, `errunion_payload_ptr_set`, or
4018 // `set_union_tag` instructions were already done above.
4019
4020 for (stores) |store_inst_idx| {
4021 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
4022 switch (store_inst.tag) {
4023 .set_union_tag => {}, // Handled implicitly by field pointers above
4024 .optional_payload_ptr_set, .errunion_payload_ptr_set => {}, // Handled explicitly above
39944025 .store, .store_safe => {
3995 const bin_op = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;
3996 const air_ptr_inst = bin_op.lhs.toIndex().?;
3997 const store_val = (try sema.resolveValue(bin_op.rhs)).?;
4026 const air_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;
4027 const store_val = (try sema.resolveValue(store_inst.data.bin_op.rhs)).?;
39984028 const new_ptr = ptr_mapping.get(air_ptr_inst).?;
3999 try sema.storePtrVal(block, .unneeded, Value.fromInterned(new_ptr), store_val, Type.fromInterned(mod.intern_pool.typeOf(store_val.toIntern())));
4029 try sema.storePtrVal(block, .unneeded, Value.fromInterned(new_ptr), store_val, Type.fromInterned(zcu.intern_pool.typeOf(store_val.toIntern())));
40004030 },
40014031 else => unreachable,
40024032 }
......@@ -4040,9 +4070,6 @@ fn finishResolveComptimeKnownAllocPtr(
40404070 for (comptime_info.stores.items(.inst)) |store_inst| {
40414071 sema.air_instructions.set(@intFromEnum(store_inst), nop_inst);
40424072 }
4043 for (comptime_info.non_elideable_pointers.items) |ptr_inst| {
4044 sema.air_instructions.set(@intFromEnum(ptr_inst), nop_inst);
4045 }
40464073
40474074 if (Value.fromInterned(result_val).canMutateComptimeVarState(zcu)) {
40484075 const alloc_index = existing_comptime_alloc orelse a: {
......@@ -4054,15 +4081,17 @@ fn finishResolveComptimeKnownAllocPtr(
40544081 sema.getComptimeAlloc(alloc_index).is_const = true;
40554082 return try zcu.intern(.{ .ptr = .{
40564083 .ty = alloc_ty.toIntern(),
4057 .addr = .{ .comptime_alloc = alloc_index },
4084 .base_addr = .{ .comptime_alloc = alloc_index },
4085 .byte_offset = 0,
40584086 } });
40594087 } else {
40604088 return try zcu.intern(.{ .ptr = .{
40614089 .ty = alloc_ty.toIntern(),
4062 .addr = .{ .anon_decl = .{
4090 .base_addr = .{ .anon_decl = .{
40634091 .orig_ty = alloc_ty.toIntern(),
40644092 .val = result_val,
40654093 } },
4094 .byte_offset = 0,
40664095 } });
40674096 }
40684097}
......@@ -4207,11 +4236,11 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42074236 sema.air_instructions.set(@intFromEnum(ptr_inst), .{ .tag = undefined, .data = undefined });
42084237 }
42094238
4210 const val = switch (mod.intern_pool.indexToKey(resolved_ptr).ptr.addr) {
4239 const val = switch (mod.intern_pool.indexToKey(resolved_ptr).ptr.base_addr) {
42114240 .anon_decl => |a| a.val,
42124241 .comptime_alloc => |i| val: {
42134242 const alloc = sema.getComptimeAlloc(i);
4214 break :val try alloc.val.intern(mod, sema.arena);
4243 break :val (try alloc.val.intern(mod, sema.arena)).toIntern();
42154244 },
42164245 else => unreachable,
42174246 };
......@@ -4388,10 +4417,10 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
43884417 .input_index = len_idx,
43894418 } };
43904419 try sema.errNote(block, a_src, msg, "length {} here", .{
4391 v.fmtValue(sema.mod),
4420 v.fmtValue(sema.mod, sema),
43924421 });
43934422 try sema.errNote(block, arg_src, msg, "length {} here", .{
4394 arg_val.fmtValue(sema.mod),
4423 arg_val.fmtValue(sema.mod, sema),
43954424 });
43964425 break :msg msg;
43974426 };
......@@ -4869,7 +4898,7 @@ fn validateUnionInit(
48694898
48704899 const new_tag = Air.internedToRef(tag_val.toIntern());
48714900 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
4872 try sema.checkComptimeKnownStore(block, set_tag_inst, init_src);
4901 try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store
48734902}
48744903
48754904fn validateStructInit(
......@@ -5331,7 +5360,7 @@ fn zirValidatePtrArrayInit(
53315360 if (array_is_comptime) {
53325361 if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| {
53335362 switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
5334 .ptr => |ptr| switch (ptr.addr) {
5363 .ptr => |ptr| switch (ptr.base_addr) {
53355364 .comptime_field => return, // This store was validated by the individual elem ptrs.
53365365 else => {},
53375366 },
......@@ -5619,17 +5648,19 @@ fn storeToInferredAllocComptime(
56195648 if (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)) {
56205649 iac.ptr = try zcu.intern(.{ .ptr = .{
56215650 .ty = alloc_ty.toIntern(),
5622 .addr = .{ .anon_decl = .{
5651 .base_addr = .{ .anon_decl = .{
56235652 .val = operand_val.toIntern(),
56245653 .orig_ty = alloc_ty.toIntern(),
56255654 } },
5655 .byte_offset = 0,
56265656 } });
56275657 } else {
56285658 const alloc_index = try sema.newComptimeAlloc(block, operand_ty, iac.alignment);
56295659 sema.getComptimeAlloc(alloc_index).val = .{ .interned = operand_val.toIntern() };
56305660 iac.ptr = try zcu.intern(.{ .ptr = .{
56315661 .ty = alloc_ty.toIntern(),
5632 .addr = .{ .comptime_alloc = alloc_index },
5662 .base_addr = .{ .comptime_alloc = alloc_index },
5663 .byte_offset = 0,
56335664 } });
56345665 }
56355666}
......@@ -5724,10 +5755,11 @@ fn refValue(sema: *Sema, val: InternPool.Index) CompileError!InternPool.Index {
57245755 })).toIntern();
57255756 return mod.intern(.{ .ptr = .{
57265757 .ty = ptr_ty,
5727 .addr = .{ .anon_decl = .{
5758 .base_addr = .{ .anon_decl = .{
57285759 .val = val,
57295760 .orig_ty = ptr_ty,
57305761 } },
5762 .byte_offset = 0,
57315763 } });
57325764}
57335765
......@@ -5813,7 +5845,7 @@ fn zirCompileLog(
58135845 const arg_ty = sema.typeOf(arg);
58145846 if (try sema.resolveValueResolveLazy(arg)) |val| {
58155847 try writer.print("@as({}, {})", .{
5816 arg_ty.fmt(mod), val.fmtValue(mod),
5848 arg_ty.fmt(mod), val.fmtValue(mod, sema),
58175849 });
58185850 } else {
58195851 try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(mod)});
......@@ -6404,7 +6436,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
64046436 else => |e| return e,
64056437 };
64066438 {
6407 try mod.ensureDeclAnalyzed(decl_index);
6439 try sema.ensureDeclAnalyzed(decl_index);
64086440 const exported_decl = mod.declPtr(decl_index);
64096441 if (exported_decl.val.getFunction(mod)) |function| {
64106442 return sema.analyzeExport(block, src, options, function.owner_decl);
......@@ -6457,7 +6489,7 @@ pub fn analyzeExport(
64576489 if (options.linkage == .internal)
64586490 return;
64596491
6460 try mod.ensureDeclAnalyzed(exported_decl_index);
6492 try sema.ensureDeclAnalyzed(exported_decl_index);
64616493 const exported_decl = mod.declPtr(exported_decl_index);
64626494 const export_ty = exported_decl.typeOf(mod);
64636495
......@@ -6880,8 +6912,8 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl {
68806912 const owner_decl_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
68816913 .extern_func => |extern_func| extern_func.decl,
68826914 .func => |func| func.owner_decl,
6883 .ptr => |ptr| switch (ptr.addr) {
6884 .decl => |decl| mod.declPtr(decl).val.getFunction(mod).?.owner_decl,
6915 .ptr => |ptr| switch (ptr.base_addr) {
6916 .decl => |decl| if (ptr.byte_offset == 0) mod.declPtr(decl).val.getFunction(mod).?.owner_decl else return null,
68856917 else => return null,
68866918 },
68876919 else => return null,
......@@ -7638,22 +7670,23 @@ fn analyzeCall(
76387670 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
76397671 }),
76407672 .func => func_val.toIntern(),
7641 .ptr => |ptr| switch (ptr.addr) {
7642 .decl => |decl| blk: {
7643 const func_val_ptr = mod.declPtr(decl).val.toIntern();
7644 const intern_index = mod.intern_pool.indexToKey(func_val_ptr);
7645 if (intern_index == .extern_func or (intern_index == .variable and intern_index.variable.is_extern))
7646 return sema.fail(block, call_src, "{s} call of extern function pointer", .{
7647 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
7648 });
7649 break :blk func_val_ptr;
7650 },
7651 else => {
7652 assert(callee_ty.isPtrAtRuntime(mod));
7653 return sema.fail(block, call_src, "{s} call of function pointer", .{
7654 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
7655 });
7656 },
7673 .ptr => |ptr| blk: {
7674 switch (ptr.base_addr) {
7675 .decl => |decl| if (ptr.byte_offset == 0) {
7676 const func_val_ptr = mod.declPtr(decl).val.toIntern();
7677 const intern_index = mod.intern_pool.indexToKey(func_val_ptr);
7678 if (intern_index == .extern_func or (intern_index == .variable and intern_index.variable.is_extern))
7679 return sema.fail(block, call_src, "{s} call of extern function pointer", .{
7680 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
7681 });
7682 break :blk func_val_ptr;
7683 },
7684 else => {},
7685 }
7686 assert(callee_ty.isPtrAtRuntime(mod));
7687 return sema.fail(block, call_src, "{s} call of function pointer", .{
7688 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
7689 });
76577690 },
76587691 else => unreachable,
76597692 };
......@@ -7971,7 +8004,7 @@ fn analyzeCall(
79718004 if (try sema.resolveValue(func)) |func_val| {
79728005 switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
79738006 .func => break :skip_safety,
7974 .ptr => |ptr| switch (ptr.addr) {
8007 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
79758008 .decl => |decl| if (!mod.declPtr(decl).isExtern(mod)) break :skip_safety,
79768009 else => {},
79778010 },
......@@ -8167,7 +8200,7 @@ fn instantiateGenericCall(
81678200 });
81688201 const generic_owner = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
81698202 .func => func_val.toIntern(),
8170 .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.toIntern(),
8203 .ptr => |ptr| mod.declPtr(ptr.base_addr.decl).val.toIntern(),
81718204 else => unreachable,
81728205 };
81738206 const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func;
......@@ -8919,7 +8952,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
89198952 return Air.internedToRef((try mod.getCoerced(int_val, dest_ty)).toIntern());
89208953 }
89218954 return sema.fail(block, src, "int value '{}' out of range of non-exhaustive enum '{}'", .{
8922 int_val.fmtValue(mod), dest_ty.fmt(mod),
8955 int_val.fmtValue(mod, sema), dest_ty.fmt(mod),
89238956 });
89248957 }
89258958 if (int_val.isUndef(mod)) {
......@@ -8927,7 +8960,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
89278960 }
89288961 if (!(try sema.enumHasInt(dest_ty, int_val))) {
89298962 return sema.fail(block, src, "enum '{}' has no tag with value '{}'", .{
8930 dest_ty.fmt(mod), int_val.fmtValue(mod),
8963 dest_ty.fmt(mod), int_val.fmtValue(mod, sema),
89318964 });
89328965 }
89338966 return Air.internedToRef((try mod.getCoerced(int_val, dest_ty)).toIntern());
......@@ -8984,47 +9017,47 @@ fn analyzeOptionalPayloadPtr(
89849017 safety_check: bool,
89859018 initializing: bool,
89869019) CompileError!Air.Inst.Ref {
8987 const mod = sema.mod;
9020 const zcu = sema.mod;
89889021 const optional_ptr_ty = sema.typeOf(optional_ptr);
8989 assert(optional_ptr_ty.zigTypeTag(mod) == .Pointer);
9022 assert(optional_ptr_ty.zigTypeTag(zcu) == .Pointer);
89909023
8991 const opt_type = optional_ptr_ty.childType(mod);
8992 if (opt_type.zigTypeTag(mod) != .Optional) {
8993 return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(mod)});
9024 const opt_type = optional_ptr_ty.childType(zcu);
9025 if (opt_type.zigTypeTag(zcu) != .Optional) {
9026 return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(zcu)});
89949027 }
89959028
8996 const child_type = opt_type.optionalChild(mod);
9029 const child_type = opt_type.optionalChild(zcu);
89979030 const child_pointer = try sema.ptrType(.{
89989031 .child = child_type.toIntern(),
89999032 .flags = .{
9000 .is_const = optional_ptr_ty.isConstPtr(mod),
9001 .address_space = optional_ptr_ty.ptrAddressSpace(mod),
9033 .is_const = optional_ptr_ty.isConstPtr(zcu),
9034 .address_space = optional_ptr_ty.ptrAddressSpace(zcu),
90029035 },
90039036 });
90049037
90059038 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| {
90069039 if (initializing) {
9007 if (!sema.isComptimeMutablePtr(ptr_val)) {
9008 // If the pointer resulting from this function was stored at comptime,
9009 // the optional non-null bit would be set that way. But in this case,
9010 // we need to emit a runtime instruction to do it.
9040 if (sema.isComptimeMutablePtr(ptr_val)) {
9041 // Set the optional to non-null at comptime.
9042 // If the payload is OPV, we must use that value instead of undef.
9043 const payload_val = try sema.typeHasOnePossibleValue(child_type) orelse try zcu.undefValue(child_type);
9044 const opt_val = try zcu.intern(.{ .opt = .{
9045 .ty = opt_type.toIntern(),
9046 .val = payload_val.toIntern(),
9047 } });
9048 try sema.storePtrVal(block, src, ptr_val, Value.fromInterned(opt_val), opt_type);
9049 } else {
9050 // Emit runtime instructions to set the optional non-null bit.
90119051 const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
90129052 try sema.checkKnownAllocPtr(block, optional_ptr, opt_payload_ptr);
90139053 }
9014 return Air.internedToRef((try mod.intern(.{ .ptr = .{
9015 .ty = child_pointer.toIntern(),
9016 .addr = .{ .opt_payload = ptr_val.toIntern() },
9017 } })));
9054 return Air.internedToRef((try ptr_val.ptrOptPayload(sema)).toIntern());
90189055 }
90199056 if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| {
9020 if (val.isNull(mod)) {
9057 if (val.isNull(zcu)) {
90219058 return sema.fail(block, src, "unable to unwrap null", .{});
90229059 }
9023 // The same Value represents the pointer to the optional and the payload.
9024 return Air.internedToRef((try mod.intern(.{ .ptr = .{
9025 .ty = child_pointer.toIntern(),
9026 .addr = .{ .opt_payload = ptr_val.toIntern() },
9027 } })));
9060 return Air.internedToRef((try ptr_val.ptrOptPayload(sema)).toIntern());
90289061 }
90299062 }
90309063
......@@ -9173,49 +9206,50 @@ fn analyzeErrUnionPayloadPtr(
91739206 safety_check: bool,
91749207 initializing: bool,
91759208) CompileError!Air.Inst.Ref {
9176 const mod = sema.mod;
9209 const zcu = sema.mod;
91779210 const operand_ty = sema.typeOf(operand);
9178 assert(operand_ty.zigTypeTag(mod) == .Pointer);
9211 assert(operand_ty.zigTypeTag(zcu) == .Pointer);
91799212
9180 if (operand_ty.childType(mod).zigTypeTag(mod) != .ErrorUnion) {
9213 if (operand_ty.childType(zcu).zigTypeTag(zcu) != .ErrorUnion) {
91819214 return sema.fail(block, src, "expected error union type, found '{}'", .{
9182 operand_ty.childType(mod).fmt(mod),
9215 operand_ty.childType(zcu).fmt(zcu),
91839216 });
91849217 }
91859218
9186 const err_union_ty = operand_ty.childType(mod);
9187 const payload_ty = err_union_ty.errorUnionPayload(mod);
9219 const err_union_ty = operand_ty.childType(zcu);
9220 const payload_ty = err_union_ty.errorUnionPayload(zcu);
91889221 const operand_pointer_ty = try sema.ptrType(.{
91899222 .child = payload_ty.toIntern(),
91909223 .flags = .{
9191 .is_const = operand_ty.isConstPtr(mod),
9192 .address_space = operand_ty.ptrAddressSpace(mod),
9224 .is_const = operand_ty.isConstPtr(zcu),
9225 .address_space = operand_ty.ptrAddressSpace(zcu),
91939226 },
91949227 });
91959228
91969229 if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| {
91979230 if (initializing) {
9198 if (!sema.isComptimeMutablePtr(ptr_val)) {
9199 // If the pointer resulting from this function was stored at comptime,
9200 // the error union error code would be set that way. But in this case,
9201 // we need to emit a runtime instruction to do it.
9231 if (sema.isComptimeMutablePtr(ptr_val)) {
9232 // Set the error union to non-error at comptime.
9233 // If the payload is OPV, we must use that value instead of undef.
9234 const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try zcu.undefValue(payload_ty);
9235 const eu_val = try zcu.intern(.{ .error_union = .{
9236 .ty = err_union_ty.toIntern(),
9237 .val = .{ .payload = payload_val.toIntern() },
9238 } });
9239 try sema.storePtrVal(block, src, ptr_val, Value.fromInterned(eu_val), err_union_ty);
9240 } else {
9241 // Emit runtime instructions to set the error union error code.
92029242 try sema.requireRuntimeBlock(block, src, null);
92039243 const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);
92049244 try sema.checkKnownAllocPtr(block, operand, eu_payload_ptr);
92059245 }
9206 return Air.internedToRef((try mod.intern(.{ .ptr = .{
9207 .ty = operand_pointer_ty.toIntern(),
9208 .addr = .{ .eu_payload = ptr_val.toIntern() },
9209 } })));
9246 return Air.internedToRef((try ptr_val.ptrEuPayload(sema)).toIntern());
92109247 }
92119248 if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| {
9212 if (val.getErrorName(mod).unwrap()) |name| {
9249 if (val.getErrorName(zcu).unwrap()) |name| {
92139250 return sema.failWithComptimeErrorRetTrace(block, src, name);
92149251 }
9215 return Air.internedToRef((try mod.intern(.{ .ptr = .{
9216 .ty = operand_pointer_ty.toIntern(),
9217 .addr = .{ .eu_payload = ptr_val.toIntern() },
9218 } })));
9252 return Air.internedToRef((try ptr_val.ptrEuPayload(sema)).toIntern());
92199253 }
92209254 }
92219255
......@@ -9223,7 +9257,7 @@ fn analyzeErrUnionPayloadPtr(
92239257
92249258 // If the error set has no fields then no safety check is needed.
92259259 if (safety_check and block.wantSafety() and
9226 !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod))
9260 !err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu))
92279261 {
92289262 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
92299263 }
......@@ -10186,49 +10220,56 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1018610220 const tracy = trace(@src());
1018710221 defer tracy.end();
1018810222
10189 const mod = sema.mod;
10223 const zcu = sema.mod;
1019010224 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
1019110225 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1019210226 const operand = try sema.resolveInst(inst_data.operand);
1019310227 const operand_ty = sema.typeOf(operand);
10194 const ptr_ty = operand_ty.scalarType(mod);
10195 const is_vector = operand_ty.zigTypeTag(mod) == .Vector;
10196 if (!ptr_ty.isPtrAtRuntime(mod)) {
10197 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(mod)});
10228 const ptr_ty = operand_ty.scalarType(zcu);
10229 const is_vector = operand_ty.zigTypeTag(zcu) == .Vector;
10230 if (!ptr_ty.isPtrAtRuntime(zcu)) {
10231 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(zcu)});
1019810232 }
10199 const pointee_ty = ptr_ty.childType(mod);
10233 const pointee_ty = ptr_ty.childType(zcu);
1020010234 if (try sema.typeRequiresComptime(ptr_ty)) {
1020110235 const msg = msg: {
10202 const msg = try sema.errMsg(block, ptr_src, "comptime-only type '{}' has no pointer address", .{pointee_ty.fmt(mod)});
10236 const msg = try sema.errMsg(block, ptr_src, "comptime-only type '{}' has no pointer address", .{pointee_ty.fmt(zcu)});
1020310237 errdefer msg.destroy(sema.gpa);
10204 const src_decl = mod.declPtr(block.src_decl);
10205 try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(ptr_src, mod), pointee_ty);
10238 const src_decl = zcu.declPtr(block.src_decl);
10239 try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(ptr_src, zcu), pointee_ty);
1020610240 break :msg msg;
1020710241 };
1020810242 return sema.failWithOwnedErrorMsg(block, msg);
1020910243 }
1021010244 if (try sema.resolveValueIntable(operand)) |operand_val| ct: {
1021110245 if (!is_vector) {
10212 return Air.internedToRef((try mod.intValue(
10246 if (operand_val.isUndef(zcu)) {
10247 return Air.internedToRef((try zcu.undefValue(Type.usize)).toIntern());
10248 }
10249 return Air.internedToRef((try zcu.intValue(
1021310250 Type.usize,
10214 (try operand_val.getUnsignedIntAdvanced(mod, sema)).?,
10251 (try operand_val.getUnsignedIntAdvanced(zcu, sema)).?,
1021510252 )).toIntern());
1021610253 }
10217 const len = operand_ty.vectorLen(mod);
10218 const dest_ty = try mod.vectorType(.{ .child = .usize_type, .len = len });
10254 const len = operand_ty.vectorLen(zcu);
10255 const dest_ty = try zcu.vectorType(.{ .child = .usize_type, .len = len });
1021910256 const new_elems = try sema.arena.alloc(InternPool.Index, len);
1022010257 for (new_elems, 0..) |*new_elem, i| {
10221 const ptr_val = try operand_val.elemValue(mod, i);
10222 const addr = try ptr_val.getUnsignedIntAdvanced(mod, sema) orelse {
10258 const ptr_val = try operand_val.elemValue(zcu, i);
10259 if (ptr_val.isUndef(zcu)) {
10260 new_elem.* = (try zcu.undefValue(Type.usize)).toIntern();
10261 continue;
10262 }
10263 const addr = try ptr_val.getUnsignedIntAdvanced(zcu, sema) orelse {
1022310264 // A vector element wasn't an integer pointer. This is a runtime operation.
1022410265 break :ct;
1022510266 };
10226 new_elem.* = (try mod.intValue(
10267 new_elem.* = (try zcu.intValue(
1022710268 Type.usize,
1022810269 addr,
1022910270 )).toIntern();
1023010271 }
10231 return Air.internedToRef(try mod.intern(.{ .aggregate = .{
10272 return Air.internedToRef(try zcu.intern(.{ .aggregate = .{
1023210273 .ty = dest_ty.toIntern(),
1023310274 .storage = .{ .elems = new_elems },
1023410275 } }));
......@@ -10238,11 +10279,11 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1023810279 if (!is_vector) {
1023910280 return block.addUnOp(.int_from_ptr, operand);
1024010281 }
10241 const len = operand_ty.vectorLen(mod);
10242 const dest_ty = try mod.vectorType(.{ .child = .usize_type, .len = len });
10282 const len = operand_ty.vectorLen(zcu);
10283 const dest_ty = try zcu.vectorType(.{ .child = .usize_type, .len = len });
1024310284 const new_elems = try sema.arena.alloc(Air.Inst.Ref, len);
1024410285 for (new_elems, 0..) |*new_elem, i| {
10245 const idx_ref = try mod.intRef(Type.usize, i);
10286 const idx_ref = try zcu.intRef(Type.usize, i);
1024610287 const old_elem = try block.addBinOp(.array_elem_val, operand, idx_ref);
1024710288 new_elem.* = try block.addUnOp(.int_from_ptr, old_elem);
1024810289 }
......@@ -11077,8 +11118,8 @@ const SwitchProngAnalysis = struct {
1107711118 inline_case_capture: Air.Inst.Ref,
1107811119 ) CompileError!Air.Inst.Ref {
1107911120 const sema = spa.sema;
11080 const mod = sema.mod;
11081 const ip = &mod.intern_pool;
11121 const zcu = sema.mod;
11122 const ip = &zcu.intern_pool;
1108211123
1108311124 const zir_datas = sema.code.instructions.items(.data);
1108411125 const switch_node_offset = zir_datas[@intFromEnum(spa.switch_block_inst)].pl_node.src_node;
......@@ -11089,27 +11130,21 @@ const SwitchProngAnalysis = struct {
1108911130
1109011131 if (inline_case_capture != .none) {
1109111132 const item_val = sema.resolveConstDefinedValue(block, .unneeded, inline_case_capture, undefined) catch unreachable;
11092 if (operand_ty.zigTypeTag(mod) == .Union) {
11093 const field_index: u32 = @intCast(operand_ty.unionTagFieldIndex(item_val, mod).?);
11094 const union_obj = mod.typeToUnion(operand_ty).?;
11133 if (operand_ty.zigTypeTag(zcu) == .Union) {
11134 const field_index: u32 = @intCast(operand_ty.unionTagFieldIndex(item_val, zcu).?);
11135 const union_obj = zcu.typeToUnion(operand_ty).?;
1109511136 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
1109611137 if (capture_byref) {
1109711138 const ptr_field_ty = try sema.ptrType(.{
1109811139 .child = field_ty.toIntern(),
1109911140 .flags = .{
11100 .is_const = !operand_ptr_ty.ptrIsMutable(mod),
11101 .is_volatile = operand_ptr_ty.isVolatilePtr(mod),
11102 .address_space = operand_ptr_ty.ptrAddressSpace(mod),
11141 .is_const = !operand_ptr_ty.ptrIsMutable(zcu),
11142 .is_volatile = operand_ptr_ty.isVolatilePtr(zcu),
11143 .address_space = operand_ptr_ty.ptrAddressSpace(zcu),
1110311144 },
1110411145 });
1110511146 if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |union_ptr| {
11106 return Air.internedToRef((try mod.intern(.{ .ptr = .{
11107 .ty = ptr_field_ty.toIntern(),
11108 .addr = .{ .field = .{
11109 .base = union_ptr.toIntern(),
11110 .index = field_index,
11111 } },
11112 } })));
11147 return Air.internedToRef((try union_ptr.ptrField(field_index, sema)).toIntern());
1111311148 }
1111411149 return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty);
1111511150 } else {
......@@ -11131,7 +11166,7 @@ const SwitchProngAnalysis = struct {
1113111166 return spa.operand_ptr;
1113211167 }
1113311168
11134 switch (operand_ty.zigTypeTag(mod)) {
11169 switch (operand_ty.zigTypeTag(zcu)) {
1113511170 .ErrorSet => if (spa.else_error_ty) |ty| {
1113611171 return sema.bitCast(block, ty, spa.operand, operand_src, null);
1113711172 } else {
......@@ -11142,25 +11177,25 @@ const SwitchProngAnalysis = struct {
1114211177 }
1114311178 }
1114411179
11145 switch (operand_ty.zigTypeTag(mod)) {
11180 switch (operand_ty.zigTypeTag(zcu)) {
1114611181 .Union => {
11147 const union_obj = mod.typeToUnion(operand_ty).?;
11182 const union_obj = zcu.typeToUnion(operand_ty).?;
1114811183 const first_item_val = sema.resolveConstDefinedValue(block, .unneeded, case_vals[0], undefined) catch unreachable;
1114911184
11150 const first_field_index: u32 = mod.unionTagFieldIndex(union_obj, first_item_val).?;
11185 const first_field_index: u32 = zcu.unionTagFieldIndex(union_obj, first_item_val).?;
1115111186 const first_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[first_field_index]);
1115211187
1115311188 const field_indices = try sema.arena.alloc(u32, case_vals.len);
1115411189 for (case_vals, field_indices) |item, *field_idx| {
1115511190 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item, undefined) catch unreachable;
11156 field_idx.* = mod.unionTagFieldIndex(union_obj, item_val).?;
11191 field_idx.* = zcu.unionTagFieldIndex(union_obj, item_val).?;
1115711192 }
1115811193
1115911194 // Fast path: if all the operands are the same type already, we don't need to hit
1116011195 // PTR! This will also allow us to emit simpler code.
1116111196 const same_types = for (field_indices[1..]) |field_idx| {
1116211197 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]);
11163 if (!field_ty.eql(first_field_ty, sema.mod)) break false;
11198 if (!field_ty.eql(first_field_ty, zcu)) break false;
1116411199 } else true;
1116511200
1116611201 const capture_ty = if (same_types) first_field_ty else capture_ty: {
......@@ -11168,7 +11203,7 @@ const SwitchProngAnalysis = struct {
1116811203 const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len);
1116911204 for (dummy_captures, field_indices) |*dummy, field_idx| {
1117011205 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]);
11171 dummy.* = try mod.undefRef(field_ty);
11206 dummy.* = try zcu.undefRef(field_ty);
1117211207 }
1117311208
1117411209 const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len);
......@@ -11178,12 +11213,12 @@ const SwitchProngAnalysis = struct {
1117811213 error.NeededSourceLocation => {
1117911214 // This must be a multi-prong so this must be a `multi_capture` src
1118011215 const multi_idx = raw_capture_src.multi_capture;
11181 const src_decl_ptr = sema.mod.declPtr(block.src_decl);
11216 const src_decl_ptr = zcu.declPtr(block.src_decl);
1118211217 for (case_srcs, 0..) |*case_src, i| {
1118311218 const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(i) } };
11184 case_src.* = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
11219 case_src.* = raw_case_src.resolve(zcu, src_decl_ptr, switch_node_offset, .none);
1118511220 }
11186 const capture_src = raw_capture_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
11221 const capture_src = raw_capture_src.resolve(zcu, src_decl_ptr, switch_node_offset, .none);
1118711222 _ = sema.resolvePeerTypes(block, capture_src, dummy_captures, .{ .override = case_srcs }) catch |err1| switch (err1) {
1118811223 error.AnalysisFail => {
1118911224 const msg = sema.err orelse return error.AnalysisFail;
......@@ -11200,7 +11235,7 @@ const SwitchProngAnalysis = struct {
1120011235
1120111236 // By-reference captures have some further restrictions which make them easier to emit
1120211237 if (capture_byref) {
11203 const operand_ptr_info = operand_ptr_ty.ptrInfo(mod);
11238 const operand_ptr_info = operand_ptr_ty.ptrInfo(zcu);
1120411239 const capture_ptr_ty = resolve: {
1120511240 // By-ref captures of hetereogeneous types are only allowed if all field
1120611241 // pointer types are peer resolvable to each other.
......@@ -11217,7 +11252,7 @@ const SwitchProngAnalysis = struct {
1121711252 .alignment = union_obj.fieldAlign(ip, field_idx),
1121811253 },
1121911254 });
11220 dummy.* = try mod.undefRef(field_ptr_ty);
11255 dummy.* = try zcu.undefRef(field_ptr_ty);
1122111256 }
1122211257 const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len);
1122311258 @memset(case_srcs, .unneeded);
......@@ -11226,12 +11261,12 @@ const SwitchProngAnalysis = struct {
1122611261 error.NeededSourceLocation => {
1122711262 // This must be a multi-prong so this must be a `multi_capture` src
1122811263 const multi_idx = raw_capture_src.multi_capture;
11229 const src_decl_ptr = sema.mod.declPtr(block.src_decl);
11264 const src_decl_ptr = zcu.declPtr(block.src_decl);
1123011265 for (case_srcs, 0..) |*case_src, i| {
1123111266 const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(i) } };
11232 case_src.* = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
11267 case_src.* = raw_case_src.resolve(zcu, src_decl_ptr, switch_node_offset, .none);
1123311268 }
11234 const capture_src = raw_capture_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
11269 const capture_src = raw_capture_src.resolve(zcu, src_decl_ptr, switch_node_offset, .none);
1123511270 _ = sema.resolvePeerTypes(block, capture_src, dummy_captures, .{ .override = case_srcs }) catch |err1| switch (err1) {
1123611271 error.AnalysisFail => {
1123711272 const msg = sema.err orelse return error.AnalysisFail;
......@@ -11248,14 +11283,9 @@ const SwitchProngAnalysis = struct {
1124811283 };
1124911284
1125011285 if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |op_ptr_val| {
11251 if (op_ptr_val.isUndef(mod)) return mod.undefRef(capture_ptr_ty);
11252 return Air.internedToRef((try mod.intern(.{ .ptr = .{
11253 .ty = capture_ptr_ty.toIntern(),
11254 .addr = .{ .field = .{
11255 .base = op_ptr_val.toIntern(),
11256 .index = first_field_index,
11257 } },
11258 } })));
11286 if (op_ptr_val.isUndef(zcu)) return zcu.undefRef(capture_ptr_ty);
11287 const field_ptr_val = try op_ptr_val.ptrField(first_field_index, sema);
11288 return Air.internedToRef((try zcu.getCoerced(field_ptr_val, capture_ptr_ty)).toIntern());
1125911289 }
1126011290
1126111291 try sema.requireRuntimeBlock(block, operand_src, null);
......@@ -11263,9 +11293,9 @@ const SwitchProngAnalysis = struct {
1126311293 }
1126411294
1126511295 if (try sema.resolveDefinedValue(block, operand_src, spa.operand)) |operand_val| {
11266 if (operand_val.isUndef(mod)) return mod.undefRef(capture_ty);
11296 if (operand_val.isUndef(zcu)) return zcu.undefRef(capture_ty);
1126711297 const union_val = ip.indexToKey(operand_val.toIntern()).un;
11268 if (Value.fromInterned(union_val.tag).isUndef(mod)) return mod.undefRef(capture_ty);
11298 if (Value.fromInterned(union_val.tag).isUndef(zcu)) return zcu.undefRef(capture_ty);
1126911299 const uncoerced = Air.internedToRef(union_val.val);
1127011300 return sema.coerce(block, capture_ty, uncoerced, operand_src);
1127111301 }
......@@ -11281,7 +11311,7 @@ const SwitchProngAnalysis = struct {
1128111311 const first_non_imc = in_mem: {
1128211312 for (field_indices, 0..) |field_idx, i| {
1128311313 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]);
11284 if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) {
11314 if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, zcu.getTarget(), .unneeded, .unneeded)) {
1128511315 break :in_mem i;
1128611316 }
1128711317 }
......@@ -11304,7 +11334,7 @@ const SwitchProngAnalysis = struct {
1130411334 const next = first_non_imc + 1;
1130511335 for (field_indices[next..], next..) |field_idx, i| {
1130611336 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]);
11307 if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) {
11337 if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, zcu.getTarget(), .unneeded, .unneeded)) {
1130811338 in_mem_coercible.unset(i);
1130911339 }
1131011340 }
......@@ -11339,9 +11369,9 @@ const SwitchProngAnalysis = struct {
1133911369 const coerced = sema.coerce(&coerce_block, capture_ty, uncoerced, .unneeded) catch |err| switch (err) {
1134011370 error.NeededSourceLocation => {
1134111371 const multi_idx = raw_capture_src.multi_capture;
11342 const src_decl_ptr = sema.mod.declPtr(block.src_decl);
11372 const src_decl_ptr = zcu.declPtr(block.src_decl);
1134311373 const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(idx) } };
11344 const case_src = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
11374 const case_src = raw_case_src.resolve(zcu, src_decl_ptr, switch_node_offset, .none);
1134511375 _ = try sema.coerce(&coerce_block, capture_ty, uncoerced, case_src);
1134611376 unreachable;
1134711377 },
......@@ -11400,7 +11430,7 @@ const SwitchProngAnalysis = struct {
1140011430 },
1140111431 .ErrorSet => {
1140211432 if (capture_byref) {
11403 const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
11433 const capture_src = raw_capture_src.resolve(zcu, zcu.declPtr(block.src_decl), switch_node_offset, .none);
1140411434 return sema.fail(
1140511435 block,
1140611436 capture_src,
......@@ -11411,7 +11441,7 @@ const SwitchProngAnalysis = struct {
1141111441
1141211442 if (case_vals.len == 1) {
1141311443 const item_val = sema.resolveConstDefinedValue(block, .unneeded, case_vals[0], undefined) catch unreachable;
11414 const item_ty = try mod.singleErrorSetType(item_val.getErrorName(mod).unwrap().?);
11444 const item_ty = try zcu.singleErrorSetType(item_val.getErrorName(zcu).unwrap().?);
1141511445 return sema.bitCast(block, item_ty, spa.operand, operand_src, null);
1141611446 }
1141711447
......@@ -11419,9 +11449,9 @@ const SwitchProngAnalysis = struct {
1141911449 try names.ensureUnusedCapacity(sema.arena, case_vals.len);
1142011450 for (case_vals) |err| {
1142111451 const err_val = sema.resolveConstDefinedValue(block, .unneeded, err, undefined) catch unreachable;
11422 names.putAssumeCapacityNoClobber(err_val.getErrorName(mod).unwrap().?, {});
11452 names.putAssumeCapacityNoClobber(err_val.getErrorName(zcu).unwrap().?, {});
1142311453 }
11424 const error_ty = try mod.errorSetFromUnsortedNames(names.keys());
11454 const error_ty = try zcu.errorSetFromUnsortedNames(names.keys());
1142511455 return sema.bitCast(block, error_ty, spa.operand, operand_src, null);
1142611456 },
1142711457 else => {
......@@ -13989,7 +14019,7 @@ fn zirShl(
1398914019 const rhs_elem = try rhs_val.elemValue(mod, i);
1399014020 if (rhs_elem.compareHetero(.gte, bit_value, mod)) {
1399114021 return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
13992 rhs_elem.fmtValue(mod),
14022 rhs_elem.fmtValue(mod, sema),
1399314023 i,
1399414024 scalar_ty.fmt(mod),
1399514025 });
......@@ -13997,7 +14027,7 @@ fn zirShl(
1399714027 }
1399814028 } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {
1399914029 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
14000 rhs_val.fmtValue(mod),
14030 rhs_val.fmtValue(mod, sema),
1400114031 scalar_ty.fmt(mod),
1400214032 });
1400314033 }
......@@ -14008,14 +14038,14 @@ fn zirShl(
1400814038 const rhs_elem = try rhs_val.elemValue(mod, i);
1400914039 if (rhs_elem.compareHetero(.lt, try mod.intValue(scalar_rhs_ty, 0), mod)) {
1401014040 return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
14011 rhs_elem.fmtValue(mod),
14041 rhs_elem.fmtValue(mod, sema),
1401214042 i,
1401314043 });
1401414044 }
1401514045 }
1401614046 } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {
1401714047 return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
14018 rhs_val.fmtValue(mod),
14048 rhs_val.fmtValue(mod, sema),
1401914049 });
1402014050 }
1402114051 }
......@@ -14154,7 +14184,7 @@ fn zirShr(
1415414184 const rhs_elem = try rhs_val.elemValue(mod, i);
1415514185 if (rhs_elem.compareHetero(.gte, bit_value, mod)) {
1415614186 return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
14157 rhs_elem.fmtValue(mod),
14187 rhs_elem.fmtValue(mod, sema),
1415814188 i,
1415914189 scalar_ty.fmt(mod),
1416014190 });
......@@ -14162,7 +14192,7 @@ fn zirShr(
1416214192 }
1416314193 } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {
1416414194 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
14165 rhs_val.fmtValue(mod),
14195 rhs_val.fmtValue(mod, sema),
1416614196 scalar_ty.fmt(mod),
1416714197 });
1416814198 }
......@@ -14173,14 +14203,14 @@ fn zirShr(
1417314203 const rhs_elem = try rhs_val.elemValue(mod, i);
1417414204 if (rhs_elem.compareHetero(.lt, try mod.intValue(rhs_ty.childType(mod), 0), mod)) {
1417514205 return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
14176 rhs_elem.fmtValue(mod),
14206 rhs_elem.fmtValue(mod, sema),
1417714207 i,
1417814208 });
1417914209 }
1418014210 }
1418114211 } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {
1418214212 return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
14183 rhs_val.fmtValue(mod),
14213 rhs_val.fmtValue(mod, sema),
1418414214 });
1418514215 }
1418614216 if (maybe_lhs_val) |lhs_val| {
......@@ -15101,7 +15131,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1510115131 block,
1510215132 src,
1510315133 "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'",
15104 .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod), rem.fmtValue(mod) },
15134 .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod), rem.fmtValue(mod, sema) },
1510515135 );
1510615136 }
1510715137 }
......@@ -16903,21 +16933,14 @@ fn analyzePtrArithmetic(
1690316933
1690416934 const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntAdvanced(sema));
1690516935 if (offset_int == 0) return ptr;
16906 if (try ptr_val.getUnsignedIntAdvanced(mod, sema)) |addr| {
16936 if (air_tag == .ptr_sub) {
1690716937 const elem_size = try sema.typeAbiSize(Type.fromInterned(ptr_info.child));
16908 const new_addr = switch (air_tag) {
16909 .ptr_add => addr + elem_size * offset_int,
16910 .ptr_sub => addr - elem_size * offset_int,
16911 else => unreachable,
16912 };
16913 const new_ptr_val = try mod.ptrIntValue(new_ptr_ty, new_addr);
16938 const new_ptr_val = try sema.ptrSubtract(block, op_src, ptr_val, offset_int * elem_size, new_ptr_ty);
16939 return Air.internedToRef(new_ptr_val.toIntern());
16940 } else {
16941 const new_ptr_val = try mod.getCoerced(try ptr_val.ptrElem(offset_int, sema), new_ptr_ty);
1691416942 return Air.internedToRef(new_ptr_val.toIntern());
1691516943 }
16916 if (air_tag == .ptr_sub) {
16917 return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{});
16918 }
16919 const new_ptr_val = try ptr_val.elemPtr(new_ptr_ty, offset_int, mod);
16920 return Air.internedToRef(new_ptr_val.toIntern());
1692116944 } else break :rs offset_src;
1692216945 } else break :rs ptr_src;
1692316946 };
......@@ -17611,13 +17634,14 @@ fn zirBuiltinSrc(
1761117634 .ty = .slice_const_u8_sentinel_0_type,
1761217635 .ptr = try ip.get(gpa, .{ .ptr = .{
1761317636 .ty = .manyptr_const_u8_sentinel_0_type,
17614 .addr = .{ .anon_decl = .{
17637 .base_addr = .{ .anon_decl = .{
1761517638 .orig_ty = .slice_const_u8_sentinel_0_type,
1761617639 .val = try ip.get(gpa, .{ .aggregate = .{
1761717640 .ty = array_ty,
1761817641 .storage = .{ .bytes = fn_owner_decl.name.toString() },
1761917642 } }),
1762017643 } },
17644 .byte_offset = 0,
1762117645 } }),
1762217646 .len = (try mod.intValue(Type.usize, func_name_len)).toIntern(),
1762317647 } });
......@@ -17635,7 +17659,7 @@ fn zirBuiltinSrc(
1763517659 .ty = .slice_const_u8_sentinel_0_type,
1763617660 .ptr = try ip.get(gpa, .{ .ptr = .{
1763717661 .ty = .manyptr_const_u8_sentinel_0_type,
17638 .addr = .{ .anon_decl = .{
17662 .base_addr = .{ .anon_decl = .{
1763917663 .orig_ty = .slice_const_u8_sentinel_0_type,
1764017664 .val = try ip.get(gpa, .{ .aggregate = .{
1764117665 .ty = array_ty,
......@@ -17644,6 +17668,7 @@ fn zirBuiltinSrc(
1764417668 },
1764517669 } }),
1764617670 } },
17671 .byte_offset = 0,
1764717672 } }),
1764817673 .len = (try mod.intValue(Type.usize, file_name.len)).toIntern(),
1764917674 } });
......@@ -17766,10 +17791,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1776617791 .ty = slice_ty,
1776717792 .ptr = try mod.intern(.{ .ptr = .{
1776817793 .ty = manyptr_ty,
17769 .addr = .{ .anon_decl = .{
17794 .base_addr = .{ .anon_decl = .{
1777017795 .orig_ty = manyptr_ty,
1777117796 .val = new_decl_val,
1777217797 } },
17798 .byte_offset = 0,
1777317799 } }),
1777417800 .len = (try mod.intValue(Type.usize, param_vals.len)).toIntern(),
1777517801 } });
......@@ -18046,10 +18072,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1804618072 .ty = .slice_const_u8_sentinel_0_type,
1804718073 .ptr = try mod.intern(.{ .ptr = .{
1804818074 .ty = .manyptr_const_u8_sentinel_0_type,
18049 .addr = .{ .anon_decl = .{
18075 .base_addr = .{ .anon_decl = .{
1805018076 .val = new_decl_val,
1805118077 .orig_ty = .slice_const_u8_sentinel_0_type,
1805218078 } },
18079 .byte_offset = 0,
1805318080 } }),
1805418081 .len = (try mod.intValue(Type.usize, error_name_len)).toIntern(),
1805518082 } });
......@@ -18092,10 +18119,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1809218119 .ty = slice_errors_ty.toIntern(),
1809318120 .ptr = try mod.intern(.{ .ptr = .{
1809418121 .ty = manyptr_errors_ty,
18095 .addr = .{ .anon_decl = .{
18122 .base_addr = .{ .anon_decl = .{
1809618123 .orig_ty = manyptr_errors_ty,
1809718124 .val = new_decl_val,
1809818125 } },
18126 .byte_offset = 0,
1809918127 } }),
1810018128 .len = (try mod.intValue(Type.usize, vals.len)).toIntern(),
1810118129 } });
......@@ -18184,10 +18212,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1818418212 .ty = .slice_const_u8_sentinel_0_type,
1818518213 .ptr = try mod.intern(.{ .ptr = .{
1818618214 .ty = .manyptr_const_u8_sentinel_0_type,
18187 .addr = .{ .anon_decl = .{
18215 .base_addr = .{ .anon_decl = .{
1818818216 .val = new_decl_val,
1818918217 .orig_ty = .slice_const_u8_sentinel_0_type,
1819018218 } },
18219 .byte_offset = 0,
1819118220 } }),
1819218221 .len = (try mod.intValue(Type.usize, tag_name_len)).toIntern(),
1819318222 } });
......@@ -18226,10 +18255,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1822618255 .ty = slice_ty,
1822718256 .ptr = try mod.intern(.{ .ptr = .{
1822818257 .ty = manyptr_ty,
18229 .addr = .{ .anon_decl = .{
18258 .base_addr = .{ .anon_decl = .{
1823018259 .val = new_decl_val,
1823118260 .orig_ty = manyptr_ty,
1823218261 } },
18262 .byte_offset = 0,
1823318263 } }),
1823418264 .len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(),
1823518265 } });
......@@ -18318,10 +18348,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1831818348 .ty = .slice_const_u8_sentinel_0_type,
1831918349 .ptr = try mod.intern(.{ .ptr = .{
1832018350 .ty = .manyptr_const_u8_sentinel_0_type,
18321 .addr = .{ .anon_decl = .{
18351 .base_addr = .{ .anon_decl = .{
1832218352 .val = new_decl_val,
1832318353 .orig_ty = .slice_const_u8_sentinel_0_type,
1832418354 } },
18355 .byte_offset = 0,
1832518356 } }),
1832618357 .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),
1832718358 } });
......@@ -18368,10 +18399,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1836818399 .ty = slice_ty,
1836918400 .ptr = try mod.intern(.{ .ptr = .{
1837018401 .ty = manyptr_ty,
18371 .addr = .{ .anon_decl = .{
18402 .base_addr = .{ .anon_decl = .{
1837218403 .orig_ty = manyptr_ty,
1837318404 .val = new_decl_val,
1837418405 } },
18406 .byte_offset = 0,
1837518407 } }),
1837618408 .len = (try mod.intValue(Type.usize, union_field_vals.len)).toIntern(),
1837718409 } });
......@@ -18471,10 +18503,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1847118503 .ty = .slice_const_u8_sentinel_0_type,
1847218504 .ptr = try mod.intern(.{ .ptr = .{
1847318505 .ty = .manyptr_const_u8_sentinel_0_type,
18474 .addr = .{ .anon_decl = .{
18506 .base_addr = .{ .anon_decl = .{
1847518507 .val = new_decl_val,
1847618508 .orig_ty = .slice_const_u8_sentinel_0_type,
1847718509 } },
18510 .byte_offset = 0,
1847818511 } }),
1847918512 .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),
1848018513 } });
......@@ -18534,10 +18567,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1853418567 .ty = .slice_const_u8_sentinel_0_type,
1853518568 .ptr = try mod.intern(.{ .ptr = .{
1853618569 .ty = .manyptr_const_u8_sentinel_0_type,
18537 .addr = .{ .anon_decl = .{
18570 .base_addr = .{ .anon_decl = .{
1853818571 .val = new_decl_val,
1853918572 .orig_ty = .slice_const_u8_sentinel_0_type,
1854018573 } },
18574 .byte_offset = 0,
1854118575 } }),
1854218576 .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),
1854318577 } });
......@@ -18594,10 +18628,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1859418628 .ty = slice_ty,
1859518629 .ptr = try mod.intern(.{ .ptr = .{
1859618630 .ty = manyptr_ty,
18597 .addr = .{ .anon_decl = .{
18631 .base_addr = .{ .anon_decl = .{
1859818632 .orig_ty = manyptr_ty,
1859918633 .val = new_decl_val,
1860018634 } },
18635 .byte_offset = 0,
1860118636 } }),
1860218637 .len = (try mod.intValue(Type.usize, struct_field_vals.len)).toIntern(),
1860318638 } });
......@@ -18733,10 +18768,11 @@ fn typeInfoDecls(
1873318768 .ty = slice_ty,
1873418769 .ptr = try mod.intern(.{ .ptr = .{
1873518770 .ty = manyptr_ty,
18736 .addr = .{ .anon_decl = .{
18771 .base_addr = .{ .anon_decl = .{
1873718772 .orig_ty = manyptr_ty,
1873818773 .val = new_decl_val,
1873918774 } },
18775 .byte_offset = 0,
1874018776 } }),
1874118777 .len = (try mod.intValue(Type.usize, decl_vals.items.len)).toIntern(),
1874218778 } });
......@@ -18765,7 +18801,7 @@ fn typeInfoNamespaceDecls(
1876518801 if (!decl.is_pub) continue;
1876618802 if (decl.kind == .@"usingnamespace") {
1876718803 if (decl.analysis == .in_progress) continue;
18768 try mod.ensureDeclAnalyzed(decl_index);
18804 try sema.ensureDeclAnalyzed(decl_index);
1876918805 try sema.typeInfoNamespaceDecls(block, decl.val.toType().getNamespaceIndex(mod), declaration_ty, decl_vals, seen_namespaces);
1877018806 continue;
1877118807 }
......@@ -18785,10 +18821,11 @@ fn typeInfoNamespaceDecls(
1878518821 .ty = .slice_const_u8_sentinel_0_type,
1878618822 .ptr = try mod.intern(.{ .ptr = .{
1878718823 .ty = .manyptr_const_u8_sentinel_0_type,
18788 .addr = .{ .anon_decl = .{
18824 .base_addr = .{ .anon_decl = .{
1878918825 .orig_ty = .slice_const_u8_sentinel_0_type,
1879018826 .val = new_decl_val,
1879118827 } },
18828 .byte_offset = 0,
1879218829 } }),
1879318830 .len = (try mod.intValue(Type.usize, decl_name_len)).toIntern(),
1879418831 } });
......@@ -19907,6 +19944,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1990719944 }
1990819945 }
1990919946
19947 if (host_size != 0 and !try sema.validatePackedType(elem_ty)) {
19948 return sema.failWithOwnedErrorMsg(block, msg: {
19949 const msg = try sema.errMsg(block, elem_ty_src, "bit-pointer cannot refer to value of type '{}'", .{elem_ty.fmt(mod)});
19950 errdefer msg.destroy(sema.gpa);
19951 const src_decl = mod.declPtr(block.src_decl);
19952 try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(elem_ty_src, mod), elem_ty);
19953 break :msg msg;
19954 });
19955 }
19956
1991019957 const ty = try sema.ptrType(.{
1991119958 .child = elem_ty.toIntern(),
1991219959 .sentinel = sentinel,
......@@ -21176,7 +21223,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2117621223 const enum_decl = mod.declPtr(enum_decl_index);
2117721224 const msg = msg: {
2117821225 const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{}'", .{
21179 val.fmtValue(sema.mod), enum_decl.name.fmt(ip),
21226 val.fmtValue(sema.mod, sema), enum_decl.name.fmt(ip),
2118021227 });
2118121228 errdefer msg.destroy(sema.gpa);
2118221229 try mod.errNoteNonLazy(enum_decl.srcLoc(mod), msg, "declared here", .{});
......@@ -21811,7 +21858,7 @@ fn reifyEnum(
2181121858 // TODO: better source location
2181221859 return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{
2181321860 field_name.fmt(ip),
21814 field_value_val.fmtValue(mod),
21861 field_value_val.fmtValue(mod, sema),
2181521862 tag_ty.fmt(mod),
2181621863 });
2181721864 }
......@@ -21827,7 +21874,7 @@ fn reifyEnum(
2182721874 break :msg msg;
2182821875 },
2182921876 .value => msg: {
21830 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{field_value_val.fmtValue(mod)});
21877 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{field_value_val.fmtValue(mod, sema)});
2183121878 errdefer msg.destroy(gpa);
2183221879 _ = conflict.prev_field_idx; // TODO: this note is incorrect
2183321880 try sema.errNote(block, src, msg, "other enum tag value here", .{});
......@@ -22681,19 +22728,25 @@ fn ptrFromIntVal(
2268122728 ptr_ty: Type,
2268222729 ptr_align: Alignment,
2268322730) !Value {
22684 const mod = sema.mod;
22731 const zcu = sema.mod;
22732 if (operand_val.isUndef(zcu)) {
22733 if (ptr_ty.isAllowzeroPtr(zcu) and ptr_align == .@"1") {
22734 return zcu.undefValue(ptr_ty);
22735 }
22736 return sema.failWithUseOfUndef(block, operand_src);
22737 }
2268522738 const addr = try operand_val.toUnsignedIntAdvanced(sema);
22686 if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)
22687 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)});
22739 if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0)
22740 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(zcu)});
2268822741 if (addr != 0 and ptr_align != .none and !ptr_align.check(addr))
22689 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
22742 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(zcu)});
2269022743
22691 return switch (ptr_ty.zigTypeTag(mod)) {
22692 .Optional => Value.fromInterned((try mod.intern(.{ .opt = .{
22744 return switch (ptr_ty.zigTypeTag(zcu)) {
22745 .Optional => Value.fromInterned((try zcu.intern(.{ .opt = .{
2269322746 .ty = ptr_ty.toIntern(),
22694 .val = if (addr == 0) .none else (try mod.ptrIntValue(ptr_ty.childType(mod), addr)).toIntern(),
22747 .val = if (addr == 0) .none else (try zcu.ptrIntValue(ptr_ty.childType(zcu), addr)).toIntern(),
2269522748 } }))),
22696 .Pointer => try mod.ptrIntValue(ptr_ty, addr),
22749 .Pointer => try zcu.ptrIntValue(ptr_ty, addr),
2269722750 else => unreachable,
2269822751 };
2269922752}
......@@ -22980,12 +23033,12 @@ fn ptrCastFull(
2298023033 return sema.failWithOwnedErrorMsg(block, msg: {
2298123034 const msg = if (src_info.sentinel == .none) blk: {
2298223035 break :blk try sema.errMsg(block, src, "destination pointer requires '{}' sentinel", .{
22983 Value.fromInterned(dest_info.sentinel).fmtValue(mod),
23036 Value.fromInterned(dest_info.sentinel).fmtValue(mod, sema),
2298423037 });
2298523038 } else blk: {
2298623039 break :blk try sema.errMsg(block, src, "pointer sentinel '{}' cannot coerce into pointer sentinel '{}'", .{
22987 Value.fromInterned(src_info.sentinel).fmtValue(mod),
22988 Value.fromInterned(dest_info.sentinel).fmtValue(mod),
23040 Value.fromInterned(src_info.sentinel).fmtValue(mod, sema),
23041 Value.fromInterned(dest_info.sentinel).fmtValue(mod, sema),
2298923042 });
2299023043 };
2299123044 errdefer msg.destroy(sema.gpa);
......@@ -23159,11 +23212,13 @@ fn ptrCastFull(
2315923212 if (dest_info.flags.size == .Slice and src_info.flags.size != .Slice) {
2316023213 if (ptr_val.isUndef(mod)) return mod.undefRef(dest_ty);
2316123214 const arr_len = try mod.intValue(Type.usize, Type.fromInterned(src_info.child).arrayLen(mod));
23215 const ptr_val_key = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
2316223216 return Air.internedToRef((try mod.intern(.{ .slice = .{
2316323217 .ty = dest_ty.toIntern(),
2316423218 .ptr = try mod.intern(.{ .ptr = .{
2316523219 .ty = dest_ty.slicePtrFieldType(mod).toIntern(),
23166 .addr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr,
23220 .base_addr = ptr_val_key.base_addr,
23221 .byte_offset = ptr_val_key.byte_offset,
2316723222 } }),
2316823223 .len = arr_len.toIntern(),
2316923224 } })));
......@@ -23834,36 +23889,6 @@ fn checkPtrIsNotComptimeMutable(
2383423889 }
2383523890}
2383623891
23837fn checkComptimeVarStore(
23838 sema: *Sema,
23839 block: *Block,
23840 src: LazySrcLoc,
23841 alloc_index: ComptimeAllocIndex,
23842) CompileError!void {
23843 const runtime_index = sema.getComptimeAlloc(alloc_index).runtime_index;
23844 if (@intFromEnum(runtime_index) < @intFromEnum(block.runtime_index)) {
23845 if (block.runtime_cond) |cond_src| {
23846 const msg = msg: {
23847 const msg = try sema.errMsg(block, src, "store to comptime variable depends on runtime condition", .{});
23848 errdefer msg.destroy(sema.gpa);
23849 try sema.mod.errNoteNonLazy(cond_src, msg, "runtime condition here", .{});
23850 break :msg msg;
23851 };
23852 return sema.failWithOwnedErrorMsg(block, msg);
23853 }
23854 if (block.runtime_loop) |loop_src| {
23855 const msg = msg: {
23856 const msg = try sema.errMsg(block, src, "cannot store to comptime variable in non-inline loop", .{});
23857 errdefer msg.destroy(sema.gpa);
23858 try sema.mod.errNoteNonLazy(loop_src, msg, "non-inline loop here", .{});
23859 break :msg msg;
23860 };
23861 return sema.failWithOwnedErrorMsg(block, msg);
23862 }
23863 unreachable;
23864 }
23865}
23866
2386723892fn checkIntOrVector(
2386823893 sema: *Sema,
2386923894 block: *Block,
......@@ -24926,8 +24951,8 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
2492624951}
2492724952
2492824953fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
24929 const mod = sema.mod;
24930 const ip = &mod.intern_pool;
24954 const zcu = sema.mod;
24955 const ip = &zcu.intern_pool;
2493124956
2493224957 const extra = sema.code.extraData(Zir.Inst.FieldParentPtr, extended.operand).data;
2493324958 const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).Struct.backing_integer.?;
......@@ -24939,23 +24964,23 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2493924964
2494024965 const parent_ptr_ty = try sema.resolveDestType(block, inst_src, extra.parent_ptr_type, .remove_eu, "@fieldParentPtr");
2494124966 try sema.checkPtrType(block, inst_src, parent_ptr_ty, true);
24942 const parent_ptr_info = parent_ptr_ty.ptrInfo(mod);
24967 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
2494324968 if (parent_ptr_info.flags.size != .One) {
24944 return sema.fail(block, inst_src, "expected single pointer type, found '{}'", .{parent_ptr_ty.fmt(sema.mod)});
24969 return sema.fail(block, inst_src, "expected single pointer type, found '{}'", .{parent_ptr_ty.fmt(zcu)});
2494524970 }
2494624971 const parent_ty = Type.fromInterned(parent_ptr_info.child);
24947 switch (parent_ty.zigTypeTag(mod)) {
24972 switch (parent_ty.zigTypeTag(zcu)) {
2494824973 .Struct, .Union => {},
24949 else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{}'", .{parent_ptr_ty.fmt(sema.mod)}),
24974 else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{}'", .{parent_ptr_ty.fmt(zcu)}),
2495024975 }
2495124976 try sema.resolveTypeLayout(parent_ty);
2495224977
2495324978 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{
2495424979 .needed_comptime_reason = "field name must be comptime-known",
2495524980 });
24956 const field_index = switch (parent_ty.zigTypeTag(mod)) {
24981 const field_index = switch (parent_ty.zigTypeTag(zcu)) {
2495724982 .Struct => blk: {
24958 if (parent_ty.isTuple(mod)) {
24983 if (parent_ty.isTuple(zcu)) {
2495924984 if (field_name.eqlSlice("len", ip)) {
2496024985 return sema.fail(block, inst_src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});
2496124986 }
......@@ -24967,19 +24992,19 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2496724992 .Union => try sema.unionFieldIndex(block, parent_ty, field_name, field_name_src),
2496824993 else => unreachable,
2496924994 };
24970 if (parent_ty.zigTypeTag(mod) == .Struct and parent_ty.structFieldIsComptime(field_index, mod)) {
24995 if (parent_ty.zigTypeTag(zcu) == .Struct and parent_ty.structFieldIsComptime(field_index, zcu)) {
2497124996 return sema.fail(block, field_name_src, "cannot get @fieldParentPtr of a comptime field", .{});
2497224997 }
2497324998
2497424999 const field_ptr = try sema.resolveInst(extra.field_ptr);
2497525000 const field_ptr_ty = sema.typeOf(field_ptr);
2497625001 try sema.checkPtrOperand(block, field_ptr_src, field_ptr_ty);
24977 const field_ptr_info = field_ptr_ty.ptrInfo(mod);
25002 const field_ptr_info = field_ptr_ty.ptrInfo(zcu);
2497825003
2497925004 var actual_parent_ptr_info: InternPool.Key.PtrType = .{
2498025005 .child = parent_ty.toIntern(),
2498125006 .flags = .{
24982 .alignment = try parent_ptr_ty.ptrAlignmentAdvanced(mod, sema),
25007 .alignment = try parent_ptr_ty.ptrAlignmentAdvanced(zcu, sema),
2498325008 .is_const = field_ptr_info.flags.is_const,
2498425009 .is_volatile = field_ptr_info.flags.is_volatile,
2498525010 .is_allowzero = field_ptr_info.flags.is_allowzero,
......@@ -24987,11 +25012,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2498725012 },
2498825013 .packed_offset = parent_ptr_info.packed_offset,
2498925014 };
24990 const field_ty = parent_ty.structFieldType(field_index, mod);
25015 const field_ty = parent_ty.structFieldType(field_index, zcu);
2499125016 var actual_field_ptr_info: InternPool.Key.PtrType = .{
2499225017 .child = field_ty.toIntern(),
2499325018 .flags = .{
24994 .alignment = try field_ptr_ty.ptrAlignmentAdvanced(mod, sema),
25019 .alignment = try field_ptr_ty.ptrAlignmentAdvanced(zcu, sema),
2499525020 .is_const = field_ptr_info.flags.is_const,
2499625021 .is_volatile = field_ptr_info.flags.is_volatile,
2499725022 .is_allowzero = field_ptr_info.flags.is_allowzero,
......@@ -24999,14 +25024,14 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2499925024 },
2500025025 .packed_offset = field_ptr_info.packed_offset,
2500125026 };
25002 switch (parent_ty.containerLayout(mod)) {
25027 switch (parent_ty.containerLayout(zcu)) {
2500325028 .auto => {
2500425029 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(
25005 if (mod.typeToStruct(parent_ty)) |struct_obj| try sema.structFieldAlignment(
25030 if (zcu.typeToStruct(parent_ty)) |struct_obj| try sema.structFieldAlignment(
2500625031 struct_obj.fieldAlign(ip, field_index),
2500725032 field_ty,
2500825033 struct_obj.layout,
25009 ) else if (mod.typeToUnion(parent_ty)) |union_obj|
25034 ) else if (zcu.typeToUnion(parent_ty)) |union_obj|
2501025035 try sema.unionFieldAlignment(union_obj, field_index)
2501125036 else
2501225037 actual_field_ptr_info.flags.alignment,
......@@ -25016,7 +25041,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2501625041 actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
2501725042 },
2501825043 .@"extern" => {
25019 const field_offset = parent_ty.structFieldOffset(field_index, mod);
25044 const field_offset = parent_ty.structFieldOffset(field_index, zcu);
2502025045 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (field_offset > 0)
2502125046 Alignment.fromLog2Units(@ctz(field_offset))
2502225047 else
......@@ -25027,7 +25052,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2502725052 },
2502825053 .@"packed" => {
2502925054 const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) +
25030 (if (mod.typeToStruct(parent_ty)) |struct_obj| mod.structPackedFieldBitOffset(struct_obj, field_index) else 0) -
25055 (if (zcu.typeToStruct(parent_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, field_index) else 0) -
2503125056 actual_field_ptr_info.packed_offset.bit_offset), 8) catch
2503225057 return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{});
2503325058 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (byte_offset > 0)
......@@ -25040,18 +25065,60 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2504025065 const actual_field_ptr_ty = try sema.ptrType(actual_field_ptr_info);
2504125066 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src);
2504225067 const actual_parent_ptr_ty = try sema.ptrType(actual_parent_ptr_info);
25068
2504325069 const result = if (try sema.resolveDefinedValue(block, field_ptr_src, casted_field_ptr)) |field_ptr_val| result: {
25044 const field = switch (ip.indexToKey(field_ptr_val.toIntern())) {
25045 .ptr => |ptr| switch (ptr.addr) {
25070 switch (parent_ty.zigTypeTag(zcu)) {
25071 .Struct => switch (parent_ty.containerLayout(zcu)) {
25072 .auto => {},
25073 .@"extern" => {
25074 const byte_offset = parent_ty.structFieldOffset(field_index, zcu);
25075 const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty);
25076 break :result Air.internedToRef(parent_ptr_val.toIntern());
25077 },
25078 .@"packed" => {
25079 // Logic lifted from type computation above - I'm just assuming it's correct.
25080 // `catch unreachable` since error case handled above.
25081 const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) +
25082 zcu.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) -
25083 actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable;
25084 const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty);
25085 break :result Air.internedToRef(parent_ptr_val.toIntern());
25086 },
25087 },
25088 .Union => switch (parent_ty.containerLayout(zcu)) {
25089 .auto => {},
25090 .@"extern", .@"packed" => {
25091 // For an extern or packed union, just coerce the pointer.
25092 const parent_ptr_val = try zcu.getCoerced(field_ptr_val, actual_parent_ptr_ty);
25093 break :result Air.internedToRef(parent_ptr_val.toIntern());
25094 },
25095 },
25096 else => unreachable,
25097 }
25098
25099 const opt_field: ?InternPool.Key.Ptr.BaseAddr.BaseIndex = opt_field: {
25100 const ptr = switch (ip.indexToKey(field_ptr_val.toIntern())) {
25101 .ptr => |ptr| ptr,
25102 else => break :opt_field null,
25103 };
25104 if (ptr.byte_offset != 0) break :opt_field null;
25105 break :opt_field switch (ptr.base_addr) {
2504625106 .field => |field| field,
2504725107 else => null,
25048 },
25049 else => null,
25050 } orelse return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{});
25108 };
25109 };
25110
25111 const field = opt_field orelse {
25112 return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{});
25113 };
25114
25115 if (Value.fromInterned(field.base).typeOf(zcu).childType(zcu).toIntern() != parent_ty.toIntern()) {
25116 return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{});
25117 }
2505125118
2505225119 if (field.index != field_index) {
2505325120 return sema.fail(block, inst_src, "field '{}' has index '{d}' but pointer value is index '{d}' of struct '{}'", .{
25054 field_name.fmt(ip), field_index, field.index, parent_ty.fmt(sema.mod),
25121 field_name.fmt(ip), field_index, field.index, parent_ty.fmt(zcu),
2505525122 });
2505625123 }
2505725124 break :result try sema.coerce(block, actual_parent_ptr_ty, Air.internedToRef(field.base), inst_src);
......@@ -25072,6 +25139,27 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2507225139 return sema.ptrCastFull(block, flags, inst_src, result, inst_src, parent_ptr_ty, "@fieldParentPtr");
2507325140}
2507425141
25142fn ptrSubtract(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, byte_subtract: u64, new_ty: Type) !Value {
25143 const zcu = sema.mod;
25144 if (byte_subtract == 0) return zcu.getCoerced(ptr_val, new_ty);
25145 var ptr = switch (zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
25146 .undef => return sema.failWithUseOfUndef(block, src),
25147 .ptr => |ptr| ptr,
25148 else => unreachable,
25149 };
25150 if (ptr.byte_offset < byte_subtract) {
25151 return sema.failWithOwnedErrorMsg(block, msg: {
25152 const msg = try sema.errMsg(block, src, "pointer computation here causes undefined behavior", .{});
25153 errdefer msg.destroy(sema.gpa);
25154 try sema.errNote(block, src, msg, "resulting pointer exceeds bounds of containing value which may trigger overflow", .{});
25155 break :msg msg;
25156 });
25157 }
25158 ptr.byte_offset -= byte_subtract;
25159 ptr.ty = new_ty.toIntern();
25160 return Value.fromInterned(try zcu.intern(.{ .ptr = ptr }));
25161}
25162
2507525163fn zirMinMax(
2507625164 sema: *Sema,
2507725165 block: *Block,
......@@ -25424,10 +25512,10 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2542425512 const msg = try sema.errMsg(block, src, "non-matching @memcpy lengths", .{});
2542525513 errdefer msg.destroy(sema.gpa);
2542625514 try sema.errNote(block, dest_src, msg, "length {} here", .{
25427 dest_len_val.fmtValue(sema.mod),
25515 dest_len_val.fmtValue(sema.mod, sema),
2542825516 });
2542925517 try sema.errNote(block, src_src, msg, "length {} here", .{
25430 src_len_val.fmtValue(sema.mod),
25518 src_len_val.fmtValue(sema.mod, sema),
2543125519 });
2543225520 break :msg msg;
2543325521 };
......@@ -26340,7 +26428,8 @@ fn zirBuiltinExtern(
2634026428 .opt_type => |child_type| child_type,
2634126429 else => unreachable,
2634226430 },
26343 .addr = .{ .decl = new_decl_index },
26431 .base_addr = .{ .decl = new_decl_index },
26432 .byte_offset = 0,
2634426433 } }))), ty)).toIntern());
2634526434}
2634626435
......@@ -26745,8 +26834,8 @@ fn explainWhyTypeIsNotExtern(
2674526834/// Returns true if `ty` is allowed in packed types.
2674626835/// Does not require `ty` to be resolved in any way, but may resolve whether it is comptime-only.
2674726836fn validatePackedType(sema: *Sema, ty: Type) !bool {
26748 const mod = sema.mod;
26749 switch (ty.zigTypeTag(mod)) {
26837 const zcu = sema.mod;
26838 return switch (ty.zigTypeTag(zcu)) {
2675026839 .Type,
2675126840 .ComptimeFloat,
2675226841 .ComptimeInt,
......@@ -26761,18 +26850,21 @@ fn validatePackedType(sema: *Sema, ty: Type) !bool {
2676126850 .AnyFrame,
2676226851 .Fn,
2676326852 .Array,
26764 => return false,
26765 .Optional => return ty.isPtrLikeOptional(mod),
26853 => false,
26854 .Optional => return ty.isPtrLikeOptional(zcu),
2676626855 .Void,
2676726856 .Bool,
2676826857 .Float,
2676926858 .Int,
2677026859 .Vector,
26771 .Enum,
26772 => return true,
26773 .Pointer => return !ty.isSlice(mod) and !try sema.typeRequiresComptime(ty),
26774 .Struct, .Union => return ty.containerLayout(mod) == .@"packed",
26775 }
26860 => true,
26861 .Enum => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).tag_mode) {
26862 .auto => false,
26863 .explicit, .nonexhaustive => true,
26864 },
26865 .Pointer => !ty.isSlice(zcu) and !try sema.typeRequiresComptime(ty),
26866 .Struct, .Union => ty.containerLayout(zcu) == .@"packed",
26867 };
2677626868}
2677726869
2677826870fn explainWhyTypeIsNotPacked(
......@@ -27443,13 +27535,7 @@ fn fieldPtr(
2744327535 });
2744427536
2744527537 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
27446 return Air.internedToRef((try mod.intern(.{ .ptr = .{
27447 .ty = result_ty.toIntern(),
27448 .addr = .{ .field = .{
27449 .base = val.toIntern(),
27450 .index = Value.slice_ptr_index,
27451 } },
27452 } })));
27538 return Air.internedToRef((try val.ptrField(Value.slice_ptr_index, sema)).toIntern());
2745327539 }
2745427540 try sema.requireRuntimeBlock(block, src, null);
2745527541
......@@ -27467,13 +27553,7 @@ fn fieldPtr(
2746727553 });
2746827554
2746927555 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
27470 return Air.internedToRef((try mod.intern(.{ .ptr = .{
27471 .ty = result_ty.toIntern(),
27472 .addr = .{ .field = .{
27473 .base = val.toIntern(),
27474 .index = Value.slice_len_index,
27475 } },
27476 } })));
27556 return Air.internedToRef((try val.ptrField(Value.slice_len_index, sema)).toIntern());
2747727557 }
2747827558 try sema.requireRuntimeBlock(block, src, null);
2747927559
......@@ -27785,13 +27865,8 @@ fn finishFieldCallBind(
2778527865 }
2778627866
2778727867 if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {
27788 const pointer = Air.internedToRef((try mod.intern(.{ .ptr = .{
27789 .ty = ptr_field_ty.toIntern(),
27790 .addr = .{ .field = .{
27791 .base = struct_ptr_val.toIntern(),
27792 .index = field_index,
27793 } },
27794 } })));
27868 const ptr_val = try struct_ptr_val.ptrField(field_index, sema);
27869 const pointer = Air.internedToRef(ptr_val.toIntern());
2779527870 return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) };
2779627871 }
2779727872
......@@ -27903,6 +27978,11 @@ fn structFieldPtrByIndex(
2790327978 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);
2790427979 }
2790527980
27981 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
27982 const val = try struct_ptr_val.ptrField(field_index, sema);
27983 return Air.internedToRef(val.toIntern());
27984 }
27985
2790627986 const struct_type = mod.typeToStruct(struct_ty).?;
2790727987 const field_ty = struct_type.field_types.get(ip)[field_index];
2790827988 const struct_ptr_ty = sema.typeOf(struct_ptr);
......@@ -27917,57 +27997,20 @@ fn structFieldPtrByIndex(
2791727997 },
2791827998 };
2791927999
27920 const target = mod.getTarget();
27921
2792228000 const parent_align = if (struct_ptr_ty_info.flags.alignment != .none)
2792328001 struct_ptr_ty_info.flags.alignment
2792428002 else
2792528003 try sema.typeAbiAlignment(Type.fromInterned(struct_ptr_ty_info.child));
2792628004
2792728005 if (struct_type.layout == .@"packed") {
27928 comptime assert(Type.packed_struct_layout_version == 2);
27929
27930 var running_bits: u16 = 0;
27931 for (0..struct_type.field_types.len) |i| {
27932 const f_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
27933 if (!(try sema.typeHasRuntimeBits(f_ty))) continue;
27934
27935 if (i == field_index) {
27936 ptr_ty_data.packed_offset.bit_offset = running_bits;
27937 }
27938 running_bits += @intCast(f_ty.bitSize(mod));
27939 }
27940 ptr_ty_data.packed_offset.host_size = (running_bits + 7) / 8;
27941
27942 // If this is a packed struct embedded in another one, we need to offset
27943 // the bits against each other.
27944 if (struct_ptr_ty_info.packed_offset.host_size != 0) {
27945 ptr_ty_data.packed_offset.host_size = struct_ptr_ty_info.packed_offset.host_size;
27946 ptr_ty_data.packed_offset.bit_offset += struct_ptr_ty_info.packed_offset.bit_offset;
27947 }
27948
27949 ptr_ty_data.flags.alignment = parent_align;
27950
27951 // If the field happens to be byte-aligned, simplify the pointer type.
27952 // The pointee type bit size must match its ABI byte size so that loads and stores
27953 // do not interfere with the surrounding packed bits.
27954 // We do not attempt this with big-endian targets yet because of nested
27955 // structs and floats. I need to double-check the desired behavior for big endian
27956 // targets before adding the necessary complications to this code. This will not
27957 // cause miscompilations; it only means the field pointer uses bit masking when it
27958 // might not be strictly necessary.
27959 if (parent_align != .none and ptr_ty_data.packed_offset.bit_offset % 8 == 0 and
27960 target.cpu.arch.endian() == .little)
27961 {
27962 const elem_size_bytes = try sema.typeAbiSize(Type.fromInterned(ptr_ty_data.child));
27963 const elem_size_bits = Type.fromInterned(ptr_ty_data.child).bitSize(mod);
27964 if (elem_size_bytes * 8 == elem_size_bits) {
27965 const byte_offset = ptr_ty_data.packed_offset.bit_offset / 8;
27966 const new_align: Alignment = @enumFromInt(@ctz(byte_offset | parent_align.toByteUnits().?));
27967 assert(new_align != .none);
27968 ptr_ty_data.flags.alignment = new_align;
27969 ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 };
27970 }
28006 switch (struct_ty.packedStructFieldPtrInfo(struct_ptr_ty, field_index, mod)) {
28007 .bit_ptr => |packed_offset| {
28008 ptr_ty_data.flags.alignment = parent_align;
28009 ptr_ty_data.packed_offset = packed_offset;
28010 },
28011 .byte_ptr => |ptr_info| {
28012 ptr_ty_data.flags.alignment = ptr_info.alignment;
28013 },
2797128014 }
2797228015 } else if (struct_type.layout == .@"extern") {
2797328016 // For extern structs, field alignment might be bigger than type's
......@@ -27997,18 +28040,8 @@ fn structFieldPtrByIndex(
2799728040 try sema.resolveStructFieldInits(struct_ty);
2799828041 const val = try mod.intern(.{ .ptr = .{
2799928042 .ty = ptr_field_ty.toIntern(),
28000 .addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },
28001 } });
28002 return Air.internedToRef(val);
28003 }
28004
28005 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
28006 const val = try mod.intern(.{ .ptr = .{
28007 .ty = ptr_field_ty.toIntern(),
28008 .addr = .{ .field = .{
28009 .base = struct_ptr_val.toIntern(),
28010 .index = field_index,
28011 } },
28043 .base_addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },
28044 .byte_offset = 0,
2801228045 } });
2801328046 return Air.internedToRef(val);
2801428047 }
......@@ -28206,7 +28239,13 @@ fn unionFieldPtr(
2820628239
2820728240 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
2820828241 switch (union_obj.getLayout(ip)) {
28209 .auto => if (!initializing) {
28242 .auto => if (initializing) {
28243 // Store to the union to initialize the tag.
28244 const field_tag = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
28245 const payload_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
28246 const new_union_val = try mod.unionValue(union_ty, field_tag, try mod.undefValue(payload_ty));
28247 try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty);
28248 } else {
2821028249 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse
2821128250 break :ct;
2821228251 if (union_val.isUndef(mod)) {
......@@ -28232,13 +28271,8 @@ fn unionFieldPtr(
2823228271 },
2823328272 .@"packed", .@"extern" => {},
2823428273 }
28235 return Air.internedToRef((try mod.intern(.{ .ptr = .{
28236 .ty = ptr_field_ty.toIntern(),
28237 .addr = .{ .field = .{
28238 .base = union_ptr_val.toIntern(),
28239 .index = field_index,
28240 } },
28241 } })));
28274 const field_ptr_val = try union_ptr_val.ptrField(field_index, sema);
28275 return Air.internedToRef(field_ptr_val.toIntern());
2824228276 }
2824328277
2824428278 try sema.requireRuntimeBlock(block, src, null);
......@@ -28268,21 +28302,21 @@ fn unionFieldVal(
2826828302 field_name_src: LazySrcLoc,
2826928303 union_ty: Type,
2827028304) CompileError!Air.Inst.Ref {
28271 const mod = sema.mod;
28272 const ip = &mod.intern_pool;
28273 assert(union_ty.zigTypeTag(mod) == .Union);
28305 const zcu = sema.mod;
28306 const ip = &zcu.intern_pool;
28307 assert(union_ty.zigTypeTag(zcu) == .Union);
2827428308
2827528309 try sema.resolveTypeFields(union_ty);
28276 const union_obj = mod.typeToUnion(union_ty).?;
28310 const union_obj = zcu.typeToUnion(union_ty).?;
2827728311 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
2827828312 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
28279 const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_ty).enumFieldIndex(field_name, mod).?);
28313 const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_ty).enumFieldIndex(field_name, zcu).?);
2828028314
2828128315 if (try sema.resolveValue(union_byval)) |union_val| {
28282 if (union_val.isUndef(mod)) return mod.undefRef(field_ty);
28316 if (union_val.isUndef(zcu)) return zcu.undefRef(field_ty);
2828328317
2828428318 const un = ip.indexToKey(union_val.toIntern()).un;
28285 const field_tag = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
28319 const field_tag = try zcu.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
2828628320 const tag_matches = un.tag == field_tag.toIntern();
2828728321 switch (union_obj.getLayout(ip)) {
2828828322 .auto => {
......@@ -28290,8 +28324,8 @@ fn unionFieldVal(
2829028324 return Air.internedToRef(un.val);
2829128325 } else {
2829228326 const msg = msg: {
28293 const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), mod).?;
28294 const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, mod);
28327 const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
28328 const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu);
2829528329 const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{
2829628330 field_name.fmt(ip), active_field_name.fmt(ip),
2829728331 });
......@@ -28302,33 +28336,31 @@ fn unionFieldVal(
2830228336 return sema.failWithOwnedErrorMsg(block, msg);
2830328337 }
2830428338 },
28305 .@"packed", .@"extern" => |layout| {
28306 if (tag_matches) {
28307 return Air.internedToRef(un.val);
28308 } else {
28309 const old_ty = if (un.tag == .none)
28310 Type.fromInterned(ip.typeOf(un.val))
28311 else
28312 union_ty.unionFieldType(Value.fromInterned(un.tag), mod).?;
28313
28314 if (try sema.bitCastUnionFieldVal(block, src, Value.fromInterned(un.val), old_ty, field_ty, layout)) |new_val| {
28315 return Air.internedToRef(new_val.toIntern());
28316 }
28317 }
28339 .@"extern" => if (tag_matches) {
28340 // Fast path - no need to use bitcast logic.
28341 return Air.internedToRef(un.val);
28342 } else if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| {
28343 return Air.internedToRef(field_val.toIntern());
28344 },
28345 .@"packed" => if (tag_matches) {
28346 // Fast path - no need to use bitcast logic.
28347 return Air.internedToRef(un.val);
28348 } else if (try sema.bitCastVal(union_val, field_ty, 0, try union_ty.bitSizeAdvanced(zcu, sema), 0)) |field_val| {
28349 return Air.internedToRef(field_val.toIntern());
2831828350 },
2831928351 }
2832028352 }
2832128353
2832228354 try sema.requireRuntimeBlock(block, src, null);
2832328355 if (union_obj.getLayout(ip) == .auto and block.wantSafety() and
28324 union_ty.unionTagTypeSafety(mod) != null and union_obj.field_types.len > 1)
28356 union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1)
2832528357 {
28326 const wanted_tag_val = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
28358 const wanted_tag_val = try zcu.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
2832728359 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
2832828360 const active_tag = try block.addTyOp(.get_union_tag, Type.fromInterned(union_obj.enum_tag_ty), union_byval);
2832928361 try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag);
2833028362 }
28331 if (field_ty.zigTypeTag(mod) == .NoReturn) {
28363 if (field_ty.zigTypeTag(zcu) == .NoReturn) {
2833228364 _ = try block.addNoOp(.unreach);
2833328365 return .unreachable_value;
2833428366 }
......@@ -28402,8 +28434,7 @@ fn elemPtrOneLayerOnly(
2840228434 const ptr_val = maybe_ptr_val orelse break :rs indexable_src;
2840328435 const index_val = maybe_index_val orelse break :rs elem_index_src;
2840428436 const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
28405 const result_ty = try sema.elemPtrType(indexable_ty, index);
28406 const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod);
28437 const elem_ptr = try ptr_val.ptrElem(index, sema);
2840728438 return Air.internedToRef(elem_ptr.toIntern());
2840828439 };
2840928440 const result_ty = try sema.elemPtrType(indexable_ty, null);
......@@ -28465,7 +28496,7 @@ fn elemVal(
2846528496 const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
2846628497 const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty);
2846728498 const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);
28468 const elem_ptr_val = try many_ptr_val.elemPtr(elem_ptr_ty, index, mod);
28499 const elem_ptr_val = try many_ptr_val.ptrElem(index, sema);
2846928500 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
2847028501 return Air.internedToRef((try mod.getCoerced(elem_val, elem_ty)).toIntern());
2847128502 }
......@@ -28571,21 +28602,18 @@ fn tupleFieldPtr(
2857128602
2857228603 if (tuple_ty.structFieldIsComptime(field_index, mod))
2857328604 try sema.resolveStructFieldInits(tuple_ty);
28605
2857428606 if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| {
2857528607 return Air.internedToRef((try mod.intern(.{ .ptr = .{
2857628608 .ty = ptr_field_ty.toIntern(),
28577 .addr = .{ .comptime_field = default_val.toIntern() },
28609 .base_addr = .{ .comptime_field = default_val.toIntern() },
28610 .byte_offset = 0,
2857828611 } })));
2857928612 }
2858028613
2858128614 if (try sema.resolveValue(tuple_ptr)) |tuple_ptr_val| {
28582 return Air.internedToRef((try mod.intern(.{ .ptr = .{
28583 .ty = ptr_field_ty.toIntern(),
28584 .addr = .{ .field = .{
28585 .base = tuple_ptr_val.toIntern(),
28586 .index = field_index,
28587 } },
28588 } })));
28615 const field_ptr_val = try tuple_ptr_val.ptrField(field_index, sema);
28616 return Air.internedToRef(field_ptr_val.toIntern());
2858928617 }
2859028618
2859128619 if (!init) {
......@@ -28747,7 +28775,7 @@ fn elemPtrArray(
2874728775 return mod.undefRef(elem_ptr_ty);
2874828776 }
2874928777 if (offset) |index| {
28750 const elem_ptr = try array_ptr_val.elemPtr(elem_ptr_ty, index, mod);
28778 const elem_ptr = try array_ptr_val.ptrElem(index, sema);
2875128779 return Air.internedToRef(elem_ptr.toIntern());
2875228780 }
2875328781 }
......@@ -28804,7 +28832,7 @@ fn elemValSlice(
2880428832 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
2880528833 }
2880628834 const elem_ptr_ty = try sema.elemPtrType(slice_ty, index);
28807 const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod);
28835 const elem_ptr_val = try slice_val.ptrElem(index, sema);
2880828836 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
2880928837 return Air.internedToRef(elem_val.toIntern());
2881028838 }
......@@ -28864,7 +28892,7 @@ fn elemPtrSlice(
2886428892 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
2886528893 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
2886628894 }
28867 const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod);
28895 const elem_ptr_val = try slice_val.ptrElem(index, sema);
2886828896 return Air.internedToRef(elem_ptr_val.toIntern());
2886928897 }
2887028898 }
......@@ -28943,14 +28971,14 @@ fn coerceExtra(
2894328971 opts: CoerceOpts,
2894428972) CoersionError!Air.Inst.Ref {
2894528973 if (dest_ty.isGenericPoison()) return inst;
28946 const mod = sema.mod;
28974 const zcu = sema.mod;
2894728975 const dest_ty_src = inst_src; // TODO better source location
2894828976 try sema.resolveTypeFields(dest_ty);
2894928977 const inst_ty = sema.typeOf(inst);
2895028978 try sema.resolveTypeFields(inst_ty);
28951 const target = mod.getTarget();
28979 const target = zcu.getTarget();
2895228980 // If the types are the same, we can return the operand.
28953 if (dest_ty.eql(inst_ty, mod))
28981 if (dest_ty.eql(inst_ty, zcu))
2895428982 return inst;
2895528983
2895628984 const maybe_inst_val = try sema.resolveValue(inst);
......@@ -28967,17 +28995,17 @@ fn coerceExtra(
2896728995 return new_val;
2896828996 }
2896928997
28970 switch (dest_ty.zigTypeTag(mod)) {
28998 switch (dest_ty.zigTypeTag(zcu)) {
2897128999 .Optional => optional: {
2897229000 if (maybe_inst_val) |val| {
2897329001 // undefined sets the optional bit also to undefined.
2897429002 if (val.toIntern() == .undef) {
28975 return mod.undefRef(dest_ty);
29003 return zcu.undefRef(dest_ty);
2897629004 }
2897729005
2897829006 // null to ?T
2897929007 if (val.toIntern() == .null_value) {
28980 return Air.internedToRef((try mod.intern(.{ .opt = .{
29008 return Air.internedToRef((try zcu.intern(.{ .opt = .{
2898129009 .ty = dest_ty.toIntern(),
2898229010 .val = .none,
2898329011 } })));
......@@ -28986,13 +29014,13 @@ fn coerceExtra(
2898629014
2898729015 // cast from ?*T and ?[*]T to ?*anyopaque
2898829016 // but don't do it if the source type is a double pointer
28989 if (dest_ty.isPtrLikeOptional(mod) and
28990 dest_ty.elemType2(mod).toIntern() == .anyopaque_type and
28991 inst_ty.isPtrAtRuntime(mod))
29017 if (dest_ty.isPtrLikeOptional(zcu) and
29018 dest_ty.elemType2(zcu).toIntern() == .anyopaque_type and
29019 inst_ty.isPtrAtRuntime(zcu))
2899229020 anyopaque_check: {
2899329021 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;
28994 const elem_ty = inst_ty.elemType2(mod);
28995 if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) {
29022 const elem_ty = inst_ty.elemType2(zcu);
29023 if (elem_ty.zigTypeTag(zcu) == .Pointer or elem_ty.isPtrLikeOptional(zcu)) {
2899629024 in_memory_result = .{ .double_ptr_to_anyopaque = .{
2899729025 .actual = inst_ty,
2899829026 .wanted = dest_ty,
......@@ -29001,12 +29029,12 @@ fn coerceExtra(
2900129029 }
2900229030 // Let the logic below handle wrapping the optional now that
2900329031 // it has been checked to correctly coerce.
29004 if (!inst_ty.isPtrLikeOptional(mod)) break :anyopaque_check;
29032 if (!inst_ty.isPtrLikeOptional(zcu)) break :anyopaque_check;
2900529033 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
2900629034 }
2900729035
2900829036 // T to ?T
29009 const child_type = dest_ty.optionalChild(mod);
29037 const child_type = dest_ty.optionalChild(zcu);
2901029038 const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
2901129039 error.NotCoercible => {
2901229040 if (in_memory_result == .no_match) {
......@@ -29020,12 +29048,12 @@ fn coerceExtra(
2902029048 return try sema.wrapOptional(block, dest_ty, intermediate, inst_src);
2902129049 },
2902229050 .Pointer => pointer: {
29023 const dest_info = dest_ty.ptrInfo(mod);
29051 const dest_info = dest_ty.ptrInfo(zcu);
2902429052
2902529053 // Function body to function pointer.
29026 if (inst_ty.zigTypeTag(mod) == .Fn) {
29054 if (inst_ty.zigTypeTag(zcu) == .Fn) {
2902729055 const fn_val = try sema.resolveConstDefinedValue(block, .unneeded, inst, undefined);
29028 const fn_decl = fn_val.pointerDecl(mod).?;
29056 const fn_decl = fn_val.pointerDecl(zcu).?;
2902929057 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);
2903029058 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
2903129059 }
......@@ -29033,13 +29061,13 @@ fn coerceExtra(
2903329061 // *T to *[1]T
2903429062 single_item: {
2903529063 if (dest_info.flags.size != .One) break :single_item;
29036 if (!inst_ty.isSinglePointer(mod)) break :single_item;
29064 if (!inst_ty.isSinglePointer(zcu)) break :single_item;
2903729065 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
29038 const ptr_elem_ty = inst_ty.childType(mod);
29066 const ptr_elem_ty = inst_ty.childType(zcu);
2903929067 const array_ty = Type.fromInterned(dest_info.child);
29040 if (array_ty.zigTypeTag(mod) != .Array) break :single_item;
29041 const array_elem_ty = array_ty.childType(mod);
29042 if (array_ty.arrayLen(mod) != 1) break :single_item;
29068 if (array_ty.zigTypeTag(zcu) != .Array) break :single_item;
29069 const array_elem_ty = array_ty.childType(zcu);
29070 if (array_ty.arrayLen(zcu) != 1) break :single_item;
2904329071 const dest_is_mut = !dest_info.flags.is_const;
2904429072 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
2904529073 .ok => {},
......@@ -29050,11 +29078,11 @@ fn coerceExtra(
2905029078
2905129079 // Coercions where the source is a single pointer to an array.
2905229080 src_array_ptr: {
29053 if (!inst_ty.isSinglePointer(mod)) break :src_array_ptr;
29081 if (!inst_ty.isSinglePointer(zcu)) break :src_array_ptr;
2905429082 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
29055 const array_ty = inst_ty.childType(mod);
29056 if (array_ty.zigTypeTag(mod) != .Array) break :src_array_ptr;
29057 const array_elem_type = array_ty.childType(mod);
29083 const array_ty = inst_ty.childType(zcu);
29084 if (array_ty.zigTypeTag(zcu) != .Array) break :src_array_ptr;
29085 const array_elem_type = array_ty.childType(zcu);
2905829086 const dest_is_mut = !dest_info.flags.is_const;
2905929087
2906029088 const dst_elem_type = Type.fromInterned(dest_info.child);
......@@ -29072,7 +29100,7 @@ fn coerceExtra(
2907229100 }
2907329101
2907429102 if (dest_info.sentinel != .none) {
29075 if (array_ty.sentinel(mod)) |inst_sent| {
29103 if (array_ty.sentinel(zcu)) |inst_sent| {
2907629104 if (Air.internedToRef(dest_info.sentinel) !=
2907729105 try sema.coerceInMemory(inst_sent, dst_elem_type))
2907829106 {
......@@ -29111,12 +29139,12 @@ fn coerceExtra(
2911129139 }
2911229140
2911329141 // coercion from C pointer
29114 if (inst_ty.isCPtr(mod)) src_c_ptr: {
29142 if (inst_ty.isCPtr(zcu)) src_c_ptr: {
2911529143 if (dest_info.flags.size == .Slice) break :src_c_ptr;
2911629144 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr;
2911729145 // In this case we must add a safety check because the C pointer
2911829146 // could be null.
29119 const src_elem_ty = inst_ty.childType(mod);
29147 const src_elem_ty = inst_ty.childType(zcu);
2912029148 const dest_is_mut = !dest_info.flags.is_const;
2912129149 const dst_elem_type = Type.fromInterned(dest_info.child);
2912229150 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
......@@ -29128,18 +29156,18 @@ fn coerceExtra(
2912829156
2912929157 // cast from *T and [*]T to *anyopaque
2913029158 // but don't do it if the source type is a double pointer
29131 if (dest_info.child == .anyopaque_type and inst_ty.zigTypeTag(mod) == .Pointer) to_anyopaque: {
29159 if (dest_info.child == .anyopaque_type and inst_ty.zigTypeTag(zcu) == .Pointer) to_anyopaque: {
2913229160 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
29133 const elem_ty = inst_ty.elemType2(mod);
29134 if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) {
29161 const elem_ty = inst_ty.elemType2(zcu);
29162 if (elem_ty.zigTypeTag(zcu) == .Pointer or elem_ty.isPtrLikeOptional(zcu)) {
2913529163 in_memory_result = .{ .double_ptr_to_anyopaque = .{
2913629164 .actual = inst_ty,
2913729165 .wanted = dest_ty,
2913829166 } };
2913929167 break :pointer;
2914029168 }
29141 if (dest_ty.isSlice(mod)) break :to_anyopaque;
29142 if (inst_ty.isSlice(mod)) {
29169 if (dest_ty.isSlice(zcu)) break :to_anyopaque;
29170 if (inst_ty.isSlice(zcu)) {
2914329171 in_memory_result = .{ .slice_to_anyopaque = .{
2914429172 .actual = inst_ty,
2914529173 .wanted = dest_ty,
......@@ -29151,10 +29179,11 @@ fn coerceExtra(
2915129179
2915229180 switch (dest_info.flags.size) {
2915329181 // coercion to C pointer
29154 .C => switch (inst_ty.zigTypeTag(mod)) {
29155 .Null => return Air.internedToRef(try mod.intern(.{ .ptr = .{
29182 .C => switch (inst_ty.zigTypeTag(zcu)) {
29183 .Null => return Air.internedToRef(try zcu.intern(.{ .ptr = .{
2915629184 .ty = dest_ty.toIntern(),
29157 .addr = .{ .int = .zero_usize },
29185 .base_addr = .int,
29186 .byte_offset = 0,
2915829187 } })),
2915929188 .ComptimeInt => {
2916029189 const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
......@@ -29164,7 +29193,7 @@ fn coerceExtra(
2916429193 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
2916529194 },
2916629195 .Int => {
29167 const ptr_size_ty = switch (inst_ty.intInfo(mod).signedness) {
29196 const ptr_size_ty = switch (inst_ty.intInfo(zcu).signedness) {
2916829197 .signed => Type.isize,
2916929198 .unsigned => Type.usize,
2917029199 };
......@@ -29180,7 +29209,7 @@ fn coerceExtra(
2918029209 },
2918129210 .Pointer => p: {
2918229211 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
29183 const inst_info = inst_ty.ptrInfo(mod);
29212 const inst_info = inst_ty.ptrInfo(zcu);
2918429213 switch (try sema.coerceInMemoryAllowed(
2918529214 block,
2918629215 Type.fromInterned(dest_info.child),
......@@ -29196,7 +29225,7 @@ fn coerceExtra(
2919629225 if (inst_info.flags.size == .Slice) {
2919729226 assert(dest_info.sentinel == .none);
2919829227 if (inst_info.sentinel == .none or
29199 inst_info.sentinel != (try mod.intValue(Type.fromInterned(inst_info.child), 0)).toIntern())
29228 inst_info.sentinel != (try zcu.intValue(Type.fromInterned(inst_info.child), 0)).toIntern())
2920029229 break :p;
2920129230
2920229231 const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
......@@ -29206,11 +29235,11 @@ fn coerceExtra(
2920629235 },
2920729236 else => {},
2920829237 },
29209 .One => switch (Type.fromInterned(dest_info.child).zigTypeTag(mod)) {
29238 .One => switch (Type.fromInterned(dest_info.child).zigTypeTag(zcu)) {
2921029239 .Union => {
2921129240 // pointer to anonymous struct to pointer to union
29212 if (inst_ty.isSinglePointer(mod) and
29213 inst_ty.childType(mod).isAnonStruct(mod) and
29241 if (inst_ty.isSinglePointer(zcu) and
29242 inst_ty.childType(zcu).isAnonStruct(zcu) and
2921429243 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
2921529244 {
2921629245 return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
......@@ -29218,8 +29247,8 @@ fn coerceExtra(
2921829247 },
2921929248 .Struct => {
2922029249 // pointer to anonymous struct to pointer to struct
29221 if (inst_ty.isSinglePointer(mod) and
29222 inst_ty.childType(mod).isAnonStruct(mod) and
29250 if (inst_ty.isSinglePointer(zcu) and
29251 inst_ty.childType(zcu).isAnonStruct(zcu) and
2922329252 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
2922429253 {
2922529254 return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) {
......@@ -29230,8 +29259,8 @@ fn coerceExtra(
2923029259 },
2923129260 .Array => {
2923229261 // pointer to tuple to pointer to array
29233 if (inst_ty.isSinglePointer(mod) and
29234 inst_ty.childType(mod).isTuple(mod) and
29262 if (inst_ty.isSinglePointer(zcu) and
29263 inst_ty.childType(zcu).isTuple(zcu) and
2923529264 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
2923629265 {
2923729266 return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
......@@ -29240,50 +29269,38 @@ fn coerceExtra(
2924029269 else => {},
2924129270 },
2924229271 .Slice => to_slice: {
29243 if (inst_ty.zigTypeTag(mod) == .Array) {
29272 if (inst_ty.zigTypeTag(zcu) == .Array) {
2924429273 return sema.fail(
2924529274 block,
2924629275 inst_src,
2924729276 "array literal requires address-of operator (&) to coerce to slice type '{}'",
29248 .{dest_ty.fmt(mod)},
29277 .{dest_ty.fmt(zcu)},
2924929278 );
2925029279 }
2925129280
29252 if (!inst_ty.isSinglePointer(mod)) break :to_slice;
29253 const inst_child_ty = inst_ty.childType(mod);
29254 if (!inst_child_ty.isTuple(mod)) break :to_slice;
29281 if (!inst_ty.isSinglePointer(zcu)) break :to_slice;
29282 const inst_child_ty = inst_ty.childType(zcu);
29283 if (!inst_child_ty.isTuple(zcu)) break :to_slice;
2925529284
2925629285 // empty tuple to zero-length slice
2925729286 // note that this allows coercing to a mutable slice.
29258 if (inst_child_ty.structFieldCount(mod) == 0) {
29259 // Optional slice is represented with a null pointer so
29260 // we use a dummy pointer value with the required alignment.
29261 return Air.internedToRef((try mod.intern(.{ .slice = .{
29287 if (inst_child_ty.structFieldCount(zcu) == 0) {
29288 const align_val = try dest_ty.ptrAlignmentAdvanced(zcu, sema);
29289 return Air.internedToRef(try zcu.intern(.{ .slice = .{
2926229290 .ty = dest_ty.toIntern(),
29263 .ptr = try mod.intern(.{ .ptr = .{
29264 .ty = dest_ty.slicePtrFieldType(mod).toIntern(),
29265 .addr = .{ .int = if (dest_info.flags.alignment != .none)
29266 (try mod.intValue(
29267 Type.usize,
29268 dest_info.flags.alignment.toByteUnits().?,
29269 )).toIntern()
29270 else
29271 try mod.intern_pool.getCoercedInts(
29272 mod.gpa,
29273 mod.intern_pool.indexToKey(
29274 (try Type.fromInterned(dest_info.child).lazyAbiAlignment(mod)).toIntern(),
29275 ).int,
29276 .usize_type,
29277 ) },
29291 .ptr = try zcu.intern(.{ .ptr = .{
29292 .ty = dest_ty.slicePtrFieldType(zcu).toIntern(),
29293 .base_addr = .int,
29294 .byte_offset = align_val.toByteUnits().?,
2927829295 } }),
29279 .len = (try mod.intValue(Type.usize, 0)).toIntern(),
29280 } })));
29296 .len = .zero_usize,
29297 } }));
2928129298 }
2928229299
2928329300 // pointer to tuple to slice
2928429301 if (!dest_info.flags.is_const) {
2928529302 const err_msg = err_msg: {
29286 const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(mod)});
29303 const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(zcu)});
2928729304 errdefer err_msg.destroy(sema.gpa);
2928829305 try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{});
2928929306 break :err_msg err_msg;
......@@ -29293,9 +29310,9 @@ fn coerceExtra(
2929329310 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
2929429311 },
2929529312 .Many => p: {
29296 if (!inst_ty.isSlice(mod)) break :p;
29313 if (!inst_ty.isSlice(zcu)) break :p;
2929729314 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
29298 const inst_info = inst_ty.ptrInfo(mod);
29315 const inst_info = inst_ty.ptrInfo(zcu);
2929929316
2930029317 switch (try sema.coerceInMemoryAllowed(
2930129318 block,
......@@ -29320,10 +29337,10 @@ fn coerceExtra(
2932029337 },
2932129338 }
2932229339 },
29323 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) {
29340 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(zcu)) {
2932429341 .Float, .ComptimeFloat => float: {
2932529342 const val = maybe_inst_val orelse {
29326 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
29343 if (dest_ty.zigTypeTag(zcu) == .ComptimeInt) {
2932729344 if (!opts.report_err) return error.NotCoercible;
2932829345 return sema.failWithNeededComptime(block, inst_src, .{
2932929346 .needed_comptime_reason = "value being casted to 'comptime_int' must be comptime-known",
......@@ -29339,17 +29356,17 @@ fn coerceExtra(
2933929356 // comptime-known integer to other number
2934029357 if (!(try sema.intFitsInType(val, dest_ty, null))) {
2934129358 if (!opts.report_err) return error.NotCoercible;
29342 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(mod) });
29359 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(zcu), val.fmtValue(zcu, sema) });
2934329360 }
29344 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
29345 .undef => try mod.undefRef(dest_ty),
29361 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
29362 .undef => try zcu.undefRef(dest_ty),
2934629363 .int => |int| Air.internedToRef(
29347 try mod.intern_pool.getCoercedInts(mod.gpa, int, dest_ty.toIntern()),
29364 try zcu.intern_pool.getCoercedInts(zcu.gpa, int, dest_ty.toIntern()),
2934829365 ),
2934929366 else => unreachable,
2935029367 };
2935129368 }
29352 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
29369 if (dest_ty.zigTypeTag(zcu) == .ComptimeInt) {
2935329370 if (!opts.report_err) return error.NotCoercible;
2935429371 if (opts.no_cast_to_comptime_int) return inst;
2935529372 return sema.failWithNeededComptime(block, inst_src, .{
......@@ -29358,8 +29375,8 @@ fn coerceExtra(
2935829375 }
2935929376
2936029377 // integer widening
29361 const dst_info = dest_ty.intInfo(mod);
29362 const src_info = inst_ty.intInfo(mod);
29378 const dst_info = dest_ty.intInfo(zcu);
29379 const src_info = inst_ty.intInfo(zcu);
2936329380 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or
2936429381 // small enough unsigned ints can get casted to large enough signed ints
2936529382 (dst_info.signedness == .signed and dst_info.bits > src_info.bits))
......@@ -29370,25 +29387,25 @@ fn coerceExtra(
2937029387 },
2937129388 else => {},
2937229389 },
29373 .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) {
29390 .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(zcu)) {
2937429391 .ComptimeFloat => {
2937529392 const val = try sema.resolveConstDefinedValue(block, .unneeded, inst, undefined);
29376 const result_val = try val.floatCast(dest_ty, mod);
29393 const result_val = try val.floatCast(dest_ty, zcu);
2937729394 return Air.internedToRef(result_val.toIntern());
2937829395 },
2937929396 .Float => {
2938029397 if (maybe_inst_val) |val| {
29381 const result_val = try val.floatCast(dest_ty, mod);
29382 if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) {
29398 const result_val = try val.floatCast(dest_ty, zcu);
29399 if (!val.eql(try result_val.floatCast(inst_ty, zcu), inst_ty, zcu)) {
2938329400 return sema.fail(
2938429401 block,
2938529402 inst_src,
2938629403 "type '{}' cannot represent float value '{}'",
29387 .{ dest_ty.fmt(mod), val.fmtValue(mod) },
29404 .{ dest_ty.fmt(zcu), val.fmtValue(zcu, sema) },
2938829405 );
2938929406 }
2939029407 return Air.internedToRef(result_val.toIntern());
29391 } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
29408 } else if (dest_ty.zigTypeTag(zcu) == .ComptimeFloat) {
2939229409 if (!opts.report_err) return error.NotCoercible;
2939329410 return sema.failWithNeededComptime(block, inst_src, .{
2939429411 .needed_comptime_reason = "value being casted to 'comptime_float' must be comptime-known",
......@@ -29405,7 +29422,7 @@ fn coerceExtra(
2940529422 },
2940629423 .Int, .ComptimeInt => int: {
2940729424 const val = maybe_inst_val orelse {
29408 if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
29425 if (dest_ty.zigTypeTag(zcu) == .ComptimeFloat) {
2940929426 if (!opts.report_err) return error.NotCoercible;
2941029427 return sema.failWithNeededComptime(block, inst_src, .{
2941129428 .needed_comptime_reason = "value being casted to 'comptime_float' must be comptime-known",
......@@ -29413,52 +29430,52 @@ fn coerceExtra(
2941329430 }
2941429431 break :int;
2941529432 };
29416 const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, mod, sema);
29433 const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, zcu, sema);
2941729434 // TODO implement this compile error
2941829435 //const int_again_val = try result_val.intFromFloat(sema.arena, inst_ty);
29419 //if (!int_again_val.eql(val, inst_ty, mod)) {
29436 //if (!int_again_val.eql(val, inst_ty, zcu)) {
2942029437 // return sema.fail(
2942129438 // block,
2942229439 // inst_src,
2942329440 // "type '{}' cannot represent integer value '{}'",
29424 // .{ dest_ty.fmt(mod), val },
29441 // .{ dest_ty.fmt(zcu), val },
2942529442 // );
2942629443 //}
2942729444 return Air.internedToRef(result_val.toIntern());
2942829445 },
2942929446 else => {},
2943029447 },
29431 .Enum => switch (inst_ty.zigTypeTag(mod)) {
29448 .Enum => switch (inst_ty.zigTypeTag(zcu)) {
2943229449 .EnumLiteral => {
2943329450 // enum literal to enum
2943429451 const val = try sema.resolveConstDefinedValue(block, .unneeded, inst, undefined);
29435 const string = mod.intern_pool.indexToKey(val.toIntern()).enum_literal;
29436 const field_index = dest_ty.enumFieldIndex(string, mod) orelse {
29452 const string = zcu.intern_pool.indexToKey(val.toIntern()).enum_literal;
29453 const field_index = dest_ty.enumFieldIndex(string, zcu) orelse {
2943729454 return sema.fail(block, inst_src, "no field named '{}' in enum '{}'", .{
29438 string.fmt(&mod.intern_pool), dest_ty.fmt(mod),
29455 string.fmt(&zcu.intern_pool), dest_ty.fmt(zcu),
2943929456 });
2944029457 };
29441 return Air.internedToRef((try mod.enumValueFieldIndex(dest_ty, @intCast(field_index))).toIntern());
29458 return Air.internedToRef((try zcu.enumValueFieldIndex(dest_ty, @intCast(field_index))).toIntern());
2944229459 },
2944329460 .Union => blk: {
2944429461 // union to its own tag type
29445 const union_tag_ty = inst_ty.unionTagType(mod) orelse break :blk;
29446 if (union_tag_ty.eql(dest_ty, mod)) {
29462 const union_tag_ty = inst_ty.unionTagType(zcu) orelse break :blk;
29463 if (union_tag_ty.eql(dest_ty, zcu)) {
2944729464 return sema.unionToTag(block, dest_ty, inst, inst_src);
2944829465 }
2944929466 },
2945029467 else => {},
2945129468 },
29452 .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) {
29469 .ErrorUnion => switch (inst_ty.zigTypeTag(zcu)) {
2945329470 .ErrorUnion => eu: {
2945429471 if (maybe_inst_val) |inst_val| {
2945529472 switch (inst_val.toIntern()) {
29456 .undef => return mod.undefRef(dest_ty),
29457 else => switch (mod.intern_pool.indexToKey(inst_val.toIntern())) {
29473 .undef => return zcu.undefRef(dest_ty),
29474 else => switch (zcu.intern_pool.indexToKey(inst_val.toIntern())) {
2945829475 .error_union => |error_union| switch (error_union.val) {
2945929476 .err_name => |err_name| {
29460 const error_set_ty = inst_ty.errorUnionSet(mod);
29461 const error_set_val = Air.internedToRef((try mod.intern(.{ .err = .{
29477 const error_set_ty = inst_ty.errorUnionSet(zcu);
29478 const error_set_val = Air.internedToRef((try zcu.intern(.{ .err = .{
2946229479 .ty = error_set_ty.toIntern(),
2946329480 .name = err_name,
2946429481 } })));
......@@ -29489,31 +29506,54 @@ fn coerceExtra(
2948929506 };
2949029507 },
2949129508 },
29492 .Union => switch (inst_ty.zigTypeTag(mod)) {
29509 .Union => switch (inst_ty.zigTypeTag(zcu)) {
2949329510 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),
2949429511 .Struct => {
29495 if (inst_ty.isAnonStruct(mod)) {
29512 if (inst_ty.isAnonStruct(zcu)) {
2949629513 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
2949729514 }
2949829515 },
2949929516 else => {},
2950029517 },
29501 .Array => switch (inst_ty.zigTypeTag(mod)) {
29518 .Array => switch (inst_ty.zigTypeTag(zcu)) {
29519 .Array => array_to_array: {
29520 // Array coercions are allowed only if the child is IMC and the sentinel is unchanged or removed.
29521 if (.ok != try sema.coerceInMemoryAllowed(
29522 block,
29523 dest_ty.childType(zcu),
29524 inst_ty.childType(zcu),
29525 false,
29526 target,
29527 dest_ty_src,
29528 inst_src,
29529 )) {
29530 break :array_to_array;
29531 }
29532
29533 if (dest_ty.sentinel(zcu)) |dest_sent| {
29534 const src_sent = inst_ty.sentinel(zcu) orelse break :array_to_array;
29535 if (dest_sent.toIntern() != (try zcu.getCoerced(src_sent, dest_ty.childType(zcu))).toIntern()) {
29536 break :array_to_array;
29537 }
29538 }
29539
29540 return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src);
29541 },
2950229542 .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
2950329543 .Struct => {
2950429544 if (inst == .empty_struct) {
2950529545 return sema.arrayInitEmpty(block, inst_src, dest_ty);
2950629546 }
29507 if (inst_ty.isTuple(mod)) {
29547 if (inst_ty.isTuple(zcu)) {
2950829548 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
2950929549 }
2951029550 },
2951129551 else => {},
2951229552 },
29513 .Vector => switch (inst_ty.zigTypeTag(mod)) {
29553 .Vector => switch (inst_ty.zigTypeTag(zcu)) {
2951429554 .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
2951529555 .Struct => {
29516 if (inst_ty.isTuple(mod)) {
29556 if (inst_ty.isTuple(zcu)) {
2951729557 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
2951829558 }
2951929559 },
......@@ -29523,7 +29563,7 @@ fn coerceExtra(
2952329563 if (inst == .empty_struct) {
2952429564 return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src);
2952529565 }
29526 if (inst_ty.isTupleOrAnonStruct(mod)) {
29566 if (inst_ty.isTupleOrAnonStruct(zcu)) {
2952729567 return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) {
2952829568 error.NotCoercible => break :blk,
2952929569 else => |e| return e,
......@@ -29536,38 +29576,38 @@ fn coerceExtra(
2953629576 // undefined to anything. We do this after the big switch above so that
2953729577 // special logic has a chance to run first, such as `*[N]T` to `[]T` which
2953829578 // should initialize the length field of the slice.
29539 if (maybe_inst_val) |val| if (val.toIntern() == .undef) return mod.undefRef(dest_ty);
29579 if (maybe_inst_val) |val| if (val.toIntern() == .undef) return zcu.undefRef(dest_ty);
2954029580
2954129581 if (!opts.report_err) return error.NotCoercible;
2954229582
29543 if (opts.is_ret and dest_ty.zigTypeTag(mod) == .NoReturn) {
29583 if (opts.is_ret and dest_ty.zigTypeTag(zcu) == .NoReturn) {
2954429584 const msg = msg: {
2954529585 const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{});
2954629586 errdefer msg.destroy(sema.gpa);
2954729587
2954829588 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
29549 const src_decl = mod.funcOwnerDeclPtr(sema.func_index);
29550 try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "'noreturn' declared here", .{});
29589 const src_decl = zcu.funcOwnerDeclPtr(sema.func_index);
29590 try zcu.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, zcu), msg, "'noreturn' declared here", .{});
2955129591 break :msg msg;
2955229592 };
2955329593 return sema.failWithOwnedErrorMsg(block, msg);
2955429594 }
2955529595
2955629596 const msg = msg: {
29557 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(mod), inst_ty.fmt(mod) });
29597 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(zcu), inst_ty.fmt(zcu) });
2955829598 errdefer msg.destroy(sema.gpa);
2955929599
2956029600 // E!T to T
29561 if (inst_ty.zigTypeTag(mod) == .ErrorUnion and
29562 (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
29601 if (inst_ty.zigTypeTag(zcu) == .ErrorUnion and
29602 (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(zcu), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
2956329603 {
2956429604 try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{});
2956529605 try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{});
2956629606 }
2956729607
2956829608 // ?T to T
29569 if (inst_ty.zigTypeTag(mod) == .Optional and
29570 (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
29609 if (inst_ty.zigTypeTag(zcu) == .Optional and
29610 (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(zcu), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
2957129611 {
2957229612 try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{});
2957329613 try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{});
......@@ -29577,19 +29617,19 @@ fn coerceExtra(
2957729617
2957829618 // Add notes about function return type
2957929619 if (opts.is_ret and
29580 mod.test_functions.get(mod.funcOwnerDeclIndex(sema.func_index)) == null)
29620 zcu.test_functions.get(zcu.funcOwnerDeclIndex(sema.func_index)) == null)
2958129621 {
2958229622 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
29583 const src_decl = mod.funcOwnerDeclPtr(sema.func_index);
29584 if (inst_ty.isError(mod) and !dest_ty.isError(mod)) {
29585 try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "function cannot return an error", .{});
29623 const src_decl = zcu.funcOwnerDeclPtr(sema.func_index);
29624 if (inst_ty.isError(zcu) and !dest_ty.isError(zcu)) {
29625 try zcu.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, zcu), msg, "function cannot return an error", .{});
2958629626 } else {
29587 try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "function return type declared here", .{});
29627 try zcu.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, zcu), msg, "function return type declared here", .{});
2958829628 }
2958929629 }
2959029630
2959129631 if (try opts.param_src.get(sema)) |param_src| {
29592 try mod.errNoteNonLazy(param_src, msg, "parameter type declared here", .{});
29632 try zcu.errNoteNonLazy(param_src, msg, "parameter type declared here", .{});
2959329633 }
2959429634
2959529635 // TODO maybe add "cannot store an error in type '{}'" note
......@@ -29755,11 +29795,11 @@ const InMemoryCoercionResult = union(enum) {
2975529795 .array_sentinel => |sentinel| {
2975629796 if (sentinel.actual.toIntern() != .unreachable_value) {
2975729797 try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{
29758 sentinel.actual.fmtValue(mod), sentinel.wanted.fmtValue(mod),
29798 sentinel.actual.fmtValue(mod, sema), sentinel.wanted.fmtValue(mod, sema),
2975929799 });
2976029800 } else {
2976129801 try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{
29762 sentinel.wanted.fmtValue(mod),
29802 sentinel.wanted.fmtValue(mod, sema),
2976329803 });
2976429804 }
2976529805 break;
......@@ -29881,11 +29921,11 @@ const InMemoryCoercionResult = union(enum) {
2988129921 .ptr_sentinel => |sentinel| {
2988229922 if (sentinel.actual.toIntern() != .unreachable_value) {
2988329923 try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{
29884 sentinel.actual.fmtValue(mod), sentinel.wanted.fmtValue(mod),
29924 sentinel.actual.fmtValue(mod, sema), sentinel.wanted.fmtValue(mod, sema),
2988529925 });
2988629926 } else {
2988729927 try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{
29888 sentinel.wanted.fmtValue(mod),
29928 sentinel.wanted.fmtValue(mod, sema),
2988929929 });
2989029930 }
2989129931 break;
......@@ -29972,7 +30012,7 @@ fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 {
2997230012/// * bit offset attributes must match exactly
2997330013/// * `*`/`[*]` must match exactly, but `[*c]` matches either one
2997430014/// * sentinel-terminated pointers can coerce into `[*]`
29975fn coerceInMemoryAllowed(
30015pub fn coerceInMemoryAllowed(
2997630016 sema: *Sema,
2997730017 block: *Block,
2997830018 dest_ty: Type,
......@@ -30082,8 +30122,9 @@ fn coerceInMemoryAllowed(
3008230122 .wanted = dest_info.elem_type,
3008330123 } };
3008430124 }
30085 const ok_sent = dest_info.sentinel == null or
30125 const ok_sent = (dest_info.sentinel == null and src_info.sentinel == null) or
3008630126 (src_info.sentinel != null and
30127 dest_info.sentinel != null and
3008730128 dest_info.sentinel.?.eql(
3008830129 try mod.getCoerced(src_info.sentinel.?, dest_info.elem_type),
3008930130 dest_info.elem_type,
......@@ -30420,9 +30461,9 @@ fn coerceInMemoryAllowedPtrs(
3042030461 dest_src: LazySrcLoc,
3042130462 src_src: LazySrcLoc,
3042230463) !InMemoryCoercionResult {
30423 const mod = sema.mod;
30424 const dest_info = dest_ptr_ty.ptrInfo(mod);
30425 const src_info = src_ptr_ty.ptrInfo(mod);
30464 const zcu = sema.mod;
30465 const dest_info = dest_ptr_ty.ptrInfo(zcu);
30466 const src_info = src_ptr_ty.ptrInfo(zcu);
3042630467
3042730468 const ok_ptr_size = src_info.flags.size == dest_info.flags.size or
3042830469 src_info.flags.size == .C or dest_info.flags.size == .C;
......@@ -30453,8 +30494,18 @@ fn coerceInMemoryAllowedPtrs(
3045330494 } };
3045430495 }
3045530496
30456 const child = try sema.coerceInMemoryAllowed(block, Type.fromInterned(dest_info.child), Type.fromInterned(src_info.child), !dest_info.flags.is_const, target, dest_src, src_src);
30457 if (child != .ok) {
30497 const dest_child = Type.fromInterned(dest_info.child);
30498 const src_child = Type.fromInterned(src_info.child);
30499 const child = try sema.coerceInMemoryAllowed(block, dest_child, src_child, !dest_info.flags.is_const, target, dest_src, src_src);
30500 if (child != .ok) allow: {
30501 // As a special case, we also allow coercing `*[n:s]T` to `*[n]T`, akin to dropping the sentinel from a slice.
30502 // `*[n:s]T` cannot coerce in memory to `*[n]T` since they have different sizes.
30503 if (src_child.zigTypeTag(zcu) == .Array and dest_child.zigTypeTag(zcu) == .Array and
30504 src_child.sentinel(zcu) != null and dest_child.sentinel(zcu) == null and
30505 .ok == try sema.coerceInMemoryAllowed(block, dest_child.childType(zcu), src_child.childType(zcu), !dest_info.flags.is_const, target, dest_src, src_src))
30506 {
30507 break :allow;
30508 }
3045830509 return InMemoryCoercionResult{ .ptr_child = .{
3045930510 .child = try child.dupe(sema.arena),
3046030511 .actual = Type.fromInterned(src_info.child),
......@@ -30462,8 +30513,8 @@ fn coerceInMemoryAllowedPtrs(
3046230513 } };
3046330514 }
3046430515
30465 const dest_allow_zero = dest_ty.ptrAllowsZero(mod);
30466 const src_allow_zero = src_ty.ptrAllowsZero(mod);
30516 const dest_allow_zero = dest_ty.ptrAllowsZero(zcu);
30517 const src_allow_zero = src_ty.ptrAllowsZero(zcu);
3046730518
3046830519 const ok_allows_zero = (dest_allow_zero and
3046930520 (src_allow_zero or !dest_is_mut)) or
......@@ -30488,7 +30539,7 @@ fn coerceInMemoryAllowedPtrs(
3048830539
3048930540 const ok_sent = dest_info.sentinel == .none or src_info.flags.size == .C or
3049030541 (src_info.sentinel != .none and
30491 dest_info.sentinel == try mod.intern_pool.getCoerced(sema.gpa, src_info.sentinel, dest_info.child));
30542 dest_info.sentinel == try zcu.intern_pool.getCoerced(sema.gpa, src_info.sentinel, dest_info.child));
3049230543 if (!ok_sent) {
3049330544 return InMemoryCoercionResult{ .ptr_sentinel = .{
3049430545 .actual = switch (src_info.sentinel) {
......@@ -30787,7 +30838,18 @@ fn checkKnownAllocPtr(sema: *Sema, block: *Block, base_ptr: Air.Inst.Ref, new_pt
3078730838 switch (sema.air_instructions.items(.tag)[@intFromEnum(new_ptr_inst)]) {
3078830839 .optional_payload_ptr_set, .errunion_payload_ptr_set => {
3078930840 const maybe_comptime_alloc = sema.maybe_comptime_allocs.getPtr(alloc_inst) orelse return;
30790 try maybe_comptime_alloc.non_elideable_pointers.append(sema.arena, new_ptr_inst);
30841
30842 // This is functionally a store, since it writes the optional payload bit.
30843 // Thus, if it is behind a runtime condition, we must mark the alloc as runtime appropriately.
30844 if (block.runtime_index != maybe_comptime_alloc.runtime_index) {
30845 return sema.markMaybeComptimeAllocRuntime(block, alloc_inst);
30846 }
30847
30848 try maybe_comptime_alloc.stores.append(sema.arena, .{
30849 .inst = new_ptr_inst,
30850 .src_decl = block.src_decl,
30851 .src = .unneeded,
30852 });
3079130853 },
3079230854 .ptr_elem_ptr => {
3079330855 const tmp_air = sema.getTmpAir();
......@@ -30812,6 +30874,12 @@ fn markMaybeComptimeAllocRuntime(sema: *Sema, block: *Block, alloc_inst: Air.Ins
3081230874 const mod = sema.mod;
3081330875 const slice = maybe_comptime_alloc.stores.slice();
3081430876 for (slice.items(.inst), slice.items(.src_decl), slice.items(.src)) |other_inst, other_src_decl, other_src| {
30877 if (other_src == .unneeded) {
30878 switch (sema.air_instructions.items(.tag)[@intFromEnum(other_inst)]) {
30879 .set_union_tag, .optional_payload_ptr_set, .errunion_payload_ptr_set => continue,
30880 else => unreachable, // assertion failure
30881 }
30882 }
3081530883 const other_data = sema.air_instructions.items(.data)[@intFromEnum(other_inst)].bin_op;
3081630884 const other_operand = other_data.rhs;
3081730885 if (!sema.checkRuntimeValue(other_operand)) {
......@@ -30866,748 +30934,46 @@ fn storePtrVal(
3086630934 operand_val: Value,
3086730935 operand_ty: Type,
3086830936) !void {
30869 const mod = sema.mod;
30870 var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty);
30871 switch (mut_kit.root) {
30872 .alloc => |a| try sema.checkComptimeVarStore(block, src, a),
30873 .comptime_field => {},
30874 }
30875
30876 try sema.resolveTypeLayout(operand_ty);
30877 switch (mut_kit.pointee) {
30878 .opv => {},
30879 .direct => |val_ptr| {
30880 if (mut_kit.root == .comptime_field) {
30881 val_ptr.* = .{ .interned = try val_ptr.intern(mod, sema.arena) };
30882 if (operand_val.toIntern() != val_ptr.interned) {
30883 // TODO use failWithInvalidComptimeFieldStore
30884 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});
30885 }
30886 return;
30887 }
30888 val_ptr.* = .{ .interned = operand_val.toIntern() };
30889 },
30890 .reinterpret => |reinterpret| {
30891 try sema.resolveTypeLayout(mut_kit.ty);
30892 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod));
30893 const buffer = try sema.gpa.alloc(u8, abi_size);
30894 defer sema.gpa.free(buffer);
30895 const interned_old = Value.fromInterned(try reinterpret.val_ptr.intern(mod, sema.arena));
30896 interned_old.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) {
30897 error.OutOfMemory => return error.OutOfMemory,
30898 error.ReinterpretDeclRef => unreachable,
30899 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
30900 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}),
30901 };
30902 if (reinterpret.write_packed) {
30903 operand_val.writeToPackedMemory(operand_ty, mod, buffer[reinterpret.byte_offset..], 0) catch |err| switch (err) {
30904 error.OutOfMemory => return error.OutOfMemory,
30905 error.ReinterpretDeclRef => unreachable,
30906 };
30907 } else {
30908 operand_val.writeToMemory(operand_ty, mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) {
30909 error.OutOfMemory => return error.OutOfMemory,
30910 error.ReinterpretDeclRef => unreachable,
30911 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
30912 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{operand_ty.fmt(mod)}),
30913 };
30914 }
30915 const val = Value.readFromMemory(mut_kit.ty, mod, buffer, sema.arena) catch |err| switch (err) {
30916 error.OutOfMemory => return error.OutOfMemory,
30917 error.IllDefinedMemoryLayout => unreachable,
30918 error.Unimplemented => return sema.fail(block, src, "TODO: implement readFromMemory for type '{}'", .{mut_kit.ty.fmt(mod)}),
30919 };
30920 reinterpret.val_ptr.* = .{ .interned = val.toIntern() };
30921 },
30922 .bad_decl_ty, .bad_ptr_ty => {
30923 // TODO show the decl declaration site in a note and explain whether the decl
30924 // or the pointer is the problematic type
30925 return sema.fail(
30926 block,
30927 src,
30928 "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout",
30929 .{mut_kit.ty.fmt(mod)},
30930 );
30931 },
30932 }
30933}
30934
30935const ComptimePtrMutationKit = struct {
30936 const Root = union(enum) {
30937 alloc: ComptimeAllocIndex,
30938 comptime_field,
30939 };
30940 root: Root,
30941 pointee: union(enum) {
30942 opv,
30943 /// The pointer type matches the actual comptime Value so a direct
30944 /// modification is possible.
30945 direct: *MutableValue,
30946 /// The largest parent Value containing pointee and having a well-defined memory layout.
30947 /// This is used for bitcasting, if direct dereferencing failed.
30948 reinterpret: struct {
30949 val_ptr: *MutableValue,
30950 byte_offset: usize,
30951 /// If set, write the operand to packed memory
30952 write_packed: bool = false,
30953 },
30954 /// If the root decl could not be used as parent, this means `ty` is the type that
30955 /// caused that by not having a well-defined layout.
30956 /// This one means the Decl that owns the value trying to be modified does not
30957 /// have a well defined memory layout.
30958 bad_decl_ty,
30959 /// If the root decl could not be used as parent, this means `ty` is the type that
30960 /// caused that by not having a well-defined layout.
30961 /// This one means the pointer type that is being stored through does not
30962 /// have a well defined memory layout.
30963 bad_ptr_ty,
30964 },
30965 ty: Type,
30966};
30967
30968fn beginComptimePtrMutation(
30969 sema: *Sema,
30970 block: *Block,
30971 src: LazySrcLoc,
30972 ptr_val: Value,
30973 ptr_elem_ty: Type,
30974) CompileError!ComptimePtrMutationKit {
30975 const mod = sema.mod;
30976 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
30977 switch (ptr.addr) {
30978 .decl, .anon_decl, .int => unreachable, // isComptimeMutablePtr has been checked already
30979 .comptime_alloc => |alloc_index| {
30980 const alloc = sema.getComptimeAlloc(alloc_index);
30981 return sema.beginComptimePtrMutationInner(block, src, alloc.val.typeOf(mod), &alloc.val, ptr_elem_ty, .{ .alloc = alloc_index });
30982 },
30983 .comptime_field => |comptime_field| {
30984 const duped = try sema.arena.create(MutableValue);
30985 duped.* = .{ .interned = comptime_field };
30986 return sema.beginComptimePtrMutationInner(
30987 block,
30988 src,
30989 duped.typeOf(mod),
30990 duped,
30991 ptr_elem_ty,
30992 .comptime_field,
30993 );
30994 },
30995 .eu_payload => |eu_ptr| {
30996 const eu_ty = Type.fromInterned(mod.intern_pool.typeOf(eu_ptr)).childType(mod);
30997 var parent = try sema.beginComptimePtrMutation(block, src, Value.fromInterned(eu_ptr), eu_ty);
30998 switch (parent.pointee) {
30999 .opv => unreachable,
31000 .direct => |val_ptr| {
31001 const payload_ty = parent.ty.errorUnionPayload(mod);
31002 try val_ptr.unintern(mod, sema.arena, false, false);
31003 if (val_ptr.* == .interned) {
31004 // An error union has been initialized to undefined at comptime and now we
31005 // are for the first time setting the payload. We must change the
31006 // representation of the error union to `eu_payload`.
31007 const child = try sema.arena.create(MutableValue);
31008 child.* = .{ .interned = try mod.intern(.{ .undef = payload_ty.toIntern() }) };
31009 val_ptr.* = .{ .eu_payload = .{
31010 .ty = parent.ty.toIntern(),
31011 .child = child,
31012 } };
31013 }
31014 return .{
31015 .root = parent.root,
31016 .pointee = .{ .direct = val_ptr.eu_payload.child },
31017 .ty = payload_ty,
31018 };
31019 },
31020 .bad_decl_ty, .bad_ptr_ty => return parent,
31021 // Even though the parent value type has well-defined memory layout, our
31022 // pointer type does not.
31023 .reinterpret => return .{
31024 .root = parent.root,
31025 .pointee = .bad_ptr_ty,
31026 .ty = eu_ty,
31027 },
31028 }
31029 },
31030 .opt_payload => |opt_ptr| {
31031 const opt_ty = Type.fromInterned(mod.intern_pool.typeOf(opt_ptr)).childType(mod);
31032 var parent = try sema.beginComptimePtrMutation(block, src, Value.fromInterned(opt_ptr), opt_ty);
31033 switch (parent.pointee) {
31034 .opv => unreachable,
31035 .direct => |val_ptr| {
31036 const payload_ty = parent.ty.optionalChild(mod);
31037 try val_ptr.unintern(mod, sema.arena, false, false);
31038 if (val_ptr.* == .interned) {
31039 // An optional has been initialized to undefined at comptime and now we
31040 // are for the first time setting the payload. We must change the
31041 // representation of the optional to `opt_payload`.
31042 const child = try sema.arena.create(MutableValue);
31043 child.* = .{ .interned = try mod.intern(.{ .undef = payload_ty.toIntern() }) };
31044 val_ptr.* = .{ .opt_payload = .{
31045 .ty = parent.ty.toIntern(),
31046 .child = child,
31047 } };
31048 }
31049 return .{
31050 .root = parent.root,
31051 .pointee = .{ .direct = val_ptr.opt_payload.child },
31052 .ty = payload_ty,
31053 };
31054 },
31055 .bad_decl_ty, .bad_ptr_ty => return parent,
31056 // Even though the parent value type has well-defined memory layout, our
31057 // pointer type does not.
31058 .reinterpret => return .{
31059 .root = parent.root,
31060 .pointee = .bad_ptr_ty,
31061 .ty = opt_ty,
31062 },
31063 }
31064 },
31065 .elem => |elem_ptr| {
31066 const base_elem_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base)).elemType2(mod);
31067 var parent = try sema.beginComptimePtrMutation(block, src, Value.fromInterned(elem_ptr.base), base_elem_ty);
31068
31069 switch (parent.pointee) {
31070 .opv => unreachable,
31071 .direct => |val_ptr| switch (parent.ty.zigTypeTag(mod)) {
31072 .Array, .Vector => {
31073 const elem_ty = parent.ty.childType(mod);
31074 const check_len = parent.ty.arrayLenIncludingSentinel(mod);
31075 if ((try sema.typeHasOnePossibleValue(ptr_elem_ty)) != null) {
31076 if (elem_ptr.index > check_len) {
31077 // TODO have the parent include the decl so we can say "declared here"
31078 return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{
31079 elem_ptr.index, check_len,
31080 });
31081 }
31082 return .{
31083 .root = parent.root,
31084 .pointee = .opv,
31085 .ty = elem_ty,
31086 };
31087 }
31088 if (elem_ptr.index >= check_len) {
31089 // TODO have the parent include the decl so we can say "declared here"
31090 return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{
31091 elem_ptr.index, check_len,
31092 });
31093 }
31094
31095 // We might have a pointer to multiple elements of the array (e.g. a pointer
31096 // to a sub-array). In this case, we just have to reinterpret the relevant
31097 // bytes of the whole array rather than any single element.
31098 reinterp_multi_elem: {
31099 if (try sema.typeRequiresComptime(base_elem_ty)) break :reinterp_multi_elem;
31100 if (try sema.typeRequiresComptime(ptr_elem_ty)) break :reinterp_multi_elem;
31101
31102 const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty);
31103 if (elem_abi_size_u64 >= try sema.typeAbiSize(ptr_elem_ty)) break :reinterp_multi_elem;
31104
31105 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
31106 const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);
31107 return .{
31108 .root = parent.root,
31109 .pointee = .{ .reinterpret = .{
31110 .val_ptr = val_ptr,
31111 .byte_offset = elem_abi_size * elem_idx,
31112 } },
31113 .ty = parent.ty,
31114 };
31115 }
31116
31117 try val_ptr.unintern(mod, sema.arena, false, false);
31118
31119 const aggregate = switch (val_ptr.*) {
31120 .interned,
31121 .bytes,
31122 .repeated,
31123 .eu_payload,
31124 .opt_payload,
31125 .slice,
31126 .un,
31127 => unreachable,
31128 .aggregate => |*a| a,
31129 };
31130
31131 return sema.beginComptimePtrMutationInner(
31132 block,
31133 src,
31134 elem_ty,
31135 &aggregate.elems[@intCast(elem_ptr.index)],
31136 ptr_elem_ty,
31137 parent.root,
31138 );
31139 },
31140 else => {
31141 if (elem_ptr.index != 0) {
31142 // TODO include a "declared here" note for the decl
31143 return sema.fail(block, src, "out of bounds comptime store of index {d}", .{
31144 elem_ptr.index,
31145 });
31146 }
31147 return beginComptimePtrMutationInner(
31148 sema,
31149 block,
31150 src,
31151 parent.ty,
31152 val_ptr,
31153 ptr_elem_ty,
31154 parent.root,
31155 );
31156 },
31157 },
31158 .reinterpret => |reinterpret| {
31159 if (!base_elem_ty.hasWellDefinedLayout(mod)) {
31160 // Even though the parent value type has well-defined memory layout, our
31161 // pointer type does not.
31162 return .{
31163 .root = parent.root,
31164 .pointee = .bad_ptr_ty,
31165 .ty = base_elem_ty,
31166 };
31167 }
31168
31169 const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty);
31170 const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
31171 const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);
31172 return .{
31173 .root = parent.root,
31174 .pointee = .{ .reinterpret = .{
31175 .val_ptr = reinterpret.val_ptr,
31176 .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_idx,
31177 } },
31178 .ty = parent.ty,
31179 };
31180 },
31181 .bad_decl_ty, .bad_ptr_ty => return parent,
31182 }
31183 },
31184 .field => |field_ptr| {
31185 const base_child_ty = Type.fromInterned(mod.intern_pool.typeOf(field_ptr.base)).childType(mod);
31186 const field_index: u32 = @intCast(field_ptr.index);
31187
31188 var parent = try sema.beginComptimePtrMutation(block, src, Value.fromInterned(field_ptr.base), base_child_ty);
31189 switch (parent.pointee) {
31190 .opv => unreachable,
31191 .direct => |val_ptr| {
31192 try val_ptr.unintern(mod, sema.arena, false, false);
31193 switch (val_ptr.*) {
31194 .interned,
31195 .eu_payload,
31196 .opt_payload,
31197 .repeated,
31198 .bytes,
31199 => unreachable,
31200 .aggregate => |*a| return sema.beginComptimePtrMutationInner(
31201 block,
31202 src,
31203 parent.ty.structFieldType(field_index, mod),
31204 &a.elems[field_index],
31205 ptr_elem_ty,
31206 parent.root,
31207 ),
31208 .slice => |*s| switch (field_index) {
31209 Value.slice_ptr_index => return sema.beginComptimePtrMutationInner(
31210 block,
31211 src,
31212 parent.ty.slicePtrFieldType(mod),
31213 s.ptr,
31214 ptr_elem_ty,
31215 parent.root,
31216 ),
31217 Value.slice_len_index => return sema.beginComptimePtrMutationInner(
31218 block,
31219 src,
31220 Type.usize,
31221 s.len,
31222 ptr_elem_ty,
31223 parent.root,
31224 ),
31225 else => unreachable,
31226 },
31227 .un => |*un| {
31228 const layout = base_child_ty.containerLayout(mod);
31229
31230 const tag_type = base_child_ty.unionTagTypeHypothetical(mod);
31231 const hypothetical_tag = try mod.enumValueFieldIndex(tag_type, field_index);
31232 if (un.tag == .none and un.payload.* == .interned and un.payload.interned == .undef) {
31233 // A union has been initialized to undefined at comptime and now we
31234 // are for the first time setting the payload. We must change the
31235 // tag implicitly.
31236 const payload_ty = parent.ty.structFieldType(field_index, mod);
31237 un.tag = hypothetical_tag.toIntern();
31238 un.payload.* = .{ .interned = try mod.intern(.{ .undef = payload_ty.toIntern() }) };
31239 return beginComptimePtrMutationInner(
31240 sema,
31241 block,
31242 src,
31243 payload_ty,
31244 un.payload,
31245 ptr_elem_ty,
31246 parent.root,
31247 );
31248 }
31249
31250 if (layout == .auto or hypothetical_tag.toIntern() == un.tag) {
31251 // We need to set the active field of the union.
31252 un.tag = hypothetical_tag.toIntern();
31253
31254 const field_ty = parent.ty.structFieldType(field_index, mod);
31255 return beginComptimePtrMutationInner(
31256 sema,
31257 block,
31258 src,
31259 field_ty,
31260 un.payload,
31261 ptr_elem_ty,
31262 parent.root,
31263 );
31264 } else {
31265 // Writing to a different field (a different or unknown tag is active) requires reinterpreting
31266 // memory of the entire union, which requires knowing its abiSize.
31267 try sema.resolveTypeLayout(parent.ty);
31268 // This union value no longer has a well-defined tag type.
31269 // The reinterpretation will read it back out as .none.
31270 try un.payload.unintern(mod, sema.arena, false, false);
31271 return .{
31272 .root = parent.root,
31273 .pointee = .{ .reinterpret = .{
31274 .val_ptr = val_ptr,
31275 .byte_offset = 0,
31276 .write_packed = layout == .@"packed",
31277 } },
31278 .ty = parent.ty,
31279 };
31280 }
31281 },
31282 }
31283 },
31284 .reinterpret => |reinterpret| {
31285 const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod);
31286 const field_offset = try sema.usizeCast(block, src, field_offset_u64);
31287 return .{
31288 .root = parent.root,
31289 .pointee = .{ .reinterpret = .{
31290 .val_ptr = reinterpret.val_ptr,
31291 .byte_offset = reinterpret.byte_offset + field_offset,
31292 } },
31293 .ty = parent.ty,
31294 };
31295 },
31296 .bad_decl_ty, .bad_ptr_ty => return parent,
31297 }
31298 },
31299 }
31300}
31301
31302fn beginComptimePtrMutationInner(
31303 sema: *Sema,
31304 block: *Block,
31305 src: LazySrcLoc,
31306 decl_ty: Type,
31307 decl_val: *MutableValue,
31308 ptr_elem_ty: Type,
31309 root: ComptimePtrMutationKit.Root,
31310) CompileError!ComptimePtrMutationKit {
31311 const mod = sema.mod;
31312 const target = mod.getTarget();
31313 const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok;
31314
31315 const old_decl_val = decl_val.*;
31316 try decl_val.unintern(mod, sema.arena, false, false);
31317 if (decl_val.* == .un and decl_val.un.tag == .none and decl_val.un.payload.* == .interned and decl_val.un.payload.interned == .undef) {
31318 // HACKHACK: undefined union - re-intern it for now
31319 // `unintern` probably should just leave these as is, but I'm leaving it until I rewrite comptime pointer access.
31320 decl_val.* = old_decl_val;
31321 }
31322
31323 if (coerce_ok) {
31324 return ComptimePtrMutationKit{
31325 .root = root,
31326 .pointee = .{ .direct = decl_val },
31327 .ty = decl_ty,
31328 };
31329 }
31330
31331 // Handle the case that the decl is an array and we're actually trying to point to an element.
31332 if (decl_ty.isArrayOrVector(mod)) {
31333 const decl_elem_ty = decl_ty.childType(mod);
31334 if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) {
31335 return ComptimePtrMutationKit{
31336 .root = root,
31337 .pointee = .{ .direct = decl_val },
31338 .ty = decl_ty,
31339 };
31340 }
31341 }
31342
31343 if (!decl_ty.hasWellDefinedLayout(mod)) {
31344 return ComptimePtrMutationKit{
31345 .root = root,
31346 .pointee = .bad_decl_ty,
31347 .ty = decl_ty,
31348 };
31349 }
31350 if (!ptr_elem_ty.hasWellDefinedLayout(mod)) {
31351 return ComptimePtrMutationKit{
31352 .root = root,
31353 .pointee = .bad_ptr_ty,
31354 .ty = ptr_elem_ty,
31355 };
31356 }
31357 return ComptimePtrMutationKit{
31358 .root = root,
31359 .pointee = .{ .reinterpret = .{
31360 .val_ptr = decl_val,
31361 .byte_offset = 0,
31362 } },
31363 .ty = decl_ty,
31364 };
31365}
31366
31367const ComptimePtrLoadKit = struct {
31368 /// The Value and Type corresponding to the pointee of the provided pointer.
31369 /// If a direct dereference is not possible, this is null.
31370 pointee: ?MutableValue,
31371 /// The largest parent Value containing `pointee` and having a well-defined memory layout.
31372 /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null).
31373 parent: ?struct {
31374 val: MutableValue,
31375 byte_offset: usize,
31376 },
31377 /// If the root decl could not be used as `parent`, this is the type that
31378 /// caused that by not having a well-defined layout
31379 ty_without_well_defined_layout: ?Type,
31380};
31381
31382const ComptimePtrLoadError = CompileError || error{
31383 RuntimeLoad,
31384};
31385
31386/// If `maybe_array_ty` is provided, it will be used to directly dereference an
31387/// .elem_ptr of type T to a value of [N]T, if necessary.
31388fn beginComptimePtrLoad(
31389 sema: *Sema,
31390 block: *Block,
31391 src: LazySrcLoc,
31392 ptr_val: Value,
31393 maybe_array_ty: ?Type,
31394) ComptimePtrLoadError!ComptimePtrLoadKit {
31395 const mod = sema.mod;
31396 const ip = &mod.intern_pool;
31397 const target = mod.getTarget();
31398
31399 var deref: ComptimePtrLoadKit = switch (ip.indexToKey(ptr_val.toIntern())) {
31400 .ptr => |ptr| switch (ptr.addr) {
31401 .decl => |decl_index| blk: {
31402 const decl = mod.declPtr(decl_index);
31403 try sema.declareDependency(.{ .decl_val = decl_index });
31404 if (decl.val.getVariable(mod) != null) return error.RuntimeLoad;
31405 const decl_val: MutableValue = .{ .interned = decl.val.toIntern() };
31406 const layout_defined = decl.typeOf(mod).hasWellDefinedLayout(mod);
31407 break :blk ComptimePtrLoadKit{
31408 .parent = if (layout_defined) .{ .val = decl_val, .byte_offset = 0 } else null,
31409 .pointee = decl_val,
31410 .ty_without_well_defined_layout = if (!layout_defined) decl.typeOf(mod) else null,
31411 };
31412 },
31413 .comptime_alloc => |alloc_index| kit: {
31414 const alloc = sema.getComptimeAlloc(alloc_index);
31415 const alloc_ty = alloc.val.typeOf(mod);
31416 const layout_defined = alloc_ty.hasWellDefinedLayout(mod);
31417 break :kit .{
31418 .parent = if (layout_defined) .{ .val = alloc.val, .byte_offset = 0 } else null,
31419 .pointee = alloc.val,
31420 .ty_without_well_defined_layout = if (!layout_defined) alloc_ty else null,
31421 };
31422 },
31423 .anon_decl => |anon_decl| blk: {
31424 const decl_val = anon_decl.val;
31425 if (Value.fromInterned(decl_val).getVariable(mod) != null) return error.RuntimeLoad;
31426 const decl_ty = Type.fromInterned(ip.typeOf(decl_val));
31427 const decl_mv: MutableValue = .{ .interned = decl_val };
31428 const layout_defined = decl_ty.hasWellDefinedLayout(mod);
31429 break :blk ComptimePtrLoadKit{
31430 .parent = if (layout_defined) .{ .val = decl_mv, .byte_offset = 0 } else null,
31431 .pointee = decl_mv,
31432 .ty_without_well_defined_layout = if (!layout_defined) decl_ty else null,
31433 };
31434 },
31435 .int => return error.RuntimeLoad,
31436 .eu_payload, .opt_payload => |container_ptr| blk: {
31437 const container_ty = Type.fromInterned(ip.typeOf(container_ptr)).childType(mod);
31438 var deref = try sema.beginComptimePtrLoad(block, src, Value.fromInterned(container_ptr), container_ty);
31439
31440 // eu_payload and opt_payload never have a well-defined layout
31441 if (deref.parent != null) {
31442 deref.parent = null;
31443 deref.ty_without_well_defined_layout = container_ty;
31444 }
31445
31446 if (deref.pointee) |pointee| {
31447 const pointee_ty = pointee.typeOf(mod);
31448 const coerce_in_mem_ok =
31449 (try sema.coerceInMemoryAllowed(block, container_ty, pointee_ty, false, target, src, src)) == .ok or
31450 (try sema.coerceInMemoryAllowed(block, pointee_ty, container_ty, false, target, src, src)) == .ok;
31451 if (coerce_in_mem_ok) {
31452 deref.pointee = switch (pointee) {
31453 .interned => |ip_index| .{ .interned = switch (ip.indexToKey(ip_index)) {
31454 .error_union => |error_union| switch (error_union.val) {
31455 .err_name => |err_name| return sema.fail(
31456 block,
31457 src,
31458 "attempt to unwrap error: {}",
31459 .{err_name.fmt(ip)},
31460 ),
31461 .payload => |payload| payload,
31462 },
31463 .opt => |opt| switch (opt.val) {
31464 .none => return sema.fail(block, src, "attempt to use null value", .{}),
31465 else => |payload| payload,
31466 },
31467 else => unreachable,
31468 } },
31469 .eu_payload, .opt_payload => |p| p.child.*,
31470 else => unreachable,
31471 };
31472 break :blk deref;
31473 }
31474 }
31475 deref.pointee = null;
31476 break :blk deref;
31477 },
31478 .comptime_field => |field_val| .{
31479 .parent = null,
31480 .pointee = .{ .interned = field_val },
31481 .ty_without_well_defined_layout = Type.fromInterned(ip.typeOf(field_val)),
31482 },
31483 .elem => |elem_ptr| blk: {
31484 const elem_ty = Type.fromInterned(ip.typeOf(elem_ptr.base)).elemType2(mod);
31485 var deref = try sema.beginComptimePtrLoad(block, src, Value.fromInterned(elem_ptr.base), null);
31486
31487 // This code assumes that elem_ptrs have been "flattened" in order for direct dereference
31488 // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that
31489 // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened"
31490 switch (ip.indexToKey(elem_ptr.base)) {
31491 .ptr => |base_ptr| switch (base_ptr.addr) {
31492 .elem => |base_elem| assert(!Type.fromInterned(ip.typeOf(base_elem.base)).elemType2(mod).eql(elem_ty, mod)),
31493 else => {},
31494 },
31495 else => {},
31496 }
31497
31498 if (elem_ptr.index != 0) {
31499 if (elem_ty.hasWellDefinedLayout(mod)) {
31500 if (deref.parent) |*parent| {
31501 // Update the byte offset (in-place)
31502 const elem_size = try sema.typeAbiSize(elem_ty);
31503 const offset = parent.byte_offset + elem_size * elem_ptr.index;
31504 parent.byte_offset = try sema.usizeCast(block, src, offset);
31505 }
31506 } else {
31507 deref.parent = null;
31508 deref.ty_without_well_defined_layout = elem_ty;
31509 }
31510 }
31511
31512 // If we're loading an elem that was derived from a different type
31513 // than the true type of the underlying decl, we cannot deref directly
31514 const ty_matches = if (deref.pointee) |pointee| match: {
31515 const ty = pointee.typeOf(mod);
31516 if (!ty.isArrayOrVector(mod)) break :match false;
31517 const deref_elem_ty = ty.childType(mod);
31518 if ((try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok) break :match true;
31519 if ((try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok) break :match true;
31520 break :match false;
31521 } else false;
31522 if (!ty_matches) {
31523 deref.pointee = null;
31524 break :blk deref;
31525 }
31526
31527 var array_val = deref.pointee.?;
31528 const check_len = array_val.typeOf(mod).arrayLenIncludingSentinel(mod);
31529 if (maybe_array_ty) |load_ty| {
31530 // It's possible that we're loading a [N]T, in which case we'd like to slice
31531 // the pointee array directly from our parent array.
31532 if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, mod)) {
31533 const len = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod));
31534 const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);
31535 deref.pointee = if (elem_ptr.index + len <= check_len) switch (array_val) {
31536 .aggregate => |a| .{ .aggregate = .{
31537 .ty = (try mod.arrayType(.{ .len = len, .child = elem_ty.toIntern() })).toIntern(),
31538 .elems = a.elems[elem_idx..][0..len],
31539 } },
31540 else => .{
31541 .interned = (try (Value.fromInterned(
31542 try array_val.intern(mod, sema.arena),
31543 ).sliceArray(sema, elem_idx, elem_idx + len))).toIntern(),
31544 },
31545 } else null;
31546 break :blk deref;
31547 }
31548 }
31549
31550 if (elem_ptr.index >= check_len) {
31551 deref.pointee = null;
31552 break :blk deref;
31553 }
31554 if (elem_ptr.index == check_len - 1) {
31555 if (array_val.typeOf(mod).sentinel(mod)) |sent| {
31556 deref.pointee = .{ .interned = sent.toIntern() };
31557 break :blk deref;
31558 }
31559 }
31560 deref.pointee = try array_val.getElem(mod, @intCast(elem_ptr.index));
31561 break :blk deref;
31562 },
31563 .field => |field_ptr| blk: {
31564 const field_index: u32 = @intCast(field_ptr.index);
31565 const container_ty = Type.fromInterned(ip.typeOf(field_ptr.base)).childType(mod);
31566 var deref = try sema.beginComptimePtrLoad(block, src, Value.fromInterned(field_ptr.base), container_ty);
31567
31568 if (container_ty.hasWellDefinedLayout(mod)) {
31569 const struct_obj = mod.typeToStruct(container_ty);
31570 if (struct_obj != null and struct_obj.?.layout == .@"packed") {
31571 // packed structs are not byte addressable
31572 deref.parent = null;
31573 } else if (deref.parent) |*parent| {
31574 // Update the byte offset (in-place)
31575 try sema.resolveTypeLayout(container_ty);
31576 const field_offset = container_ty.structFieldOffset(field_index, mod);
31577 parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset);
31578 }
31579 } else {
31580 deref.parent = null;
31581 deref.ty_without_well_defined_layout = container_ty;
31582 }
31583
31584 const pointee = deref.pointee orelse break :blk deref;
31585 const pointee_ty = pointee.typeOf(mod);
31586 const coerce_in_mem_ok =
31587 (try sema.coerceInMemoryAllowed(block, container_ty, pointee_ty, false, target, src, src)) == .ok or
31588 (try sema.coerceInMemoryAllowed(block, pointee_ty, container_ty, false, target, src, src)) == .ok;
31589 if (!coerce_in_mem_ok) {
31590 deref.pointee = null;
31591 break :blk deref;
31592 }
31593
31594 deref.pointee = try pointee.getElem(mod, field_index);
31595 break :blk deref;
31596 },
31597 },
31598 .opt => |opt| switch (opt.val) {
31599 .none => return sema.fail(block, src, "attempt to use null value", .{}),
31600 else => |payload| try sema.beginComptimePtrLoad(block, src, Value.fromInterned(payload), null),
31601 },
31602 else => unreachable,
31603 };
30937 const zcu = sema.mod;
30938 const ip = &zcu.intern_pool;
30939 // TODO: audit use sites to eliminate this coercion
30940 const coerced_operand_val = try zcu.getCoerced(operand_val, operand_ty);
30941 // TODO: audit use sites to eliminate this coercion
30942 const ptr_ty = try zcu.ptrType(info: {
30943 var info = ptr_val.typeOf(zcu).ptrInfo(zcu);
30944 info.child = operand_ty.toIntern();
30945 break :info info;
30946 });
30947 const coerced_ptr_val = try zcu.getCoerced(ptr_val, ptr_ty);
3160430948
31605 if (deref.pointee) |val| {
31606 if (deref.parent == null and val.typeOf(mod).hasWellDefinedLayout(mod)) {
31607 deref.parent = .{ .val = val, .byte_offset = 0 };
31608 }
30949 switch (try sema.storeComptimePtr(block, src, coerced_ptr_val, coerced_operand_val)) {
30950 .success => {},
30951 .runtime_store => unreachable, // use sites check this
30952 // TODO use failWithInvalidComptimeFieldStore
30953 .comptime_field_mismatch => return sema.fail(
30954 block,
30955 src,
30956 "value stored in comptime field does not match the default value of the field",
30957 .{},
30958 ),
30959 .undef => return sema.failWithUseOfUndef(block, src),
30960 .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {}", .{err_name.fmt(ip)}),
30961 .null_payload => return sema.fail(block, src, "attempt to use null value", .{}),
30962 .inactive_union_field => return sema.fail(block, src, "access of inactive union field", .{}),
30963 .needed_well_defined => |ty| return sema.fail(
30964 block,
30965 src,
30966 "comptime dereference requires '{}' to have a well-defined layout",
30967 .{ty.fmt(zcu)},
30968 ),
30969 .out_of_bounds => |ty| return sema.fail(
30970 block,
30971 src,
30972 "dereference of '{}' exceeds bounds of containing decl of type '{}'",
30973 .{ ptr_ty.fmt(zcu), ty.fmt(zcu) },
30974 ),
30975 .exceeds_host_size => return sema.fail(block, src, "bit-pointer target exceeds host size", .{}),
3160930976 }
31610 return deref;
3161130977}
3161230978
3161330979fn bitCast(
......@@ -31618,28 +30984,33 @@ fn bitCast(
3161830984 inst_src: LazySrcLoc,
3161930985 operand_src: ?LazySrcLoc,
3162030986) CompileError!Air.Inst.Ref {
31621 const mod = sema.mod;
30987 const zcu = sema.mod;
3162230988 try sema.resolveTypeLayout(dest_ty);
3162330989
3162430990 const old_ty = sema.typeOf(inst);
3162530991 try sema.resolveTypeLayout(old_ty);
3162630992
31627 const dest_bits = dest_ty.bitSize(mod);
31628 const old_bits = old_ty.bitSize(mod);
30993 const dest_bits = dest_ty.bitSize(zcu);
30994 const old_bits = old_ty.bitSize(zcu);
3162930995
3163030996 if (old_bits != dest_bits) {
3163130997 return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{
31632 dest_ty.fmt(mod),
30998 dest_ty.fmt(zcu),
3163330999 dest_bits,
31634 old_ty.fmt(mod),
31000 old_ty.fmt(zcu),
3163531001 old_bits,
3163631002 });
3163731003 }
3163831004
3163931005 if (try sema.resolveValue(inst)) |val| {
31640 if (val.isUndef(mod))
31641 return mod.undefRef(dest_ty);
31642 if (try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0)) |result_val| {
31006 if (val.isUndef(zcu))
31007 return zcu.undefRef(dest_ty);
31008 if (old_ty.zigTypeTag(zcu) == .ErrorSet and dest_ty.zigTypeTag(zcu) == .ErrorSet) {
31009 // Special case: we sometimes call `bitCast` on error set values, but they
31010 // don't have a well-defined layout, so we can't use `bitCastVal` on them.
31011 return Air.internedToRef((try zcu.getCoerced(val, dest_ty)).toIntern());
31012 }
31013 if (try sema.bitCastVal(val, dest_ty, 0, 0, 0)) |result_val| {
3164331014 return Air.internedToRef(result_val.toIntern());
3164431015 }
3164531016 }
......@@ -31648,98 +31019,6 @@ fn bitCast(
3164831019 return block.addBitCast(dest_ty, inst);
3164931020}
3165031021
31651fn bitCastVal(
31652 sema: *Sema,
31653 block: *Block,
31654 src: LazySrcLoc,
31655 val: Value,
31656 old_ty: Type,
31657 new_ty: Type,
31658 buffer_offset: usize,
31659) !?Value {
31660 const mod = sema.mod;
31661 if (old_ty.eql(new_ty, mod)) return val;
31662
31663 // For types with well-defined memory layouts, we serialize them a byte buffer,
31664 // then deserialize to the new type.
31665 const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(mod));
31666
31667 const buffer = try sema.gpa.alloc(u8, abi_size);
31668 defer sema.gpa.free(buffer);
31669 val.writeToMemory(old_ty, mod, buffer) catch |err| switch (err) {
31670 error.OutOfMemory => return error.OutOfMemory,
31671 error.ReinterpretDeclRef => return null,
31672 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
31673 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{old_ty.fmt(mod)}),
31674 };
31675
31676 return Value.readFromMemory(new_ty, mod, buffer[buffer_offset..], sema.arena) catch |err| switch (err) {
31677 error.OutOfMemory => return error.OutOfMemory,
31678 error.IllDefinedMemoryLayout => unreachable,
31679 error.Unimplemented => return sema.fail(block, src, "TODO: implement readFromMemory for type '{}'", .{new_ty.fmt(mod)}),
31680 };
31681}
31682
31683fn bitCastUnionFieldVal(
31684 sema: *Sema,
31685 block: *Block,
31686 src: LazySrcLoc,
31687 val: Value,
31688 old_ty: Type,
31689 field_ty: Type,
31690 layout: std.builtin.Type.ContainerLayout,
31691) !?Value {
31692 const mod = sema.mod;
31693 if (old_ty.eql(field_ty, mod)) return val;
31694
31695 // Bitcasting a union field value requires that that field's layout be known
31696 try sema.resolveTypeLayout(field_ty);
31697
31698 const old_size = try sema.usizeCast(block, src, old_ty.abiSize(mod));
31699 const field_size = try sema.usizeCast(block, src, field_ty.abiSize(mod));
31700 const endian = mod.getTarget().cpu.arch.endian();
31701
31702 const buffer = try sema.gpa.alloc(u8, @max(old_size, field_size));
31703 defer sema.gpa.free(buffer);
31704
31705 // Reading a larger value means we need to reinterpret from undefined bytes.
31706 const offset = switch (layout) {
31707 .@"extern" => offset: {
31708 if (field_size > old_size) @memset(buffer[old_size..], 0xaa);
31709 val.writeToMemory(old_ty, mod, buffer) catch |err| switch (err) {
31710 error.OutOfMemory => return error.OutOfMemory,
31711 error.ReinterpretDeclRef => return null,
31712 error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
31713 error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{old_ty.fmt(mod)}),
31714 };
31715 break :offset 0;
31716 },
31717 .@"packed" => offset: {
31718 if (field_size > old_size) {
31719 const min_size = @max(old_size, 1);
31720 switch (endian) {
31721 .little => @memset(buffer[min_size - 1 ..], 0xaa),
31722 .big => @memset(buffer[0 .. buffer.len - min_size + 1], 0xaa),
31723 }
31724 }
31725
31726 val.writeToPackedMemory(old_ty, mod, buffer, 0) catch |err| switch (err) {
31727 error.OutOfMemory => return error.OutOfMemory,
31728 error.ReinterpretDeclRef => return null,
31729 };
31730
31731 break :offset if (endian == .big) buffer.len - field_size else 0;
31732 },
31733 .auto => unreachable,
31734 };
31735
31736 return Value.readFromMemory(field_ty, mod, buffer[offset..], sema.arena) catch |err| switch (err) {
31737 error.OutOfMemory => return error.OutOfMemory,
31738 error.IllDefinedMemoryLayout => unreachable,
31739 error.Unimplemented => return sema.fail(block, src, "TODO: implement readFromMemory for type '{}'", .{field_ty.fmt(mod)}),
31740 };
31741}
31742
3174331022fn coerceArrayPtrToSlice(
3174431023 sema: *Sema,
3174531024 block: *Block,
......@@ -31885,7 +31164,7 @@ fn coerceEnumToUnion(
3188531164 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
3188631165 const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse {
3188731166 return sema.fail(block, inst_src, "union '{}' has no tag with value '{}'", .{
31888 union_ty.fmt(sema.mod), val.fmtValue(sema.mod),
31167 union_ty.fmt(sema.mod), val.fmtValue(sema.mod, sema),
3188931168 });
3189031169 };
3189131170
......@@ -32595,7 +31874,7 @@ fn addReferencedBy(
3259531874 });
3259631875}
3259731876
32598fn ensureDeclAnalyzed(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!void {
31877pub fn ensureDeclAnalyzed(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!void {
3259931878 const mod = sema.mod;
3260031879 const ip = &mod.intern_pool;
3260131880 const decl = mod.declPtr(decl_index);
......@@ -32673,7 +31952,8 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
3267331952 }
3267431953 return Air.internedToRef((try mod.intern(.{ .ptr = .{
3267531954 .ty = ptr_ty.toIntern(),
32676 .addr = .{ .decl = decl_index },
31955 .base_addr = .{ .decl = decl_index },
31956 .byte_offset = 0,
3267731957 } })));
3267831958}
3267931959
......@@ -33102,8 +32382,8 @@ fn analyzeSlice(
3310232382 msg,
3310332383 "expected '{}', found '{}'",
3310432384 .{
33105 Value.zero_comptime_int.fmtValue(mod),
33106 start_value.fmtValue(mod),
32385 Value.zero_comptime_int.fmtValue(mod, sema),
32386 start_value.fmtValue(mod, sema),
3310732387 },
3310832388 );
3310932389 break :msg msg;
......@@ -33119,8 +32399,8 @@ fn analyzeSlice(
3311932399 msg,
3312032400 "expected '{}', found '{}'",
3312132401 .{
33122 Value.one_comptime_int.fmtValue(mod),
33123 end_value.fmtValue(mod),
32402 Value.one_comptime_int.fmtValue(mod, sema),
32403 end_value.fmtValue(mod, sema),
3312432404 },
3312532405 );
3312632406 break :msg msg;
......@@ -33133,7 +32413,7 @@ fn analyzeSlice(
3313332413 block,
3313432414 end_src,
3313532415 "end index {} out of bounds for slice of single-item pointer",
33136 .{end_value.fmtValue(mod)},
32416 .{end_value.fmtValue(mod, sema)},
3313732417 );
3313832418 }
3313932419 }
......@@ -33228,8 +32508,8 @@ fn analyzeSlice(
3322832508 end_src,
3322932509 "end index {} out of bounds for array of length {}{s}",
3323032510 .{
33231 end_val.fmtValue(mod),
33232 len_val.fmtValue(mod),
32511 end_val.fmtValue(mod, sema),
32512 len_val.fmtValue(mod, sema),
3323332513 sentinel_label,
3323432514 },
3323532515 );
......@@ -33273,7 +32553,7 @@ fn analyzeSlice(
3327332553 end_src,
3327432554 "end index {} out of bounds for slice of length {d}{s}",
3327532555 .{
33276 end_val.fmtValue(mod),
32556 end_val.fmtValue(mod, sema),
3327732557 try slice_val.sliceLen(sema),
3327832558 sentinel_label,
3327932559 },
......@@ -33333,8 +32613,8 @@ fn analyzeSlice(
3333332613 start_src,
3333432614 "start index {} is larger than end index {}",
3333532615 .{
33336 start_val.fmtValue(mod),
33337 end_val.fmtValue(mod),
32616 start_val.fmtValue(mod, sema),
32617 end_val.fmtValue(mod, sema),
3333832618 },
3333932619 );
3334032620 }
......@@ -33347,16 +32627,15 @@ fn analyzeSlice(
3334732627
3334832628 const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
3334932629 const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty);
33350 const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);
33351 const elem_ptr = try many_ptr_val.elemPtr(elem_ptr_ty, sentinel_index, mod);
33352 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty);
32630 const elem_ptr = try many_ptr_val.ptrElem(sentinel_index, sema);
32631 const res = try sema.pointerDerefExtra(block, src, elem_ptr);
3335332632 const actual_sentinel = switch (res) {
3335432633 .runtime_load => break :sentinel_check,
3335532634 .val => |v| v,
3335632635 .needed_well_defined => |ty| return sema.fail(
3335732636 block,
3335832637 src,
33359 "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
32638 "comptime dereference requires '{}' to have a well-defined layout",
3336032639 .{ty.fmt(mod)},
3336132640 ),
3336232641 .out_of_bounds => |ty| return sema.fail(
......@@ -33372,8 +32651,8 @@ fn analyzeSlice(
3337232651 const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});
3337332652 errdefer msg.destroy(sema.gpa);
3337432653 try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{
33375 expected_sentinel.fmtValue(mod),
33376 actual_sentinel.fmtValue(mod),
32654 expected_sentinel.fmtValue(mod, sema),
32655 actual_sentinel.fmtValue(mod, sema),
3337732656 });
3337832657
3337932658 break :msg msg;
......@@ -35599,8 +34878,8 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
3559934878 } }));
3560034879 },
3560134880 .ptr => |ptr| {
35602 switch (ptr.addr) {
35603 .decl, .comptime_alloc, .anon_decl => return val,
34881 switch (ptr.base_addr) {
34882 .decl, .comptime_alloc, .anon_decl, .int => return val,
3560434883 .comptime_field => |field_val| {
3560534884 const resolved_field_val =
3560634885 (try sema.resolveLazyValue(Value.fromInterned(field_val))).toIntern();
......@@ -35609,17 +34888,8 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
3560934888 else
3561034889 Value.fromInterned((try mod.intern(.{ .ptr = .{
3561134890 .ty = ptr.ty,
35612 .addr = .{ .comptime_field = resolved_field_val },
35613 } })));
35614 },
35615 .int => |int| {
35616 const resolved_int = (try sema.resolveLazyValue(Value.fromInterned(int))).toIntern();
35617 return if (resolved_int == int)
35618 val
35619 else
35620 Value.fromInterned((try mod.intern(.{ .ptr = .{
35621 .ty = ptr.ty,
35622 .addr = .{ .int = resolved_int },
34891 .base_addr = .{ .comptime_field = resolved_field_val },
34892 .byte_offset = ptr.byte_offset,
3562334893 } })));
3562434894 },
3562534895 .eu_payload, .opt_payload => |base| {
......@@ -35629,22 +34899,23 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
3562934899 else
3563034900 Value.fromInterned((try mod.intern(.{ .ptr = .{
3563134901 .ty = ptr.ty,
35632 .addr = switch (ptr.addr) {
34902 .base_addr = switch (ptr.base_addr) {
3563334903 .eu_payload => .{ .eu_payload = resolved_base },
3563434904 .opt_payload => .{ .opt_payload = resolved_base },
3563534905 else => unreachable,
3563634906 },
34907 .byte_offset = ptr.byte_offset,
3563734908 } })));
3563834909 },
35639 .elem, .field => |base_index| {
34910 .arr_elem, .field => |base_index| {
3564034911 const resolved_base = (try sema.resolveLazyValue(Value.fromInterned(base_index.base))).toIntern();
3564134912 return if (resolved_base == base_index.base)
3564234913 val
3564334914 else
3564434915 Value.fromInterned((try mod.intern(.{ .ptr = .{
3564534916 .ty = ptr.ty,
35646 .addr = switch (ptr.addr) {
35647 .elem => .{ .elem = .{
34917 .base_addr = switch (ptr.base_addr) {
34918 .arr_elem => .{ .arr_elem = .{
3564834919 .base = resolved_base,
3564934920 .index = base_index.index,
3565034921 } },
......@@ -35654,6 +34925,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
3565434925 } },
3565534926 else => unreachable,
3565634927 },
34928 .byte_offset = ptr.byte_offset,
3565734929 } })));
3565834930 },
3565934931 }
......@@ -36166,7 +35438,8 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
3616635438 var max_align: Alignment = .@"1";
3616735439 for (0..union_type.field_types.len) |field_index| {
3616835440 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
36169 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
35441
35442 if (try sema.typeRequiresComptime(field_ty) or field_ty.zigTypeTag(mod) == .NoReturn) continue; // TODO: should this affect alignment?
3617035443
3617135444 max_size = @max(max_size, sema.typeAbiSize(field_ty) catch |err| switch (err) {
3617235445 error.AnalysisFail => {
......@@ -36496,7 +35769,15 @@ pub fn resolveTypeFieldsStruct(
3649635769 }
3649735770 defer struct_type.clearTypesWip(ip);
3649835771
36499 try semaStructFields(mod, sema.arena, struct_type);
35772 semaStructFields(mod, sema.arena, struct_type) catch |err| switch (err) {
35773 error.AnalysisFail => {
35774 if (mod.declPtr(owner_decl).analysis == .complete) {
35775 mod.declPtr(owner_decl).analysis = .dependency_failure;
35776 }
35777 return error.AnalysisFail;
35778 },
35779 else => |e| return e,
35780 };
3650035781}
3650135782
3650235783pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {
......@@ -36521,7 +35802,15 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {
3652135802 }
3652235803 defer struct_type.clearInitsWip(ip);
3652335804
36524 try semaStructFieldInits(mod, sema.arena, struct_type);
35805 semaStructFieldInits(mod, sema.arena, struct_type) catch |err| switch (err) {
35806 error.AnalysisFail => {
35807 if (mod.declPtr(owner_decl).analysis == .complete) {
35808 mod.declPtr(owner_decl).analysis = .dependency_failure;
35809 }
35810 return error.AnalysisFail;
35811 },
35812 else => |e| return e,
35813 };
3652535814 struct_type.setHaveFieldInits(ip);
3652635815}
3652735816
......@@ -36560,7 +35849,15 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Load
3656035849
3656135850 union_type.flagsPtr(ip).status = .field_types_wip;
3656235851 errdefer union_type.flagsPtr(ip).status = .none;
36563 try semaUnionFields(mod, sema.arena, union_type);
35852 semaUnionFields(mod, sema.arena, union_type) catch |err| switch (err) {
35853 error.AnalysisFail => {
35854 if (owner_decl.analysis == .complete) {
35855 owner_decl.analysis = .dependency_failure;
35856 }
35857 return error.AnalysisFail;
35858 },
35859 else => |e| return e,
35860 };
3656435861 union_type.flagsPtr(ip).status = .have_field_types;
3656535862}
3656635863
......@@ -37391,7 +36688,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
3739136688 const field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = field_i }).lazy;
3739236689 const other_field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = gop.index }).lazy;
3739336690 const msg = msg: {
37394 const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(mod)});
36691 const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(mod, &sema)});
3739536692 errdefer msg.destroy(gpa);
3739636693 try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{});
3739736694 break :msg msg;
......@@ -38158,7 +37455,8 @@ fn analyzeComptimeAlloc(
3815837455
3815937456 return Air.internedToRef((try mod.intern(.{ .ptr = .{
3816037457 .ty = ptr_type.toIntern(),
38161 .addr = .{ .comptime_alloc = alloc },
37458 .base_addr = .{ .comptime_alloc = alloc },
37459 .byte_offset = 0,
3816237460 } })));
3816337461}
3816437462
......@@ -38247,16 +37545,15 @@ pub fn analyzeAsAddressSpace(
3824737545/// Asserts the value is a pointer and dereferences it.
3824837546/// Returns `null` if the pointer contents cannot be loaded at comptime.
3824937547fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value {
38250 const mod = sema.mod;
38251 const load_ty = ptr_ty.childType(mod);
38252 const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty);
38253 switch (res) {
37548 // TODO: audit use sites to eliminate this coercion
37549 const coerced_ptr_val = try sema.mod.getCoerced(ptr_val, ptr_ty);
37550 switch (try sema.pointerDerefExtra(block, src, coerced_ptr_val)) {
3825437551 .runtime_load => return null,
3825537552 .val => |v| return v,
3825637553 .needed_well_defined => |ty| return sema.fail(
3825737554 block,
3825837555 src,
38259 "comptime dereference requires '{}' to have a well-defined layout, but it does not.",
37556 "comptime dereference requires '{}' to have a well-defined layout",
3826037557 .{ty.fmt(sema.mod)},
3826137558 ),
3826237559 .out_of_bounds => |ty| return sema.fail(
......@@ -38275,68 +37572,19 @@ const DerefResult = union(enum) {
3827537572 out_of_bounds: Type,
3827637573};
3827737574
38278fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type) CompileError!DerefResult {
38279 const mod = sema.mod;
38280 const target = mod.getTarget();
38281 const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) {
38282 error.RuntimeLoad => return DerefResult{ .runtime_load = {} },
38283 else => |e| return e,
38284 };
38285
38286 if (deref.pointee) |pointee| {
38287 const uncoerced_val = Value.fromInterned(try pointee.intern(mod, sema.arena));
38288 const ty = Type.fromInterned(mod.intern_pool.typeOf(uncoerced_val.toIntern()));
38289 const coerce_in_mem_ok =
38290 (try sema.coerceInMemoryAllowed(block, load_ty, ty, false, target, src, src)) == .ok or
38291 (try sema.coerceInMemoryAllowed(block, ty, load_ty, false, target, src, src)) == .ok;
38292 if (coerce_in_mem_ok) {
38293 // We have a Value that lines up in virtual memory exactly with what we want to load,
38294 // and it is in-memory coercible to load_ty. It may be returned without modifications.
38295 // Move mutable decl values to the InternPool and assert other decls are already in
38296 // the InternPool.
38297 const coerced_val = try mod.getCoerced(uncoerced_val, load_ty);
38298 return .{ .val = coerced_val };
38299 }
38300 }
38301
38302 // The type is not in-memory coercible or the direct dereference failed, so it must
38303 // be bitcast according to the pointer type we are performing the load through.
38304 if (!load_ty.hasWellDefinedLayout(mod)) {
38305 return DerefResult{ .needed_well_defined = load_ty };
38306 }
38307
38308 const load_sz = try sema.typeAbiSize(load_ty);
38309
38310 // Try the smaller bit-cast first, since that's more efficient than using the larger `parent`
38311 if (deref.pointee) |pointee| {
38312 const val_ip_index = try pointee.intern(mod, sema.arena);
38313 const val = Value.fromInterned(val_ip_index);
38314 const ty = Type.fromInterned(mod.intern_pool.typeOf(val_ip_index));
38315 if (load_sz <= try sema.typeAbiSize(ty)) {
38316 return .{ .val = (try sema.bitCastVal(block, src, val, ty, load_ty, 0)) orelse return .runtime_load };
38317 }
38318 }
38319
38320 // If that fails, try to bit-cast from the largest parent value with a well-defined layout
38321 if (deref.parent) |parent| {
38322 const parent_ip_index = try parent.val.intern(mod, sema.arena);
38323 const parent_val = Value.fromInterned(parent_ip_index);
38324 const parent_ty = Type.fromInterned(mod.intern_pool.typeOf(parent_ip_index));
38325 if (load_sz + parent.byte_offset <= try sema.typeAbiSize(parent_ty)) {
38326 return .{ .val = (try sema.bitCastVal(block, src, parent_val, parent_ty, load_ty, parent.byte_offset)) orelse return .runtime_load };
38327 }
38328 }
38329
38330 if (deref.ty_without_well_defined_layout) |bad_ty| {
38331 // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem
38332 // is that some type we encountered when de-referencing does not have a well-defined layout.
38333 return .{ .needed_well_defined = bad_ty };
38334 } else {
38335 // If all encountered types had well-defined layouts, the parent is the root decl and it just
38336 // wasn't big enough for the load.
38337 const parent_ip_index = try deref.parent.?.val.intern(mod, sema.arena);
38338 const parent_ty = Type.fromInterned(mod.intern_pool.typeOf(parent_ip_index));
38339 return .{ .out_of_bounds = parent_ty };
37575fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value) CompileError!DerefResult {
37576 const zcu = sema.mod;
37577 const ip = &zcu.intern_pool;
37578 switch (try sema.loadComptimePtr(block, src, ptr_val)) {
37579 .success => |mv| return .{ .val = try mv.intern(zcu, sema.arena) },
37580 .runtime_load => return .runtime_load,
37581 .undef => return sema.failWithUseOfUndef(block, src),
37582 .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {}", .{err_name.fmt(ip)}),
37583 .null_payload => return sema.fail(block, src, "attempt to use null value", .{}),
37584 .inactive_union_field => return sema.fail(block, src, "access of inactive union field", .{}),
37585 .needed_well_defined => |ty| return .{ .needed_well_defined = ty },
37586 .out_of_bounds => |ty| return .{ .out_of_bounds = ty },
37587 .exceeds_host_size => return sema.fail(block, src, "bit-pointer target exceeds host size", .{}),
3834037588 }
3834137589}
3834237590
......@@ -38394,18 +37642,18 @@ pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
3839437642 };
3839537643}
3839637644
38397fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
37645pub fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
3839837646 try sema.resolveTypeLayout(ty);
3839937647 return ty.abiSize(sema.mod);
3840037648}
3840137649
38402fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {
37650pub fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {
3840337651 return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar;
3840437652}
3840537653
3840637654/// Not valid to call for packed unions.
3840737655/// Keep implementation in sync with `Module.unionFieldNormalAlignment`.
38408fn unionFieldAlignment(sema: *Sema, u: InternPool.LoadedUnionType, field_index: u32) !Alignment {
37656pub fn unionFieldAlignment(sema: *Sema, u: InternPool.LoadedUnionType, field_index: u32) !Alignment {
3840937657 const mod = sema.mod;
3841037658 const ip = &mod.intern_pool;
3841137659 const field_align = u.fieldAlign(ip, field_index);
......@@ -38416,7 +37664,7 @@ fn unionFieldAlignment(sema: *Sema, u: InternPool.LoadedUnionType, field_index:
3841637664}
3841737665
3841837666/// Keep implementation in sync with `Module.structFieldAlignment`.
38419fn structFieldAlignment(
37667pub fn structFieldAlignment(
3842037668 sema: *Sema,
3842137669 explicit_alignment: InternPool.Alignment,
3842237670 field_ty: Type,
......@@ -38724,6 +37972,13 @@ fn intSubWithOverflowScalar(
3872437972 const mod = sema.mod;
3872537973 const info = ty.intInfo(mod);
3872637974
37975 if (lhs.isUndef(mod) or rhs.isUndef(mod)) {
37976 return .{
37977 .overflow_bit = try mod.undefValue(Type.u1),
37978 .wrapped_result = try mod.undefValue(ty),
37979 };
37980 }
37981
3872737982 var lhs_space: Value.BigIntSpace = undefined;
3872837983 var rhs_space: Value.BigIntSpace = undefined;
3872937984 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
......@@ -38808,7 +38063,7 @@ fn intFromFloatScalar(
3880838063 block,
3880938064 src,
3881038065 "fractional component prevents float value '{}' from coercion to type '{}'",
38811 .{ val.fmtValue(mod), int_ty.fmt(mod) },
38066 .{ val.fmtValue(mod, sema), int_ty.fmt(mod) },
3881238067 );
3881338068
3881438069 const float = val.toFloat(f128, mod);
......@@ -38830,7 +38085,7 @@ fn intFromFloatScalar(
3883038085
3883138086 if (!(try sema.intFitsInType(cti_result, int_ty, null))) {
3883238087 return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{
38833 val.fmtValue(sema.mod), int_ty.fmt(sema.mod),
38088 val.fmtValue(sema.mod, sema), int_ty.fmt(sema.mod),
3883438089 });
3883538090 }
3883638091 return mod.getCoerced(cti_result, int_ty);
......@@ -38975,6 +38230,13 @@ fn intAddWithOverflowScalar(
3897538230 const mod = sema.mod;
3897638231 const info = ty.intInfo(mod);
3897738232
38233 if (lhs.isUndef(mod) or rhs.isUndef(mod)) {
38234 return .{
38235 .overflow_bit = try mod.undefValue(Type.u1),
38236 .wrapped_result = try mod.undefValue(ty),
38237 };
38238 }
38239
3897838240 var lhs_space: Value.BigIntSpace = undefined;
3897938241 var rhs_space: Value.BigIntSpace = undefined;
3898038242 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
......@@ -39070,12 +38332,14 @@ fn compareVector(
3907038332
3907138333/// Returns the type of a pointer to an element.
3907238334/// Asserts that the type is a pointer, and that the element type is indexable.
38335/// If the element index is comptime-known, it must be passed in `offset`.
38336/// For *@Vector(n, T), return *align(a:b:h:v) T
3907338337/// For *[N]T, return *T
3907438338/// For [*]T, returns *T
3907538339/// For []T, returns *T
3907638340/// Handles const-ness and address spaces in particular.
3907738341/// This code is duplicated in `analyzePtrArithmetic`.
39078fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
38342pub fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3907938343 const mod = sema.mod;
3908038344 const ptr_info = ptr_ty.ptrInfo(mod);
3908138345 const elem_ty = ptr_ty.elemType2(mod);
......@@ -39180,7 +38444,7 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool
3918038444 return sema.typeOf(ref).zigTypeTag(sema.mod) == tag;
3918138445}
3918238446
39183fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {
38447pub fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {
3918438448 if (info.flags.alignment != .none) {
3918538449 _ = try sema.typeAbiAlignment(Type.fromInterned(info.child));
3918638450 }
......@@ -39210,12 +38474,12 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
3921038474fn isComptimeMutablePtr(sema: *Sema, val: Value) bool {
3921138475 return switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {
3921238476 .slice => |slice| sema.isComptimeMutablePtr(Value.fromInterned(slice.ptr)),
39213 .ptr => |ptr| switch (ptr.addr) {
38477 .ptr => |ptr| switch (ptr.base_addr) {
3921438478 .anon_decl, .decl, .int => false,
3921538479 .comptime_field => true,
3921638480 .comptime_alloc => |alloc_index| !sema.getComptimeAlloc(alloc_index).is_const,
3921738481 .eu_payload, .opt_payload => |base| sema.isComptimeMutablePtr(Value.fromInterned(base)),
39218 .elem, .field => |bi| sema.isComptimeMutablePtr(Value.fromInterned(bi.base)),
38482 .arr_elem, .field => |bi| sema.isComptimeMutablePtr(Value.fromInterned(bi.base)),
3921938483 },
3922038484 else => false,
3922138485 };
......@@ -39321,3 +38585,11 @@ fn maybeDerefSliceAsArray(
3932138585 const casted_ptr = try zcu.getCoerced(Value.fromInterned(slice.ptr), ptr_ty);
3932238586 return sema.pointerDeref(block, src, casted_ptr, ptr_ty);
3932338587}
38588
38589pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;
38590pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;
38591
38592const loadComptimePtr = @import("Sema/comptime_ptr_access.zig").loadComptimePtr;
38593const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadResult;
38594const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr;
38595const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult;
src/Sema/bitcast.zig created+772
......@@ -0,0 +1,772 @@
1//! This file contains logic for bit-casting arbitrary values at comptime, including splicing
2//! bits together for comptime stores of bit-pointers. The strategy is to "flatten" values to
3//! a sequence of values in *packed* memory, and then unflatten through a combination of special
4//! cases (particularly for pointers and `undefined` values) and in-memory buffer reinterprets.
5//!
6//! This is a little awkward on big-endian targets, as non-packed datastructures (e.g. `extern struct`)
7//! have their fields reversed when represented as packed memory on such targets.
8
9/// If `host_bits` is `0`, attempts to convert the memory at offset
10/// `byte_offset` into `val` to a non-packed value of type `dest_ty`,
11/// ignoring `bit_offset`.
12///
13/// Otherwise, `byte_offset` is an offset in bytes into `val` to a
14/// non-packed value consisting of `host_bits` bits. A value of type
15/// `dest_ty` will be interpreted at a packed offset of `bit_offset`
16/// into this value.
17///
18/// Returns `null` if the operation must be performed at runtime.
19pub fn bitCast(
20 sema: *Sema,
21 val: Value,
22 dest_ty: Type,
23 byte_offset: u64,
24 host_bits: u64,
25 bit_offset: u64,
26) CompileError!?Value {
27 return bitCastInner(sema, val, dest_ty, byte_offset, host_bits, bit_offset) catch |err| switch (err) {
28 error.ReinterpretDeclRef => return null,
29 error.IllDefinedMemoryLayout => unreachable,
30 error.Unimplemented => @panic("unimplemented bitcast"),
31 else => |e| return e,
32 };
33}
34
35/// Uses bitcasting to splice the value `splice_val` into `val`,
36/// replacing overlapping bits and returning the modified value.
37///
38/// If `host_bits` is `0`, splices `splice_val` at an offset
39/// `byte_offset` bytes into the virtual memory of `val`, ignoring
40/// `bit_offset`.
41///
42/// Otherwise, `byte_offset` is an offset into bytes into `val` to
43/// a non-packed value consisting of `host_bits` bits. The value
44/// `splice_val` will be placed at a packed offset of `bit_offset`
45/// into this value.
46pub fn bitCastSplice(
47 sema: *Sema,
48 val: Value,
49 splice_val: Value,
50 byte_offset: u64,
51 host_bits: u64,
52 bit_offset: u64,
53) CompileError!?Value {
54 return bitCastSpliceInner(sema, val, splice_val, byte_offset, host_bits, bit_offset) catch |err| switch (err) {
55 error.ReinterpretDeclRef => return null,
56 error.IllDefinedMemoryLayout => unreachable,
57 error.Unimplemented => @panic("unimplemented bitcast"),
58 else => |e| return e,
59 };
60}
61
62const BitCastError = CompileError || error{ ReinterpretDeclRef, IllDefinedMemoryLayout, Unimplemented };
63
64fn bitCastInner(
65 sema: *Sema,
66 val: Value,
67 dest_ty: Type,
68 byte_offset: u64,
69 host_bits: u64,
70 bit_offset: u64,
71) BitCastError!Value {
72 const zcu = sema.mod;
73 const endian = zcu.getTarget().cpu.arch.endian();
74
75 if (dest_ty.toIntern() == val.typeOf(zcu).toIntern() and bit_offset == 0) {
76 return val;
77 }
78
79 const val_ty = val.typeOf(zcu);
80
81 try sema.resolveTypeLayout(val_ty);
82 try sema.resolveTypeLayout(dest_ty);
83
84 assert(val_ty.hasWellDefinedLayout(zcu));
85
86 const abi_pad_bits, const host_pad_bits = if (host_bits > 0)
87 .{ val_ty.abiSize(zcu) * 8 - host_bits, host_bits - val_ty.bitSize(zcu) }
88 else
89 .{ val_ty.abiSize(zcu) * 8 - val_ty.bitSize(zcu), 0 };
90
91 const skip_bits = switch (endian) {
92 .little => bit_offset + byte_offset * 8,
93 .big => if (host_bits > 0)
94 val_ty.abiSize(zcu) * 8 - byte_offset * 8 - host_bits + bit_offset
95 else
96 val_ty.abiSize(zcu) * 8 - byte_offset * 8 - dest_ty.bitSize(zcu),
97 };
98
99 var unpack: UnpackValueBits = .{
100 .zcu = zcu,
101 .arena = sema.arena,
102 .skip_bits = skip_bits,
103 .remaining_bits = dest_ty.bitSize(zcu),
104 .unpacked = std.ArrayList(InternPool.Index).init(sema.arena),
105 };
106 switch (endian) {
107 .little => {
108 try unpack.add(val);
109 try unpack.padding(abi_pad_bits);
110 },
111 .big => {
112 try unpack.padding(abi_pad_bits);
113 try unpack.add(val);
114 },
115 }
116 try unpack.padding(host_pad_bits);
117
118 var pack: PackValueBits = .{
119 .zcu = zcu,
120 .arena = sema.arena,
121 .unpacked = unpack.unpacked.items,
122 };
123 return pack.get(dest_ty);
124}
125
126fn bitCastSpliceInner(
127 sema: *Sema,
128 val: Value,
129 splice_val: Value,
130 byte_offset: u64,
131 host_bits: u64,
132 bit_offset: u64,
133) BitCastError!Value {
134 const zcu = sema.mod;
135 const endian = zcu.getTarget().cpu.arch.endian();
136 const val_ty = val.typeOf(zcu);
137 const splice_val_ty = splice_val.typeOf(zcu);
138
139 try sema.resolveTypeLayout(val_ty);
140 try sema.resolveTypeLayout(splice_val_ty);
141
142 const splice_bits = splice_val_ty.bitSize(zcu);
143
144 const splice_offset = switch (endian) {
145 .little => bit_offset + byte_offset * 8,
146 .big => if (host_bits > 0)
147 val_ty.abiSize(zcu) * 8 - byte_offset * 8 - host_bits + bit_offset
148 else
149 val_ty.abiSize(zcu) * 8 - byte_offset * 8 - splice_bits,
150 };
151
152 assert(splice_offset + splice_bits <= val_ty.abiSize(zcu) * 8);
153
154 const abi_pad_bits, const host_pad_bits = if (host_bits > 0)
155 .{ val_ty.abiSize(zcu) * 8 - host_bits, host_bits - val_ty.bitSize(zcu) }
156 else
157 .{ val_ty.abiSize(zcu) * 8 - val_ty.bitSize(zcu), 0 };
158
159 var unpack: UnpackValueBits = .{
160 .zcu = zcu,
161 .arena = sema.arena,
162 .skip_bits = 0,
163 .remaining_bits = splice_offset,
164 .unpacked = std.ArrayList(InternPool.Index).init(sema.arena),
165 };
166 switch (endian) {
167 .little => {
168 try unpack.add(val);
169 try unpack.padding(abi_pad_bits);
170 },
171 .big => {
172 try unpack.padding(abi_pad_bits);
173 try unpack.add(val);
174 },
175 }
176 try unpack.padding(host_pad_bits);
177
178 unpack.remaining_bits = splice_bits;
179 try unpack.add(splice_val);
180
181 unpack.skip_bits = splice_offset + splice_bits;
182 unpack.remaining_bits = val_ty.abiSize(zcu) * 8 - splice_offset - splice_bits;
183 switch (endian) {
184 .little => {
185 try unpack.add(val);
186 try unpack.padding(abi_pad_bits);
187 },
188 .big => {
189 try unpack.padding(abi_pad_bits);
190 try unpack.add(val);
191 },
192 }
193 try unpack.padding(host_pad_bits);
194
195 var pack: PackValueBits = .{
196 .zcu = zcu,
197 .arena = sema.arena,
198 .unpacked = unpack.unpacked.items,
199 };
200 switch (endian) {
201 .little => {},
202 .big => try pack.padding(abi_pad_bits),
203 }
204 return pack.get(val_ty);
205}
206
207/// Recurses through struct fields, array elements, etc, to get a sequence of "primitive" values
208/// which are bit-packed in memory to represent a single value. `unpacked` represents a series
209/// of values in *packed* memory - therefore, on big-endian targets, the first element of this
210/// list contains bits from the *final* byte of the value.
211const UnpackValueBits = struct {
212 zcu: *Zcu,
213 arena: Allocator,
214 skip_bits: u64,
215 remaining_bits: u64,
216 extra_bits: u64 = undefined,
217 unpacked: std.ArrayList(InternPool.Index),
218
219 fn add(unpack: *UnpackValueBits, val: Value) BitCastError!void {
220 const zcu = unpack.zcu;
221 const endian = zcu.getTarget().cpu.arch.endian();
222 const ip = &zcu.intern_pool;
223
224 if (unpack.remaining_bits == 0) {
225 return;
226 }
227
228 const ty = val.typeOf(zcu);
229 const bit_size = ty.bitSize(zcu);
230
231 if (unpack.skip_bits >= bit_size) {
232 unpack.skip_bits -= bit_size;
233 return;
234 }
235
236 switch (ip.indexToKey(val.toIntern())) {
237 .int_type,
238 .ptr_type,
239 .array_type,
240 .vector_type,
241 .opt_type,
242 .anyframe_type,
243 .error_union_type,
244 .simple_type,
245 .struct_type,
246 .anon_struct_type,
247 .union_type,
248 .opaque_type,
249 .enum_type,
250 .func_type,
251 .error_set_type,
252 .inferred_error_set_type,
253 .variable,
254 .extern_func,
255 .func,
256 .err,
257 .error_union,
258 .enum_literal,
259 .slice,
260 .memoized_call,
261 => unreachable, // ill-defined layout or not real values
262
263 .undef,
264 .int,
265 .enum_tag,
266 .simple_value,
267 .empty_enum_value,
268 .float,
269 .ptr,
270 .opt,
271 => try unpack.primitive(val),
272
273 .aggregate => switch (ty.zigTypeTag(zcu)) {
274 .Vector => {
275 const len: usize = @intCast(ty.arrayLen(zcu));
276 for (0..len) |i| {
277 // We reverse vector elements in packed memory on BE targets.
278 const real_idx = switch (endian) {
279 .little => i,
280 .big => len - i - 1,
281 };
282 const elem_val = try val.elemValue(zcu, real_idx);
283 try unpack.add(elem_val);
284 }
285 },
286 .Array => {
287 // Each element is padded up to its ABI size. Padding bits are undefined.
288 // The final element does not have trailing padding.
289 // Elements are reversed in packed memory on BE targets.
290 const elem_ty = ty.childType(zcu);
291 const pad_bits = elem_ty.abiSize(zcu) * 8 - elem_ty.bitSize(zcu);
292 const len = ty.arrayLen(zcu);
293 const maybe_sent = ty.sentinel(zcu);
294
295 if (endian == .big) if (maybe_sent) |s| {
296 try unpack.add(s);
297 if (len != 0) try unpack.padding(pad_bits);
298 };
299
300 for (0..@intCast(len)) |i| {
301 // We reverse array elements in packed memory on BE targets.
302 const real_idx = switch (endian) {
303 .little => i,
304 .big => len - i - 1,
305 };
306 const elem_val = try val.elemValue(zcu, @intCast(real_idx));
307 try unpack.add(elem_val);
308 if (i != len - 1) try unpack.padding(pad_bits);
309 }
310
311 if (endian == .little) if (maybe_sent) |s| {
312 if (len != 0) try unpack.padding(pad_bits);
313 try unpack.add(s);
314 };
315 },
316 .Struct => switch (ty.containerLayout(zcu)) {
317 .auto => unreachable, // ill-defined layout
318 .@"extern" => switch (endian) {
319 .little => {
320 var cur_bit_off: u64 = 0;
321 var it = zcu.typeToStruct(ty).?.iterateRuntimeOrder(ip);
322 while (it.next()) |field_idx| {
323 const want_bit_off = ty.structFieldOffset(field_idx, zcu) * 8;
324 const pad_bits = want_bit_off - cur_bit_off;
325 const field_val = try val.fieldValue(zcu, field_idx);
326 try unpack.padding(pad_bits);
327 try unpack.add(field_val);
328 cur_bit_off = want_bit_off + field_val.typeOf(zcu).bitSize(zcu);
329 }
330 // Add trailing padding bits.
331 try unpack.padding(bit_size - cur_bit_off);
332 },
333 .big => {
334 var cur_bit_off: u64 = bit_size;
335 var it = zcu.typeToStruct(ty).?.iterateRuntimeOrderReverse(ip);
336 while (it.next()) |field_idx| {
337 const field_val = try val.fieldValue(zcu, field_idx);
338 const field_ty = field_val.typeOf(zcu);
339 const want_bit_off = ty.structFieldOffset(field_idx, zcu) * 8 + field_ty.bitSize(zcu);
340 const pad_bits = cur_bit_off - want_bit_off;
341 try unpack.padding(pad_bits);
342 try unpack.add(field_val);
343 cur_bit_off = want_bit_off - field_ty.bitSize(zcu);
344 }
345 assert(cur_bit_off == 0);
346 },
347 },
348 .@"packed" => {
349 // Just add all fields in order. There are no padding bits.
350 // This is identical between LE and BE targets.
351 for (0..ty.structFieldCount(zcu)) |i| {
352 const field_val = try val.fieldValue(zcu, i);
353 try unpack.add(field_val);
354 }
355 },
356 },
357 else => unreachable,
358 },
359
360 .un => |un| {
361 // We actually don't care about the tag here!
362 // Instead, we just need to write the payload value, plus any necessary padding.
363 // This correctly handles the case where `tag == .none`, since the payload is then
364 // either an integer or a byte array, both of which we can unpack.
365 const payload_val = Value.fromInterned(un.val);
366 const pad_bits = bit_size - payload_val.typeOf(zcu).bitSize(zcu);
367 if (endian == .little or ty.containerLayout(zcu) == .@"packed") {
368 try unpack.add(payload_val);
369 try unpack.padding(pad_bits);
370 } else {
371 try unpack.padding(pad_bits);
372 try unpack.add(payload_val);
373 }
374 },
375 }
376 }
377
378 fn padding(unpack: *UnpackValueBits, pad_bits: u64) BitCastError!void {
379 if (pad_bits == 0) return;
380 const zcu = unpack.zcu;
381 // Figure out how many full bytes and leftover bits there are.
382 const bytes = pad_bits / 8;
383 const bits = pad_bits % 8;
384 // Add undef u8 values for the bytes...
385 const undef_u8 = try zcu.undefValue(Type.u8);
386 for (0..@intCast(bytes)) |_| {
387 try unpack.primitive(undef_u8);
388 }
389 // ...and an undef int for the leftover bits.
390 if (bits == 0) return;
391 const bits_ty = try zcu.intType(.unsigned, @intCast(bits));
392 const bits_val = try zcu.undefValue(bits_ty);
393 try unpack.primitive(bits_val);
394 }
395
396 fn primitive(unpack: *UnpackValueBits, val: Value) BitCastError!void {
397 const zcu = unpack.zcu;
398
399 if (unpack.remaining_bits == 0) {
400 return;
401 }
402
403 const ty = val.typeOf(zcu);
404 const bit_size = ty.bitSize(zcu);
405
406 // Note that this skips all zero-bit types.
407 if (unpack.skip_bits >= bit_size) {
408 unpack.skip_bits -= bit_size;
409 return;
410 }
411
412 if (unpack.skip_bits > 0) {
413 const skip = unpack.skip_bits;
414 unpack.skip_bits = 0;
415 return unpack.splitPrimitive(val, skip, bit_size - skip);
416 }
417
418 if (unpack.remaining_bits < bit_size) {
419 return unpack.splitPrimitive(val, 0, unpack.remaining_bits);
420 }
421
422 unpack.remaining_bits -|= bit_size;
423
424 try unpack.unpacked.append(val.toIntern());
425 }
426
427 fn splitPrimitive(unpack: *UnpackValueBits, val: Value, bit_offset: u64, bit_count: u64) BitCastError!void {
428 const zcu = unpack.zcu;
429 const ty = val.typeOf(zcu);
430
431 const val_bits = ty.bitSize(zcu);
432 assert(bit_offset + bit_count <= val_bits);
433
434 switch (zcu.intern_pool.indexToKey(val.toIntern())) {
435 // In the `ptr` case, this will return `error.ReinterpretDeclRef`
436 // if we're trying to split a non-integer pointer value.
437 .int, .float, .enum_tag, .ptr, .opt => {
438 // This @intCast is okay because no primitive can exceed the size of a u16.
439 const int_ty = try zcu.intType(.unsigned, @intCast(bit_count));
440 const buf = try unpack.arena.alloc(u8, @intCast((val_bits + 7) / 8));
441 try val.writeToPackedMemory(ty, zcu, buf, 0);
442 const sub_val = try Value.readFromPackedMemory(int_ty, zcu, buf, @intCast(bit_offset), unpack.arena);
443 try unpack.primitive(sub_val);
444 },
445 .undef => try unpack.padding(bit_count),
446 // The only values here with runtime bits are `true` and `false.
447 // These are both 1 bit, so will never need truncating.
448 .simple_value => unreachable,
449 .empty_enum_value => unreachable, // zero-bit
450 else => unreachable, // zero-bit or not primitives
451 }
452 }
453};
454
455/// Given a sequence of bit-packed values in packed memory (see `UnpackValueBits`),
456/// reconstructs a value of an arbitrary type, with correct handling of `undefined`
457/// values and of pointers which align in virtual memory.
458const PackValueBits = struct {
459 zcu: *Zcu,
460 arena: Allocator,
461 bit_offset: u64 = 0,
462 unpacked: []const InternPool.Index,
463
464 fn get(pack: *PackValueBits, ty: Type) BitCastError!Value {
465 const zcu = pack.zcu;
466 const endian = zcu.getTarget().cpu.arch.endian();
467 const ip = &zcu.intern_pool;
468 const arena = pack.arena;
469 switch (ty.zigTypeTag(zcu)) {
470 .Vector => {
471 // Elements are bit-packed.
472 const len = ty.arrayLen(zcu);
473 const elem_ty = ty.childType(zcu);
474 const elems = try arena.alloc(InternPool.Index, @intCast(len));
475 // We reverse vector elements in packed memory on BE targets.
476 switch (endian) {
477 .little => for (elems) |*elem| {
478 elem.* = (try pack.get(elem_ty)).toIntern();
479 },
480 .big => {
481 var i = elems.len;
482 while (i > 0) {
483 i -= 1;
484 elems[i] = (try pack.get(elem_ty)).toIntern();
485 }
486 },
487 }
488 return Value.fromInterned(try zcu.intern(.{ .aggregate = .{
489 .ty = ty.toIntern(),
490 .storage = .{ .elems = elems },
491 } }));
492 },
493 .Array => {
494 // Each element is padded up to its ABI size. The final element does not have trailing padding.
495 const len = ty.arrayLen(zcu);
496 const elem_ty = ty.childType(zcu);
497 const maybe_sent = ty.sentinel(zcu);
498 const pad_bits = elem_ty.abiSize(zcu) * 8 - elem_ty.bitSize(zcu);
499 const elems = try arena.alloc(InternPool.Index, @intCast(len));
500
501 if (endian == .big and maybe_sent != null) {
502 // TODO: validate sentinel was preserved!
503 try pack.padding(elem_ty.bitSize(zcu));
504 if (len != 0) try pack.padding(pad_bits);
505 }
506
507 for (0..elems.len) |i| {
508 const real_idx = switch (endian) {
509 .little => i,
510 .big => len - i - 1,
511 };
512 elems[@intCast(real_idx)] = (try pack.get(elem_ty)).toIntern();
513 if (i != len - 1) try pack.padding(pad_bits);
514 }
515
516 if (endian == .little and maybe_sent != null) {
517 // TODO: validate sentinel was preserved!
518 if (len != 0) try pack.padding(pad_bits);
519 try pack.padding(elem_ty.bitSize(zcu));
520 }
521
522 return Value.fromInterned(try zcu.intern(.{ .aggregate = .{
523 .ty = ty.toIntern(),
524 .storage = .{ .elems = elems },
525 } }));
526 },
527 .Struct => switch (ty.containerLayout(zcu)) {
528 .auto => unreachable, // ill-defined layout
529 .@"extern" => {
530 const elems = try arena.alloc(InternPool.Index, ty.structFieldCount(zcu));
531 @memset(elems, .none);
532 switch (endian) {
533 .little => {
534 var cur_bit_off: u64 = 0;
535 var it = zcu.typeToStruct(ty).?.iterateRuntimeOrder(ip);
536 while (it.next()) |field_idx| {
537 const want_bit_off = ty.structFieldOffset(field_idx, zcu) * 8;
538 try pack.padding(want_bit_off - cur_bit_off);
539 const field_ty = ty.structFieldType(field_idx, zcu);
540 elems[field_idx] = (try pack.get(field_ty)).toIntern();
541 cur_bit_off = want_bit_off + field_ty.bitSize(zcu);
542 }
543 try pack.padding(ty.bitSize(zcu) - cur_bit_off);
544 },
545 .big => {
546 var cur_bit_off: u64 = ty.bitSize(zcu);
547 var it = zcu.typeToStruct(ty).?.iterateRuntimeOrderReverse(ip);
548 while (it.next()) |field_idx| {
549 const field_ty = ty.structFieldType(field_idx, zcu);
550 const want_bit_off = ty.structFieldOffset(field_idx, zcu) * 8 + field_ty.bitSize(zcu);
551 try pack.padding(cur_bit_off - want_bit_off);
552 elems[field_idx] = (try pack.get(field_ty)).toIntern();
553 cur_bit_off = want_bit_off - field_ty.bitSize(zcu);
554 }
555 assert(cur_bit_off == 0);
556 },
557 }
558 // Any fields which do not have runtime bits should be OPV or comptime fields.
559 // Fill those values now.
560 for (elems, 0..) |*elem, field_idx| {
561 if (elem.* != .none) continue;
562 const val = (try ty.structFieldValueComptime(zcu, field_idx)).?;
563 elem.* = val.toIntern();
564 }
565 return Value.fromInterned(try zcu.intern(.{ .aggregate = .{
566 .ty = ty.toIntern(),
567 .storage = .{ .elems = elems },
568 } }));
569 },
570 .@"packed" => {
571 // All fields are in order with no padding.
572 // This is identical between LE and BE targets.
573 const elems = try arena.alloc(InternPool.Index, ty.structFieldCount(zcu));
574 for (elems, 0..) |*elem, i| {
575 const field_ty = ty.structFieldType(i, zcu);
576 elem.* = (try pack.get(field_ty)).toIntern();
577 }
578 return Value.fromInterned(try zcu.intern(.{ .aggregate = .{
579 .ty = ty.toIntern(),
580 .storage = .{ .elems = elems },
581 } }));
582 },
583 },
584 .Union => {
585 // We will attempt to read as the backing representation. If this emits
586 // `error.ReinterpretDeclRef`, we will try each union field, preferring larger ones.
587 // We will also attempt smaller fields when we get `undefined`, as if some bits are
588 // defined we want to include them.
589 // TODO: this is very very bad. We need a more sophisticated union representation.
590
591 const prev_unpacked = pack.unpacked;
592 const prev_bit_offset = pack.bit_offset;
593
594 const backing_ty = try ty.unionBackingType(zcu);
595
596 backing: {
597 const backing_val = pack.get(backing_ty) catch |err| switch (err) {
598 error.ReinterpretDeclRef => {
599 pack.unpacked = prev_unpacked;
600 pack.bit_offset = prev_bit_offset;
601 break :backing;
602 },
603 else => |e| return e,
604 };
605 if (backing_val.isUndef(zcu)) {
606 pack.unpacked = prev_unpacked;
607 pack.bit_offset = prev_bit_offset;
608 break :backing;
609 }
610 return Value.fromInterned(try zcu.intern(.{ .un = .{
611 .ty = ty.toIntern(),
612 .tag = .none,
613 .val = backing_val.toIntern(),
614 } }));
615 }
616
617 const field_order = try pack.arena.alloc(u32, ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu));
618 for (field_order, 0..) |*f, i| f.* = @intCast(i);
619 // Sort `field_order` to put the fields with the largest bit sizes first.
620 const SizeSortCtx = struct {
621 zcu: *Zcu,
622 field_types: []const InternPool.Index,
623 fn lessThan(ctx: @This(), a_idx: u32, b_idx: u32) bool {
624 const a_ty = Type.fromInterned(ctx.field_types[a_idx]);
625 const b_ty = Type.fromInterned(ctx.field_types[b_idx]);
626 return a_ty.bitSize(ctx.zcu) > b_ty.bitSize(ctx.zcu);
627 }
628 };
629 std.mem.sortUnstable(u32, field_order, SizeSortCtx{
630 .zcu = zcu,
631 .field_types = zcu.typeToUnion(ty).?.field_types.get(ip),
632 }, SizeSortCtx.lessThan);
633
634 const padding_after = endian == .little or ty.containerLayout(zcu) == .@"packed";
635
636 for (field_order) |field_idx| {
637 const field_ty = Type.fromInterned(zcu.typeToUnion(ty).?.field_types.get(ip)[field_idx]);
638 const pad_bits = ty.bitSize(zcu) - field_ty.bitSize(zcu);
639 if (!padding_after) try pack.padding(pad_bits);
640 const field_val = pack.get(field_ty) catch |err| switch (err) {
641 error.ReinterpretDeclRef => {
642 pack.unpacked = prev_unpacked;
643 pack.bit_offset = prev_bit_offset;
644 continue;
645 },
646 else => |e| return e,
647 };
648 if (padding_after) try pack.padding(pad_bits);
649 if (field_val.isUndef(zcu)) {
650 pack.unpacked = prev_unpacked;
651 pack.bit_offset = prev_bit_offset;
652 continue;
653 }
654 const tag_val = try zcu.enumValueFieldIndex(ty.unionTagTypeHypothetical(zcu), field_idx);
655 return Value.fromInterned(try zcu.intern(.{ .un = .{
656 .ty = ty.toIntern(),
657 .tag = tag_val.toIntern(),
658 .val = field_val.toIntern(),
659 } }));
660 }
661
662 // No field could represent the value. Just do whatever happens when we try to read
663 // the backing type - either `undefined` or `error.ReinterpretDeclRef`.
664 const backing_val = try pack.get(backing_ty);
665 return Value.fromInterned(try zcu.intern(.{ .un = .{
666 .ty = ty.toIntern(),
667 .tag = .none,
668 .val = backing_val.toIntern(),
669 } }));
670 },
671 else => return pack.primitive(ty),
672 }
673 }
674
675 fn padding(pack: *PackValueBits, pad_bits: u64) BitCastError!void {
676 _ = pack.prepareBits(pad_bits);
677 }
678
679 fn primitive(pack: *PackValueBits, want_ty: Type) BitCastError!Value {
680 const zcu = pack.zcu;
681 const vals, const bit_offset = pack.prepareBits(want_ty.bitSize(zcu));
682
683 for (vals) |val| {
684 if (!Value.fromInterned(val).isUndef(zcu)) break;
685 } else {
686 // All bits of the value are `undefined`.
687 return zcu.undefValue(want_ty);
688 }
689
690 // TODO: we need to decide how to handle partially-undef values here.
691 // Currently, a value with some undefined bits becomes `0xAA` so that we
692 // preserve the well-defined bits, because we can't currently represent
693 // a partially-undefined primitive (e.g. an int with some undef bits).
694 // In future, we probably want to take one of these two routes:
695 // * Define that if any bits are `undefined`, the entire value is `undefined`.
696 // This is a major breaking change, and probably a footgun.
697 // * Introduce tracking for partially-undef values at comptime.
698 // This would complicate a lot of operations in Sema, such as basic
699 // arithmetic.
700 // This design complexity is tracked by #19634.
701
702 ptr_cast: {
703 if (vals.len != 1) break :ptr_cast;
704 const val = Value.fromInterned(vals[0]);
705 if (!val.typeOf(zcu).isPtrAtRuntime(zcu)) break :ptr_cast;
706 if (!want_ty.isPtrAtRuntime(zcu)) break :ptr_cast;
707 return zcu.getCoerced(val, want_ty);
708 }
709
710 // Reinterpret via an in-memory buffer.
711
712 var buf_bits: u64 = 0;
713 for (vals) |ip_val| {
714 const val = Value.fromInterned(ip_val);
715 const ty = val.typeOf(zcu);
716 buf_bits += ty.bitSize(zcu);
717 }
718
719 const buf = try pack.arena.alloc(u8, @intCast((buf_bits + 7) / 8));
720 // We will skip writing undefined values, so mark the buffer as `0xAA` so we get "undefined" bits.
721 @memset(buf, 0xAA);
722 var cur_bit_off: usize = 0;
723 for (vals) |ip_val| {
724 const val = Value.fromInterned(ip_val);
725 const ty = val.typeOf(zcu);
726 if (!val.isUndef(zcu)) {
727 try val.writeToPackedMemory(ty, zcu, buf, cur_bit_off);
728 }
729 cur_bit_off += @intCast(ty.bitSize(zcu));
730 }
731
732 return Value.readFromPackedMemory(want_ty, zcu, buf, @intCast(bit_offset), pack.arena);
733 }
734
735 fn prepareBits(pack: *PackValueBits, need_bits: u64) struct { []const InternPool.Index, u64 } {
736 if (need_bits == 0) return .{ &.{}, 0 };
737
738 const zcu = pack.zcu;
739
740 var bits: u64 = 0;
741 var len: usize = 0;
742 while (bits < pack.bit_offset + need_bits) {
743 bits += Value.fromInterned(pack.unpacked[len]).typeOf(zcu).bitSize(zcu);
744 len += 1;
745 }
746
747 const result_vals = pack.unpacked[0..len];
748 const result_offset = pack.bit_offset;
749
750 const extra_bits = bits - pack.bit_offset - need_bits;
751 if (extra_bits == 0) {
752 pack.unpacked = pack.unpacked[len..];
753 pack.bit_offset = 0;
754 } else {
755 pack.unpacked = pack.unpacked[len - 1 ..];
756 pack.bit_offset = Value.fromInterned(pack.unpacked[0]).typeOf(zcu).bitSize(zcu) - extra_bits;
757 }
758
759 return .{ result_vals, result_offset };
760 }
761};
762
763const std = @import("std");
764const Allocator = std.mem.Allocator;
765const assert = std.debug.assert;
766
767const Sema = @import("../Sema.zig");
768const Zcu = @import("../Module.zig");
769const InternPool = @import("../InternPool.zig");
770const Type = @import("../type.zig").Type;
771const Value = @import("../Value.zig");
772const CompileError = Zcu.CompileError;
src/Sema/comptime_ptr_access.zig created+1059
......@@ -0,0 +1,1059 @@
1pub const ComptimeLoadResult = union(enum) {
2 success: MutableValue,
3
4 runtime_load,
5 undef,
6 err_payload: InternPool.NullTerminatedString,
7 null_payload,
8 inactive_union_field,
9 needed_well_defined: Type,
10 out_of_bounds: Type,
11 exceeds_host_size,
12};
13
14pub fn loadComptimePtr(sema: *Sema, block: *Block, src: LazySrcLoc, ptr: Value) !ComptimeLoadResult {
15 const zcu = sema.mod;
16 const ptr_info = ptr.typeOf(zcu).ptrInfo(zcu);
17 // TODO: host size for vectors is terrible
18 const host_bits = switch (ptr_info.flags.vector_index) {
19 .none => ptr_info.packed_offset.host_size * 8,
20 else => ptr_info.packed_offset.host_size * Type.fromInterned(ptr_info.child).bitSize(zcu),
21 };
22 const bit_offset = if (host_bits != 0) bit_offset: {
23 const child_bits = Type.fromInterned(ptr_info.child).bitSize(zcu);
24 const bit_offset = ptr_info.packed_offset.bit_offset + switch (ptr_info.flags.vector_index) {
25 .none => 0,
26 .runtime => return .runtime_load,
27 else => |idx| switch (zcu.getTarget().cpu.arch.endian()) {
28 .little => child_bits * @intFromEnum(idx),
29 .big => host_bits - child_bits * (@intFromEnum(idx) + 1), // element order reversed on big endian
30 },
31 };
32 if (child_bits + bit_offset > host_bits) {
33 return .exceeds_host_size;
34 }
35 break :bit_offset bit_offset;
36 } else 0;
37 return loadComptimePtrInner(sema, block, src, ptr, bit_offset, host_bits, Type.fromInterned(ptr_info.child), 0);
38}
39
40pub const ComptimeStoreResult = union(enum) {
41 success,
42
43 runtime_store,
44 comptime_field_mismatch: Value,
45 undef,
46 err_payload: InternPool.NullTerminatedString,
47 null_payload,
48 inactive_union_field,
49 needed_well_defined: Type,
50 out_of_bounds: Type,
51 exceeds_host_size,
52};
53
54/// Perform a comptime load of value `store_val` to a pointer.
55/// The pointer's type is ignored.
56pub fn storeComptimePtr(
57 sema: *Sema,
58 block: *Block,
59 src: LazySrcLoc,
60 ptr: Value,
61 store_val: Value,
62) !ComptimeStoreResult {
63 const zcu = sema.mod;
64 const ptr_info = ptr.typeOf(zcu).ptrInfo(zcu);
65 assert(store_val.typeOf(zcu).toIntern() == ptr_info.child);
66 // TODO: host size for vectors is terrible
67 const host_bits = switch (ptr_info.flags.vector_index) {
68 .none => ptr_info.packed_offset.host_size * 8,
69 else => ptr_info.packed_offset.host_size * Type.fromInterned(ptr_info.child).bitSize(zcu),
70 };
71 const bit_offset = ptr_info.packed_offset.bit_offset + switch (ptr_info.flags.vector_index) {
72 .none => 0,
73 .runtime => return .runtime_store,
74 else => |idx| switch (zcu.getTarget().cpu.arch.endian()) {
75 .little => Type.fromInterned(ptr_info.child).bitSize(zcu) * @intFromEnum(idx),
76 .big => host_bits - Type.fromInterned(ptr_info.child).bitSize(zcu) * (@intFromEnum(idx) + 1), // element order reversed on big endian
77 },
78 };
79 const pseudo_store_ty = if (host_bits > 0) t: {
80 const need_bits = Type.fromInterned(ptr_info.child).bitSize(zcu);
81 if (need_bits + bit_offset > host_bits) {
82 return .exceeds_host_size;
83 }
84 break :t try zcu.intType(.unsigned, @intCast(host_bits));
85 } else Type.fromInterned(ptr_info.child);
86
87 const strat = try prepareComptimePtrStore(sema, block, src, ptr, pseudo_store_ty, 0);
88
89 // Propagate errors and handle comptime fields.
90 switch (strat) {
91 .direct, .index, .flat_index, .reinterpret => {},
92 .comptime_field => {
93 // To "store" to a comptime field, just perform a load of the field
94 // and see if the store value matches.
95 const expected_mv = switch (try loadComptimePtr(sema, block, src, ptr)) {
96 .success => |mv| mv,
97 .runtime_load => unreachable, // this is a comptime field
98 .exceeds_host_size => unreachable, // checked above
99 .undef => return .undef,
100 .err_payload => |err| return .{ .err_payload = err },
101 .null_payload => return .null_payload,
102 .inactive_union_field => return .inactive_union_field,
103 .needed_well_defined => |ty| return .{ .needed_well_defined = ty },
104 .out_of_bounds => |ty| return .{ .out_of_bounds = ty },
105 };
106 const expected = try expected_mv.intern(zcu, sema.arena);
107 if (store_val.toIntern() != expected.toIntern()) {
108 return .{ .comptime_field_mismatch = expected };
109 }
110 return .success;
111 },
112 .runtime_store => return .runtime_store,
113 .undef => return .undef,
114 .err_payload => |err| return .{ .err_payload = err },
115 .null_payload => return .null_payload,
116 .inactive_union_field => return .inactive_union_field,
117 .needed_well_defined => |ty| return .{ .needed_well_defined = ty },
118 .out_of_bounds => |ty| return .{ .out_of_bounds = ty },
119 }
120
121 // Check the store is not inside a runtime condition
122 try checkComptimeVarStore(sema, block, src, strat.alloc());
123
124 if (host_bits == 0) {
125 // We can attempt a direct store depending on the strategy.
126 switch (strat) {
127 .direct => |direct| {
128 const want_ty = direct.val.typeOf(zcu);
129 const coerced_store_val = try zcu.getCoerced(store_val, want_ty);
130 direct.val.* = .{ .interned = coerced_store_val.toIntern() };
131 return .success;
132 },
133 .index => |index| {
134 const want_ty = index.val.typeOf(zcu).childType(zcu);
135 const coerced_store_val = try zcu.getCoerced(store_val, want_ty);
136 try index.val.setElem(zcu, sema.arena, @intCast(index.elem_index), .{ .interned = coerced_store_val.toIntern() });
137 return .success;
138 },
139 .flat_index => |flat| {
140 const store_elems = store_val.typeOf(zcu).arrayBase(zcu)[1];
141 const flat_elems = try sema.arena.alloc(InternPool.Index, @intCast(store_elems));
142 {
143 var next_idx: u64 = 0;
144 var skip: u64 = 0;
145 try flattenArray(sema, .{ .interned = store_val.toIntern() }, &skip, &next_idx, flat_elems);
146 }
147 for (flat_elems, 0..) |elem, idx| {
148 // TODO: recursiveIndex in a loop does a lot of redundant work!
149 // Better would be to gather all the store targets into an array.
150 var index: u64 = flat.flat_elem_index + idx;
151 const val_ptr, const final_idx = (try recursiveIndex(sema, flat.val, &index)).?;
152 try val_ptr.setElem(zcu, sema.arena, @intCast(final_idx), .{ .interned = elem });
153 }
154 return .success;
155 },
156 .reinterpret => {},
157 else => unreachable,
158 }
159 }
160
161 // Either there is a bit offset, or the strategy required reinterpreting.
162 // Therefore, we must perform a bitcast.
163
164 const val_ptr: *MutableValue, const byte_offset: u64 = switch (strat) {
165 .direct => |direct| .{ direct.val, 0 },
166 .index => |index| .{
167 index.val,
168 index.elem_index * index.val.typeOf(zcu).childType(zcu).abiSize(zcu),
169 },
170 .flat_index => |flat| .{ flat.val, flat.flat_elem_index * flat.val.typeOf(zcu).arrayBase(zcu)[0].abiSize(zcu) },
171 .reinterpret => |reinterpret| .{ reinterpret.val, reinterpret.byte_offset },
172 else => unreachable,
173 };
174
175 if (!val_ptr.typeOf(zcu).hasWellDefinedLayout(zcu)) {
176 return .{ .needed_well_defined = val_ptr.typeOf(zcu) };
177 }
178
179 if (!store_val.typeOf(zcu).hasWellDefinedLayout(zcu)) {
180 return .{ .needed_well_defined = store_val.typeOf(zcu) };
181 }
182
183 const new_val = try sema.bitCastSpliceVal(
184 try val_ptr.intern(zcu, sema.arena),
185 store_val,
186 byte_offset,
187 host_bits,
188 bit_offset,
189 ) orelse return .runtime_store;
190 val_ptr.* = .{ .interned = new_val.toIntern() };
191 return .success;
192}
193
194/// Perform a comptime load of type `load_ty` from a pointer.
195/// The pointer's type is ignored.
196fn loadComptimePtrInner(
197 sema: *Sema,
198 block: *Block,
199 src: LazySrcLoc,
200 ptr_val: Value,
201 bit_offset: u64,
202 host_bits: u64,
203 load_ty: Type,
204 /// If `load_ty` is an array, this is the number of array elements to skip
205 /// before `load_ty`. Otherwise, it is ignored and may be `undefined`.
206 array_offset: u64,
207) !ComptimeLoadResult {
208 const zcu = sema.mod;
209 const ip = &zcu.intern_pool;
210
211 const ptr = switch (ip.indexToKey(ptr_val.toIntern())) {
212 .undef => return .undef,
213 .ptr => |ptr| ptr,
214 else => unreachable,
215 };
216
217 const base_val: MutableValue = switch (ptr.base_addr) {
218 .decl => |decl_index| val: {
219 try sema.declareDependency(.{ .decl_val = decl_index });
220 try sema.ensureDeclAnalyzed(decl_index);
221 const decl = zcu.declPtr(decl_index);
222 if (decl.val.getVariable(zcu) != null) return .runtime_load;
223 break :val .{ .interned = decl.val.toIntern() };
224 },
225 .comptime_alloc => |alloc_index| sema.getComptimeAlloc(alloc_index).val,
226 .anon_decl => |anon_decl| .{ .interned = anon_decl.val },
227 .comptime_field => |val| .{ .interned = val },
228 .int => return .runtime_load,
229 .eu_payload => |base_ptr_ip| val: {
230 const base_ptr = Value.fromInterned(base_ptr_ip);
231 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
232 switch (try loadComptimePtrInner(sema, block, src, base_ptr, 0, 0, base_ty, undefined)) {
233 .success => |eu_val| switch (eu_val.unpackErrorUnion(zcu)) {
234 .undef => return .undef,
235 .err => |err| return .{ .err_payload = err },
236 .payload => |payload| break :val payload,
237 },
238 else => |err| return err,
239 }
240 },
241 .opt_payload => |base_ptr_ip| val: {
242 const base_ptr = Value.fromInterned(base_ptr_ip);
243 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
244 switch (try loadComptimePtrInner(sema, block, src, base_ptr, 0, 0, base_ty, undefined)) {
245 .success => |eu_val| switch (eu_val.unpackOptional(zcu)) {
246 .undef => return .undef,
247 .null => return .null_payload,
248 .payload => |payload| break :val payload,
249 },
250 else => |err| return err,
251 }
252 },
253 .arr_elem => |base_index| val: {
254 const base_ptr = Value.fromInterned(base_index.base);
255 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
256
257 // We have a comptime-only array. This case is a little nasty.
258 // To avoid loading too much data, we want to figure out how many elements we need.
259 // If `load_ty` and the array share a base type, we'll load the correct number of elements.
260 // Otherwise, we'll be reinterpreting (which we can't do, since it's comptime-only); just
261 // load a single element and let the logic below emit its error.
262
263 const load_one_ty, const load_count = load_ty.arrayBase(zcu);
264 const count = if (load_one_ty.toIntern() == base_ty.toIntern()) load_count else 1;
265
266 const want_ty = try zcu.arrayType(.{
267 .len = count,
268 .child = base_ty.toIntern(),
269 });
270
271 switch (try loadComptimePtrInner(sema, block, src, base_ptr, 0, 0, want_ty, base_index.index)) {
272 .success => |arr_val| break :val arr_val,
273 else => |err| return err,
274 }
275 },
276 .field => |base_index| val: {
277 const base_ptr = Value.fromInterned(base_index.base);
278 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
279
280 // Field of a slice, or of an auto-layout struct or union.
281 const agg_val = switch (try loadComptimePtrInner(sema, block, src, base_ptr, 0, 0, base_ty, undefined)) {
282 .success => |val| val,
283 else => |err| return err,
284 };
285
286 const agg_ty = agg_val.typeOf(zcu);
287 switch (agg_ty.zigTypeTag(zcu)) {
288 .Struct, .Pointer => break :val try agg_val.getElem(zcu, @intCast(base_index.index)),
289 .Union => {
290 const tag_val: Value, const payload_mv: MutableValue = switch (agg_val) {
291 .un => |un| .{ Value.fromInterned(un.tag), un.payload.* },
292 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
293 .undef => return .undef,
294 .un => |un| .{ Value.fromInterned(un.tag), .{ .interned = un.val } },
295 else => unreachable,
296 },
297 else => unreachable,
298 };
299 const tag_ty = agg_ty.unionTagTypeHypothetical(zcu);
300 if (tag_ty.enumTagFieldIndex(tag_val, zcu).? != base_index.index) {
301 return .inactive_union_field;
302 }
303 break :val payload_mv;
304 },
305 else => unreachable,
306 }
307
308 break :val try agg_val.getElem(zcu, base_index.index);
309 },
310 };
311
312 if (ptr.byte_offset == 0 and host_bits == 0) {
313 if (load_ty.zigTypeTag(zcu) != .Array or array_offset == 0) {
314 if (.ok == try sema.coerceInMemoryAllowed(
315 block,
316 load_ty,
317 base_val.typeOf(zcu),
318 false,
319 zcu.getTarget(),
320 src,
321 src,
322 )) {
323 // We already have a value which is IMC to the desired type.
324 return .{ .success = base_val };
325 }
326 }
327 }
328
329 restructure_array: {
330 if (host_bits != 0) break :restructure_array;
331
332 // We might also be changing the length of an array, or restructuring it.
333 // e.g. [1][2][3]T -> [3][2]T.
334 // This case is important because it's permitted for types with ill-defined layouts.
335
336 const load_one_ty, const load_count = load_ty.arrayBase(zcu);
337
338 const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: {
339 if (try sema.typeRequiresComptime(load_one_ty)) break :restructure_array;
340 const elem_len = try sema.typeAbiSize(load_one_ty);
341 if (ptr.byte_offset % elem_len != 0) break :restructure_array;
342 break :idx @divExact(ptr.byte_offset, elem_len);
343 };
344
345 const val_one_ty, const val_count = base_val.typeOf(zcu).arrayBase(zcu);
346 if (.ok == try sema.coerceInMemoryAllowed(
347 block,
348 load_one_ty,
349 val_one_ty,
350 false,
351 zcu.getTarget(),
352 src,
353 src,
354 )) {
355 // Changing the length of an array.
356 const skip_base: u64 = extra_base_index + if (load_ty.zigTypeTag(zcu) == .Array) skip: {
357 break :skip load_ty.childType(zcu).arrayBase(zcu)[1] * array_offset;
358 } else 0;
359 if (skip_base + load_count > val_count) return .{ .out_of_bounds = base_val.typeOf(zcu) };
360 const elems = try sema.arena.alloc(InternPool.Index, @intCast(load_count));
361 var skip: u64 = skip_base;
362 var next_idx: u64 = 0;
363 try flattenArray(sema, base_val, &skip, &next_idx, elems);
364 next_idx = 0;
365 const val = try unflattenArray(sema, load_ty, elems, &next_idx);
366 return .{ .success = .{ .interned = val.toIntern() } };
367 }
368 }
369
370 // We need to reinterpret memory, which is only possible if neither the load
371 // type nor the type of the base value are comptime-only.
372
373 if (!load_ty.hasWellDefinedLayout(zcu)) {
374 return .{ .needed_well_defined = load_ty };
375 }
376
377 if (!base_val.typeOf(zcu).hasWellDefinedLayout(zcu)) {
378 return .{ .needed_well_defined = base_val.typeOf(zcu) };
379 }
380
381 var cur_val = base_val;
382 var cur_offset = ptr.byte_offset;
383
384 if (load_ty.zigTypeTag(zcu) == .Array and array_offset > 0) {
385 cur_offset += try sema.typeAbiSize(load_ty.childType(zcu)) * array_offset;
386 }
387
388 const need_bytes = if (host_bits > 0) (host_bits + 7) / 8 else try sema.typeAbiSize(load_ty);
389
390 if (cur_offset + need_bytes > try sema.typeAbiSize(cur_val.typeOf(zcu))) {
391 return .{ .out_of_bounds = cur_val.typeOf(zcu) };
392 }
393
394 // In the worst case, we can reinterpret the entire value - however, that's
395 // pretty wasteful. If the memory region we're interested in refers to one
396 // field or array element, let's just look at that.
397 while (true) {
398 const cur_ty = cur_val.typeOf(zcu);
399 switch (cur_ty.zigTypeTag(zcu)) {
400 .NoReturn,
401 .Type,
402 .ComptimeInt,
403 .ComptimeFloat,
404 .Null,
405 .Undefined,
406 .EnumLiteral,
407 .Opaque,
408 .Fn,
409 .ErrorUnion,
410 => unreachable, // ill-defined layout
411 .Int,
412 .Float,
413 .Bool,
414 .Void,
415 .Pointer,
416 .ErrorSet,
417 .AnyFrame,
418 .Frame,
419 .Enum,
420 .Vector,
421 => break, // terminal types (no sub-values)
422 .Optional => break, // this can only be a pointer-like optional so is terminal
423 .Array => {
424 const elem_ty = cur_ty.childType(zcu);
425 const elem_size = try sema.typeAbiSize(elem_ty);
426 const elem_idx = cur_offset / elem_size;
427 const next_elem_off = elem_size * (elem_idx + 1);
428 if (cur_offset + need_bytes <= next_elem_off) {
429 // We can look at a single array element.
430 cur_val = try cur_val.getElem(zcu, @intCast(elem_idx));
431 cur_offset -= elem_idx * elem_size;
432 } else {
433 break;
434 }
435 },
436 .Struct => switch (cur_ty.containerLayout(zcu)) {
437 .auto => unreachable, // ill-defined layout
438 .@"packed" => break, // let the bitcast logic handle this
439 .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| {
440 const start_off = cur_ty.structFieldOffset(field_idx, zcu);
441 const end_off = start_off + try sema.typeAbiSize(cur_ty.structFieldType(field_idx, zcu));
442 if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {
443 cur_val = try cur_val.getElem(zcu, field_idx);
444 cur_offset -= start_off;
445 break;
446 }
447 } else break, // pointer spans multiple fields
448 },
449 .Union => switch (cur_ty.containerLayout(zcu)) {
450 .auto => unreachable, // ill-defined layout
451 .@"packed" => break, // let the bitcast logic handle this
452 .@"extern" => {
453 // TODO: we have to let bitcast logic handle this for now.
454 // Otherwise, we might traverse into a union field which doesn't allow pointers.
455 // Figure out a solution!
456 if (true) break;
457 const payload: MutableValue = switch (cur_val) {
458 .un => |un| un.payload.*,
459 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
460 .un => |un| .{ .interned = un.val },
461 .undef => return .undef,
462 else => unreachable,
463 },
464 else => unreachable,
465 };
466 // The payload always has offset 0. If it's big enough
467 // to represent the whole load type, we can use it.
468 if (try sema.typeAbiSize(payload.typeOf(zcu)) >= need_bytes) {
469 cur_val = payload;
470 } else {
471 break;
472 }
473 },
474 },
475 }
476 }
477
478 // Fast path: check again if we're now at the type we want to load.
479 // If so, just return the loaded value.
480 if (cur_offset == 0 and host_bits == 0 and cur_val.typeOf(zcu).toIntern() == load_ty.toIntern()) {
481 return .{ .success = cur_val };
482 }
483
484 const result_val = try sema.bitCastVal(
485 try cur_val.intern(zcu, sema.arena),
486 load_ty,
487 cur_offset,
488 host_bits,
489 bit_offset,
490 ) orelse return .runtime_load;
491 return .{ .success = .{ .interned = result_val.toIntern() } };
492}
493
494const ComptimeStoreStrategy = union(enum) {
495 /// The store should be performed directly to this value, which `store_ty`
496 /// is in-memory coercible to.
497 direct: struct {
498 alloc: ComptimeAllocIndex,
499 val: *MutableValue,
500 },
501 /// The store should be performed at the index `elem_index` into `val`,
502 /// which is an array.
503 /// This strategy exists to avoid the need to convert the parent value
504 /// to the `aggregate` representation when `repeated` or `bytes` may
505 /// suffice.
506 index: struct {
507 alloc: ComptimeAllocIndex,
508 val: *MutableValue,
509 elem_index: u64,
510 },
511 /// The store should be performed on this array value, but it is being
512 /// restructured, e.g. [3][2][1]T -> [2][3]T.
513 /// This includes the case where it is a sub-array, e.g. [3]T -> [2]T.
514 /// This is only returned if `store_ty` is an array type, and its array
515 /// base type is IMC to that of the type of `val`.
516 flat_index: struct {
517 alloc: ComptimeAllocIndex,
518 val: *MutableValue,
519 flat_elem_index: u64,
520 },
521 /// This value should be reinterpreted using bitcast logic to perform the
522 /// store. Only returned if `store_ty` and the type of `val` both have
523 /// well-defined layouts.
524 reinterpret: struct {
525 alloc: ComptimeAllocIndex,
526 val: *MutableValue,
527 byte_offset: u64,
528 },
529
530 comptime_field,
531 runtime_store,
532 undef,
533 err_payload: InternPool.NullTerminatedString,
534 null_payload,
535 inactive_union_field,
536 needed_well_defined: Type,
537 out_of_bounds: Type,
538
539 fn alloc(strat: ComptimeStoreStrategy) ComptimeAllocIndex {
540 return switch (strat) {
541 inline .direct, .index, .flat_index, .reinterpret => |info| info.alloc,
542 .comptime_field,
543 .runtime_store,
544 .undef,
545 .err_payload,
546 .null_payload,
547 .inactive_union_field,
548 .needed_well_defined,
549 .out_of_bounds,
550 => unreachable,
551 };
552 }
553};
554
555/// Decide the strategy we will use to perform a comptime store of type `store_ty` to a pointer.
556/// The pointer's type is ignored.
557fn prepareComptimePtrStore(
558 sema: *Sema,
559 block: *Block,
560 src: LazySrcLoc,
561 ptr_val: Value,
562 store_ty: Type,
563 /// If `store_ty` is an array, this is the number of array elements to skip
564 /// before `store_ty`. Otherwise, it is ignored and may be `undefined`.
565 array_offset: u64,
566) !ComptimeStoreStrategy {
567 const zcu = sema.mod;
568 const ip = &zcu.intern_pool;
569
570 const ptr = switch (ip.indexToKey(ptr_val.toIntern())) {
571 .undef => return .undef,
572 .ptr => |ptr| ptr,
573 else => unreachable,
574 };
575
576 // `base_strat` will not be an error case.
577 const base_strat: ComptimeStoreStrategy = switch (ptr.base_addr) {
578 .decl, .anon_decl, .int => return .runtime_store,
579 .comptime_field => return .comptime_field,
580 .comptime_alloc => |alloc_index| .{ .direct = .{
581 .alloc = alloc_index,
582 .val = &sema.getComptimeAlloc(alloc_index).val,
583 } },
584 .eu_payload => |base_ptr_ip| base_val: {
585 const base_ptr = Value.fromInterned(base_ptr_ip);
586 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
587 const eu_val_ptr, const alloc = switch (try prepareComptimePtrStore(sema, block, src, base_ptr, base_ty, undefined)) {
588 .direct => |direct| .{ direct.val, direct.alloc },
589 .index => |index| .{
590 try index.val.elem(zcu, sema.arena, @intCast(index.elem_index)),
591 index.alloc,
592 },
593 .flat_index => unreachable, // base_ty is not an array
594 .reinterpret => unreachable, // base_ty has ill-defined layout
595 else => |err| return err,
596 };
597 try eu_val_ptr.unintern(zcu, sema.arena, false, false);
598 switch (eu_val_ptr.*) {
599 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
600 .undef => return .undef,
601 .error_union => |eu| return .{ .err_payload = eu.val.err_name },
602 else => unreachable,
603 },
604 .eu_payload => |data| break :base_val .{ .direct = .{
605 .val = data.child,
606 .alloc = alloc,
607 } },
608 else => unreachable,
609 }
610 },
611 .opt_payload => |base_ptr_ip| base_val: {
612 const base_ptr = Value.fromInterned(base_ptr_ip);
613 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
614 const opt_val_ptr, const alloc = switch (try prepareComptimePtrStore(sema, block, src, base_ptr, base_ty, undefined)) {
615 .direct => |direct| .{ direct.val, direct.alloc },
616 .index => |index| .{
617 try index.val.elem(zcu, sema.arena, @intCast(index.elem_index)),
618 index.alloc,
619 },
620 .flat_index => unreachable, // base_ty is not an array
621 .reinterpret => unreachable, // base_ty has ill-defined layout
622 else => |err| return err,
623 };
624 try opt_val_ptr.unintern(zcu, sema.arena, false, false);
625 switch (opt_val_ptr.*) {
626 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
627 .undef => return .undef,
628 .opt => return .null_payload,
629 else => unreachable,
630 },
631 .opt_payload => |data| break :base_val .{ .direct = .{
632 .val = data.child,
633 .alloc = alloc,
634 } },
635 else => unreachable,
636 }
637 },
638 .arr_elem => |base_index| base_val: {
639 const base_ptr = Value.fromInterned(base_index.base);
640 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
641
642 // We have a comptime-only array. This case is a little nasty.
643 // To avoid messing with too much data, we want to figure out how many elements we need to store.
644 // If `store_ty` and the array share a base type, we'll store the correct number of elements.
645 // Otherwise, we'll be reinterpreting (which we can't do, since it's comptime-only); just
646 // load a single element and let the logic below emit its error.
647
648 const store_one_ty, const store_count = store_ty.arrayBase(zcu);
649 const count = if (store_one_ty.toIntern() == base_ty.toIntern()) store_count else 1;
650
651 const want_ty = try zcu.arrayType(.{
652 .len = count,
653 .child = base_ty.toIntern(),
654 });
655
656 const result = try prepareComptimePtrStore(sema, block, src, base_ptr, want_ty, base_index.index);
657 switch (result) {
658 .direct, .index, .flat_index => break :base_val result,
659 .reinterpret => unreachable, // comptime-only array so ill-defined layout
660 else => |err| return err,
661 }
662 },
663 .field => |base_index| strat: {
664 const base_ptr = Value.fromInterned(base_index.base);
665 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
666
667 // Field of a slice, or of an auto-layout struct or union.
668 const agg_val, const alloc = switch (try prepareComptimePtrStore(sema, block, src, base_ptr, base_ty, undefined)) {
669 .direct => |direct| .{ direct.val, direct.alloc },
670 .index => |index| .{
671 try index.val.elem(zcu, sema.arena, @intCast(index.elem_index)),
672 index.alloc,
673 },
674 .flat_index => unreachable, // base_ty is not an array
675 .reinterpret => unreachable, // base_ty has ill-defined layout
676 else => |err| return err,
677 };
678
679 const agg_ty = agg_val.typeOf(zcu);
680 switch (agg_ty.zigTypeTag(zcu)) {
681 .Struct, .Pointer => break :strat .{ .direct = .{
682 .val = try agg_val.elem(zcu, sema.arena, @intCast(base_index.index)),
683 .alloc = alloc,
684 } },
685 .Union => {
686 if (agg_val.* == .interned and Value.fromInterned(agg_val.interned).isUndef(zcu)) {
687 return .undef;
688 }
689 try agg_val.unintern(zcu, sema.arena, false, false);
690 const un = agg_val.un;
691 const tag_ty = agg_ty.unionTagTypeHypothetical(zcu);
692 if (tag_ty.enumTagFieldIndex(Value.fromInterned(un.tag), zcu).? != base_index.index) {
693 return .inactive_union_field;
694 }
695 break :strat .{ .direct = .{
696 .val = un.payload,
697 .alloc = alloc,
698 } };
699 },
700 else => unreachable,
701 }
702 },
703 };
704
705 if (ptr.byte_offset == 0) {
706 if (store_ty.zigTypeTag(zcu) != .Array or array_offset == 0) direct: {
707 const base_val_ty = switch (base_strat) {
708 .direct => |direct| direct.val.typeOf(zcu),
709 .index => |index| index.val.typeOf(zcu).childType(zcu),
710 .flat_index, .reinterpret => break :direct,
711 else => unreachable,
712 };
713 if (.ok == try sema.coerceInMemoryAllowed(
714 block,
715 base_val_ty,
716 store_ty,
717 true,
718 zcu.getTarget(),
719 src,
720 src,
721 )) {
722 // The base strategy already gets us a value which the desired type is IMC to.
723 return base_strat;
724 }
725 }
726 }
727
728 restructure_array: {
729 // We might also be changing the length of an array, or restructuring it.
730 // e.g. [1][2][3]T -> [3][2]T.
731 // This case is important because it's permitted for types with ill-defined layouts.
732
733 const store_one_ty, const store_count = store_ty.arrayBase(zcu);
734 const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: {
735 if (try sema.typeRequiresComptime(store_one_ty)) break :restructure_array;
736 const elem_len = try sema.typeAbiSize(store_one_ty);
737 if (ptr.byte_offset % elem_len != 0) break :restructure_array;
738 break :idx @divExact(ptr.byte_offset, elem_len);
739 };
740
741 const base_val, const base_elem_offset, const oob_ty = switch (base_strat) {
742 .direct => |direct| .{ direct.val, 0, direct.val.typeOf(zcu) },
743 .index => |index| restructure_info: {
744 const elem_ty = index.val.typeOf(zcu).childType(zcu);
745 const elem_off = elem_ty.arrayBase(zcu)[1] * index.elem_index;
746 break :restructure_info .{ index.val, elem_off, elem_ty };
747 },
748 .flat_index => |flat| .{ flat.val, flat.flat_elem_index, flat.val.typeOf(zcu) },
749 .reinterpret => break :restructure_array,
750 else => unreachable,
751 };
752 const val_one_ty, const val_count = base_val.typeOf(zcu).arrayBase(zcu);
753 if (.ok != try sema.coerceInMemoryAllowed(block, val_one_ty, store_one_ty, true, zcu.getTarget(), src, src)) {
754 break :restructure_array;
755 }
756 if (base_elem_offset + extra_base_index + store_count > val_count) return .{ .out_of_bounds = oob_ty };
757
758 if (store_ty.zigTypeTag(zcu) == .Array) {
759 const skip = store_ty.childType(zcu).arrayBase(zcu)[1] * array_offset;
760 return .{ .flat_index = .{
761 .alloc = base_strat.alloc(),
762 .val = base_val,
763 .flat_elem_index = skip + base_elem_offset + extra_base_index,
764 } };
765 }
766
767 // `base_val` must be an array, since otherwise the "direct reinterpret" logic above noticed it.
768 assert(base_val.typeOf(zcu).zigTypeTag(zcu) == .Array);
769
770 var index: u64 = base_elem_offset + extra_base_index;
771 const arr_val, const arr_index = (try recursiveIndex(sema, base_val, &index)).?;
772 return .{ .index = .{
773 .alloc = base_strat.alloc(),
774 .val = arr_val,
775 .elem_index = arr_index,
776 } };
777 }
778
779 // We need to reinterpret memory, which is only possible if neither the store
780 // type nor the type of the base value have an ill-defined layout.
781
782 if (!store_ty.hasWellDefinedLayout(zcu)) {
783 return .{ .needed_well_defined = store_ty };
784 }
785
786 var cur_val: *MutableValue, var cur_offset: u64 = switch (base_strat) {
787 .direct => |direct| .{ direct.val, 0 },
788 // It's okay to do `abiSize` - the comptime-only case will be caught below.
789 .index => |index| .{ index.val, index.elem_index * try sema.typeAbiSize(index.val.typeOf(zcu).childType(zcu)) },
790 .flat_index => |flat_index| .{
791 flat_index.val,
792 // It's okay to do `abiSize` - the comptime-only case will be caught below.
793 flat_index.flat_elem_index * try sema.typeAbiSize(flat_index.val.typeOf(zcu).arrayBase(zcu)[0]),
794 },
795 .reinterpret => |r| .{ r.val, r.byte_offset },
796 else => unreachable,
797 };
798 cur_offset += ptr.byte_offset;
799
800 if (!cur_val.typeOf(zcu).hasWellDefinedLayout(zcu)) {
801 return .{ .needed_well_defined = cur_val.typeOf(zcu) };
802 }
803
804 if (store_ty.zigTypeTag(zcu) == .Array and array_offset > 0) {
805 cur_offset += try sema.typeAbiSize(store_ty.childType(zcu)) * array_offset;
806 }
807
808 const need_bytes = try sema.typeAbiSize(store_ty);
809
810 if (cur_offset + need_bytes > try sema.typeAbiSize(cur_val.typeOf(zcu))) {
811 return .{ .out_of_bounds = cur_val.typeOf(zcu) };
812 }
813
814 // In the worst case, we can reinterpret the entire value - however, that's
815 // pretty wasteful. If the memory region we're interested in refers to one
816 // field or array element, let's just look at that.
817 while (true) {
818 const cur_ty = cur_val.typeOf(zcu);
819 switch (cur_ty.zigTypeTag(zcu)) {
820 .NoReturn,
821 .Type,
822 .ComptimeInt,
823 .ComptimeFloat,
824 .Null,
825 .Undefined,
826 .EnumLiteral,
827 .Opaque,
828 .Fn,
829 .ErrorUnion,
830 => unreachable, // ill-defined layout
831 .Int,
832 .Float,
833 .Bool,
834 .Void,
835 .Pointer,
836 .ErrorSet,
837 .AnyFrame,
838 .Frame,
839 .Enum,
840 .Vector,
841 => break, // terminal types (no sub-values)
842 .Optional => break, // this can only be a pointer-like optional so is terminal
843 .Array => {
844 const elem_ty = cur_ty.childType(zcu);
845 const elem_size = try sema.typeAbiSize(elem_ty);
846 const elem_idx = cur_offset / elem_size;
847 const next_elem_off = elem_size * (elem_idx + 1);
848 if (cur_offset + need_bytes <= next_elem_off) {
849 // We can look at a single array element.
850 cur_val = try cur_val.elem(zcu, sema.arena, @intCast(elem_idx));
851 cur_offset -= elem_idx * elem_size;
852 } else {
853 break;
854 }
855 },
856 .Struct => switch (cur_ty.containerLayout(zcu)) {
857 .auto => unreachable, // ill-defined layout
858 .@"packed" => break, // let the bitcast logic handle this
859 .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| {
860 const start_off = cur_ty.structFieldOffset(field_idx, zcu);
861 const end_off = start_off + try sema.typeAbiSize(cur_ty.structFieldType(field_idx, zcu));
862 if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {
863 cur_val = try cur_val.elem(zcu, sema.arena, field_idx);
864 cur_offset -= start_off;
865 break;
866 }
867 } else break, // pointer spans multiple fields
868 },
869 .Union => switch (cur_ty.containerLayout(zcu)) {
870 .auto => unreachable, // ill-defined layout
871 .@"packed" => break, // let the bitcast logic handle this
872 .@"extern" => {
873 // TODO: we have to let bitcast logic handle this for now.
874 // Otherwise, we might traverse into a union field which doesn't allow pointers.
875 // Figure out a solution!
876 if (true) break;
877 try cur_val.unintern(zcu, sema.arena, false, false);
878 const payload = switch (cur_val.*) {
879 .un => |un| un.payload,
880 else => unreachable,
881 };
882 // The payload always has offset 0. If it's big enough
883 // to represent the whole load type, we can use it.
884 if (try sema.typeAbiSize(payload.typeOf(zcu)) >= need_bytes) {
885 cur_val = payload;
886 } else {
887 break;
888 }
889 },
890 },
891 }
892 }
893
894 // Fast path: check again if we're now at the type we want to store.
895 // If so, we can use the `direct` strategy.
896 if (cur_offset == 0 and cur_val.typeOf(zcu).toIntern() == store_ty.toIntern()) {
897 return .{ .direct = .{
898 .alloc = base_strat.alloc(),
899 .val = cur_val,
900 } };
901 }
902
903 return .{ .reinterpret = .{
904 .alloc = base_strat.alloc(),
905 .val = cur_val,
906 .byte_offset = cur_offset,
907 } };
908}
909
910/// Given a potentially-nested array value, recursively flatten all of its elements into the given
911/// output array. The result can be used by `unflattenArray` to restructure array values.
912fn flattenArray(
913 sema: *Sema,
914 val: MutableValue,
915 skip: *u64,
916 next_idx: *u64,
917 out: []InternPool.Index,
918) Allocator.Error!void {
919 if (next_idx.* == out.len) return;
920
921 const zcu = sema.mod;
922
923 const ty = val.typeOf(zcu);
924 const base_elem_count = ty.arrayBase(zcu)[1];
925 if (skip.* >= base_elem_count) {
926 skip.* -= base_elem_count;
927 return;
928 }
929
930 if (ty.zigTypeTag(zcu) != .Array) {
931 out[@intCast(next_idx.*)] = (try val.intern(zcu, sema.arena)).toIntern();
932 next_idx.* += 1;
933 return;
934 }
935
936 const arr_base_elem_count = ty.childType(zcu).arrayBase(zcu)[1];
937 for (0..@intCast(ty.arrayLen(zcu))) |elem_idx| {
938 // Optimization: the `getElem` here may be expensive since we might intern an
939 // element of the `bytes` representation, so avoid doing it unnecessarily.
940 if (next_idx.* == out.len) return;
941 if (skip.* >= arr_base_elem_count) {
942 skip.* -= arr_base_elem_count;
943 continue;
944 }
945 try flattenArray(sema, try val.getElem(zcu, elem_idx), skip, next_idx, out);
946 }
947 if (ty.sentinel(zcu)) |s| {
948 try flattenArray(sema, .{ .interned = s.toIntern() }, skip, next_idx, out);
949 }
950}
951
952/// Given a sequence of non-array elements, "unflatten" them into the given array type.
953/// Asserts that values of `elems` are in-memory coercible to the array base type of `ty`.
954fn unflattenArray(
955 sema: *Sema,
956 ty: Type,
957 elems: []const InternPool.Index,
958 next_idx: *u64,
959) Allocator.Error!Value {
960 const zcu = sema.mod;
961 const arena = sema.arena;
962
963 if (ty.zigTypeTag(zcu) != .Array) {
964 const val = Value.fromInterned(elems[@intCast(next_idx.*)]);
965 next_idx.* += 1;
966 return zcu.getCoerced(val, ty);
967 }
968
969 const elem_ty = ty.childType(zcu);
970 const buf = try arena.alloc(InternPool.Index, @intCast(ty.arrayLen(zcu)));
971 for (buf) |*elem| {
972 elem.* = (try unflattenArray(sema, elem_ty, elems, next_idx)).toIntern();
973 }
974 if (ty.sentinel(zcu) != null) {
975 // TODO: validate sentinel
976 _ = try unflattenArray(sema, elem_ty, elems, next_idx);
977 }
978 return Value.fromInterned(try zcu.intern(.{ .aggregate = .{
979 .ty = ty.toIntern(),
980 .storage = .{ .elems = buf },
981 } }));
982}
983
984/// Given a `MutableValue` representing a potentially-nested array, treats `index` as an index into
985/// the array's base type. For instance, given a [3][3]T, the index 5 represents 'val[1][2]'.
986/// The final level of array is not dereferenced. This allows use sites to use `setElem` to prevent
987/// unnecessary `MutableValue` representation changes.
988fn recursiveIndex(
989 sema: *Sema,
990 mv: *MutableValue,
991 index: *u64,
992) !?struct { *MutableValue, u64 } {
993 const zcu = sema.mod;
994
995 const ty = mv.typeOf(zcu);
996 assert(ty.zigTypeTag(zcu) == .Array);
997
998 const ty_base_elems = ty.arrayBase(zcu)[1];
999 if (index.* >= ty_base_elems) {
1000 index.* -= ty_base_elems;
1001 return null;
1002 }
1003
1004 const elem_ty = ty.childType(zcu);
1005 if (elem_ty.zigTypeTag(zcu) != .Array) {
1006 assert(index.* < ty.arrayLenIncludingSentinel(zcu)); // should be handled by initial check
1007 return .{ mv, index.* };
1008 }
1009
1010 for (0..@intCast(ty.arrayLenIncludingSentinel(zcu))) |elem_index| {
1011 if (try recursiveIndex(sema, try mv.elem(zcu, sema.arena, elem_index), index)) |result| {
1012 return result;
1013 }
1014 }
1015 unreachable; // should be handled by initial check
1016}
1017
1018fn checkComptimeVarStore(
1019 sema: *Sema,
1020 block: *Block,
1021 src: LazySrcLoc,
1022 alloc_index: ComptimeAllocIndex,
1023) !void {
1024 const runtime_index = sema.getComptimeAlloc(alloc_index).runtime_index;
1025 if (@intFromEnum(runtime_index) < @intFromEnum(block.runtime_index)) {
1026 if (block.runtime_cond) |cond_src| {
1027 const msg = msg: {
1028 const msg = try sema.errMsg(block, src, "store to comptime variable depends on runtime condition", .{});
1029 errdefer msg.destroy(sema.gpa);
1030 try sema.mod.errNoteNonLazy(cond_src, msg, "runtime condition here", .{});
1031 break :msg msg;
1032 };
1033 return sema.failWithOwnedErrorMsg(block, msg);
1034 }
1035 if (block.runtime_loop) |loop_src| {
1036 const msg = msg: {
1037 const msg = try sema.errMsg(block, src, "cannot store to comptime variable in non-inline loop", .{});
1038 errdefer msg.destroy(sema.gpa);
1039 try sema.mod.errNoteNonLazy(loop_src, msg, "non-inline loop here", .{});
1040 break :msg msg;
1041 };
1042 return sema.failWithOwnedErrorMsg(block, msg);
1043 }
1044 unreachable;
1045 }
1046}
1047
1048const std = @import("std");
1049const assert = std.debug.assert;
1050const Allocator = std.mem.Allocator;
1051const LazySrcLoc = std.zig.LazySrcLoc;
1052
1053const InternPool = @import("../InternPool.zig");
1054const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
1055const Sema = @import("../Sema.zig");
1056const Block = Sema.Block;
1057const MutableValue = @import("../mutable_value.zig").MutableValue;
1058const Type = @import("../type.zig").Type;
1059const Value = @import("../Value.zig");
src/Value.zig+771-92
......@@ -39,10 +39,11 @@ pub fn fmtDebug(val: Value) std.fmt.Formatter(dump) {
3939 return .{ .data = val };
4040}
4141
42pub fn fmtValue(val: Value, mod: *Module) std.fmt.Formatter(print_value.format) {
42pub fn fmtValue(val: Value, mod: *Module, opt_sema: ?*Sema) std.fmt.Formatter(print_value.format) {
4343 return .{ .data = .{
4444 .val = val,
4545 .mod = mod,
46 .opt_sema = opt_sema,
4647 } };
4748}
4849
......@@ -246,18 +247,13 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64
246247 else
247248 Type.fromInterned(ty).abiSize(mod),
248249 },
249 .ptr => |ptr| switch (ptr.addr) {
250 .int => |int| Value.fromInterned(int).getUnsignedIntAdvanced(mod, opt_sema),
251 .elem => |elem| {
252 const base_addr = (try Value.fromInterned(elem.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null;
253 const elem_ty = Value.fromInterned(elem.base).typeOf(mod).elemType2(mod);
254 return base_addr + elem.index * elem_ty.abiSize(mod);
255 },
250 .ptr => |ptr| switch (ptr.base_addr) {
251 .int => ptr.byte_offset,
256252 .field => |field| {
257253 const base_addr = (try Value.fromInterned(field.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null;
258254 const struct_ty = Value.fromInterned(field.base).typeOf(mod).childType(mod);
259255 if (opt_sema) |sema| try sema.resolveTypeLayout(struct_ty);
260 return base_addr + struct_ty.structFieldOffset(@intCast(field.index), mod);
256 return base_addr + struct_ty.structFieldOffset(@intCast(field.index), mod) + ptr.byte_offset;
261257 },
262258 else => null,
263259 },
......@@ -309,11 +305,11 @@ pub fn toBool(val: Value) bool {
309305fn ptrHasIntAddr(val: Value, mod: *Module) bool {
310306 var check = val;
311307 while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) {
312 .ptr => |ptr| switch (ptr.addr) {
308 .ptr => |ptr| switch (ptr.base_addr) {
313309 .decl, .comptime_alloc, .comptime_field, .anon_decl => return false,
314310 .int => return true,
315311 .eu_payload, .opt_payload => |base| check = Value.fromInterned(base),
316 .elem, .field => |base_index| check = Value.fromInterned(base_index.base),
312 .arr_elem, .field => |base_index| check = Value.fromInterned(base_index.base),
317313 },
318314 else => unreachable,
319315 };
......@@ -473,7 +469,9 @@ pub fn writeToPackedMemory(
473469 const endian = target.cpu.arch.endian();
474470 if (val.isUndef(mod)) {
475471 const bit_size: usize = @intCast(ty.bitSize(mod));
476 std.mem.writeVarPackedInt(buffer, bit_offset, bit_size, @as(u1, 0), endian);
472 if (bit_size != 0) {
473 std.mem.writeVarPackedInt(buffer, bit_offset, bit_size, @as(u1, 0), endian);
474 }
477475 return;
478476 }
479477 switch (ty.zigTypeTag(mod)) {
......@@ -731,7 +729,8 @@ pub fn readFromMemory(
731729 const int_val = try readFromMemory(Type.usize, mod, buffer, arena);
732730 return Value.fromInterned((try mod.intern(.{ .ptr = .{
733731 .ty = ty.toIntern(),
734 .addr = .{ .int = int_val.toIntern() },
732 .base_addr = .int,
733 .byte_offset = int_val.toUnsignedInt(mod),
735734 } })));
736735 },
737736 .Optional => {
......@@ -869,12 +868,25 @@ pub fn readFromPackedMemory(
869868 },
870869 .Pointer => {
871870 assert(!ty.isSlice(mod)); // No well defined layout.
872 return readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena);
871 const int_val = try readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena);
872 return Value.fromInterned(try mod.intern(.{ .ptr = .{
873 .ty = ty.toIntern(),
874 .base_addr = .int,
875 .byte_offset = int_val.toUnsignedInt(mod),
876 } }));
873877 },
874878 .Optional => {
875879 assert(ty.isPtrLikeOptional(mod));
876 const child = ty.optionalChild(mod);
877 return readFromPackedMemory(child, mod, buffer, bit_offset, arena);
880 const child_ty = ty.optionalChild(mod);
881 const child_val = try readFromPackedMemory(child_ty, mod, buffer, bit_offset, arena);
882 return Value.fromInterned(try mod.intern(.{ .opt = .{
883 .ty = ty.toIntern(),
884 .val = switch (child_val.orderAgainstZero(mod)) {
885 .lt => unreachable,
886 .eq => .none,
887 .gt => child_val.toIntern(),
888 },
889 } }));
878890 },
879891 else => @panic("TODO implement readFromPackedMemory for more types"),
880892 }
......@@ -983,16 +995,17 @@ pub fn intBitCountTwosComp(self: Value, mod: *Module) usize {
983995
984996/// Converts an integer or a float to a float. May result in a loss of information.
985997/// Caller can find out by equality checking the result against the operand.
986pub fn floatCast(self: Value, dest_ty: Type, mod: *Module) !Value {
987 const target = mod.getTarget();
988 return Value.fromInterned((try mod.intern(.{ .float = .{
998pub fn floatCast(val: Value, dest_ty: Type, zcu: *Zcu) !Value {
999 const target = zcu.getTarget();
1000 if (val.isUndef(zcu)) return zcu.undefValue(dest_ty);
1001 return Value.fromInterned((try zcu.intern(.{ .float = .{
9891002 .ty = dest_ty.toIntern(),
9901003 .storage = switch (dest_ty.floatBits(target)) {
991 16 => .{ .f16 = self.toFloat(f16, mod) },
992 32 => .{ .f32 = self.toFloat(f32, mod) },
993 64 => .{ .f64 = self.toFloat(f64, mod) },
994 80 => .{ .f80 = self.toFloat(f80, mod) },
995 128 => .{ .f128 = self.toFloat(f128, mod) },
1004 16 => .{ .f16 = val.toFloat(f16, zcu) },
1005 32 => .{ .f32 = val.toFloat(f32, zcu) },
1006 64 => .{ .f64 = val.toFloat(f64, zcu) },
1007 80 => .{ .f80 = val.toFloat(f80, zcu) },
1008 128 => .{ .f128 = val.toFloat(f128, zcu) },
9961009 else => unreachable,
9971010 },
9981011 } })));
......@@ -1021,14 +1034,9 @@ pub fn orderAgainstZeroAdvanced(
10211034 .bool_false => .eq,
10221035 .bool_true => .gt,
10231036 else => switch (mod.intern_pool.indexToKey(lhs.toIntern())) {
1024 .ptr => |ptr| switch (ptr.addr) {
1037 .ptr => |ptr| if (ptr.byte_offset > 0) .gt else switch (ptr.base_addr) {
10251038 .decl, .comptime_alloc, .comptime_field => .gt,
1026 .int => |int| Value.fromInterned(int).orderAgainstZeroAdvanced(mod, opt_sema),
1027 .elem => |elem| switch (try Value.fromInterned(elem.base).orderAgainstZeroAdvanced(mod, opt_sema)) {
1028 .lt => unreachable,
1029 .gt => .gt,
1030 .eq => if (elem.index == 0) .eq else .gt,
1031 },
1039 .int => .eq,
10321040 else => unreachable,
10331041 },
10341042 .int => |int| switch (int.storage) {
......@@ -1158,6 +1166,7 @@ pub fn compareScalar(
11581166
11591167/// Asserts the value is comparable.
11601168/// For vectors, returns true if comparison is true for ALL elements.
1169/// Returns `false` if the value or any vector element is undefined.
11611170///
11621171/// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`
11631172pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, mod: *Module) bool {
......@@ -1200,6 +1209,7 @@ pub fn compareAllWithZeroAdvancedExtra(
12001209 } else true,
12011210 .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, opt_sema),
12021211 },
1212 .undef => return false,
12031213 else => {},
12041214 }
12051215 return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op);
......@@ -1217,14 +1227,14 @@ pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool {
12171227 .err_name => false,
12181228 .payload => |payload| Value.fromInterned(payload).canMutateComptimeVarState(zcu),
12191229 },
1220 .ptr => |ptr| switch (ptr.addr) {
1230 .ptr => |ptr| switch (ptr.base_addr) {
12211231 .decl => false, // The value of a Decl can never reference a comptime alloc.
12221232 .int => false,
12231233 .comptime_alloc => true, // A comptime alloc is either mutable or references comptime-mutable memory.
12241234 .comptime_field => true, // Comptime field pointers are comptime-mutable, albeit only to the "correct" value.
12251235 .eu_payload, .opt_payload => |base| Value.fromInterned(base).canMutateComptimeVarState(zcu),
12261236 .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).canMutateComptimeVarState(zcu),
1227 .elem, .field => |base_index| Value.fromInterned(base_index.base).canMutateComptimeVarState(zcu),
1237 .arr_elem, .field => |base_index| Value.fromInterned(base_index.base).canMutateComptimeVarState(zcu),
12281238 },
12291239 .slice => |slice| return Value.fromInterned(slice.ptr).canMutateComptimeVarState(zcu),
12301240 .opt => |opt| switch (opt.val) {
......@@ -1247,10 +1257,10 @@ pub fn pointerDecl(val: Value, mod: *Module) ?InternPool.DeclIndex {
12471257 .variable => |variable| variable.decl,
12481258 .extern_func => |extern_func| extern_func.decl,
12491259 .func => |func| func.owner_decl,
1250 .ptr => |ptr| switch (ptr.addr) {
1260 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
12511261 .decl => |decl| decl,
12521262 else => null,
1253 },
1263 } else null,
12541264 else => null,
12551265 };
12561266}
......@@ -1386,44 +1396,6 @@ pub fn unionValue(val: Value, mod: *Module) Value {
13861396 };
13871397}
13881398
1389/// Returns a pointer to the element value at the index.
1390pub fn elemPtr(
1391 val: Value,
1392 elem_ptr_ty: Type,
1393 index: usize,
1394 mod: *Module,
1395) Allocator.Error!Value {
1396 const elem_ty = elem_ptr_ty.childType(mod);
1397 const ptr_val = switch (mod.intern_pool.indexToKey(val.toIntern())) {
1398 .slice => |slice| Value.fromInterned(slice.ptr),
1399 else => val,
1400 };
1401 switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
1402 .ptr => |ptr| switch (ptr.addr) {
1403 .elem => |elem| if (Value.fromInterned(elem.base).typeOf(mod).elemType2(mod).eql(elem_ty, mod))
1404 return Value.fromInterned((try mod.intern(.{ .ptr = .{
1405 .ty = elem_ptr_ty.toIntern(),
1406 .addr = .{ .elem = .{
1407 .base = elem.base,
1408 .index = elem.index + index,
1409 } },
1410 } }))),
1411 else => {},
1412 },
1413 else => {},
1414 }
1415 var ptr_ty_key = mod.intern_pool.indexToKey(elem_ptr_ty.toIntern()).ptr_type;
1416 assert(ptr_ty_key.flags.size != .Slice);
1417 ptr_ty_key.flags.size = .Many;
1418 return Value.fromInterned((try mod.intern(.{ .ptr = .{
1419 .ty = elem_ptr_ty.toIntern(),
1420 .addr = .{ .elem = .{
1421 .base = (try mod.getCoerced(ptr_val, try mod.ptrType(ptr_ty_key))).toIntern(),
1422 .index = index,
1423 } },
1424 } })));
1425}
1426
14271399pub fn isUndef(val: Value, mod: *Module) bool {
14281400 return mod.intern_pool.isUndef(val.toIntern());
14291401}
......@@ -1444,11 +1416,8 @@ pub fn isNull(val: Value, mod: *Module) bool {
14441416 .null_value => true,
14451417 else => return switch (mod.intern_pool.indexToKey(val.toIntern())) {
14461418 .undef => unreachable,
1447 .ptr => |ptr| switch (ptr.addr) {
1448 .int => {
1449 var buf: BigIntSpace = undefined;
1450 return val.toBigInt(&buf, mod).eqlZero();
1451 },
1419 .ptr => |ptr| switch (ptr.base_addr) {
1420 .int => ptr.byte_offset == 0,
14521421 else => false,
14531422 },
14541423 .opt => |opt| opt.val == .none,
......@@ -1725,6 +1694,13 @@ pub fn intMulWithOverflowScalar(
17251694) !OverflowArithmeticResult {
17261695 const info = ty.intInfo(mod);
17271696
1697 if (lhs.isUndef(mod) or rhs.isUndef(mod)) {
1698 return .{
1699 .overflow_bit = try mod.undefValue(Type.u1),
1700 .wrapped_result = try mod.undefValue(ty),
1701 };
1702 }
1703
17281704 var lhs_space: Value.BigIntSpace = undefined;
17291705 var rhs_space: Value.BigIntSpace = undefined;
17301706 const lhs_bigint = lhs.toBigInt(&lhs_space, mod);
......@@ -1941,16 +1917,29 @@ pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *
19411917}
19421918
19431919/// operands must be integers; handles undefined.
1944pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
1945 if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.fromInterned((try mod.intern(.{ .undef = ty.toIntern() })));
1920pub fn bitwiseAndScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Allocator, zcu: *Zcu) !Value {
1921 // If one operand is defined, we turn the other into `0xAA` so the bitwise AND can
1922 // still zero out some bits.
1923 // TODO: ideally we'd still like tracking for the undef bits. Related: #19634.
1924 const lhs: Value, const rhs: Value = make_defined: {
1925 const lhs_undef = orig_lhs.isUndef(zcu);
1926 const rhs_undef = orig_rhs.isUndef(zcu);
1927 break :make_defined switch ((@as(u2, @intFromBool(lhs_undef)) << 1) | @intFromBool(rhs_undef)) {
1928 0b00 => .{ orig_lhs, orig_rhs },
1929 0b01 => .{ orig_lhs, try intValueAa(ty, arena, zcu) },
1930 0b10 => .{ try intValueAa(ty, arena, zcu), orig_rhs },
1931 0b11 => return zcu.undefValue(ty),
1932 };
1933 };
1934
19461935 if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() and rhs.toBool());
19471936
19481937 // TODO is this a performance issue? maybe we should try the operation without
19491938 // resorting to BigInt first.
19501939 var lhs_space: Value.BigIntSpace = undefined;
19511940 var rhs_space: Value.BigIntSpace = undefined;
1952 const lhs_bigint = lhs.toBigInt(&lhs_space, mod);
1953 const rhs_bigint = rhs.toBigInt(&rhs_space, mod);
1941 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
1942 const rhs_bigint = rhs.toBigInt(&rhs_space, zcu);
19541943 const limbs = try arena.alloc(
19551944 std.math.big.Limb,
19561945 // + 1 for negatives
......@@ -1958,7 +1947,25 @@ pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod:
19581947 );
19591948 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
19601949 result_bigint.bitAnd(lhs_bigint, rhs_bigint);
1961 return mod.intValue_big(ty, result_bigint.toConst());
1950 return zcu.intValue_big(ty, result_bigint.toConst());
1951}
1952
1953/// Given an integer or boolean type, creates an value of that with the bit pattern 0xAA.
1954/// This is used to convert undef values into 0xAA when performing e.g. bitwise operations.
1955fn intValueAa(ty: Type, arena: Allocator, zcu: *Zcu) !Value {
1956 if (ty.toIntern() == .bool_type) return Value.true;
1957 const info = ty.intInfo(zcu);
1958
1959 const buf = try arena.alloc(u8, (info.bits + 7) / 8);
1960 @memset(buf, 0xAA);
1961
1962 const limbs = try arena.alloc(
1963 std.math.big.Limb,
1964 std.math.big.int.calcTwosCompLimbCount(info.bits),
1965 );
1966 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
1967 result_bigint.readTwosComplement(buf, info.bits, zcu.getTarget().cpu.arch.endian(), info.signedness);
1968 return zcu.intValue_big(ty, result_bigint.toConst());
19621969}
19631970
19641971/// operands must be (vectors of) integers; handles undefined scalars.
......@@ -2008,23 +2015,36 @@ pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *M
20082015}
20092016
20102017/// operands must be integers; handles undefined.
2011pub fn bitwiseOrScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
2012 if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.fromInterned((try mod.intern(.{ .undef = ty.toIntern() })));
2018pub fn bitwiseOrScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Allocator, zcu: *Zcu) !Value {
2019 // If one operand is defined, we turn the other into `0xAA` so the bitwise AND can
2020 // still zero out some bits.
2021 // TODO: ideally we'd still like tracking for the undef bits. Related: #19634.
2022 const lhs: Value, const rhs: Value = make_defined: {
2023 const lhs_undef = orig_lhs.isUndef(zcu);
2024 const rhs_undef = orig_rhs.isUndef(zcu);
2025 break :make_defined switch ((@as(u2, @intFromBool(lhs_undef)) << 1) | @intFromBool(rhs_undef)) {
2026 0b00 => .{ orig_lhs, orig_rhs },
2027 0b01 => .{ orig_lhs, try intValueAa(ty, arena, zcu) },
2028 0b10 => .{ try intValueAa(ty, arena, zcu), orig_rhs },
2029 0b11 => return zcu.undefValue(ty),
2030 };
2031 };
2032
20132033 if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() or rhs.toBool());
20142034
20152035 // TODO is this a performance issue? maybe we should try the operation without
20162036 // resorting to BigInt first.
20172037 var lhs_space: Value.BigIntSpace = undefined;
20182038 var rhs_space: Value.BigIntSpace = undefined;
2019 const lhs_bigint = lhs.toBigInt(&lhs_space, mod);
2020 const rhs_bigint = rhs.toBigInt(&rhs_space, mod);
2039 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
2040 const rhs_bigint = rhs.toBigInt(&rhs_space, zcu);
20212041 const limbs = try arena.alloc(
20222042 std.math.big.Limb,
20232043 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
20242044 );
20252045 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
20262046 result_bigint.bitOr(lhs_bigint, rhs_bigint);
2027 return mod.intValue_big(ty, result_bigint.toConst());
2047 return zcu.intValue_big(ty, result_bigint.toConst());
20282048}
20292049
20302050/// operands must be (vectors of) integers; handles undefined scalars.
......@@ -2439,12 +2459,14 @@ pub fn intTruncScalar(
24392459 allocator: Allocator,
24402460 signedness: std.builtin.Signedness,
24412461 bits: u16,
2442 mod: *Module,
2462 zcu: *Zcu,
24432463) !Value {
2444 if (bits == 0) return mod.intValue(ty, 0);
2464 if (bits == 0) return zcu.intValue(ty, 0);
2465
2466 if (val.isUndef(zcu)) return zcu.undefValue(ty);
24452467
24462468 var val_space: Value.BigIntSpace = undefined;
2447 const val_bigint = val.toBigInt(&val_space, mod);
2469 const val_bigint = val.toBigInt(&val_space, zcu);
24482470
24492471 const limbs = try allocator.alloc(
24502472 std.math.big.Limb,
......@@ -2453,7 +2475,7 @@ pub fn intTruncScalar(
24532475 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
24542476
24552477 result_bigint.truncate(val_bigint, signedness, bits);
2456 return mod.intValue_big(ty, result_bigint.toConst());
2478 return zcu.intValue_big(ty, result_bigint.toConst());
24572479}
24582480
24592481pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value {
......@@ -3585,3 +3607,660 @@ pub fn makeBool(x: bool) Value {
35853607}
35863608
35873609pub const RuntimeIndex = InternPool.RuntimeIndex;
3610
3611/// `parent_ptr` must be a single-pointer to some optional.
3612/// Returns a pointer to the payload of the optional.
3613/// This takes a `Sema` because it may need to perform type resolution.
3614pub fn ptrOptPayload(parent_ptr: Value, sema: *Sema) !Value {
3615 const zcu = sema.mod;
3616
3617 const parent_ptr_ty = parent_ptr.typeOf(zcu);
3618 const opt_ty = parent_ptr_ty.childType(zcu);
3619
3620 assert(parent_ptr_ty.ptrSize(zcu) == .One);
3621 assert(opt_ty.zigTypeTag(zcu) == .Optional);
3622
3623 const result_ty = try sema.ptrType(info: {
3624 var new = parent_ptr_ty.ptrInfo(zcu);
3625 // We can correctly preserve alignment `.none`, since an optional has the same
3626 // natural alignment as its child type.
3627 new.child = opt_ty.childType(zcu).toIntern();
3628 break :info new;
3629 });
3630
3631 if (parent_ptr.isUndef(zcu)) return zcu.undefValue(result_ty);
3632
3633 if (opt_ty.isPtrLikeOptional(zcu)) {
3634 // Just reinterpret the pointer, since the layout is well-defined
3635 return zcu.getCoerced(parent_ptr, result_ty);
3636 }
3637
3638 const base_ptr = try parent_ptr.canonicalizeBasePtr(.One, opt_ty, zcu);
3639 return Value.fromInterned(try zcu.intern(.{ .ptr = .{
3640 .ty = result_ty.toIntern(),
3641 .base_addr = .{ .opt_payload = base_ptr.toIntern() },
3642 .byte_offset = 0,
3643 } }));
3644}
3645
3646/// `parent_ptr` must be a single-pointer to some error union.
3647/// Returns a pointer to the payload of the error union.
3648/// This takes a `Sema` because it may need to perform type resolution.
3649pub fn ptrEuPayload(parent_ptr: Value, sema: *Sema) !Value {
3650 const zcu = sema.mod;
3651
3652 const parent_ptr_ty = parent_ptr.typeOf(zcu);
3653 const eu_ty = parent_ptr_ty.childType(zcu);
3654
3655 assert(parent_ptr_ty.ptrSize(zcu) == .One);
3656 assert(eu_ty.zigTypeTag(zcu) == .ErrorUnion);
3657
3658 const result_ty = try sema.ptrType(info: {
3659 var new = parent_ptr_ty.ptrInfo(zcu);
3660 // We can correctly preserve alignment `.none`, since an error union has a
3661 // natural alignment greater than or equal to that of its payload type.
3662 new.child = eu_ty.errorUnionPayload(zcu).toIntern();
3663 break :info new;
3664 });
3665
3666 if (parent_ptr.isUndef(zcu)) return zcu.undefValue(result_ty);
3667
3668 const base_ptr = try parent_ptr.canonicalizeBasePtr(.One, eu_ty, zcu);
3669 return Value.fromInterned(try zcu.intern(.{ .ptr = .{
3670 .ty = result_ty.toIntern(),
3671 .base_addr = .{ .eu_payload = base_ptr.toIntern() },
3672 .byte_offset = 0,
3673 } }));
3674}
3675
3676/// `parent_ptr` must be a single-pointer to a struct, union, or slice.
3677/// Returns a pointer to the aggregate field at the specified index.
3678/// For slices, uses `slice_ptr_index` and `slice_len_index`.
3679/// This takes a `Sema` because it may need to perform type resolution.
3680pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value {
3681 const zcu = sema.mod;
3682
3683 const parent_ptr_ty = parent_ptr.typeOf(zcu);
3684 const aggregate_ty = parent_ptr_ty.childType(zcu);
3685
3686 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
3687 assert(parent_ptr_info.flags.size == .One);
3688
3689 // Exiting this `switch` indicates that the `field` pointer repsentation should be used.
3690 // `field_align` may be `.none` to represent the natural alignment of `field_ty`, but is not necessarily.
3691 const field_ty: Type, const field_align: InternPool.Alignment = switch (aggregate_ty.zigTypeTag(zcu)) {
3692 .Struct => field: {
3693 const field_ty = aggregate_ty.structFieldType(field_idx, zcu);
3694 switch (aggregate_ty.containerLayout(zcu)) {
3695 .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, sema) },
3696 .@"extern" => {
3697 // Well-defined layout, so just offset the pointer appropriately.
3698 const byte_off = aggregate_ty.structFieldOffset(field_idx, zcu);
3699 const field_align = a: {
3700 const parent_align = if (parent_ptr_info.flags.alignment == .none) pa: {
3701 break :pa try sema.typeAbiAlignment(aggregate_ty);
3702 } else parent_ptr_info.flags.alignment;
3703 break :a InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(byte_off)));
3704 };
3705 const result_ty = try sema.ptrType(info: {
3706 var new = parent_ptr_info;
3707 new.child = field_ty.toIntern();
3708 new.flags.alignment = field_align;
3709 break :info new;
3710 });
3711 return parent_ptr.getOffsetPtr(byte_off, result_ty, zcu);
3712 },
3713 .@"packed" => switch (aggregate_ty.packedStructFieldPtrInfo(parent_ptr_ty, field_idx, zcu)) {
3714 .bit_ptr => |packed_offset| {
3715 const result_ty = try zcu.ptrType(info: {
3716 var new = parent_ptr_info;
3717 new.packed_offset = packed_offset;
3718 new.child = field_ty.toIntern();
3719 if (new.flags.alignment == .none) {
3720 new.flags.alignment = try sema.typeAbiAlignment(aggregate_ty);
3721 }
3722 break :info new;
3723 });
3724 return zcu.getCoerced(parent_ptr, result_ty);
3725 },
3726 .byte_ptr => |ptr_info| {
3727 const result_ty = try sema.ptrType(info: {
3728 var new = parent_ptr_info;
3729 new.child = field_ty.toIntern();
3730 new.packed_offset = .{
3731 .host_size = 0,
3732 .bit_offset = 0,
3733 };
3734 new.flags.alignment = ptr_info.alignment;
3735 break :info new;
3736 });
3737 return parent_ptr.getOffsetPtr(ptr_info.offset, result_ty, zcu);
3738 },
3739 },
3740 }
3741 },
3742 .Union => field: {
3743 const union_obj = zcu.typeToUnion(aggregate_ty).?;
3744 const field_ty = Type.fromInterned(union_obj.field_types.get(&zcu.intern_pool)[field_idx]);
3745 switch (aggregate_ty.containerLayout(zcu)) {
3746 .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, sema) },
3747 .@"extern" => {
3748 // Point to the same address.
3749 const result_ty = try sema.ptrType(info: {
3750 var new = parent_ptr_info;
3751 new.child = field_ty.toIntern();
3752 break :info new;
3753 });
3754 return zcu.getCoerced(parent_ptr, result_ty);
3755 },
3756 .@"packed" => {
3757 // If the field has an ABI size matching its bit size, then we can continue to use a
3758 // non-bit pointer if the parent pointer is also a non-bit pointer.
3759 if (parent_ptr_info.packed_offset.host_size == 0 and try sema.typeAbiSize(field_ty) * 8 == try field_ty.bitSizeAdvanced(zcu, sema)) {
3760 // We must offset the pointer on big-endian targets, since the bits of packed memory don't align nicely.
3761 const byte_offset = switch (zcu.getTarget().cpu.arch.endian()) {
3762 .little => 0,
3763 .big => try sema.typeAbiSize(aggregate_ty) - try sema.typeAbiSize(field_ty),
3764 };
3765 const result_ty = try sema.ptrType(info: {
3766 var new = parent_ptr_info;
3767 new.child = field_ty.toIntern();
3768 new.flags.alignment = InternPool.Alignment.fromLog2Units(
3769 @ctz(byte_offset | (try parent_ptr_ty.ptrAlignmentAdvanced(zcu, sema)).toByteUnits().?),
3770 );
3771 break :info new;
3772 });
3773 return parent_ptr.getOffsetPtr(byte_offset, result_ty, zcu);
3774 } else {
3775 // The result must be a bit-pointer if it is not already.
3776 const result_ty = try sema.ptrType(info: {
3777 var new = parent_ptr_info;
3778 new.child = field_ty.toIntern();
3779 if (new.packed_offset.host_size == 0) {
3780 new.packed_offset.host_size = @intCast(((try aggregate_ty.bitSizeAdvanced(zcu, sema)) + 7) / 8);
3781 assert(new.packed_offset.bit_offset == 0);
3782 }
3783 break :info new;
3784 });
3785 return zcu.getCoerced(parent_ptr, result_ty);
3786 }
3787 },
3788 }
3789 },
3790 .Pointer => field_ty: {
3791 assert(aggregate_ty.isSlice(zcu));
3792 break :field_ty switch (field_idx) {
3793 Value.slice_ptr_index => .{ aggregate_ty.slicePtrFieldType(zcu), Type.usize.abiAlignment(zcu) },
3794 Value.slice_len_index => .{ Type.usize, Type.usize.abiAlignment(zcu) },
3795 else => unreachable,
3796 };
3797 },
3798 else => unreachable,
3799 };
3800
3801 const new_align: InternPool.Alignment = if (parent_ptr_info.flags.alignment != .none) a: {
3802 const ty_align = try sema.typeAbiAlignment(field_ty);
3803 const true_field_align = if (field_align == .none) ty_align else field_align;
3804 const new_align = true_field_align.min(parent_ptr_info.flags.alignment);
3805 if (new_align == ty_align) break :a .none;
3806 break :a new_align;
3807 } else field_align;
3808
3809 const result_ty = try sema.ptrType(info: {
3810 var new = parent_ptr_info;
3811 new.child = field_ty.toIntern();
3812 new.flags.alignment = new_align;
3813 break :info new;
3814 });
3815
3816 if (parent_ptr.isUndef(zcu)) return zcu.undefValue(result_ty);
3817
3818 const base_ptr = try parent_ptr.canonicalizeBasePtr(.One, aggregate_ty, zcu);
3819 return Value.fromInterned(try zcu.intern(.{ .ptr = .{
3820 .ty = result_ty.toIntern(),
3821 .base_addr = .{ .field = .{
3822 .base = base_ptr.toIntern(),
3823 .index = field_idx,
3824 } },
3825 .byte_offset = 0,
3826 } }));
3827}
3828
3829/// `orig_parent_ptr` must be either a single-pointer to an array or vector, or a many-pointer or C-pointer or slice.
3830/// Returns a pointer to the element at the specified index.
3831/// This takes a `Sema` because it may need to perform type resolution.
3832pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, sema: *Sema) !Value {
3833 const zcu = sema.mod;
3834
3835 const parent_ptr = switch (orig_parent_ptr.typeOf(zcu).ptrSize(zcu)) {
3836 .One, .Many, .C => orig_parent_ptr,
3837 .Slice => orig_parent_ptr.slicePtr(zcu),
3838 };
3839
3840 const parent_ptr_ty = parent_ptr.typeOf(zcu);
3841 const elem_ty = parent_ptr_ty.childType(zcu);
3842 const result_ty = try sema.elemPtrType(parent_ptr_ty, @intCast(field_idx));
3843
3844 if (parent_ptr.isUndef(zcu)) return zcu.undefValue(result_ty);
3845
3846 if (result_ty.ptrInfo(zcu).packed_offset.host_size != 0) {
3847 // Since we have a bit-pointer, the pointer address should be unchanged.
3848 assert(elem_ty.zigTypeTag(zcu) == .Vector);
3849 return zcu.getCoerced(parent_ptr, result_ty);
3850 }
3851
3852 const PtrStrat = union(enum) {
3853 offset: u64,
3854 elem_ptr: Type, // many-ptr elem ty
3855 };
3856
3857 const strat: PtrStrat = switch (parent_ptr_ty.ptrSize(zcu)) {
3858 .One => switch (elem_ty.zigTypeTag(zcu)) {
3859 .Vector => .{ .offset = field_idx * @divExact(try elem_ty.childType(zcu).bitSizeAdvanced(zcu, sema), 8) },
3860 .Array => strat: {
3861 const arr_elem_ty = elem_ty.childType(zcu);
3862 if (try sema.typeRequiresComptime(arr_elem_ty)) {
3863 break :strat .{ .elem_ptr = arr_elem_ty };
3864 }
3865 break :strat .{ .offset = field_idx * try sema.typeAbiSize(arr_elem_ty) };
3866 },
3867 else => unreachable,
3868 },
3869
3870 .Many, .C => if (try sema.typeRequiresComptime(elem_ty))
3871 .{ .elem_ptr = elem_ty }
3872 else
3873 .{ .offset = field_idx * try sema.typeAbiSize(elem_ty) },
3874
3875 .Slice => unreachable,
3876 };
3877
3878 switch (strat) {
3879 .offset => |byte_offset| {
3880 return parent_ptr.getOffsetPtr(byte_offset, result_ty, zcu);
3881 },
3882 .elem_ptr => |manyptr_elem_ty| if (field_idx == 0) {
3883 return zcu.getCoerced(parent_ptr, result_ty);
3884 } else {
3885 const arr_base_ty, const arr_base_len = manyptr_elem_ty.arrayBase(zcu);
3886 const base_idx = arr_base_len * field_idx;
3887 const parent_info = zcu.intern_pool.indexToKey(parent_ptr.toIntern()).ptr;
3888 switch (parent_info.base_addr) {
3889 .arr_elem => |arr_elem| {
3890 if (Value.fromInterned(arr_elem.base).typeOf(zcu).childType(zcu).toIntern() == arr_base_ty.toIntern()) {
3891 // We already have a pointer to an element of an array of this type.
3892 // Just modify the index.
3893 return Value.fromInterned(try zcu.intern(.{ .ptr = ptr: {
3894 var new = parent_info;
3895 new.base_addr.arr_elem.index += base_idx;
3896 new.ty = result_ty.toIntern();
3897 break :ptr new;
3898 } }));
3899 }
3900 },
3901 else => {},
3902 }
3903 const base_ptr = try parent_ptr.canonicalizeBasePtr(.Many, arr_base_ty, zcu);
3904 return Value.fromInterned(try zcu.intern(.{ .ptr = .{
3905 .ty = result_ty.toIntern(),
3906 .base_addr = .{ .arr_elem = .{
3907 .base = base_ptr.toIntern(),
3908 .index = base_idx,
3909 } },
3910 .byte_offset = 0,
3911 } }));
3912 },
3913 }
3914}
3915
3916fn canonicalizeBasePtr(base_ptr: Value, want_size: std.builtin.Type.Pointer.Size, want_child: Type, zcu: *Zcu) !Value {
3917 const ptr_ty = base_ptr.typeOf(zcu);
3918 const ptr_info = ptr_ty.ptrInfo(zcu);
3919
3920 if (ptr_info.flags.size == want_size and
3921 ptr_info.child == want_child.toIntern() and
3922 !ptr_info.flags.is_const and
3923 !ptr_info.flags.is_volatile and
3924 !ptr_info.flags.is_allowzero and
3925 ptr_info.sentinel == .none and
3926 ptr_info.flags.alignment == .none)
3927 {
3928 // Already canonical!
3929 return base_ptr;
3930 }
3931
3932 const new_ty = try zcu.ptrType(.{
3933 .child = want_child.toIntern(),
3934 .sentinel = .none,
3935 .flags = .{
3936 .size = want_size,
3937 .alignment = .none,
3938 .is_const = false,
3939 .is_volatile = false,
3940 .is_allowzero = false,
3941 .address_space = ptr_info.flags.address_space,
3942 },
3943 });
3944 return zcu.getCoerced(base_ptr, new_ty);
3945}
3946
3947pub fn getOffsetPtr(ptr_val: Value, byte_off: u64, new_ty: Type, zcu: *Zcu) !Value {
3948 if (ptr_val.isUndef(zcu)) return ptr_val;
3949 var ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
3950 ptr.ty = new_ty.toIntern();
3951 ptr.byte_offset += byte_off;
3952 return Value.fromInterned(try zcu.intern(.{ .ptr = ptr }));
3953}
3954
3955pub const PointerDeriveStep = union(enum) {
3956 int: struct {
3957 addr: u64,
3958 ptr_ty: Type,
3959 },
3960 decl_ptr: InternPool.DeclIndex,
3961 anon_decl_ptr: InternPool.Key.Ptr.BaseAddr.AnonDecl,
3962 comptime_alloc_ptr: struct {
3963 val: Value,
3964 ptr_ty: Type,
3965 },
3966 comptime_field_ptr: Value,
3967 eu_payload_ptr: struct {
3968 parent: *PointerDeriveStep,
3969 /// This type will never be cast: it is provided for convenience.
3970 result_ptr_ty: Type,
3971 },
3972 opt_payload_ptr: struct {
3973 parent: *PointerDeriveStep,
3974 /// This type will never be cast: it is provided for convenience.
3975 result_ptr_ty: Type,
3976 },
3977 field_ptr: struct {
3978 parent: *PointerDeriveStep,
3979 field_idx: u32,
3980 /// This type will never be cast: it is provided for convenience.
3981 result_ptr_ty: Type,
3982 },
3983 elem_ptr: struct {
3984 parent: *PointerDeriveStep,
3985 elem_idx: u64,
3986 /// This type will never be cast: it is provided for convenience.
3987 result_ptr_ty: Type,
3988 },
3989 offset_and_cast: struct {
3990 parent: *PointerDeriveStep,
3991 byte_offset: u64,
3992 new_ptr_ty: Type,
3993 },
3994
3995 pub fn ptrType(step: PointerDeriveStep, zcu: *Zcu) !Type {
3996 return switch (step) {
3997 .int => |int| int.ptr_ty,
3998 .decl_ptr => |decl| try zcu.declPtr(decl).declPtrType(zcu),
3999 .anon_decl_ptr => |ad| Type.fromInterned(ad.orig_ty),
4000 .comptime_alloc_ptr => |info| info.ptr_ty,
4001 .comptime_field_ptr => |val| try zcu.singleConstPtrType(val.typeOf(zcu)),
4002 .offset_and_cast => |oac| oac.new_ptr_ty,
4003 inline .eu_payload_ptr, .opt_payload_ptr, .field_ptr, .elem_ptr => |x| x.result_ptr_ty,
4004 };
4005 }
4006};
4007
4008pub fn pointerDerivation(ptr_val: Value, arena: Allocator, zcu: *Zcu) Allocator.Error!PointerDeriveStep {
4009 return ptr_val.pointerDerivationAdvanced(arena, zcu, null) catch |err| switch (err) {
4010 error.OutOfMemory => |e| return e,
4011 error.AnalysisFail,
4012 error.NeededSourceLocation,
4013 error.GenericPoison,
4014 error.ComptimeReturn,
4015 error.ComptimeBreak,
4016 => unreachable,
4017 };
4018}
4019
4020/// Given a pointer value, get the sequence of steps to derive it, ideally by taking
4021/// only field and element pointers with no casts. This can be used by codegen backends
4022/// which prefer field/elem accesses when lowering constant pointer values.
4023/// It is also used by the Value printing logic for pointers.
4024pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, zcu: *Zcu, opt_sema: ?*Sema) !PointerDeriveStep {
4025 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
4026 const base_derive: PointerDeriveStep = switch (ptr.base_addr) {
4027 .int => return .{ .int = .{
4028 .addr = ptr.byte_offset,
4029 .ptr_ty = Type.fromInterned(ptr.ty),
4030 } },
4031 .decl => |decl| .{ .decl_ptr = decl },
4032 .anon_decl => |ad| base: {
4033 // A slight tweak: `orig_ty` here is sometimes not `const`, but it ought to be.
4034 // TODO: fix this in the sites interning anon decls!
4035 const const_ty = try zcu.ptrType(info: {
4036 var info = Type.fromInterned(ad.orig_ty).ptrInfo(zcu);
4037 info.flags.is_const = true;
4038 break :info info;
4039 });
4040 break :base .{ .anon_decl_ptr = .{
4041 .val = ad.val,
4042 .orig_ty = const_ty.toIntern(),
4043 } };
4044 },
4045 .comptime_alloc => |idx| base: {
4046 const alloc = opt_sema.?.getComptimeAlloc(idx);
4047 const val = try alloc.val.intern(zcu, opt_sema.?.arena);
4048 const ty = val.typeOf(zcu);
4049 break :base .{ .comptime_alloc_ptr = .{
4050 .val = val,
4051 .ptr_ty = try zcu.ptrType(.{
4052 .child = ty.toIntern(),
4053 .flags = .{
4054 .alignment = alloc.alignment,
4055 },
4056 }),
4057 } };
4058 },
4059 .comptime_field => |val| .{ .comptime_field_ptr = Value.fromInterned(val) },
4060 .eu_payload => |eu_ptr| base: {
4061 const base_ptr = Value.fromInterned(eu_ptr);
4062 const base_ptr_ty = base_ptr.typeOf(zcu);
4063 const parent_step = try arena.create(PointerDeriveStep);
4064 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(eu_ptr), arena, zcu, opt_sema);
4065 break :base .{ .eu_payload_ptr = .{
4066 .parent = parent_step,
4067 .result_ptr_ty = try zcu.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).errorUnionPayload(zcu)),
4068 } };
4069 },
4070 .opt_payload => |opt_ptr| base: {
4071 const base_ptr = Value.fromInterned(opt_ptr);
4072 const base_ptr_ty = base_ptr.typeOf(zcu);
4073 const parent_step = try arena.create(PointerDeriveStep);
4074 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(opt_ptr), arena, zcu, opt_sema);
4075 break :base .{ .opt_payload_ptr = .{
4076 .parent = parent_step,
4077 .result_ptr_ty = try zcu.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).optionalChild(zcu)),
4078 } };
4079 },
4080 .field => |field| base: {
4081 const base_ptr = Value.fromInterned(field.base);
4082 const base_ptr_ty = base_ptr.typeOf(zcu);
4083 const agg_ty = base_ptr_ty.childType(zcu);
4084 const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) {
4085 .Struct => .{ agg_ty.structFieldType(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, opt_sema) },
4086 .Union => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, opt_sema) },
4087 .Pointer => .{ switch (field.index) {
4088 Value.slice_ptr_index => agg_ty.slicePtrFieldType(zcu),
4089 Value.slice_len_index => Type.usize,
4090 else => unreachable,
4091 }, Type.usize.abiAlignment(zcu) },
4092 else => unreachable,
4093 };
4094 const base_align = base_ptr_ty.ptrAlignment(zcu);
4095 const result_align = field_align.minStrict(base_align);
4096 const result_ty = try zcu.ptrType(.{
4097 .child = field_ty.toIntern(),
4098 .flags = flags: {
4099 var flags = base_ptr_ty.ptrInfo(zcu).flags;
4100 if (result_align == field_ty.abiAlignment(zcu)) {
4101 flags.alignment = .none;
4102 } else {
4103 flags.alignment = result_align;
4104 }
4105 break :flags flags;
4106 },
4107 });
4108 const parent_step = try arena.create(PointerDeriveStep);
4109 parent_step.* = try pointerDerivationAdvanced(base_ptr, arena, zcu, opt_sema);
4110 break :base .{ .field_ptr = .{
4111 .parent = parent_step,
4112 .field_idx = @intCast(field.index),
4113 .result_ptr_ty = result_ty,
4114 } };
4115 },
4116 .arr_elem => |arr_elem| base: {
4117 const parent_step = try arena.create(PointerDeriveStep);
4118 parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(arr_elem.base), arena, zcu, opt_sema);
4119 const parent_ptr_info = (try parent_step.ptrType(zcu)).ptrInfo(zcu);
4120 const result_ptr_ty = try zcu.ptrType(.{
4121 .child = parent_ptr_info.child,
4122 .flags = flags: {
4123 var flags = parent_ptr_info.flags;
4124 flags.size = .One;
4125 break :flags flags;
4126 },
4127 });
4128 break :base .{ .elem_ptr = .{
4129 .parent = parent_step,
4130 .elem_idx = arr_elem.index,
4131 .result_ptr_ty = result_ptr_ty,
4132 } };
4133 },
4134 };
4135
4136 if (ptr.byte_offset == 0 and ptr.ty == (try base_derive.ptrType(zcu)).toIntern()) {
4137 return base_derive;
4138 }
4139
4140 const need_child = Type.fromInterned(ptr.ty).childType(zcu);
4141 if (need_child.comptimeOnly(zcu)) {
4142 // No refinement can happen - this pointer is presumably invalid.
4143 // Just offset it.
4144 const parent = try arena.create(PointerDeriveStep);
4145 parent.* = base_derive;
4146 return .{ .offset_and_cast = .{
4147 .parent = parent,
4148 .byte_offset = ptr.byte_offset,
4149 .new_ptr_ty = Type.fromInterned(ptr.ty),
4150 } };
4151 }
4152 const need_bytes = need_child.abiSize(zcu);
4153
4154 var cur_derive = base_derive;
4155 var cur_offset = ptr.byte_offset;
4156
4157 // Refine through fields and array elements as much as possible.
4158
4159 if (need_bytes > 0) while (true) {
4160 const cur_ty = (try cur_derive.ptrType(zcu)).childType(zcu);
4161 if (cur_ty.toIntern() == need_child.toIntern() and cur_offset == 0) {
4162 break;
4163 }
4164 switch (cur_ty.zigTypeTag(zcu)) {
4165 .NoReturn,
4166 .Type,
4167 .ComptimeInt,
4168 .ComptimeFloat,
4169 .Null,
4170 .Undefined,
4171 .EnumLiteral,
4172 .Opaque,
4173 .Fn,
4174 .ErrorUnion,
4175 .Int,
4176 .Float,
4177 .Bool,
4178 .Void,
4179 .Pointer,
4180 .ErrorSet,
4181 .AnyFrame,
4182 .Frame,
4183 .Enum,
4184 .Vector,
4185 .Optional,
4186 .Union,
4187 => break,
4188
4189 .Array => {
4190 const elem_ty = cur_ty.childType(zcu);
4191 const elem_size = elem_ty.abiSize(zcu);
4192 const start_idx = cur_offset / elem_size;
4193 const end_idx = (cur_offset + need_bytes + elem_size - 1) / elem_size;
4194 if (end_idx == start_idx + 1) {
4195 const parent = try arena.create(PointerDeriveStep);
4196 parent.* = cur_derive;
4197 cur_derive = .{ .elem_ptr = .{
4198 .parent = parent,
4199 .elem_idx = start_idx,
4200 .result_ptr_ty = try zcu.adjustPtrTypeChild(try parent.ptrType(zcu), elem_ty),
4201 } };
4202 cur_offset -= start_idx * elem_size;
4203 } else {
4204 // Go into the first element if needed, but don't go any deeper.
4205 if (start_idx > 0) {
4206 const parent = try arena.create(PointerDeriveStep);
4207 parent.* = cur_derive;
4208 cur_derive = .{ .elem_ptr = .{
4209 .parent = parent,
4210 .elem_idx = start_idx,
4211 .result_ptr_ty = try zcu.adjustPtrTypeChild(try parent.ptrType(zcu), elem_ty),
4212 } };
4213 cur_offset -= start_idx * elem_size;
4214 }
4215 break;
4216 }
4217 },
4218 .Struct => switch (cur_ty.containerLayout(zcu)) {
4219 .auto, .@"packed" => break,
4220 .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| {
4221 const field_ty = cur_ty.structFieldType(field_idx, zcu);
4222 const start_off = cur_ty.structFieldOffset(field_idx, zcu);
4223 const end_off = start_off + field_ty.abiSize(zcu);
4224 if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {
4225 const old_ptr_ty = try cur_derive.ptrType(zcu);
4226 const parent_align = old_ptr_ty.ptrAlignment(zcu);
4227 const field_align = InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(start_off)));
4228 const parent = try arena.create(PointerDeriveStep);
4229 parent.* = cur_derive;
4230 const new_ptr_ty = try zcu.ptrType(.{
4231 .child = field_ty.toIntern(),
4232 .flags = flags: {
4233 var flags = old_ptr_ty.ptrInfo(zcu).flags;
4234 if (field_align == field_ty.abiAlignment(zcu)) {
4235 flags.alignment = .none;
4236 } else {
4237 flags.alignment = field_align;
4238 }
4239 break :flags flags;
4240 },
4241 });
4242 cur_derive = .{ .field_ptr = .{
4243 .parent = parent,
4244 .field_idx = @intCast(field_idx),
4245 .result_ptr_ty = new_ptr_ty,
4246 } };
4247 cur_offset -= start_off;
4248 break;
4249 }
4250 } else break, // pointer spans multiple fields
4251 },
4252 }
4253 };
4254
4255 if (cur_offset == 0 and (try cur_derive.ptrType(zcu)).toIntern() == ptr.ty) {
4256 return cur_derive;
4257 }
4258
4259 const parent = try arena.create(PointerDeriveStep);
4260 parent.* = cur_derive;
4261 return .{ .offset_and_cast = .{
4262 .parent = parent,
4263 .byte_offset = cur_offset,
4264 .new_ptr_ty = Type.fromInterned(ptr.ty),
4265 } };
4266}
src/arch/wasm/CodeGen.zig+53-70
......@@ -2206,7 +2206,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
22062206 );
22072207 break :blk extern_func.decl;
22082208 } else switch (mod.intern_pool.indexToKey(func_val.ip_index)) {
2209 .ptr => |ptr| switch (ptr.addr) {
2209 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
22102210 .decl => |decl| {
22112211 _ = try func.bin_file.getOrCreateAtomForDecl(decl);
22122212 break :blk decl;
......@@ -3058,72 +3058,59 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
30583058 return WValue{ .stack = {} };
30593059}
30603060
3061fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue {
3062 const mod = func.bin_file.base.comp.module.?;
3063 const ptr = mod.intern_pool.indexToKey(ptr_val.ip_index).ptr;
3064 switch (ptr.addr) {
3065 .decl => |decl_index| {
3066 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
3067 },
3068 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, offset),
3069 .eu_payload => |tag| return func.fail("TODO: Implement lowerParentPtr for {}", .{tag}),
3070 .int => |base| return func.lowerConstant(Value.fromInterned(base), Type.usize),
3071 .opt_payload => |base_ptr| return func.lowerParentPtr(Value.fromInterned(base_ptr), offset),
3072 .comptime_field, .comptime_alloc => unreachable,
3073 .elem => |elem| {
3074 const index = elem.index;
3075 const elem_type = Type.fromInterned(mod.intern_pool.typeOf(elem.base)).elemType2(mod);
3076 const elem_offset = index * elem_type.abiSize(mod);
3077 return func.lowerParentPtr(Value.fromInterned(elem.base), @as(u32, @intCast(elem_offset + offset)));
3078 },
3061fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {
3062 const zcu = func.bin_file.base.comp.module.?;
3063 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
3064 const offset: u64 = prev_offset + ptr.byte_offset;
3065 return switch (ptr.base_addr) {
3066 .decl => |decl| return func.lowerDeclRefValue(decl, @intCast(offset)),
3067 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, @intCast(offset)),
3068 .int => return func.lowerConstant(try zcu.intValue(Type.usize, offset), Type.usize),
3069 .eu_payload => return func.fail("Wasm TODO: lower error union payload pointer", .{}),
3070 .opt_payload => |opt_ptr| return func.lowerPtr(opt_ptr, offset),
30793071 .field => |field| {
3080 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(field.base));
3081 const parent_ty = parent_ptr_ty.childType(mod);
3082 const field_index: u32 = @intCast(field.index);
3083
3084 const field_offset = switch (parent_ty.zigTypeTag(mod)) {
3085 .Struct => blk: {
3086 if (mod.typeToPackedStruct(parent_ty)) |struct_type| {
3087 if (Type.fromInterned(ptr.ty).ptrInfo(mod).packed_offset.host_size == 0)
3088 break :blk @divExact(mod.structPackedFieldBitOffset(struct_type, field_index) + parent_ptr_ty.ptrInfo(mod).packed_offset.bit_offset, 8)
3089 else
3090 break :blk 0;
3091 }
3092 break :blk parent_ty.structFieldOffset(field_index, mod);
3072 const base_ptr = Value.fromInterned(field.base);
3073 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
3074 const field_off: u64 = switch (base_ty.zigTypeTag(zcu)) {
3075 .Pointer => off: {
3076 assert(base_ty.isSlice(zcu));
3077 break :off switch (field.index) {
3078 Value.slice_ptr_index => 0,
3079 Value.slice_len_index => @divExact(zcu.getTarget().ptrBitWidth(), 8),
3080 else => unreachable,
3081 };
30933082 },
3094 .Union => switch (parent_ty.containerLayout(mod)) {
3095 .@"packed" => 0,
3096 else => blk: {
3097 const layout: Module.UnionLayout = parent_ty.unionGetLayout(mod);
3098 if (layout.payload_size == 0) break :blk 0;
3099 if (layout.payload_align.compare(.gt, layout.tag_align)) break :blk 0;
3100
3101 // tag is stored first so calculate offset from where payload starts
3102 break :blk layout.tag_align.forward(layout.tag_size);
3103 },
3083 .Struct => switch (base_ty.containerLayout(zcu)) {
3084 .auto => base_ty.structFieldOffset(@intCast(field.index), zcu),
3085 .@"extern", .@"packed" => unreachable,
31043086 },
3105 .Pointer => switch (parent_ty.ptrSize(mod)) {
3106 .Slice => switch (field.index) {
3107 0 => 0,
3108 1 => func.ptrSize(),
3109 else => unreachable,
3087 .Union => switch (base_ty.containerLayout(zcu)) {
3088 .auto => off: {
3089 // Keep in sync with the `un` case of `generateSymbol`.
3090 const layout = base_ty.unionGetLayout(zcu);
3091 if (layout.payload_size == 0) break :off 0;
3092 if (layout.tag_size == 0) break :off 0;
3093 if (layout.tag_align.compare(.gte, layout.payload_align)) {
3094 // Tag first.
3095 break :off layout.tag_size;
3096 } else {
3097 // Payload first.
3098 break :off 0;
3099 }
31103100 },
3111 else => unreachable,
3101 .@"extern", .@"packed" => unreachable,
31123102 },
31133103 else => unreachable,
31143104 };
3115 return func.lowerParentPtr(Value.fromInterned(field.base), @as(u32, @intCast(offset + field_offset)));
3105 return func.lowerPtr(field.base, offset + field_off);
31163106 },
3117 }
3118}
3119
3120fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue {
3121 return func.lowerDeclRefValue(ptr_val, decl_index, offset);
3107 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
3108 };
31223109}
31233110
31243111fn lowerAnonDeclRef(
31253112 func: *CodeGen,
3126 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
3113 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
31273114 offset: u32,
31283115) InnerError!WValue {
31293116 const mod = func.bin_file.base.comp.module.?;
......@@ -3153,7 +3140,7 @@ fn lowerAnonDeclRef(
31533140 } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } };
31543141}
31553142
3156fn lowerDeclRefValue(func: *CodeGen, val: Value, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue {
3143fn lowerDeclRefValue(func: *CodeGen, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue {
31573144 const mod = func.bin_file.base.comp.module.?;
31583145
31593146 const decl = mod.declPtr(decl_index);
......@@ -3161,11 +3148,11 @@ fn lowerDeclRefValue(func: *CodeGen, val: Value, decl_index: InternPool.DeclInde
31613148 // want to lower the actual decl, rather than the alias itself.
31623149 if (decl.val.getFunction(mod)) |func_val| {
31633150 if (func_val.owner_decl != decl_index) {
3164 return func.lowerDeclRefValue(val, func_val.owner_decl, offset);
3151 return func.lowerDeclRefValue(func_val.owner_decl, offset);
31653152 }
31663153 } else if (decl.val.getExternFunc(mod)) |func_val| {
31673154 if (func_val.decl != decl_index) {
3168 return func.lowerDeclRefValue(val, func_val.decl, offset);
3155 return func.lowerDeclRefValue(func_val.decl, offset);
31693156 }
31703157 }
31713158 const decl_ty = decl.typeOf(mod);
......@@ -3309,23 +3296,16 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
33093296 },
33103297 .slice => |slice| {
33113298 var ptr = ip.indexToKey(slice.ptr).ptr;
3312 const owner_decl = while (true) switch (ptr.addr) {
3299 const owner_decl = while (true) switch (ptr.base_addr) {
33133300 .decl => |decl| break decl,
33143301 .int, .anon_decl => return func.fail("Wasm TODO: lower slice where ptr is not owned by decl", .{}),
33153302 .opt_payload, .eu_payload => |base| ptr = ip.indexToKey(base).ptr,
3316 .elem, .field => |base_index| ptr = ip.indexToKey(base_index.base).ptr,
3317 .comptime_field, .comptime_alloc => unreachable,
3303 .field => |base_index| ptr = ip.indexToKey(base_index.base).ptr,
3304 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
33183305 };
33193306 return .{ .memory = try func.bin_file.lowerUnnamedConst(val, owner_decl) };
33203307 },
3321 .ptr => |ptr| switch (ptr.addr) {
3322 .decl => |decl| return func.lowerDeclRefValue(val, decl, 0),
3323 .int => |int| return func.lowerConstant(Value.fromInterned(int), Type.fromInterned(ip.typeOf(int))),
3324 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),
3325 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0),
3326 .comptime_field, .comptime_alloc => unreachable,
3327 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),
3328 },
3308 .ptr => return func.lowerPtr(val.toIntern(), 0),
33293309 .opt => if (ty.optionalReprIsPayload(mod)) {
33303310 const pl_ty = ty.optionalChild(mod);
33313311 if (val.optionalValue(mod)) |payload| {
......@@ -3435,7 +3415,10 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 {
34353415 else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {
34363416 .enum_tag => |enum_tag| intIndexAsI32(&mod.intern_pool, enum_tag.int, mod),
34373417 .int => |int| intStorageAsI32(int.storage, mod),
3438 .ptr => |ptr| intIndexAsI32(&mod.intern_pool, ptr.addr.int, mod),
3418 .ptr => |ptr| {
3419 assert(ptr.base_addr == .int);
3420 return @intCast(ptr.byte_offset);
3421 },
34393422 .err => |err| @as(i32, @bitCast(@as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(err.name).?)))),
34403423 else => unreachable,
34413424 },
src/arch/x86_64/CodeGen.zig+4-4
......@@ -12249,10 +12249,10 @@ fn genCall(self: *Self, info: union(enum) {
1224912249 const func_key = mod.intern_pool.indexToKey(func_value.ip_index);
1225012250 switch (switch (func_key) {
1225112251 else => func_key,
12252 .ptr => |ptr| switch (ptr.addr) {
12252 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
1225312253 .decl => |decl| mod.intern_pool.indexToKey(mod.declPtr(decl).val.toIntern()),
1225412254 else => func_key,
12255 },
12255 } else func_key,
1225612256 }) {
1225712257 .func => |func| {
1225812258 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
......@@ -17877,8 +17877,8 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
1787717877
1787817878 break :result null;
1787917879 }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{
17880 lhs_ty.fmt(mod), rhs_ty.fmt(mod), dst_ty.fmt(mod),
17881 Value.fromInterned(extra.mask).fmtValue(mod),
17880 lhs_ty.fmt(mod), rhs_ty.fmt(mod), dst_ty.fmt(mod),
17881 Value.fromInterned(extra.mask).fmtValue(mod, null),
1788217882 });
1788317883 return self.finishAir(inst, result, .{ extra.a, extra.b, .none });
1788417884}
src/codegen.zig+52-82
......@@ -16,7 +16,8 @@ const Compilation = @import("Compilation.zig");
1616const ErrorMsg = Module.ErrorMsg;
1717const InternPool = @import("InternPool.zig");
1818const Liveness = @import("Liveness.zig");
19const Module = @import("Module.zig");
19const Zcu = @import("Module.zig");
20const Module = Zcu;
2021const Target = std.Target;
2122const Type = @import("type.zig").Type;
2223const Value = @import("Value.zig");
......@@ -185,7 +186,7 @@ pub fn generateSymbol(
185186 const target = mod.getTarget();
186187 const endian = target.cpu.arch.endian();
187188
188 log.debug("generateSymbol: val = {}", .{val.fmtValue(mod)});
189 log.debug("generateSymbol: val = {}", .{val.fmtValue(mod, null)});
189190
190191 if (val.isUndefDeep(mod)) {
191192 const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow;
......@@ -314,7 +315,7 @@ pub fn generateSymbol(
314315 },
315316 .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(16)),
316317 },
317 .ptr => switch (try lowerParentPtr(bin_file, src_loc, val.toIntern(), code, debug_output, reloc_info)) {
318 .ptr => switch (try lowerPtr(bin_file, src_loc, val.toIntern(), code, debug_output, reloc_info, 0)) {
318319 .ok => {},
319320 .fail => |em| return .{ .fail = em },
320321 },
......@@ -614,111 +615,79 @@ pub fn generateSymbol(
614615 return .ok;
615616}
616617
617fn lowerParentPtr(
618fn lowerPtr(
618619 bin_file: *link.File,
619620 src_loc: Module.SrcLoc,
620 parent_ptr: InternPool.Index,
621 ptr_val: InternPool.Index,
621622 code: *std.ArrayList(u8),
622623 debug_output: DebugInfoOutput,
623624 reloc_info: RelocInfo,
625 prev_offset: u64,
624626) CodeGenError!Result {
625 const mod = bin_file.comp.module.?;
626 const ip = &mod.intern_pool;
627 const ptr = ip.indexToKey(parent_ptr).ptr;
628 return switch (ptr.addr) {
629 .decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info),
630 .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info),
631 .int => |int| try generateSymbol(bin_file, src_loc, Value.fromInterned(int), code, debug_output, reloc_info),
632 .eu_payload => |eu_payload| try lowerParentPtr(
627 const zcu = bin_file.comp.module.?;
628 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
629 const offset: u64 = prev_offset + ptr.byte_offset;
630 return switch (ptr.base_addr) {
631 .decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info, offset),
632 .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info, offset),
633 .int => try generateSymbol(bin_file, src_loc, try zcu.intValue(Type.usize, offset), code, debug_output, reloc_info),
634 .eu_payload => |eu_ptr| try lowerPtr(
633635 bin_file,
634636 src_loc,
635 eu_payload,
636 code,
637 debug_output,
638 reloc_info.offset(@intCast(errUnionPayloadOffset(
639 Type.fromInterned(ip.typeOf(eu_payload)),
640 mod,
641 ))),
642 ),
643 .opt_payload => |opt_payload| try lowerParentPtr(
644 bin_file,
645 src_loc,
646 opt_payload,
637 eu_ptr,
647638 code,
648639 debug_output,
649640 reloc_info,
641 offset + errUnionPayloadOffset(
642 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu).errorUnionPayload(zcu),
643 zcu,
644 ),
650645 ),
651 .elem => |elem| try lowerParentPtr(
646 .opt_payload => |opt_ptr| try lowerPtr(
652647 bin_file,
653648 src_loc,
654 elem.base,
649 opt_ptr,
655650 code,
656651 debug_output,
657 reloc_info.offset(@intCast(elem.index *
658 Type.fromInterned(ip.typeOf(elem.base)).elemType2(mod).abiSize(mod))),
652 reloc_info,
653 offset,
659654 ),
660655 .field => |field| {
661 const base_ptr_ty = ip.typeOf(field.base);
662 const base_ty = ip.indexToKey(base_ptr_ty).ptr_type.child;
663 return lowerParentPtr(
664 bin_file,
665 src_loc,
666 field.base,
667 code,
668 debug_output,
669 reloc_info.offset(switch (ip.indexToKey(base_ty)) {
670 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
671 .One, .Many, .C => unreachable,
672 .Slice => switch (field.index) {
673 0 => 0,
674 1 => @divExact(mod.getTarget().ptrBitWidth(), 8),
675 else => unreachable,
676 },
677 },
678 .struct_type,
679 .anon_struct_type,
680 .union_type,
681 => switch (Type.fromInterned(base_ty).containerLayout(mod)) {
682 .auto, .@"extern" => @intCast(Type.fromInterned(base_ty).structFieldOffset(
683 @intCast(field.index),
684 mod,
685 )),
686 .@"packed" => if (mod.typeToStruct(Type.fromInterned(base_ty))) |struct_obj|
687 if (Type.fromInterned(ptr.ty).ptrInfo(mod).packed_offset.host_size == 0)
688 @divExact(Type.fromInterned(base_ptr_ty).ptrInfo(mod)
689 .packed_offset.bit_offset + mod.structPackedFieldBitOffset(
690 struct_obj,
691 @intCast(field.index),
692 ), 8)
693 else
694 0
695 else
696 0,
697 },
698 else => unreachable,
699 }),
700 );
656 const base_ptr = Value.fromInterned(field.base);
657 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
658 const field_off: u64 = switch (base_ty.zigTypeTag(zcu)) {
659 .Pointer => off: {
660 assert(base_ty.isSlice(zcu));
661 break :off switch (field.index) {
662 Value.slice_ptr_index => 0,
663 Value.slice_len_index => @divExact(zcu.getTarget().ptrBitWidth(), 8),
664 else => unreachable,
665 };
666 },
667 .Struct, .Union => switch (base_ty.containerLayout(zcu)) {
668 .auto => base_ty.structFieldOffset(@intCast(field.index), zcu),
669 .@"extern", .@"packed" => unreachable,
670 },
671 else => unreachable,
672 };
673 return lowerPtr(bin_file, src_loc, field.base, code, debug_output, reloc_info, offset + field_off);
701674 },
702 .comptime_field, .comptime_alloc => unreachable,
675 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
703676 };
704677}
705678
706679const RelocInfo = struct {
707680 parent_atom_index: u32,
708 addend: ?u32 = null,
709
710 fn offset(ri: RelocInfo, addend: u32) RelocInfo {
711 return .{ .parent_atom_index = ri.parent_atom_index, .addend = (ri.addend orelse 0) + addend };
712 }
713681};
714682
715683fn lowerAnonDeclRef(
716684 lf: *link.File,
717685 src_loc: Module.SrcLoc,
718 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
686 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
719687 code: *std.ArrayList(u8),
720688 debug_output: DebugInfoOutput,
721689 reloc_info: RelocInfo,
690 offset: u64,
722691) CodeGenError!Result {
723692 _ = debug_output;
724693 const zcu = lf.comp.module.?;
......@@ -745,7 +714,7 @@ fn lowerAnonDeclRef(
745714 const vaddr = try lf.getAnonDeclVAddr(decl_val, .{
746715 .parent_atom_index = reloc_info.parent_atom_index,
747716 .offset = code.items.len,
748 .addend = reloc_info.addend orelse 0,
717 .addend = @intCast(offset),
749718 });
750719 const endian = target.cpu.arch.endian();
751720 switch (ptr_width_bytes) {
......@@ -765,6 +734,7 @@ fn lowerDeclRef(
765734 code: *std.ArrayList(u8),
766735 debug_output: DebugInfoOutput,
767736 reloc_info: RelocInfo,
737 offset: u64,
768738) CodeGenError!Result {
769739 _ = src_loc;
770740 _ = debug_output;
......@@ -783,7 +753,7 @@ fn lowerDeclRef(
783753 const vaddr = try lf.getDeclVAddr(decl_index, .{
784754 .parent_atom_index = reloc_info.parent_atom_index,
785755 .offset = code.items.len,
786 .addend = reloc_info.addend orelse 0,
756 .addend = @intCast(offset),
787757 });
788758 const endian = target.cpu.arch.endian();
789759 switch (ptr_width) {
......@@ -861,7 +831,7 @@ fn genDeclRef(
861831 const zcu = lf.comp.module.?;
862832 const ip = &zcu.intern_pool;
863833 const ty = val.typeOf(zcu);
864 log.debug("genDeclRef: val = {}", .{val.fmtValue(zcu)});
834 log.debug("genDeclRef: val = {}", .{val.fmtValue(zcu, null)});
865835
866836 const ptr_decl = zcu.declPtr(ptr_decl_index);
867837 const namespace = zcu.namespacePtr(ptr_decl.src_namespace);
......@@ -966,7 +936,7 @@ fn genUnnamedConst(
966936) CodeGenError!GenResult {
967937 const zcu = lf.comp.module.?;
968938 const gpa = lf.comp.gpa;
969 log.debug("genUnnamedConst: val = {}", .{val.fmtValue(zcu)});
939 log.debug("genUnnamedConst: val = {}", .{val.fmtValue(zcu, null)});
970940
971941 const local_sym_index = lf.lowerUnnamedConst(val, owner_decl_index) catch |err| {
972942 return GenResult.fail(gpa, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)});
......@@ -1007,7 +977,7 @@ pub fn genTypedValue(
1007977 const ip = &zcu.intern_pool;
1008978 const ty = val.typeOf(zcu);
1009979
1010 log.debug("genTypedValue: val = {}", .{val.fmtValue(zcu)});
980 log.debug("genTypedValue: val = {}", .{val.fmtValue(zcu, null)});
1011981
1012982 if (val.isUndef(zcu))
1013983 return GenResult.mcv(.undef);
......@@ -1018,7 +988,7 @@ pub fn genTypedValue(
1018988 const ptr_bits = target.ptrBitWidth();
1019989
1020990 if (!ty.isSlice(zcu)) switch (ip.indexToKey(val.toIntern())) {
1021 .ptr => |ptr| switch (ptr.addr) {
991 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
1022992 .decl => |decl| return genDeclRef(lf, src_loc, val, decl),
1023993 else => {},
1024994 },
src/codegen/c.zig+96-124
......@@ -646,8 +646,7 @@ pub const DeclGen = struct {
646646 fn renderAnonDeclValue(
647647 dg: *DeclGen,
648648 writer: anytype,
649 ptr_val: Value,
650 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
649 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
651650 location: ValueRenderLocation,
652651 ) error{ OutOfMemory, AnalysisFail }!void {
653652 const zcu = dg.zcu;
......@@ -657,16 +656,16 @@ pub const DeclGen = struct {
657656 const decl_ty = decl_val.typeOf(zcu);
658657
659658 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
660 const ptr_ty = ptr_val.typeOf(zcu);
659 const ptr_ty = Type.fromInterned(anon_decl.orig_ty);
661660 if (ptr_ty.isPtrAtRuntime(zcu) and !decl_ty.isFnOrHasRuntimeBits(zcu)) {
662661 return dg.writeCValue(writer, .{ .undef = ptr_ty });
663662 }
664663
665664 // Chase function values in order to be able to reference the original function.
666665 if (decl_val.getFunction(zcu)) |func|
667 return dg.renderDeclValue(writer, ptr_val, func.owner_decl, location);
666 return dg.renderDeclValue(writer, func.owner_decl, location);
668667 if (decl_val.getExternFunc(zcu)) |extern_func|
669 return dg.renderDeclValue(writer, ptr_val, extern_func.decl, location);
668 return dg.renderDeclValue(writer, extern_func.decl, location);
670669
671670 assert(decl_val.getVariable(zcu) == null);
672671
......@@ -712,7 +711,6 @@ pub const DeclGen = struct {
712711 fn renderDeclValue(
713712 dg: *DeclGen,
714713 writer: anytype,
715 val: Value,
716714 decl_index: InternPool.DeclIndex,
717715 location: ValueRenderLocation,
718716 ) error{ OutOfMemory, AnalysisFail }!void {
......@@ -722,17 +720,17 @@ pub const DeclGen = struct {
722720 assert(decl.has_tv);
723721
724722 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
725 const ty = val.typeOf(zcu);
726723 const decl_ty = decl.typeOf(zcu);
727 if (ty.isPtrAtRuntime(zcu) and !decl_ty.isFnOrHasRuntimeBits(zcu)) {
728 return dg.writeCValue(writer, .{ .undef = ty });
724 const ptr_ty = try decl.declPtrType(zcu);
725 if (!decl_ty.isFnOrHasRuntimeBits(zcu)) {
726 return dg.writeCValue(writer, .{ .undef = ptr_ty });
729727 }
730728
731729 // Chase function values in order to be able to reference the original function.
732730 if (decl.val.getFunction(zcu)) |func| if (func.owner_decl != decl_index)
733 return dg.renderDeclValue(writer, val, func.owner_decl, location);
731 return dg.renderDeclValue(writer, func.owner_decl, location);
734732 if (decl.val.getExternFunc(zcu)) |extern_func| if (extern_func.decl != decl_index)
735 return dg.renderDeclValue(writer, val, extern_func.decl, location);
733 return dg.renderDeclValue(writer, extern_func.decl, location);
736734
737735 if (decl.val.getVariable(zcu)) |variable| try dg.renderFwdDecl(decl_index, variable, .tentative);
738736
......@@ -740,7 +738,7 @@ pub const DeclGen = struct {
740738 // them). The analysis until now should ensure that the C function
741739 // pointers are compatible. If they are not, then there is a bug
742740 // somewhere and we should let the C compiler tell us about it.
743 const ctype = try dg.ctypeFromType(ty, .complete);
741 const ctype = try dg.ctypeFromType(ptr_ty, .complete);
744742 const elem_ctype = ctype.info(ctype_pool).pointer.elem_ctype;
745743 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
746744 const need_cast = !elem_ctype.eql(decl_ctype) and
......@@ -755,125 +753,108 @@ pub const DeclGen = struct {
755753 if (need_cast) try writer.writeByte(')');
756754 }
757755
758 /// Renders a "parent" pointer by recursing to the root decl/variable
759 /// that its contents are defined with respect to.
760 fn renderParentPtr(
756 fn renderPointer(
761757 dg: *DeclGen,
762758 writer: anytype,
763 ptr_val: InternPool.Index,
759 derivation: Value.PointerDeriveStep,
764760 location: ValueRenderLocation,
765761 ) error{ OutOfMemory, AnalysisFail }!void {
766762 const zcu = dg.zcu;
767 const ip = &zcu.intern_pool;
768 const ptr_ty = Type.fromInterned(ip.typeOf(ptr_val));
769 const ptr_ctype = try dg.ctypeFromType(ptr_ty, .complete);
770 const ptr_child_ctype = ptr_ctype.info(&dg.ctype_pool).pointer.elem_ctype;
771 const ptr = ip.indexToKey(ptr_val).ptr;
772 switch (ptr.addr) {
773 .decl => |d| try dg.renderDeclValue(writer, Value.fromInterned(ptr_val), d, location),
774 .anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, Value.fromInterned(ptr_val), anon_decl, location),
763 switch (derivation) {
764 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
775765 .int => |int| {
766 const ptr_ctype = try dg.ctypeFromType(int.ptr_ty, .complete);
767 const addr_val = try zcu.intValue(Type.usize, int.addr);
776768 try writer.writeByte('(');
777769 try dg.renderCType(writer, ptr_ctype);
778 try writer.print("){x}", .{try dg.fmtIntLiteral(Value.fromInterned(int), .Other)});
770 try writer.print("){x}", .{try dg.fmtIntLiteral(addr_val, .Other)});
779771 },
780 .eu_payload, .opt_payload => |base| {
781 const ptr_base_ty = Type.fromInterned(ip.typeOf(base));
782 const base_ty = ptr_base_ty.childType(zcu);
783 // Ensure complete type definition is visible before accessing fields.
784 _ = try dg.ctypeFromType(base_ty, .complete);
785 const payload_ty = switch (ptr.addr) {
786 .eu_payload => base_ty.errorUnionPayload(zcu),
787 .opt_payload => base_ty.optionalChild(zcu),
788 else => unreachable,
789 };
790 const payload_ctype = try dg.ctypeFromType(payload_ty, .forward);
791 if (!ptr_child_ctype.eql(payload_ctype)) {
792 try writer.writeByte('(');
793 try dg.renderCType(writer, ptr_ctype);
794 try writer.writeByte(')');
795 }
772
773 .decl_ptr => |decl| try dg.renderDeclValue(writer, decl, location),
774 .anon_decl_ptr => |ad| try dg.renderAnonDeclValue(writer, ad, location),
775
776 inline .eu_payload_ptr, .opt_payload_ptr => |info| {
796777 try writer.writeAll("&(");
797 try dg.renderParentPtr(writer, base, location);
778 try dg.renderPointer(writer, info.parent.*, location);
798779 try writer.writeAll(")->payload");
799780 },
800 .elem => |elem| {
801 const ptr_base_ty = Type.fromInterned(ip.typeOf(elem.base));
802 const elem_ty = ptr_base_ty.elemType2(zcu);
803 const elem_ctype = try dg.ctypeFromType(elem_ty, .forward);
804 if (!ptr_child_ctype.eql(elem_ctype)) {
805 try writer.writeByte('(');
806 try dg.renderCType(writer, ptr_ctype);
807 try writer.writeByte(')');
808 }
809 try writer.writeAll("&(");
810 if (ip.indexToKey(ptr_base_ty.toIntern()).ptr_type.flags.size == .One)
811 try writer.writeByte('*');
812 try dg.renderParentPtr(writer, elem.base, location);
813 try writer.print(")[{d}]", .{elem.index});
814 },
815 .field => |field| {
816 const ptr_base_ty = Type.fromInterned(ip.typeOf(field.base));
817 const base_ty = ptr_base_ty.childType(zcu);
781
782 .field_ptr => |field| {
783 const parent_ptr_ty = try field.parent.ptrType(zcu);
784
818785 // Ensure complete type definition is available before accessing fields.
819 _ = try dg.ctypeFromType(base_ty, .complete);
820 switch (fieldLocation(ptr_base_ty, ptr_ty, @as(u32, @intCast(field.index)), zcu)) {
786 _ = try dg.ctypeFromType(parent_ptr_ty.childType(zcu), .complete);
787
788 switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, zcu)) {
821789 .begin => {
822 const ptr_base_ctype = try dg.ctypeFromType(ptr_base_ty, .complete);
823 if (!ptr_ctype.eql(ptr_base_ctype)) {
824 try writer.writeByte('(');
825 try dg.renderCType(writer, ptr_ctype);
826 try writer.writeByte(')');
827 }
828 try dg.renderParentPtr(writer, field.base, location);
790 const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
791 try writer.writeByte('(');
792 try dg.renderCType(writer, ptr_ctype);
793 try writer.writeByte(')');
794 try dg.renderPointer(writer, field.parent.*, location);
829795 },
830796 .field => |name| {
831 const field_ty = switch (ip.indexToKey(base_ty.toIntern())) {
832 .anon_struct_type,
833 .struct_type,
834 .union_type,
835 => base_ty.structFieldType(@as(usize, @intCast(field.index)), zcu),
836 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
837 .One, .Many, .C => unreachable,
838 .Slice => switch (field.index) {
839 Value.slice_ptr_index => base_ty.slicePtrFieldType(zcu),
840 Value.slice_len_index => Type.usize,
841 else => unreachable,
842 },
843 },
844 else => unreachable,
845 };
846 const field_ctype = try dg.ctypeFromType(field_ty, .forward);
847 if (!ptr_child_ctype.eql(field_ctype)) {
848 try writer.writeByte('(');
849 try dg.renderCType(writer, ptr_ctype);
850 try writer.writeByte(')');
851 }
852797 try writer.writeAll("&(");
853 try dg.renderParentPtr(writer, field.base, location);
798 try dg.renderPointer(writer, field.parent.*, location);
854799 try writer.writeAll(")->");
855800 try dg.writeCValue(writer, name);
856801 },
857802 .byte_offset => |byte_offset| {
858 const u8_ptr_ty = try zcu.adjustPtrTypeChild(ptr_ty, Type.u8);
859 const u8_ptr_ctype = try dg.ctypeFromType(u8_ptr_ty, .complete);
860
861 if (!ptr_ctype.eql(u8_ptr_ctype)) {
862 try writer.writeByte('(');
863 try dg.renderCType(writer, ptr_ctype);
864 try writer.writeByte(')');
865 }
866 try writer.writeAll("((");
867 try dg.renderCType(writer, u8_ptr_ctype);
803 const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
804 try writer.writeByte('(');
805 try dg.renderCType(writer, ptr_ctype);
868806 try writer.writeByte(')');
869 try dg.renderParentPtr(writer, field.base, location);
870 try writer.print(" + {})", .{
871 try dg.fmtIntLiteral(try zcu.intValue(Type.usize, byte_offset), .Other),
872 });
807 const offset_val = try zcu.intValue(Type.usize, byte_offset);
808 try writer.writeAll("((char *)");
809 try dg.renderPointer(writer, field.parent.*, location);
810 try writer.print(" + {})", .{try dg.fmtIntLiteral(offset_val, .Other)});
873811 },
874812 }
875813 },
876 .comptime_field, .comptime_alloc => unreachable,
814
815 .elem_ptr => |elem| if (!(try elem.parent.ptrType(zcu)).childType(zcu).hasRuntimeBits(zcu)) {
816 // Element type is zero-bit, so lowers to `void`. The index is irrelevant; just cast the pointer.
817 const ptr_ctype = try dg.ctypeFromType(elem.result_ptr_ty, .complete);
818 try writer.writeByte('(');
819 try dg.renderCType(writer, ptr_ctype);
820 try writer.writeByte(')');
821 try dg.renderPointer(writer, elem.parent.*, location);
822 } else {
823 const index_val = try zcu.intValue(Type.usize, elem.elem_idx);
824 // We want to do pointer arithmetic on a pointer to the element type.
825 // We might have a pointer-to-array. In this case, we must cast first.
826 const result_ctype = try dg.ctypeFromType(elem.result_ptr_ty, .complete);
827 const parent_ctype = try dg.ctypeFromType(try elem.parent.ptrType(zcu), .complete);
828 if (result_ctype.eql(parent_ctype)) {
829 // The pointer already has an appropriate type - just do the arithmetic.
830 try writer.writeByte('(');
831 try dg.renderPointer(writer, elem.parent.*, location);
832 try writer.print(" + {})", .{try dg.fmtIntLiteral(index_val, .Other)});
833 } else {
834 // We probably have an array pointer `T (*)[n]`. Cast to an element pointer,
835 // and *then* apply the index.
836 try writer.writeAll("((");
837 try dg.renderCType(writer, result_ctype);
838 try writer.writeByte(')');
839 try dg.renderPointer(writer, elem.parent.*, location);
840 try writer.print(" + {})", .{try dg.fmtIntLiteral(index_val, .Other)});
841 }
842 },
843
844 .offset_and_cast => |oac| {
845 const ptr_ctype = try dg.ctypeFromType(oac.new_ptr_ty, .complete);
846 try writer.writeByte('(');
847 try dg.renderCType(writer, ptr_ctype);
848 try writer.writeByte(')');
849 if (oac.byte_offset == 0) {
850 try dg.renderPointer(writer, oac.parent.*, location);
851 } else {
852 const offset_val = try zcu.intValue(Type.usize, oac.byte_offset);
853 try writer.writeAll("((char *)");
854 try dg.renderPointer(writer, oac.parent.*, location);
855 try writer.print(" + {})", .{try dg.fmtIntLiteral(offset_val, .Other)});
856 }
857 },
877858 }
878859 }
879860
......@@ -1103,20 +1084,11 @@ pub const DeclGen = struct {
11031084 }
11041085 try writer.writeByte('}');
11051086 },
1106 .ptr => |ptr| switch (ptr.addr) {
1107 .decl => |d| try dg.renderDeclValue(writer, val, d, location),
1108 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, val, decl_val, location),
1109 .int => |int| {
1110 try writer.writeAll("((");
1111 try dg.renderCType(writer, ctype);
1112 try writer.print("){x})", .{try dg.fmtIntLiteral(Value.fromInterned(int), location)});
1113 },
1114 .eu_payload,
1115 .opt_payload,
1116 .elem,
1117 .field,
1118 => try dg.renderParentPtr(writer, val.toIntern(), location),
1119 .comptime_field, .comptime_alloc => unreachable,
1087 .ptr => {
1088 var arena = std.heap.ArenaAllocator.init(zcu.gpa);
1089 defer arena.deinit();
1090 const derivation = try val.pointerDerivation(arena.allocator(), zcu);
1091 try dg.renderPointer(writer, derivation, location);
11201092 },
11211093 .opt => |opt| switch (ctype.info(ctype_pool)) {
11221094 .basic => if (ctype.isBool()) try writer.writeAll(switch (opt.val) {
......@@ -4574,10 +4546,10 @@ fn airCall(
45744546 break :fn_decl switch (zcu.intern_pool.indexToKey(callee_val.toIntern())) {
45754547 .extern_func => |extern_func| extern_func.decl,
45764548 .func => |func| func.owner_decl,
4577 .ptr => |ptr| switch (ptr.addr) {
4549 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
45784550 .decl => |decl| decl,
45794551 else => break :known,
4580 },
4552 } else break :known,
45814553 else => break :known,
45824554 };
45834555 };
......@@ -5147,10 +5119,10 @@ fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool
51475119 'I' => !target.cpu.arch.isArmOrThumb(),
51485120 else => switch (value) {
51495121 .constant => |val| switch (f.object.dg.zcu.intern_pool.indexToKey(val.toIntern())) {
5150 .ptr => |ptr| switch (ptr.addr) {
5122 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
51515123 .decl => false,
51525124 else => true,
5153 },
5125 } else true,
51545126 else => true,
51555127 },
51565128 else => false,
src/codegen/llvm.zig+66-157
......@@ -3262,6 +3262,7 @@ pub const Object = struct {
32623262 try o.lowerType(Type.fromInterned(vector_type.child)),
32633263 ),
32643264 .opt_type => |child_ty| {
3265 // Must stay in sync with `opt_payload` logic in `lowerPtr`.
32653266 if (!Type.fromInterned(child_ty).hasRuntimeBitsIgnoreComptime(mod)) return .i8;
32663267
32673268 const payload_ty = try o.lowerType(Type.fromInterned(child_ty));
......@@ -3281,6 +3282,8 @@ pub const Object = struct {
32813282 },
32823283 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
32833284 .error_union_type => |error_union_type| {
3285 // Must stay in sync with `codegen.errUnionPayloadOffset`.
3286 // See logic in `lowerPtr`.
32843287 const error_type = try o.errorIntType();
32853288 if (!Type.fromInterned(error_union_type.payload_type).hasRuntimeBitsIgnoreComptime(mod))
32863289 return error_type;
......@@ -3792,17 +3795,7 @@ pub const Object = struct {
37923795 128 => try o.builder.fp128Const(val.toFloat(f128, mod)),
37933796 else => unreachable,
37943797 },
3795 .ptr => |ptr| return switch (ptr.addr) {
3796 .decl => |decl| try o.lowerDeclRefValue(ty, decl),
3797 .anon_decl => |anon_decl| try o.lowerAnonDeclRef(ty, anon_decl),
3798 .int => |int| try o.lowerIntAsPtr(int),
3799 .eu_payload,
3800 .opt_payload,
3801 .elem,
3802 .field,
3803 => try o.lowerParentPtr(val),
3804 .comptime_field, .comptime_alloc => unreachable,
3805 },
3798 .ptr => try o.lowerPtr(arg_val, 0),
38063799 .slice => |slice| return o.builder.structConst(try o.lowerType(ty), &.{
38073800 try o.lowerValue(slice.ptr),
38083801 try o.lowerValue(slice.len),
......@@ -4223,20 +4216,6 @@ pub const Object = struct {
42234216 };
42244217 }
42254218
4226 fn lowerIntAsPtr(o: *Object, val: InternPool.Index) Allocator.Error!Builder.Constant {
4227 const mod = o.module;
4228 switch (mod.intern_pool.indexToKey(val)) {
4229 .undef => return o.builder.undefConst(.ptr),
4230 .int => {
4231 var bigint_space: Value.BigIntSpace = undefined;
4232 const bigint = Value.fromInterned(val).toBigInt(&bigint_space, mod);
4233 const llvm_int = try lowerBigInt(o, Type.usize, bigint);
4234 return o.builder.castConst(.inttoptr, llvm_int, .ptr);
4235 },
4236 else => unreachable,
4237 }
4238 }
4239
42404219 fn lowerBigInt(
42414220 o: *Object,
42424221 ty: Type,
......@@ -4246,129 +4225,60 @@ pub const Object = struct {
42464225 return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint);
42474226 }
42484227
4249 fn lowerParentPtrDecl(o: *Object, decl_index: InternPool.DeclIndex) Allocator.Error!Builder.Constant {
4250 const mod = o.module;
4251 const decl = mod.declPtr(decl_index);
4252 const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod));
4253 return o.lowerDeclRefValue(ptr_ty, decl_index);
4254 }
4255
4256 fn lowerParentPtr(o: *Object, ptr_val: Value) Error!Builder.Constant {
4257 const mod = o.module;
4258 const ip = &mod.intern_pool;
4259 const ptr = ip.indexToKey(ptr_val.toIntern()).ptr;
4260 return switch (ptr.addr) {
4261 .decl => |decl| try o.lowerParentPtrDecl(decl),
4262 .anon_decl => |ad| try o.lowerAnonDeclRef(Type.fromInterned(ad.orig_ty), ad),
4263 .int => |int| try o.lowerIntAsPtr(int),
4264 .eu_payload => |eu_ptr| {
4265 const parent_ptr = try o.lowerParentPtr(Value.fromInterned(eu_ptr));
4266
4267 const eu_ty = Type.fromInterned(ip.typeOf(eu_ptr)).childType(mod);
4268 const payload_ty = eu_ty.errorUnionPayload(mod);
4269 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
4270 // In this case, we represent pointer to error union the same as pointer
4271 // to the payload.
4272 return parent_ptr;
4273 }
4274
4275 const err_int_ty = try mod.errorIntType();
4276 const payload_align = payload_ty.abiAlignment(mod);
4277 const err_align = err_int_ty.abiAlignment(mod);
4278 const index: u32 = if (payload_align.compare(.gt, err_align)) 2 else 1;
4279 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{
4280 .@"0", try o.builder.intConst(.i32, index),
4228 fn lowerPtr(
4229 o: *Object,
4230 ptr_val: InternPool.Index,
4231 prev_offset: u64,
4232 ) Error!Builder.Constant {
4233 const zcu = o.module;
4234 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
4235 const offset: u64 = prev_offset + ptr.byte_offset;
4236 return switch (ptr.base_addr) {
4237 .decl => |decl| {
4238 const base_ptr = try o.lowerDeclRefValue(decl);
4239 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
4240 try o.builder.intConst(.i64, offset),
42814241 });
42824242 },
4283 .opt_payload => |opt_ptr| {
4284 const parent_ptr = try o.lowerParentPtr(Value.fromInterned(opt_ptr));
4285
4286 const opt_ty = Type.fromInterned(ip.typeOf(opt_ptr)).childType(mod);
4287 const payload_ty = opt_ty.optionalChild(mod);
4288 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or
4289 payload_ty.optionalReprIsPayload(mod))
4290 {
4291 // In this case, we represent pointer to optional the same as pointer
4292 // to the payload.
4293 return parent_ptr;
4294 }
4295
4296 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, null, &.{ .@"0", .@"0" });
4297 },
4298 .comptime_field, .comptime_alloc => unreachable,
4299 .elem => |elem_ptr| {
4300 const parent_ptr = try o.lowerParentPtr(Value.fromInterned(elem_ptr.base));
4301 const elem_ty = Type.fromInterned(ip.typeOf(elem_ptr.base)).elemType2(mod);
4302
4303 return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{
4304 try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index),
4243 .anon_decl => |ad| {
4244 const base_ptr = try o.lowerAnonDeclRef(ad);
4245 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
4246 try o.builder.intConst(.i64, offset),
43054247 });
43064248 },
4307 .field => |field_ptr| {
4308 const parent_ptr = try o.lowerParentPtr(Value.fromInterned(field_ptr.base));
4309 const parent_ptr_ty = Type.fromInterned(ip.typeOf(field_ptr.base));
4310 const parent_ty = parent_ptr_ty.childType(mod);
4311 const field_index: u32 = @intCast(field_ptr.index);
4312 switch (parent_ty.zigTypeTag(mod)) {
4313 .Union => {
4314 if (parent_ty.containerLayout(mod) == .@"packed") {
4315 return parent_ptr;
4316 }
4317
4318 const layout = parent_ty.unionGetLayout(mod);
4319 if (layout.payload_size == 0) {
4320 // In this case a pointer to the union and a pointer to any
4321 // (void) payload is the same.
4322 return parent_ptr;
4323 }
4324
4325 const parent_llvm_ty = try o.lowerType(parent_ty);
4326 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4327 .@"0",
4328 try o.builder.intConst(.i32, @intFromBool(
4329 layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align),
4330 )),
4331 });
4332 },
4333 .Struct => {
4334 if (mod.typeToPackedStruct(parent_ty)) |struct_type| {
4335 const ptr_info = Type.fromInterned(ptr.ty).ptrInfo(mod);
4336 if (ptr_info.packed_offset.host_size != 0) return parent_ptr;
4337
4338 const parent_ptr_info = parent_ptr_ty.ptrInfo(mod);
4339 const bit_offset = mod.structPackedFieldBitOffset(struct_type, field_index) + parent_ptr_info.packed_offset.bit_offset;
4340 const llvm_usize = try o.lowerType(Type.usize);
4341 const base_addr = try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize);
4342 const byte_offset = try o.builder.intConst(llvm_usize, @divExact(bit_offset, 8));
4343 const field_addr = try o.builder.binConst(.add, base_addr, byte_offset);
4344 return o.builder.castConst(.inttoptr, field_addr, .ptr);
4345 }
4346
4347 return o.builder.gepConst(
4348 .inbounds,
4349 try o.lowerType(parent_ty),
4350 parent_ptr,
4351 null,
4352 if (o.llvmFieldIndex(parent_ty, field_index)) |llvm_field_index| &.{
4353 .@"0",
4354 try o.builder.intConst(.i32, llvm_field_index),
4355 } else &.{
4356 try o.builder.intConst(.i32, @intFromBool(
4357 parent_ty.hasRuntimeBitsIgnoreComptime(mod),
4358 )),
4359 },
4360 );
4249 .int => try o.builder.castConst(
4250 .inttoptr,
4251 try o.builder.intConst(try o.lowerType(Type.usize), offset),
4252 .ptr,
4253 ),
4254 .eu_payload => |eu_ptr| try o.lowerPtr(
4255 eu_ptr,
4256 offset + @import("../codegen.zig").errUnionPayloadOffset(
4257 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),
4258 zcu,
4259 ),
4260 ),
4261 .opt_payload => |opt_ptr| try o.lowerPtr(opt_ptr, offset),
4262 .field => |field| {
4263 const agg_ty = Value.fromInterned(field.base).typeOf(zcu).childType(zcu);
4264 const field_off: u64 = switch (agg_ty.zigTypeTag(zcu)) {
4265 .Pointer => off: {
4266 assert(agg_ty.isSlice(zcu));
4267 break :off switch (field.index) {
4268 Value.slice_ptr_index => 0,
4269 Value.slice_len_index => @divExact(zcu.getTarget().ptrBitWidth(), 8),
4270 else => unreachable,
4271 };
43614272 },
4362 .Pointer => {
4363 assert(parent_ty.isSlice(mod));
4364 const parent_llvm_ty = try o.lowerType(parent_ty);
4365 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4366 .@"0", try o.builder.intConst(.i32, field_index),
4367 });
4273 .Struct, .Union => switch (agg_ty.containerLayout(zcu)) {
4274 .auto => agg_ty.structFieldOffset(@intCast(field.index), zcu),
4275 .@"extern", .@"packed" => unreachable,
43684276 },
43694277 else => unreachable,
4370 }
4278 };
4279 return o.lowerPtr(field.base, offset + field_off);
43714280 },
4281 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
43724282 };
43734283 }
43744284
......@@ -4376,8 +4286,7 @@ pub const Object = struct {
43764286 /// Maybe the logic could be unified.
43774287 fn lowerAnonDeclRef(
43784288 o: *Object,
4379 ptr_ty: Type,
4380 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
4289 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
43814290 ) Error!Builder.Constant {
43824291 const mod = o.module;
43834292 const ip = &mod.intern_pool;
......@@ -4393,6 +4302,8 @@ pub const Object = struct {
43934302 @panic("TODO");
43944303 }
43954304
4305 const ptr_ty = Type.fromInterned(anon_decl.orig_ty);
4306
43964307 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
43974308 if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or
43984309 (is_fn_body and mod.typeToFunc(decl_ty).?.is_generic)) return o.lowerPtrToVoid(ptr_ty);
......@@ -4400,9 +4311,8 @@ pub const Object = struct {
44004311 if (is_fn_body)
44014312 @panic("TODO");
44024313
4403 const orig_ty = Type.fromInterned(anon_decl.orig_ty);
4404 const llvm_addr_space = toLlvmAddressSpace(orig_ty.ptrAddressSpace(mod), target);
4405 const alignment = orig_ty.ptrAlignment(mod);
4314 const llvm_addr_space = toLlvmAddressSpace(ptr_ty.ptrAddressSpace(mod), target);
4315 const alignment = ptr_ty.ptrAlignment(mod);
44064316 const llvm_global = (try o.resolveGlobalAnonDecl(decl_val, llvm_addr_space, alignment)).ptrConst(&o.builder).global;
44074317
44084318 const llvm_val = try o.builder.convConst(
......@@ -4411,13 +4321,10 @@ pub const Object = struct {
44114321 try o.builder.ptrType(llvm_addr_space),
44124322 );
44134323
4414 return o.builder.convConst(if (ptr_ty.isAbiInt(mod)) switch (ptr_ty.intInfo(mod).signedness) {
4415 .signed => .signed,
4416 .unsigned => .unsigned,
4417 } else .unneeded, llvm_val, try o.lowerType(ptr_ty));
4324 return o.builder.convConst(.unneeded, llvm_val, try o.lowerType(ptr_ty));
44184325 }
44194326
4420 fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: InternPool.DeclIndex) Allocator.Error!Builder.Constant {
4327 fn lowerDeclRefValue(o: *Object, decl_index: InternPool.DeclIndex) Allocator.Error!Builder.Constant {
44214328 const mod = o.module;
44224329
44234330 // In the case of something like:
......@@ -4428,18 +4335,23 @@ pub const Object = struct {
44284335 const decl = mod.declPtr(decl_index);
44294336 if (decl.val.getFunction(mod)) |func| {
44304337 if (func.owner_decl != decl_index) {
4431 return o.lowerDeclRefValue(ty, func.owner_decl);
4338 return o.lowerDeclRefValue(func.owner_decl);
44324339 }
44334340 } else if (decl.val.getExternFunc(mod)) |func| {
44344341 if (func.decl != decl_index) {
4435 return o.lowerDeclRefValue(ty, func.decl);
4342 return o.lowerDeclRefValue(func.decl);
44364343 }
44374344 }
44384345
44394346 const decl_ty = decl.typeOf(mod);
4347 const ptr_ty = try decl.declPtrType(mod);
4348
44404349 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
44414350 if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or
4442 (is_fn_body and mod.typeToFunc(decl_ty).?.is_generic)) return o.lowerPtrToVoid(ty);
4351 (is_fn_body and mod.typeToFunc(decl_ty).?.is_generic))
4352 {
4353 return o.lowerPtrToVoid(ptr_ty);
4354 }
44434355
44444356 const llvm_global = if (is_fn_body)
44454357 (try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global
......@@ -4452,10 +4364,7 @@ pub const Object = struct {
44524364 try o.builder.ptrType(toLlvmAddressSpace(decl.@"addrspace", mod.getTarget())),
44534365 );
44544366
4455 return o.builder.convConst(if (ty.isAbiInt(mod)) switch (ty.intInfo(mod).signedness) {
4456 .signed => .signed,
4457 .unsigned => .unsigned,
4458 } else .unneeded, llvm_val, try o.lowerType(ty));
4367 return o.builder.convConst(.unneeded, llvm_val, try o.lowerType(ptr_ty));
44594368 }
44604369
44614370 fn lowerPtrToVoid(o: *Object, ptr_ty: Type) Allocator.Error!Builder.Constant {
src/codegen/spirv.zig+80-52
......@@ -863,7 +863,7 @@ const DeclGen = struct {
863863 const result_ty_id = try self.resolveType(ty, repr);
864864 const ip = &mod.intern_pool;
865865
866 log.debug("lowering constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod) });
866 log.debug("lowering constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod, null) });
867867 if (val.isUndefDeep(mod)) {
868868 return self.spv.constUndef(result_ty_id);
869869 }
......@@ -983,10 +983,10 @@ const DeclGen = struct {
983983 const int_ty = ty.intTagType(mod);
984984 break :cache try self.constant(int_ty, int_val, repr);
985985 },
986 .ptr => return self.constantPtr(ty, val),
986 .ptr => return self.constantPtr(val),
987987 .slice => |slice| {
988988 const ptr_ty = ty.slicePtrFieldType(mod);
989 const ptr_id = try self.constantPtr(ptr_ty, Value.fromInterned(slice.ptr));
989 const ptr_id = try self.constantPtr(Value.fromInterned(slice.ptr));
990990 const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);
991991 return self.constructStruct(
992992 ty,
......@@ -1107,62 +1107,86 @@ const DeclGen = struct {
11071107 return cacheable_id;
11081108 }
11091109
1110 fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) Error!IdRef {
1110 fn constantPtr(self: *DeclGen, ptr_val: Value) Error!IdRef {
11111111 // TODO: Caching??
11121112
1113 const result_ty_id = try self.resolveType(ptr_ty, .direct);
1114 const mod = self.module;
1113 const zcu = self.module;
1114
1115 if (ptr_val.isUndef(zcu)) {
1116 const result_ty = ptr_val.typeOf(zcu);
1117 const result_ty_id = try self.resolveType(result_ty, .direct);
1118 return self.spv.constUndef(result_ty_id);
1119 }
11151120
1116 if (ptr_val.isUndef(mod)) return self.spv.constUndef(result_ty_id);
1121 var arena = std.heap.ArenaAllocator.init(self.gpa);
1122 defer arena.deinit();
11171123
1118 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
1119 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),
1120 .anon_decl => |anon_decl| return try self.constantAnonDeclRef(ptr_ty, anon_decl),
1124 const derivation = try ptr_val.pointerDerivation(arena.allocator(), zcu);
1125 return self.derivePtr(derivation);
1126 }
1127
1128 fn derivePtr(self: *DeclGen, derivation: Value.PointerDeriveStep) Error!IdRef {
1129 const zcu = self.module;
1130 switch (derivation) {
1131 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
11211132 .int => |int| {
1122 const ptr_id = self.spv.allocId();
1133 const result_ty_id = try self.resolveType(int.ptr_ty, .direct);
11231134 // TODO: This can probably be an OpSpecConstantOp Bitcast, but
11241135 // that is not implemented by Mesa yet. Therefore, just generate it
11251136 // as a runtime operation.
1137 const result_ptr_id = self.spv.allocId();
11261138 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
11271139 .id_result_type = result_ty_id,
1128 .id_result = ptr_id,
1129 .integer_value = try self.constant(Type.usize, Value.fromInterned(int), .direct),
1140 .id_result = result_ptr_id,
1141 .integer_value = try self.constant(Type.usize, try zcu.intValue(Type.usize, int.addr), .direct),
11301142 });
1131 return ptr_id;
1143 return result_ptr_id;
1144 },
1145 .decl_ptr => |decl| {
1146 const result_ptr_ty = try zcu.declPtr(decl).declPtrType(zcu);
1147 return self.constantDeclRef(result_ptr_ty, decl);
11321148 },
1133 .eu_payload => unreachable, // TODO
1134 .opt_payload => unreachable, // TODO
1135 .comptime_field, .comptime_alloc => unreachable,
1136 .elem => |elem_ptr| {
1137 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));
1138 const parent_ptr_id = try self.constantPtr(parent_ptr_ty, Value.fromInterned(elem_ptr.base));
1139 const index_id = try self.constInt(Type.usize, elem_ptr.index, .direct);
1140
1141 const elem_ptr_id = try self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);
1142
1143 // TODO: Can we consolidate this in ptrElemPtr?
1144 const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T.
1145 const elem_ptr_ty_id = try self.ptrType(elem_ty, self.spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod)));
1146
1147 // TODO: Can we remove this ID comparison?
1148 if (elem_ptr_ty_id == result_ty_id) {
1149 return elem_ptr_id;
1149 .anon_decl_ptr => |ad| {
1150 const result_ptr_ty = Type.fromInterned(ad.orig_ty);
1151 return self.constantAnonDeclRef(result_ptr_ty, ad);
1152 },
1153 .eu_payload_ptr => @panic("TODO"),
1154 .opt_payload_ptr => @panic("TODO"),
1155 .field_ptr => |field| {
1156 const parent_ptr_id = try self.derivePtr(field.parent.*);
1157 const parent_ptr_ty = try field.parent.ptrType(zcu);
1158 return self.structFieldPtr(field.result_ptr_ty, parent_ptr_ty, parent_ptr_id, field.field_idx);
1159 },
1160 .elem_ptr => |elem| {
1161 const parent_ptr_id = try self.derivePtr(elem.parent.*);
1162 const parent_ptr_ty = try elem.parent.ptrType(zcu);
1163 const index_id = try self.constInt(Type.usize, elem.elem_idx, .direct);
1164 return self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);
1165 },
1166 .offset_and_cast => |oac| {
1167 const parent_ptr_id = try self.derivePtr(oac.parent.*);
1168 const parent_ptr_ty = try oac.parent.ptrType(zcu);
1169 disallow: {
1170 if (oac.byte_offset != 0) break :disallow;
1171 // Allow changing the pointer type child only to restructure arrays.
1172 // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T.
1173 const src_base_ty = parent_ptr_ty.arrayBase(zcu)[0];
1174 const dest_base_ty = oac.new_ptr_ty.arrayBase(zcu)[0];
1175 if (self.getTarget().os.tag == .vulkan and src_base_ty.toIntern() != dest_base_ty.toIntern()) break :disallow;
1176
1177 const result_ty_id = try self.resolveType(oac.new_ptr_ty, .direct);
1178 const result_ptr_id = self.spv.allocId();
1179 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
1180 .id_result_type = result_ty_id,
1181 .id_result = result_ptr_id,
1182 .operand = parent_ptr_id,
1183 });
1184 return result_ptr_id;
11501185 }
1151 // This may happen when we have pointer-to-array and the result is
1152 // another pointer-to-array instead of a pointer-to-element.
1153 const result_id = self.spv.allocId();
1154 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
1155 .id_result_type = result_ty_id,
1156 .id_result = result_id,
1157 .operand = elem_ptr_id,
1186 return self.fail("Cannot perform pointer cast: '{}' to '{}'", .{
1187 parent_ptr_ty.fmt(zcu),
1188 oac.new_ptr_ty.fmt(zcu),
11581189 });
1159 return result_id;
1160 },
1161 .field => |field| {
1162 const base_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(field.base));
1163 const base_ptr = try self.constantPtr(base_ptr_ty, Value.fromInterned(field.base));
1164 const field_index: u32 = @intCast(field.index);
1165 return try self.structFieldPtr(ptr_ty, base_ptr_ty, base_ptr, field_index);
11661190 },
11671191 }
11681192 }
......@@ -1170,7 +1194,7 @@ const DeclGen = struct {
11701194 fn constantAnonDeclRef(
11711195 self: *DeclGen,
11721196 ty: Type,
1173 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
1197 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
11741198 ) !IdRef {
11751199 // TODO: Merge this function with constantDeclRef.
11761200
......@@ -4456,16 +4480,20 @@ const DeclGen = struct {
44564480 ) !IdRef {
44574481 const result_ty_id = try self.resolveType(result_ptr_ty, .direct);
44584482
4459 const mod = self.module;
4460 const object_ty = object_ptr_ty.childType(mod);
4461 switch (object_ty.zigTypeTag(mod)) {
4462 .Struct => switch (object_ty.containerLayout(mod)) {
4483 const zcu = self.module;
4484 const object_ty = object_ptr_ty.childType(zcu);
4485 switch (object_ty.zigTypeTag(zcu)) {
4486 .Pointer => {
4487 assert(object_ty.isSlice(zcu));
4488 return self.accessChain(result_ty_id, object_ptr, &.{field_index});
4489 },
4490 .Struct => switch (object_ty.containerLayout(zcu)) {
44634491 .@"packed" => unreachable, // TODO
44644492 else => {
44654493 return try self.accessChain(result_ty_id, object_ptr, &.{field_index});
44664494 },
44674495 },
4468 .Union => switch (object_ty.containerLayout(mod)) {
4496 .Union => switch (object_ty.containerLayout(zcu)) {
44694497 .@"packed" => unreachable, // TODO
44704498 else => {
44714499 const layout = self.unionLayout(object_ty);
......@@ -4475,7 +4503,7 @@ const DeclGen = struct {
44754503 return try self.spv.constUndef(result_ty_id);
44764504 }
44774505
4478 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(mod));
4506 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(zcu));
44794507 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, storage_class);
44804508 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
44814509
src/link/Wasm/ZigObject.zig-1
......@@ -539,7 +539,6 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, val: V
539539 .none,
540540 .{
541541 .parent_atom_index = @intFromEnum(atom.sym_index),
542 .addend = null,
543542 },
544543 );
545544 break :code switch (result) {
src/mutable_value.zig+111-38
......@@ -54,22 +54,22 @@ pub const MutableValue = union(enum) {
5454 payload: *MutableValue,
5555 };
5656
57 pub fn intern(mv: MutableValue, zcu: *Zcu, arena: Allocator) Allocator.Error!InternPool.Index {
57 pub fn intern(mv: MutableValue, zcu: *Zcu, arena: Allocator) Allocator.Error!Value {
5858 const ip = &zcu.intern_pool;
5959 const gpa = zcu.gpa;
60 return switch (mv) {
60 return Value.fromInterned(switch (mv) {
6161 .interned => |ip_index| ip_index,
6262 .eu_payload => |sv| try ip.get(gpa, .{ .error_union = .{
6363 .ty = sv.ty,
64 .val = .{ .payload = try sv.child.intern(zcu, arena) },
64 .val = .{ .payload = (try sv.child.intern(zcu, arena)).toIntern() },
6565 } }),
6666 .opt_payload => |sv| try ip.get(gpa, .{ .opt = .{
6767 .ty = sv.ty,
68 .val = try sv.child.intern(zcu, arena),
68 .val = (try sv.child.intern(zcu, arena)).toIntern(),
6969 } }),
7070 .repeated => |sv| try ip.get(gpa, .{ .aggregate = .{
7171 .ty = sv.ty,
72 .storage = .{ .repeated_elem = try sv.child.intern(zcu, arena) },
72 .storage = .{ .repeated_elem = (try sv.child.intern(zcu, arena)).toIntern() },
7373 } }),
7474 .bytes => |b| try ip.get(gpa, .{ .aggregate = .{
7575 .ty = b.ty,
......@@ -78,24 +78,24 @@ pub const MutableValue = union(enum) {
7878 .aggregate => |a| {
7979 const elems = try arena.alloc(InternPool.Index, a.elems.len);
8080 for (a.elems, elems) |mut_elem, *interned_elem| {
81 interned_elem.* = try mut_elem.intern(zcu, arena);
81 interned_elem.* = (try mut_elem.intern(zcu, arena)).toIntern();
8282 }
83 return ip.get(gpa, .{ .aggregate = .{
83 return Value.fromInterned(try ip.get(gpa, .{ .aggregate = .{
8484 .ty = a.ty,
8585 .storage = .{ .elems = elems },
86 } });
86 } }));
8787 },
8888 .slice => |s| try ip.get(gpa, .{ .slice = .{
8989 .ty = s.ty,
90 .ptr = try s.ptr.intern(zcu, arena),
91 .len = try s.len.intern(zcu, arena),
90 .ptr = (try s.ptr.intern(zcu, arena)).toIntern(),
91 .len = (try s.len.intern(zcu, arena)).toIntern(),
9292 } }),
9393 .un => |u| try ip.get(gpa, .{ .un = .{
9494 .ty = u.ty,
9595 .tag = u.tag,
96 .val = try u.payload.intern(zcu, arena),
96 .val = (try u.payload.intern(zcu, arena)).toIntern(),
9797 } }),
98 };
98 });
9999 }
100100
101101 /// Un-interns the top level of this `MutableValue`, if applicable.
......@@ -248,9 +248,11 @@ pub const MutableValue = union(enum) {
248248 },
249249 .Union => {
250250 const payload = try arena.create(MutableValue);
251 // HACKHACK: this logic is silly, but Sema detects it and reverts the change where needed.
252 // See comment at the top of `Sema.beginComptimePtrMutationInner`.
253 payload.* = .{ .interned = .undef };
251 const backing_ty = try Type.fromInterned(ty_ip).unionBackingType(zcu);
252 payload.* = .{ .interned = try ip.get(
253 gpa,
254 .{ .undef = backing_ty.toIntern() },
255 ) };
254256 mv.* = .{ .un = .{
255257 .ty = ty_ip,
256258 .tag = .none,
......@@ -294,7 +296,6 @@ pub const MutableValue = union(enum) {
294296 /// Get a pointer to the `MutableValue` associated with a field/element.
295297 /// The returned pointer can be safety mutated through to modify the field value.
296298 /// The returned pointer is valid until the representation of `mv` changes.
297 /// This function does *not* support accessing the ptr/len field of slices.
298299 pub fn elem(
299300 mv: *MutableValue,
300301 zcu: *Zcu,
......@@ -304,18 +305,18 @@ pub const MutableValue = union(enum) {
304305 const ip = &zcu.intern_pool;
305306 const gpa = zcu.gpa;
306307 // Convert to the `aggregate` representation.
307 switch (mv) {
308 .eu_payload, .opt_payload, .slice, .un => unreachable,
308 switch (mv.*) {
309 .eu_payload, .opt_payload, .un => unreachable,
309310 .interned => {
310311 try mv.unintern(zcu, arena, false, false);
311312 },
312313 .bytes => |bytes| {
313314 const elems = try arena.alloc(MutableValue, bytes.data.len);
314 for (bytes.data, elems) |byte, interned_byte| {
315 interned_byte.* = try ip.get(gpa, .{ .int = .{
315 for (bytes.data, elems) |byte, *interned_byte| {
316 interned_byte.* = .{ .interned = try ip.get(gpa, .{ .int = .{
316317 .ty = .u8_type,
317318 .storage = .{ .u64 = byte },
318 } });
319 } }) };
319320 }
320321 mv.* = .{ .aggregate = .{
321322 .ty = bytes.ty,
......@@ -331,9 +332,17 @@ pub const MutableValue = union(enum) {
331332 .elems = elems,
332333 } };
333334 },
334 .aggregate => {},
335 .slice, .aggregate => {},
336 }
337 switch (mv.*) {
338 .aggregate => |*agg| return &agg.elems[field_idx],
339 .slice => |*slice| return switch (field_idx) {
340 Value.slice_ptr_index => slice.ptr,
341 Value.slice_len_index => slice.len,
342 else => unreachable,
343 },
344 else => unreachable,
335345 }
336 return &mv.aggregate.elems[field_idx];
337346 }
338347
339348 /// Modify a single field of a `MutableValue` which represents an aggregate or slice, leaving others
......@@ -349,43 +358,44 @@ pub const MutableValue = union(enum) {
349358 ) Allocator.Error!void {
350359 const ip = &zcu.intern_pool;
351360 const is_trivial_int = field_val.isTrivialInt(zcu);
352 try mv.unintern(arena, is_trivial_int, true);
353 switch (mv) {
361 try mv.unintern(zcu, arena, is_trivial_int, true);
362 switch (mv.*) {
354363 .interned,
355364 .eu_payload,
356365 .opt_payload,
357366 .un,
358367 => unreachable,
359368 .slice => |*s| switch (field_idx) {
360 Value.slice_ptr_index => s.ptr = field_val,
361 Value.slice_len_index => s.len = field_val,
369 Value.slice_ptr_index => s.ptr.* = field_val,
370 Value.slice_len_index => s.len.* = field_val,
371 else => unreachable,
362372 },
363373 .bytes => |b| {
364374 assert(is_trivial_int);
365 assert(field_val.typeOf() == Type.u8);
366 b.data[field_idx] = Value.fromInterned(field_val.interned).toUnsignedInt(zcu);
375 assert(field_val.typeOf(zcu).toIntern() == .u8_type);
376 b.data[field_idx] = @intCast(Value.fromInterned(field_val.interned).toUnsignedInt(zcu));
367377 },
368378 .repeated => |r| {
369379 if (field_val.eqlTrivial(r.child.*)) return;
370380 // We must switch to either the `aggregate` or the `bytes` representation.
371381 const len_inc_sent = ip.aggregateTypeLenIncludingSentinel(r.ty);
372 if (ip.zigTypeTag(r.ty) != .Struct and
382 if (Type.fromInterned(r.ty).zigTypeTag(zcu) != .Struct and
373383 is_trivial_int and
374 Type.fromInterned(r.ty).childType(zcu) == .u8_type and
384 Type.fromInterned(r.ty).childType(zcu).toIntern() == .u8_type and
375385 r.child.isTrivialInt(zcu))
376386 {
377387 // We can use the `bytes` representation.
378388 const bytes = try arena.alloc(u8, @intCast(len_inc_sent));
379 const repeated_byte = Value.fromInterned(r.child.interned).getUnsignedInt(zcu);
380 @memset(bytes, repeated_byte);
381 bytes[field_idx] = Value.fromInterned(field_val.interned).getUnsignedInt(zcu);
389 const repeated_byte = Value.fromInterned(r.child.interned).toUnsignedInt(zcu);
390 @memset(bytes, @intCast(repeated_byte));
391 bytes[field_idx] = @intCast(Value.fromInterned(field_val.interned).toUnsignedInt(zcu));
382392 mv.* = .{ .bytes = .{
383393 .ty = r.ty,
384394 .data = bytes,
385395 } };
386396 } else {
387397 // We must use the `aggregate` representation.
388 const mut_elems = try arena.alloc(u8, @intCast(len_inc_sent));
398 const mut_elems = try arena.alloc(MutableValue, @intCast(len_inc_sent));
389399 @memset(mut_elems, r.child.*);
390400 mut_elems[field_idx] = field_val;
391401 mv.* = .{ .aggregate = .{
......@@ -396,12 +406,12 @@ pub const MutableValue = union(enum) {
396406 },
397407 .aggregate => |a| {
398408 a.elems[field_idx] = field_val;
399 const is_struct = ip.zigTypeTag(a.ty) == .Struct;
409 const is_struct = Type.fromInterned(a.ty).zigTypeTag(zcu) == .Struct;
400410 // Attempt to switch to a more efficient representation.
401411 const is_repeated = for (a.elems) |e| {
402412 if (!e.eqlTrivial(field_val)) break false;
403413 } else true;
404 if (is_repeated) {
414 if (!is_struct and is_repeated) {
405415 // Switch to `repeated` repr
406416 const mut_repeated = try arena.create(MutableValue);
407417 mut_repeated.* = field_val;
......@@ -425,7 +435,7 @@ pub const MutableValue = union(enum) {
425435 } else {
426436 const bytes = try arena.alloc(u8, a.elems.len);
427437 for (a.elems, bytes) |elem_val, *b| {
428 b.* = Value.fromInterned(elem_val.interned).toUnsignedInt(zcu);
438 b.* = @intCast(Value.fromInterned(elem_val.interned).toUnsignedInt(zcu));
429439 }
430440 mv.* = .{ .bytes = .{
431441 .ty = a.ty,
......@@ -505,4 +515,67 @@ pub const MutableValue = union(enum) {
505515 inline else => |x| Type.fromInterned(x.ty),
506516 };
507517 }
518
519 pub fn unpackOptional(mv: MutableValue, zcu: *Zcu) union(enum) {
520 undef,
521 null,
522 payload: MutableValue,
523 } {
524 return switch (mv) {
525 .opt_payload => |pl| return .{ .payload = pl.child.* },
526 .interned => |ip_index| switch (zcu.intern_pool.indexToKey(ip_index)) {
527 .undef => return .undef,
528 .opt => |opt| if (opt.val == .none) .null else .{ .payload = .{ .interned = opt.val } },
529 else => unreachable,
530 },
531 else => unreachable,
532 };
533 }
534
535 pub fn unpackErrorUnion(mv: MutableValue, zcu: *Zcu) union(enum) {
536 undef,
537 err: InternPool.NullTerminatedString,
538 payload: MutableValue,
539 } {
540 return switch (mv) {
541 .eu_payload => |pl| return .{ .payload = pl.child.* },
542 .interned => |ip_index| switch (zcu.intern_pool.indexToKey(ip_index)) {
543 .undef => return .undef,
544 .error_union => |eu| switch (eu.val) {
545 .err_name => |name| .{ .err = name },
546 .payload => |pl| .{ .payload = .{ .interned = pl } },
547 },
548 else => unreachable,
549 },
550 else => unreachable,
551 };
552 }
553
554 /// Fast equality checking which may return false negatives.
555 /// Used for deciding when to switch aggregate representations without fully
556 /// interning many values.
557 fn eqlTrivial(a: MutableValue, b: MutableValue) bool {
558 const Tag = @typeInfo(MutableValue).Union.tag_type.?;
559 if (@as(Tag, a) != @as(Tag, b)) return false;
560 return switch (a) {
561 .interned => |a_ip| a_ip == b.interned,
562 .eu_payload => |a_pl| a_pl.ty == b.eu_payload.ty and a_pl.child.eqlTrivial(b.eu_payload.child.*),
563 .opt_payload => |a_pl| a_pl.ty == b.opt_payload.ty and a_pl.child.eqlTrivial(b.opt_payload.child.*),
564 .repeated => |a_rep| a_rep.ty == b.repeated.ty and a_rep.child.eqlTrivial(b.repeated.child.*),
565 .bytes => |a_bytes| a_bytes.ty == b.bytes.ty and std.mem.eql(u8, a_bytes.data, b.bytes.data),
566 .aggregate => |a_agg| {
567 const b_agg = b.aggregate;
568 if (a_agg.ty != b_agg.ty) return false;
569 if (a_agg.elems.len != b_agg.elems.len) return false;
570 for (a_agg.elems, b_agg.elems) |a_elem, b_elem| {
571 if (!a_elem.eqlTrivial(b_elem)) return false;
572 }
573 return true;
574 },
575 .slice => |a_slice| a_slice.ty == b.slice.ty and
576 a_slice.ptr.interned == b.slice.ptr.interned and
577 a_slice.len.interned == b.slice.len.interned,
578 .un => |a_un| a_un.ty == b.un.ty and a_un.tag == b.un.tag and a_un.payload.eqlTrivial(b.un.payload.*),
579 };
580 }
508581};
src/print_air.zig+1-1
......@@ -951,7 +951,7 @@ const Writer = struct {
951951 const ty = Type.fromInterned(mod.intern_pool.indexToKey(ip_index).typeOf());
952952 try s.print("<{}, {}>", .{
953953 ty.fmt(mod),
954 Value.fromInterned(ip_index).fmtValue(mod),
954 Value.fromInterned(ip_index).fmtValue(mod, null),
955955 });
956956 } else {
957957 return w.writeInstIndex(s, operand.toIndex().?, dies);
src/print_value.zig+87-86
......@@ -17,6 +17,7 @@ const max_string_len = 256;
1717const FormatContext = struct {
1818 val: Value,
1919 mod: *Module,
20 opt_sema: ?*Sema,
2021};
2122
2223pub fn format(
......@@ -27,10 +28,10 @@ pub fn format(
2728) !void {
2829 _ = options;
2930 comptime std.debug.assert(fmt.len == 0);
30 return print(ctx.val, writer, 3, ctx.mod, null) catch |err| switch (err) {
31 return print(ctx.val, writer, 3, ctx.mod, ctx.opt_sema) catch |err| switch (err) {
3132 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
3233 error.ComptimeBreak, error.ComptimeReturn => unreachable,
33 error.AnalysisFail, error.NeededSourceLocation => unreachable, // TODO: re-evaluate when we actually pass `opt_sema`
34 error.AnalysisFail, error.NeededSourceLocation => unreachable, // TODO: re-evaluate when we use `opt_sema` more fully
3435 else => |e| return e,
3536 };
3637}
......@@ -117,7 +118,7 @@ pub fn print(
117118 },
118119 .slice => |slice| {
119120 const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) {
120 .field, .elem, .eu_payload, .opt_payload => unreachable,
121 .field, .arr_elem, .eu_payload, .opt_payload => unreachable,
121122 .anon_decl, .comptime_alloc, .comptime_field => true,
122123 .decl, .int => false,
123124 };
......@@ -125,7 +126,7 @@ pub fn print(
125126 // TODO: eventually we want to load the slice as an array with `opt_sema`, but that's
126127 // currently not possible without e.g. triggering compile errors.
127128 }
128 try printPtr(slice.ptr, writer, false, false, 0, level, mod, opt_sema);
129 try printPtr(Value.fromInterned(slice.ptr), writer, level, mod, opt_sema);
129130 try writer.writeAll("[0..");
130131 if (level == 0) {
131132 try writer.writeAll("(...)");
......@@ -136,7 +137,7 @@ pub fn print(
136137 },
137138 .ptr => {
138139 const print_contents = switch (ip.getBackingAddrTag(val.toIntern()).?) {
139 .field, .elem, .eu_payload, .opt_payload => unreachable,
140 .field, .arr_elem, .eu_payload, .opt_payload => unreachable,
140141 .anon_decl, .comptime_alloc, .comptime_field => true,
141142 .decl, .int => false,
142143 };
......@@ -144,13 +145,13 @@ pub fn print(
144145 // TODO: eventually we want to load the pointer with `opt_sema`, but that's
145146 // currently not possible without e.g. triggering compile errors.
146147 }
147 try printPtr(val.toIntern(), writer, false, false, 0, level, mod, opt_sema);
148 try printPtr(val, writer, level, mod, opt_sema);
148149 },
149150 .opt => |opt| switch (opt.val) {
150151 .none => try writer.writeAll("null"),
151152 else => |payload| try print(Value.fromInterned(payload), writer, level, mod, opt_sema),
152153 },
153 .aggregate => |aggregate| try printAggregate(val, aggregate, writer, level, false, mod, opt_sema),
154 .aggregate => |aggregate| try printAggregate(val, aggregate, false, writer, level, mod, opt_sema),
154155 .un => |un| {
155156 if (level == 0) {
156157 try writer.writeAll(".{ ... }");
......@@ -176,13 +177,14 @@ pub fn print(
176177fn printAggregate(
177178 val: Value,
178179 aggregate: InternPool.Key.Aggregate,
180 is_ref: bool,
179181 writer: anytype,
180182 level: u8,
181 is_ref: bool,
182183 zcu: *Zcu,
183184 opt_sema: ?*Sema,
184185) (@TypeOf(writer).Error || Module.CompileError)!void {
185186 if (level == 0) {
187 if (is_ref) try writer.writeByte('&');
186188 return writer.writeAll(".{ ... }");
187189 }
188190 const ip = &zcu.intern_pool;
......@@ -257,101 +259,87 @@ fn printAggregate(
257259 return writer.writeAll(" }");
258260}
259261
260fn printPtr(
261 ptr_val: InternPool.Index,
262 writer: anytype,
263 force_type: bool,
264 force_addrof: bool,
265 leading_parens: u32,
266 level: u8,
267 zcu: *Zcu,
268 opt_sema: ?*Sema,
269) (@TypeOf(writer).Error || Module.CompileError)!void {
270 const ip = &zcu.intern_pool;
271 const ptr = switch (ip.indexToKey(ptr_val)) {
272 .undef => |ptr_ty| {
273 if (force_addrof) try writer.writeAll("&");
274 try writer.writeByteNTimes('(', leading_parens);
275 try writer.print("@as({}, undefined)", .{Type.fromInterned(ptr_ty).fmt(zcu)});
276 return;
277 },
262fn printPtr(ptr_val: Value, writer: anytype, level: u8, zcu: *Zcu, opt_sema: ?*Sema) (@TypeOf(writer).Error || Module.CompileError)!void {
263 const ptr = switch (zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
264 .undef => return writer.writeAll("undefined"),
278265 .ptr => |ptr| ptr,
279266 else => unreachable,
280267 };
281 if (level == 0) {
282 return writer.writeAll("&...");
283 }
284 switch (ptr.addr) {
285 .int => |int| {
286 if (force_addrof) try writer.writeAll("&");
287 try writer.writeByteNTimes('(', leading_parens);
288 if (force_type) {
289 try writer.print("@as({}, @ptrFromInt(", .{Type.fromInterned(ptr.ty).fmt(zcu)});
290 try print(Value.fromInterned(int), writer, level - 1, zcu, opt_sema);
291 try writer.writeAll("))");
292 } else {
293 try writer.writeAll("@ptrFromInt(");
294 try print(Value.fromInterned(int), writer, level - 1, zcu, opt_sema);
295 try writer.writeAll(")");
296 }
297 },
298 .decl => |index| {
299 try writer.writeAll("&");
300 try zcu.declPtr(index).renderFullyQualifiedName(zcu, writer);
301 },
302 .comptime_alloc => try writer.writeAll("&(comptime alloc)"),
303 .anon_decl => |anon| switch (ip.indexToKey(anon.val)) {
304 .aggregate => |aggregate| try printAggregate(
305 Value.fromInterned(anon.val),
306 aggregate,
307 writer,
308 level - 1,
268
269 if (ptr.base_addr == .anon_decl) {
270 // If the value is an aggregate, we can potentially print it more nicely.
271 switch (zcu.intern_pool.indexToKey(ptr.base_addr.anon_decl.val)) {
272 .aggregate => |agg| return printAggregate(
273 Value.fromInterned(ptr.base_addr.anon_decl.val),
274 agg,
309275 true,
276 writer,
277 level,
310278 zcu,
311279 opt_sema,
312280 ),
313 else => {
314 const ty = Type.fromInterned(ip.typeOf(anon.val));
315 try writer.print("&@as({}, ", .{ty.fmt(zcu)});
316 try print(Value.fromInterned(anon.val), writer, level - 1, zcu, opt_sema);
317 try writer.writeAll(")");
318 },
281 else => {},
282 }
283 }
284
285 var arena = std.heap.ArenaAllocator.init(zcu.gpa);
286 defer arena.deinit();
287 const derivation = try ptr_val.pointerDerivationAdvanced(arena.allocator(), zcu, opt_sema);
288 try printPtrDerivation(derivation, writer, level, zcu, opt_sema);
289}
290
291/// Print `derivation` as an lvalue, i.e. such that writing `&` before this gives the pointer value.
292fn printPtrDerivation(derivation: Value.PointerDeriveStep, writer: anytype, level: u8, zcu: *Zcu, opt_sema: ?*Sema) (@TypeOf(writer).Error || Module.CompileError)!void {
293 const ip = &zcu.intern_pool;
294 switch (derivation) {
295 .int => |int| try writer.print("@as({}, @ptrFromInt({x})).*", .{
296 int.ptr_ty.fmt(zcu),
297 int.addr,
298 }),
299 .decl_ptr => |decl| {
300 try zcu.declPtr(decl).renderFullyQualifiedName(zcu, writer);
319301 },
320 .comptime_field => |val| {
321 const ty = Type.fromInterned(ip.typeOf(val));
322 try writer.print("&@as({}, ", .{ty.fmt(zcu)});
323 try print(Value.fromInterned(val), writer, level - 1, zcu, opt_sema);
324 try writer.writeAll(")");
302 .anon_decl_ptr => |anon| {
303 const ty = Value.fromInterned(anon.val).typeOf(zcu);
304 try writer.print("@as({}, ", .{ty.fmt(zcu)});
305 try print(Value.fromInterned(anon.val), writer, level - 1, zcu, opt_sema);
306 try writer.writeByte(')');
325307 },
326 .eu_payload => |base| {
327 try printPtr(base, writer, true, true, leading_parens, level, zcu, opt_sema);
328 try writer.writeAll(".?");
308 .comptime_alloc_ptr => |info| {
309 try writer.print("@as({}, ", .{info.val.typeOf(zcu).fmt(zcu)});
310 try print(info.val, writer, level - 1, zcu, opt_sema);
311 try writer.writeByte(')');
329312 },
330 .opt_payload => |base| {
331 try writer.writeAll("(");
332 try printPtr(base, writer, true, true, leading_parens + 1, level, zcu, opt_sema);
333 try writer.writeAll(" catch unreachable");
313 .comptime_field_ptr => |val| {
314 const ty = val.typeOf(zcu);
315 try writer.print("@as({}, ", .{ty.fmt(zcu)});
316 try print(val, writer, level - 1, zcu, opt_sema);
317 try writer.writeByte(')');
334318 },
335 .elem => |elem| {
336 try printPtr(elem.base, writer, true, true, leading_parens, level, zcu, opt_sema);
337 try writer.print("[{d}]", .{elem.index});
319 .eu_payload_ptr => |info| {
320 try writer.writeByte('(');
321 try printPtrDerivation(info.parent.*, writer, level, zcu, opt_sema);
322 try writer.writeAll(" catch unreachable)");
338323 },
339 .field => |field| {
340 try printPtr(field.base, writer, true, true, leading_parens, level, zcu, opt_sema);
341 const base_ty = Type.fromInterned(ip.typeOf(field.base)).childType(zcu);
342 switch (base_ty.zigTypeTag(zcu)) {
343 .Struct => if (base_ty.isTuple(zcu)) {
344 try writer.print("[{d}]", .{field.index});
345 } else {
346 const field_name = base_ty.structFieldName(@intCast(field.index), zcu).unwrap().?;
324 .opt_payload_ptr => |info| {
325 try printPtrDerivation(info.parent.*, writer, level, zcu, opt_sema);
326 try writer.writeAll(".?");
327 },
328 .field_ptr => |field| {
329 try printPtrDerivation(field.parent.*, writer, level, zcu, opt_sema);
330 const agg_ty = (try field.parent.ptrType(zcu)).childType(zcu);
331 switch (agg_ty.zigTypeTag(zcu)) {
332 .Struct => if (agg_ty.structFieldName(field.field_idx, zcu).unwrap()) |field_name| {
347333 try writer.print(".{i}", .{field_name.fmt(ip)});
334 } else {
335 try writer.print("[{d}]", .{field.field_idx});
348336 },
349337 .Union => {
350 const tag_ty = base_ty.unionTagTypeHypothetical(zcu);
351 const field_name = tag_ty.enumFieldName(@intCast(field.index), zcu);
338 const tag_ty = agg_ty.unionTagTypeHypothetical(zcu);
339 const field_name = tag_ty.enumFieldName(field.field_idx, zcu);
352340 try writer.print(".{i}", .{field_name.fmt(ip)});
353341 },
354 .Pointer => switch (field.index) {
342 .Pointer => switch (field.field_idx) {
355343 Value.slice_ptr_index => try writer.writeAll(".ptr"),
356344 Value.slice_len_index => try writer.writeAll(".len"),
357345 else => unreachable,
......@@ -359,5 +347,18 @@ fn printPtr(
359347 else => unreachable,
360348 }
361349 },
350 .elem_ptr => |elem| {
351 try printPtrDerivation(elem.parent.*, writer, level, zcu, opt_sema);
352 try writer.print("[{d}]", .{elem.elem_idx});
353 },
354 .offset_and_cast => |oac| if (oac.byte_offset == 0) {
355 try writer.print("@as({}, @ptrCast(", .{oac.new_ptr_ty.fmt(zcu)});
356 try printPtrDerivation(oac.parent.*, writer, level, zcu, opt_sema);
357 try writer.writeAll("))");
358 } else {
359 try writer.print("@as({}, @ptrFromInt(@intFromPtr(", .{oac.new_ptr_ty.fmt(zcu)});
360 try printPtrDerivation(oac.parent.*, writer, level, zcu, opt_sema);
361 try writer.print(") + {d}))", .{oac.byte_offset});
362 },
362363 }
363364}
src/type.zig+93-9
......@@ -172,6 +172,7 @@ pub const Type = struct {
172172 }
173173
174174 /// Prints a name suitable for `@typeName`.
175 /// TODO: take an `opt_sema` to pass to `fmtValue` when printing sentinels.
175176 pub fn print(ty: Type, writer: anytype, mod: *Module) @TypeOf(writer).Error!void {
176177 const ip = &mod.intern_pool;
177178 switch (ip.indexToKey(ty.toIntern())) {
......@@ -187,8 +188,8 @@ pub const Type = struct {
187188
188189 if (info.sentinel != .none) switch (info.flags.size) {
189190 .One, .C => unreachable,
190 .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod)}),
191 .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod)}),
191 .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod, null)}),
192 .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod, null)}),
192193 } else switch (info.flags.size) {
193194 .One => try writer.writeAll("*"),
194195 .Many => try writer.writeAll("[*]"),
......@@ -234,7 +235,7 @@ pub const Type = struct {
234235 } else {
235236 try writer.print("[{d}:{}]", .{
236237 array_type.len,
237 Value.fromInterned(array_type.sentinel).fmtValue(mod),
238 Value.fromInterned(array_type.sentinel).fmtValue(mod, null),
238239 });
239240 try print(Type.fromInterned(array_type.child), writer, mod);
240241 }
......@@ -352,7 +353,7 @@ pub const Type = struct {
352353 try print(Type.fromInterned(field_ty), writer, mod);
353354
354355 if (val != .none) {
355 try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(mod)});
356 try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(mod, null)});
356357 }
357358 }
358359 try writer.writeAll("}");
......@@ -1965,6 +1966,12 @@ pub const Type = struct {
19651966 return Type.fromInterned(union_fields[index]);
19661967 }
19671968
1969 pub fn unionFieldTypeByIndex(ty: Type, index: usize, mod: *Module) Type {
1970 const ip = &mod.intern_pool;
1971 const union_obj = mod.typeToUnion(ty).?;
1972 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
1973 }
1974
19681975 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
19691976 const union_obj = mod.typeToUnion(ty).?;
19701977 return mod.unionTagFieldIndex(union_obj, enum_tag);
......@@ -3049,22 +3056,34 @@ pub const Type = struct {
30493056 };
30503057 }
30513058
3052 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) Alignment {
3053 const ip = &mod.intern_pool;
3059 pub fn structFieldAlign(ty: Type, index: usize, zcu: *Zcu) Alignment {
3060 return ty.structFieldAlignAdvanced(index, zcu, null) catch unreachable;
3061 }
3062
3063 pub fn structFieldAlignAdvanced(ty: Type, index: usize, zcu: *Zcu, opt_sema: ?*Sema) !Alignment {
3064 const ip = &zcu.intern_pool;
30543065 switch (ip.indexToKey(ty.toIntern())) {
30553066 .struct_type => {
30563067 const struct_type = ip.loadStructType(ty.toIntern());
30573068 assert(struct_type.layout != .@"packed");
30583069 const explicit_align = struct_type.fieldAlign(ip, index);
30593070 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
3060 return mod.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
3071 if (opt_sema) |sema| {
3072 return sema.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
3073 } else {
3074 return zcu.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
3075 }
30613076 },
30623077 .anon_struct_type => |anon_struct| {
3063 return Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignment(mod);
3078 return (try Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignmentAdvanced(zcu, if (opt_sema) |sema| .{ .sema = sema } else .eager)).scalar;
30643079 },
30653080 .union_type => {
30663081 const union_obj = ip.loadUnionType(ty.toIntern());
3067 return mod.unionFieldNormalAlignment(union_obj, @intCast(index));
3082 if (opt_sema) |sema| {
3083 return sema.unionFieldAlignment(union_obj, @intCast(index));
3084 } else {
3085 return zcu.unionFieldNormalAlignment(union_obj, @intCast(index));
3086 }
30683087 },
30693088 else => unreachable,
30703089 }
......@@ -3301,6 +3320,71 @@ pub const Type = struct {
33013320 };
33023321 }
33033322
3323 pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } {
3324 var cur_ty: Type = ty;
3325 var cur_len: u64 = 1;
3326 while (cur_ty.zigTypeTag(zcu) == .Array) {
3327 cur_len *= cur_ty.arrayLenIncludingSentinel(zcu);
3328 cur_ty = cur_ty.childType(zcu);
3329 }
3330 return .{ cur_ty, cur_len };
3331 }
3332
3333 pub fn packedStructFieldPtrInfo(struct_ty: Type, parent_ptr_ty: Type, field_idx: u32, zcu: *Zcu) union(enum) {
3334 /// The result is a bit-pointer with the same value and a new packed offset.
3335 bit_ptr: InternPool.Key.PtrType.PackedOffset,
3336 /// The result is a standard pointer.
3337 byte_ptr: struct {
3338 /// The byte offset of the field pointer from the parent pointer value.
3339 offset: u64,
3340 /// The alignment of the field pointer type.
3341 alignment: InternPool.Alignment,
3342 },
3343 } {
3344 comptime assert(Type.packed_struct_layout_version == 2);
3345
3346 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
3347 const field_ty = struct_ty.structFieldType(field_idx, zcu);
3348
3349 var bit_offset: u16 = 0;
3350 var running_bits: u16 = 0;
3351 for (0..struct_ty.structFieldCount(zcu)) |i| {
3352 const f_ty = struct_ty.structFieldType(i, zcu);
3353 if (i == field_idx) {
3354 bit_offset = running_bits;
3355 }
3356 running_bits += @intCast(f_ty.bitSize(zcu));
3357 }
3358
3359 const res_host_size: u16, const res_bit_offset: u16 = if (parent_ptr_info.packed_offset.host_size != 0)
3360 .{ parent_ptr_info.packed_offset.host_size, parent_ptr_info.packed_offset.bit_offset + bit_offset }
3361 else
3362 .{ (running_bits + 7) / 8, bit_offset };
3363
3364 // If the field happens to be byte-aligned, simplify the pointer type.
3365 // We can only do this if the pointee's bit size matches its ABI byte size,
3366 // so that loads and stores do not interfere with surrounding packed bits.
3367 //
3368 // TODO: we do not attempt this with big-endian targets yet because of nested
3369 // structs and floats. I need to double-check the desired behavior for big endian
3370 // targets before adding the necessary complications to this code. This will not
3371 // cause miscompilations; it only means the field pointer uses bit masking when it
3372 // might not be strictly necessary.
3373 if (res_bit_offset % 8 == 0 and field_ty.bitSize(zcu) == field_ty.abiSize(zcu) * 8 and zcu.getTarget().cpu.arch.endian() == .little) {
3374 const byte_offset = res_bit_offset / 8;
3375 const new_align = Alignment.fromLog2Units(@ctz(byte_offset | parent_ptr_ty.ptrAlignment(zcu).toByteUnits().?));
3376 return .{ .byte_ptr = .{
3377 .offset = byte_offset,
3378 .alignment = new_align,
3379 } };
3380 }
3381
3382 return .{ .bit_ptr = .{
3383 .host_size = res_host_size,
3384 .bit_offset = res_bit_offset,
3385 } };
3386 }
3387
33043388 pub const @"u1": Type = .{ .ip_index = .u1_type };
33053389 pub const @"u8": Type = .{ .ip_index = .u8_type };
33063390 pub const @"u16": Type = .{ .ip_index = .u16_type };
test/behavior/bitcast.zig+58
......@@ -517,3 +517,61 @@ test "@bitCast of packed struct of bools all false" {
517517 p.b3 = false;
518518 try expect(@as(u8, @as(u4, @bitCast(p))) == 0);
519519}
520
521test "@bitCast of packed struct containing pointer" {
522 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
523 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
524 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
525 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
526 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
527
528 const S = struct {
529 const A = packed struct {
530 ptr: *const u32,
531 };
532
533 const B = packed struct {
534 ptr: *const i32,
535 };
536
537 fn doTheTest() !void {
538 const x: u32 = 123;
539 var a: A = undefined;
540 a = .{ .ptr = &x };
541 const b: B = @bitCast(a);
542 try expect(b.ptr.* == 123);
543 }
544 };
545
546 try S.doTheTest();
547 try comptime S.doTheTest();
548}
549
550test "@bitCast of extern struct containing pointer" {
551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
552 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
553 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
554 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
555 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
556
557 const S = struct {
558 const A = extern struct {
559 ptr: *const u32,
560 };
561
562 const B = extern struct {
563 ptr: *const i32,
564 };
565
566 fn doTheTest() !void {
567 const x: u32 = 123;
568 var a: A = undefined;
569 a = .{ .ptr = &x };
570 const b: B = @bitCast(a);
571 try expect(b.ptr.* == 123);
572 }
573 };
574
575 try S.doTheTest();
576 try comptime S.doTheTest();
577}
test/behavior/cast_int.zig+2-2
......@@ -139,8 +139,8 @@ const Piece = packed struct {
139139 color: Color,
140140 type: Type,
141141
142 const Type = enum { KING, QUEEN, BISHOP, KNIGHT, ROOK, PAWN };
143 const Color = enum { WHITE, BLACK };
142 const Type = enum(u3) { KING, QUEEN, BISHOP, KNIGHT, ROOK, PAWN };
143 const Color = enum(u1) { WHITE, BLACK };
144144
145145 fn charToPiece(c: u8) !@This() {
146146 return .{
test/behavior/comptime_memory.zig+21-43
......@@ -32,32 +32,22 @@ test "type pun signed and unsigned as array pointer" {
3232}
3333
3434test "type pun signed and unsigned as offset many pointer" {
35 if (true) {
36 // TODO https://github.com/ziglang/zig/issues/9646
37 return error.SkipZigTest;
38 }
39
4035 comptime {
41 var x: u32 = 0;
42 var y = @as([*]i32, @ptrCast(&x));
36 var x: [11]u32 = undefined;
37 var y: [*]i32 = @ptrCast(&x[10]);
4338 y -= 10;
4439 y[10] = -1;
45 try testing.expectEqual(@as(u32, 0xFFFFFFFF), x);
40 try testing.expectEqual(@as(u32, 0xFFFFFFFF), x[10]);
4641 }
4742}
4843
4944test "type pun signed and unsigned as array pointer with pointer arithemtic" {
50 if (true) {
51 // TODO https://github.com/ziglang/zig/issues/9646
52 return error.SkipZigTest;
53 }
54
5545 comptime {
56 var x: u32 = 0;
57 const y = @as([*]i32, @ptrCast(&x)) - 10;
46 var x: [11]u32 = undefined;
47 const y = @as([*]i32, @ptrCast(&x[10])) - 10;
5848 const z: *[15]i32 = y[0..15];
5949 z[10] = -1;
60 try testing.expectEqual(@as(u32, 0xFFFFFFFF), x);
50 try testing.expectEqual(@as(u32, 0xFFFFFFFF), x[10]);
6151 }
6252}
6353
......@@ -171,10 +161,13 @@ fn doTypePunBitsTest(as_bits: *Bits) !void {
171161
172162test "type pun bits" {
173163 if (true) {
174 // TODO https://github.com/ziglang/zig/issues/9646
164 // TODO: currently, marking one bit of `Bits` as `undefined` does
165 // mark the whole value as `undefined`, since the pointer interpretation
166 // logic reads it back in as a `u32`, which is partially-undef and thus
167 // has value `undefined`. We need an improved comptime memory representation
168 // to make this work.
175169 return error.SkipZigTest;
176170 }
177
178171 comptime {
179172 var v: u32 = undefined;
180173 try doTypePunBitsTest(@as(*Bits, @ptrCast(&v)));
......@@ -296,11 +289,6 @@ test "dance on linker values" {
296289}
297290
298291test "offset array ptr by element size" {
299 if (true) {
300 // TODO https://github.com/ziglang/zig/issues/9646
301 return error.SkipZigTest;
302 }
303
304292 comptime {
305293 const VirtualStruct = struct { x: u32 };
306294 var arr: [4]VirtualStruct = .{
......@@ -310,15 +298,10 @@ test "offset array ptr by element size" {
310298 .{ .x = bigToNativeEndian(u32, 0x03070b0f) },
311299 };
312300
313 const address = @intFromPtr(&arr);
314 try testing.expectEqual(@intFromPtr(&arr[0]), address);
315 try testing.expectEqual(@intFromPtr(&arr[0]) + 10, address + 10);
316 try testing.expectEqual(@intFromPtr(&arr[1]), address + @sizeOf(VirtualStruct));
317 try testing.expectEqual(@intFromPtr(&arr[2]), address + 2 * @sizeOf(VirtualStruct));
318 try testing.expectEqual(@intFromPtr(&arr[3]), address + @sizeOf(VirtualStruct) * 3);
301 const buf: [*]align(@alignOf(VirtualStruct)) u8 = @ptrCast(&arr);
319302
320 const secondElement = @as(*VirtualStruct, @ptrFromInt(@intFromPtr(&arr[0]) + 2 * @sizeOf(VirtualStruct)));
321 try testing.expectEqual(bigToNativeEndian(u32, 0x02060a0e), secondElement.x);
303 const second_element: *VirtualStruct = @ptrCast(buf + 2 * @sizeOf(VirtualStruct));
304 try testing.expectEqual(bigToNativeEndian(u32, 0x02060a0e), second_element.x);
322305 }
323306}
324307
......@@ -364,7 +347,7 @@ test "offset field ptr by enclosing array element size" {
364347
365348 var i: usize = 0;
366349 while (i < 4) : (i += 1) {
367 var ptr: [*]u8 = @as([*]u8, @ptrCast(&arr[0]));
350 var ptr: [*]u8 = @ptrCast(&arr[0]);
368351 ptr += i;
369352 ptr += @offsetOf(VirtualStruct, "x");
370353 var j: usize = 0;
......@@ -400,23 +383,18 @@ test "accessing reinterpreted memory of parent object" {
400383}
401384
402385test "bitcast packed union to integer" {
403 if (true) {
404 // https://github.com/ziglang/zig/issues/19384
405 return error.SkipZigTest;
406 }
407386 const U = packed union {
408 x: u1,
387 x: i2,
409388 y: u2,
410389 };
411390
412391 comptime {
413 const a = U{ .x = 1 };
414 const b = U{ .y = 2 };
415 const cast_a = @as(u2, @bitCast(a));
416 const cast_b = @as(u2, @bitCast(b));
392 const a: U = .{ .x = -1 };
393 const b: U = .{ .y = 2 };
394 const cast_a: u2 = @bitCast(a);
395 const cast_b: u2 = @bitCast(b);
417396
418 // truncated because the upper bit is garbage memory that we don't care about
419 try testing.expectEqual(@as(u1, 1), @as(u1, @truncate(cast_a)));
397 try testing.expectEqual(@as(u2, 3), cast_a);
420398 try testing.expectEqual(@as(u2, 2), cast_b);
421399 }
422400}
test/behavior/error.zig+23
......@@ -1054,3 +1054,26 @@ test "errorCast from error sets to error unions" {
10541054 const err_union: Set1!void = @errorCast(error.A);
10551055 try expectError(error.A, err_union);
10561056}
1057
1058test "result location initialization of error union with OPV payload" {
1059 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1060 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1061 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1062
1063 const S = struct {
1064 x: u0,
1065 };
1066
1067 const a: anyerror!S = .{ .x = 0 };
1068 comptime assert((a catch unreachable).x == 0);
1069
1070 comptime {
1071 var b: anyerror!S = .{ .x = 0 };
1072 _ = &b;
1073 assert((b catch unreachable).x == 0);
1074 }
1075
1076 var c: anyerror!S = .{ .x = 0 };
1077 _ = &c;
1078 try expectEqual(0, (c catch return error.TestFailed).x);
1079}
test/behavior/field_parent_ptr.zig+1
......@@ -1731,6 +1731,7 @@ test "@fieldParentPtr extern union" {
17311731test "@fieldParentPtr packed union" {
17321732 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
17331733 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1734 if (builtin.target.cpu.arch.endian() == .big) return error.SkipZigTest; // TODO
17341735
17351736 const C = packed union {
17361737 a: bool,
test/behavior/optional.zig+29-7
......@@ -92,13 +92,11 @@ test "optional with zero-bit type" {
9292
9393 var two: ?struct { ZeroBit, ZeroBit } = undefined;
9494 two = .{ with_runtime.zero_bit, with_runtime.zero_bit };
95 if (!@inComptime()) {
96 try expect(two != null);
97 try expect(two.?[0] == zero_bit);
98 try expect(two.?[0] == with_runtime.zero_bit);
99 try expect(two.?[1] == zero_bit);
100 try expect(two.?[1] == with_runtime.zero_bit);
101 }
95 try expect(two != null);
96 try expect(two.?[0] == zero_bit);
97 try expect(two.?[0] == with_runtime.zero_bit);
98 try expect(two.?[1] == zero_bit);
99 try expect(two.?[1] == with_runtime.zero_bit);
102100 }
103101 };
104102
......@@ -610,3 +608,27 @@ test "copied optional doesn't alias source" {
610608
611609 try expect(x[0] == 0.0);
612610}
611
612test "result location initialization of optional with OPV payload" {
613 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
614 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
615 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
616 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
617
618 const S = struct {
619 x: u0,
620 };
621
622 const a: ?S = .{ .x = 0 };
623 comptime assert(a.?.x == 0);
624
625 comptime {
626 var b: ?S = .{ .x = 0 };
627 _ = &b;
628 assert(b.?.x == 0);
629 }
630
631 var c: ?S = .{ .x = 0 };
632 _ = &c;
633 try expectEqual(0, (c orelse return error.TestFailed).x);
634}
test/behavior/packed-struct.zig+1-1
......@@ -1025,7 +1025,7 @@ test "modify nested packed struct aligned field" {
10251025 pretty_print: packed struct {
10261026 enabled: bool = false,
10271027 num_spaces: u4 = 4,
1028 space_char: enum { space, tab } = .space,
1028 space_char: enum(u1) { space, tab } = .space,
10291029 indent: u8 = 0,
10301030 } = .{},
10311031 baz: bool = false,
test/behavior/packed-union.zig+14-1
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const assert = std.debug.assert;
34const expectEqual = std.testing.expectEqual;
45
56test "flags in packed union" {
......@@ -106,7 +107,7 @@ test "packed union in packed struct" {
106107
107108fn testPackedUnionInPackedStruct() !void {
108109 const ReadRequest = packed struct { key: i32 };
109 const RequestType = enum {
110 const RequestType = enum(u1) {
110111 read,
111112 insert,
112113 };
......@@ -169,3 +170,15 @@ test "assigning to non-active field at comptime" {
169170 test_bits.bits = .{};
170171 }
171172}
173
174test "comptime packed union of pointers" {
175 const U = packed union {
176 a: *const u32,
177 b: *const [1]u32,
178 };
179
180 const x: u32 = 123;
181 const u: U = .{ .a = &x };
182
183 comptime assert(u.b[0] == 123);
184}
test/behavior/pointers.zig+36
......@@ -621,3 +621,39 @@ test "cast pointers with zero sized elements" {
621621 const d: []u8 = c;
622622 _ = d;
623623}
624
625test "comptime pointer equality through distinct fields with well-defined layout" {
626 const A = extern struct {
627 x: u32,
628 z: u16,
629 };
630 const B = extern struct {
631 x: u16,
632 y: u16,
633 z: u16,
634 };
635
636 const a: A = .{
637 .x = undefined,
638 .z = 123,
639 };
640
641 const ap: *const A = &a;
642 const bp: *const B = @ptrCast(ap);
643
644 comptime assert(&ap.z == &bp.z);
645 comptime assert(ap.z == 123);
646 comptime assert(bp.z == 123);
647}
648
649test "comptime pointer equality through distinct elements with well-defined layout" {
650 const buf: [2]u32 = .{ 123, 456 };
651
652 const ptr: *const [2]u32 = &buf;
653 const byte_ptr: *align(4) const [8]u8 = @ptrCast(ptr);
654 const second_elem: *const u32 = @ptrCast(byte_ptr[4..8]);
655
656 comptime assert(&buf[1] == second_elem);
657 comptime assert(buf[1] == 456);
658 comptime assert(second_elem.* == 456);
659}
test/behavior/ptrcast.zig+59-1
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const builtin = @import("builtin");
33const expect = std.testing.expect;
4const assert = std.debug.assert;
45const native_endian = builtin.target.cpu.arch.endian();
56
67test "reinterpret bytes as integer with nonzero offset" {
......@@ -277,7 +278,7 @@ test "@ptrCast undefined value at comptime" {
277278 }
278279 };
279280 comptime {
280 const x = S.transmute([]u8, i32, undefined);
281 const x = S.transmute(u64, i32, undefined);
281282 _ = x;
282283 }
283284}
......@@ -292,3 +293,60 @@ test "comptime @ptrCast with packed struct leaves value unmodified" {
292293 try expect(p.*[0] == 6);
293294 try expect(st.three == 6);
294295}
296
297test "@ptrCast restructures comptime-only array" {
298 {
299 const a3a2: [3][2]comptime_int = .{
300 .{ 1, 2 },
301 .{ 3, 4 },
302 .{ 5, 6 },
303 };
304 const a2a3: *const [2][3]comptime_int = @ptrCast(&a3a2);
305 comptime assert(a2a3[0][0] == 1);
306 comptime assert(a2a3[0][1] == 2);
307 comptime assert(a2a3[0][2] == 3);
308 comptime assert(a2a3[1][0] == 4);
309 comptime assert(a2a3[1][1] == 5);
310 comptime assert(a2a3[1][2] == 6);
311 }
312
313 {
314 const a6a1: [6][1]comptime_int = .{
315 .{1}, .{2}, .{3}, .{4}, .{5}, .{6},
316 };
317 const a1a2a3: *const [1][2][3]comptime_int = @ptrCast(&a6a1);
318 comptime assert(a1a2a3[0][0][0] == 1);
319 comptime assert(a1a2a3[0][0][1] == 2);
320 comptime assert(a1a2a3[0][0][2] == 3);
321 comptime assert(a1a2a3[0][1][0] == 4);
322 comptime assert(a1a2a3[0][1][1] == 5);
323 comptime assert(a1a2a3[0][1][2] == 6);
324 }
325
326 {
327 const a1: [1]comptime_int = .{123};
328 const raw: *const comptime_int = @ptrCast(&a1);
329 comptime assert(raw.* == 123);
330 }
331
332 {
333 const raw: comptime_int = 123;
334 const a1: *const [1]comptime_int = @ptrCast(&raw);
335 comptime assert(a1[0] == 123);
336 }
337}
338
339test "@ptrCast restructures sliced comptime-only array" {
340 const a3a2: [4][2]comptime_int = .{
341 .{ 1, 2 },
342 .{ 3, 4 },
343 .{ 5, 6 },
344 .{ 7, 8 },
345 };
346
347 const sub: *const [4]comptime_int = @ptrCast(a3a2[1..]);
348 comptime assert(sub[0] == 3);
349 comptime assert(sub[1] == 4);
350 comptime assert(sub[2] == 5);
351 comptime assert(sub[3] == 6);
352}
test/behavior/type.zig+21
......@@ -758,3 +758,24 @@ test "matching captures causes opaque equivalence" {
758758 comptime assert(@TypeOf(a) == @TypeOf(b));
759759 try testing.expect(a == b);
760760}
761
762test "reify enum where fields refers to part of array" {
763 const fields: [3]std.builtin.Type.EnumField = .{
764 .{ .name = "foo", .value = 0 },
765 .{ .name = "bar", .value = 1 },
766 undefined,
767 };
768 const E = @Type(.{ .Enum = .{
769 .tag_type = u8,
770 .fields = fields[0..2],
771 .decls = &.{},
772 .is_exhaustive = true,
773 } });
774 var a: E = undefined;
775 var b: E = undefined;
776 a = .foo;
777 b = .bar;
778 try testing.expect(a == .foo);
779 try testing.expect(b == .bar);
780 try testing.expect(a != b);
781}
test/behavior/union.zig+3-4
......@@ -1532,7 +1532,7 @@ test "reinterpreting enum value inside packed union" {
15321532 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
15331533
15341534 const U = packed union {
1535 tag: enum { a, b },
1535 tag: enum(u8) { a, b },
15361536 val: u8,
15371537
15381538 fn doTest() !void {
......@@ -1850,9 +1850,8 @@ test "reinterpret packed union" {
18501850
18511851 {
18521852 // Union initialization
1853 var u: U = .{
1854 .qux = 0xe2a,
1855 };
1853 var u: U = .{ .baz = 0 }; // ensure all bits are defined
1854 u.qux = 0xe2a;
18561855 try expectEqual(@as(u8, 0x2a), u.foo);
18571856 try expectEqual(@as(u12, 0xe2a), u.qux);
18581857 try expectEqual(@as(u29, 0xe2a), u.bar & 0xfff);
test/cases/compile_errors/bad_usingnamespace_transitive_failure.zig created+31
......@@ -0,0 +1,31 @@
1//! The full test name would be:
2//! struct field type resolution marks transitive error from bad usingnamespace in @typeInfo call from non-initial field type
3//!
4//! This test is rather esoteric. It's ensuring that errors triggered by `@typeInfo` analyzing
5//! a bad `usingnamespace` correctly trigger transitive errors when analyzed by struct field type
6//! resolution, meaning we don't incorrectly analyze code past the uses of `S`.
7
8const S = struct {
9 ok: u32,
10 bad: @typeInfo(T),
11};
12
13const T = struct {
14 pub usingnamespace @compileError("usingnamespace analyzed");
15};
16
17comptime {
18 const a: S = .{ .ok = 123, .bad = undefined };
19 _ = a;
20 @compileError("should not be reached");
21}
22
23comptime {
24 const b: S = .{ .ok = 123, .bad = undefined };
25 _ = b;
26 @compileError("should not be reached");
27}
28
29// error
30//
31// :14:24: error: usingnamespace analyzed
test/cases/compile_errors/bit_ptr_non_packed.zig created+22
......@@ -0,0 +1,22 @@
1export fn entry1() void {
2 const S = extern struct { x: u32 };
3 _ = *align(1:2:8) S;
4}
5
6export fn entry2() void {
7 const S = struct { x: u32 };
8 _ = *align(1:2:@sizeOf(S) * 2) S;
9}
10
11export fn entry3() void {
12 const E = enum { implicit, backing, type };
13 _ = *align(1:2:8) E;
14}
15
16// error
17//
18// :3:23: error: bit-pointer cannot refer to value of type 'tmp.entry1.S'
19// :3:23: note: only packed structs layout are allowed in packed types
20// :8:36: error: bit-pointer cannot refer to value of type 'tmp.entry2.S'
21// :8:36: note: only packed structs layout are allowed in packed types
22// :13:23: error: bit-pointer cannot refer to value of type 'tmp.entry3.E'
test/cases/compile_errors/bitcast_undef.zig created+12
......@@ -0,0 +1,12 @@
1export fn entry1() void {
2 const x: i32 = undefined;
3 const y: u32 = @bitCast(x);
4 @compileLog(y);
5}
6
7// error
8//
9// :4:5: error: found compile log statement
10//
11// Compile Log Output:
12// @as(u32, undefined)
test/cases/compile_errors/compile_log_a_pointer_to_an_opaque_value.zig+1-1
......@@ -9,4 +9,4 @@ export fn entry() void {
99// :2:5: error: found compile log statement
1010//
1111// Compile Log Output:
12// @as(*const anyopaque, &tmp.entry)
12// @as(*const anyopaque, @as(*const anyopaque, @ptrCast(tmp.entry)))
test/cases/compile_errors/comptime_dereference_slice_of_struct.zig deleted-13
......@@ -1,13 +0,0 @@
1const MyStruct = struct { x: bool = false };
2
3comptime {
4 const x = &[_]MyStruct{ .{}, .{} };
5 const y = x[0..1] ++ &[_]MyStruct{};
6 _ = y;
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :5:16: error: comptime dereference requires '[1]tmp.MyStruct' to have a well-defined layout, but it does not.
test/cases/compile_errors/dereferencing_invalid_payload_ptr_at_comptime.zig+1-2
......@@ -6,7 +6,7 @@ comptime {
66
77 const payload_ptr = &opt_ptr.?;
88 opt_ptr = null;
9 _ = payload_ptr.*.*;
9 _ = payload_ptr.*.*; // TODO: this case was regressed by #19630
1010}
1111comptime {
1212 var opt: ?u8 = 15;
......@@ -28,6 +28,5 @@ comptime {
2828// backend=stage2
2929// target=native
3030//
31// :9:20: error: attempt to use null value
3231// :16:20: error: attempt to use null value
3332// :24:20: error: attempt to unwrap error: Foo
test/cases/compile_errors/function_call_assigned_to_incorrect_type.zig+2-1
......@@ -11,4 +11,5 @@ fn concat() [16]f32 {
1111// target=native
1212//
1313// :3:17: error: expected type '[4]f32', found '[16]f32'
14// :3:17: note: array of length 16 cannot cast into an array of length 4
14// :3:17: note: destination has length 4
15// :3:17: note: source has length 16
test/cases/compile_errors/issue_7810-comptime_slice-len_increment_beyond_bounds.zig+1-3
......@@ -8,7 +8,5 @@ export fn foo_slice_len_increment_beyond_bounds() void {
88}
99
1010// error
11// backend=stage2
12// target=native
1311//
14// :6:16: error: comptime store of index 8 out of bounds of array length 8
12// :6:16: error: dereference of '*u8' exceeds bounds of containing decl of type '[8]u8'
test/cases/compile_errors/overflow_arithmetic_on_vector_with_undefined_elems.zig created+26
......@@ -0,0 +1,26 @@
1comptime {
2 const a: @Vector(3, u8) = .{ 1, 200, undefined };
3 @compileLog(@addWithOverflow(a, a));
4}
5
6comptime {
7 const a: @Vector(3, u8) = .{ 1, 2, undefined };
8 const b: @Vector(3, u8) = .{ 0, 3, 10 };
9 @compileLog(@subWithOverflow(a, b));
10}
11
12comptime {
13 const a: @Vector(3, u8) = .{ 1, 200, undefined };
14 @compileLog(@mulWithOverflow(a, a));
15}
16
17// error
18//
19// :3:5: error: found compile log statement
20// :9:5: note: also here
21// :14:5: note: also here
22//
23// Compile Log Output:
24// @as(struct{@Vector(3, u8), @Vector(3, u1)}, .{ .{ 2, 144, undefined }, .{ 0, 1, undefined } })
25// @as(struct{@Vector(3, u8), @Vector(3, u1)}, .{ .{ 1, 255, undefined }, .{ 0, 1, undefined } })
26// @as(struct{@Vector(3, u8), @Vector(3, u1)}, .{ .{ 1, 64, undefined }, .{ 0, 1, undefined } })
test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig+9-1
......@@ -30,7 +30,7 @@ export fn entry6() void {
3030}
3131export fn entry7() void {
3232 _ = @sizeOf(packed struct {
33 x: enum { A, B },
33 x: enum(u1) { A, B },
3434 });
3535}
3636export fn entry8() void {
......@@ -70,6 +70,12 @@ export fn entry13() void {
7070 x: *type,
7171 });
7272}
73export fn entry14() void {
74 const E = enum { implicit, backing, type };
75 _ = @sizeOf(packed struct {
76 x: E,
77 });
78}
7379
7480// error
7581// backend=llvm
......@@ -97,3 +103,5 @@ export fn entry13() void {
97103// :70:12: error: packed structs cannot contain fields of type '*type'
98104// :70:12: note: comptime-only pointer has no guaranteed in-memory representation
99105// :70:12: note: types are not available at runtime
106// :76:12: error: packed structs cannot contain fields of type 'tmp.entry14.E'
107// :74:15: note: enum declared here
test/cases/compile_errors/pointer_exceeds_containing_value.zig created+19
......@@ -0,0 +1,19 @@
1export fn entry1() void {
2 const x: u32 = 123;
3 const ptr: [*]const u32 = @ptrCast(&x);
4 _ = ptr - 1;
5}
6
7export fn entry2() void {
8 const S = extern struct { x: u32, y: u32 };
9 const y: u32 = 123;
10 const parent_ptr: *const S = @fieldParentPtr("y", &y);
11 _ = parent_ptr;
12}
13
14// error
15//
16// :4:13: error: pointer computation here causes undefined behavior
17// :4:13: note: resulting pointer exceeds bounds of containing value which may trigger overflow
18// :10:55: error: pointer computation here causes undefined behavior
19// :10:55: note: resulting pointer exceeds bounds of containing value which may trigger overflow
test/cases/compile_errors/reading_past_end_of_pointer_casted_array.zig+8
......@@ -5,9 +5,17 @@ comptime {
55 const deref = int_ptr.*;
66 _ = deref;
77}
8comptime {
9 const array: [4]u8 = "aoeu".*;
10 const sub_array = array[1..];
11 const int_ptr: *const u32 = @ptrCast(@alignCast(sub_array));
12 const deref = int_ptr.*;
13 _ = deref;
14}
815
916// error
1017// backend=stage2
1118// target=native
1219//
1320// :5:26: error: dereference of '*const u24' exceeds bounds of containing decl of type '[4]u8'
21// :12:26: error: dereference of '*const u32' exceeds bounds of containing decl of type '[4]u8'
test/cases/compile_errors/slice_cannot_have_its_bytes_reinterpreted.zig+1-1
......@@ -7,4 +7,4 @@ export fn foo() void {
77// backend=stage2
88// target=native
99//
10// :3:49: error: comptime dereference requires '[]const u8' to have a well-defined layout, but it does not.
10// :3:49: error: comptime dereference requires '[]const u8' to have a well-defined layout
test/cases/comptime_aggregate_print.zig+2-2
......@@ -31,5 +31,5 @@ pub fn main() !void {}
3131// :20:5: error: found compile log statement
3232//
3333// Compile Log Output:
34// @as([]i32, &(comptime alloc).buf[0..2])
35// @as([]i32, &(comptime alloc).buf[0..2])
34// @as([]i32, @as([*]i32, @ptrCast(@as(tmp.UnionContainer, .{ .buf = .{ 1, 2 } }).buf[0]))[0..2])
35// @as([]i32, @as([*]i32, @ptrCast(@as(tmp.StructContainer, .{ .buf = .{ 3, 4 } }).buf[0]))[0..2])