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" {...@@ -232,7 +232,7 @@ test "icon data size too small" {
232 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));232 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));
233}233}
234234
235pub const ImageFormat = enum {235pub const ImageFormat = enum(u2) {
236 dib,236 dib,
237 png,237 png,
238 riff,238 riff,
...@@ -272,7 +272,7 @@ pub const BitmapHeader = extern struct {...@@ -272,7 +272,7 @@ pub const BitmapHeader = extern struct {
272 }272 }
273273
274 /// https://en.wikipedia.org/wiki/BMP_file_format#DIB_header_(bitmap_information_header)274 /// https://en.wikipedia.org/wiki/BMP_file_format#DIB_header_(bitmap_information_header)
275 pub const Version = enum {275 pub const Version = enum(u3) {
276 unknown,276 unknown,
277 @"win2.0", // Windows 2.0 or later277 @"win2.0", // Windows 2.0 or later
278 @"nt3.1", // Windows NT, 3.1x or later278 @"nt3.1", // Windows NT, 3.1x or later
lib/docs/wasm/markdown/Document.zig+1-1
...@@ -131,7 +131,7 @@ pub const Node = struct {...@@ -131,7 +131,7 @@ pub const Node = struct {
131 }131 }
132 };132 };
133133
134 pub const TableCellAlignment = enum {134 pub const TableCellAlignment = enum(u2) {
135 unset,135 unset,
136 left,136 left,
137 center,137 center,
lib/std/net.zig+1-1
...@@ -271,7 +271,7 @@ pub const Ip4Address = extern struct {...@@ -271,7 +271,7 @@ pub const Ip4Address = extern struct {
271 sa: posix.sockaddr.in,271 sa: posix.sockaddr.in,
272272
273 pub fn parse(buf: []const u8, port: u16) IPv4ParseError!Ip4Address {273 pub fn parse(buf: []const u8, port: u16) IPv4ParseError!Ip4Address {
274 var result = Ip4Address{274 var result: Ip4Address = .{
275 .sa = .{275 .sa = .{
276 .port = mem.nativeToBig(u16, port),276 .port = mem.nativeToBig(u16, port),
277 .addr = undefined,277 .addr = undefined,
src/InternPool.zig+312-140
...@@ -565,7 +565,7 @@ pub const OptionalNullTerminatedString = enum(u32) {...@@ -565,7 +565,7 @@ pub const OptionalNullTerminatedString = enum(u32) {
565/// * decl val (so that we can analyze the value lazily)565/// * decl val (so that we can analyze the value lazily)
566/// * decl ref (so that we can analyze the reference lazily)566/// * decl ref (so that we can analyze the reference lazily)
567pub const CaptureValue = packed struct(u32) {567pub const CaptureValue = packed struct(u32) {
568 tag: enum { @"comptime", runtime, decl_val, decl_ref },568 tag: enum(u2) { @"comptime", runtime, decl_val, decl_ref },
569 idx: u30,569 idx: u30,
570570
571 pub fn wrap(val: Unwrapped) CaptureValue {571 pub fn wrap(val: Unwrapped) CaptureValue {
...@@ -1026,22 +1026,76 @@ pub const Key = union(enum) {...@@ -1026,22 +1026,76 @@ pub const Key = union(enum) {
1026 pub const Ptr = struct {1026 pub const Ptr = struct {
1027 /// This is the pointer type, not the element type.1027 /// This is the pointer type, not the element type.
1028 ty: Index,1028 ty: Index,
1029 /// The value of the address that the pointer points to.1029 /// The base address which this pointer is offset from.
1030 addr: Addr,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) {1034 pub const BaseAddr = union(enum) {
1033 const Tag = @typeInfo(Addr).Union.tag_type.?;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`.
1035 decl: DeclIndex,1038 decl: DeclIndex,
1039
1040 /// Points to the value of a single comptime alloc stored in `Sema`.
1036 comptime_alloc: ComptimeAllocIndex,1041 comptime_alloc: ComptimeAllocIndex,
1042
1043 /// Points to a single unnamed constant value.
1037 anon_decl: AnonDecl,1044 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.
1038 comptime_field: Index,1050 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.
1040 eu_payload: Index,1066 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`.
1041 opt_payload: Index,1071 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`.
1043 field: BaseIndex,1077 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
1045 pub const MutDecl = struct {1099 pub const MutDecl = struct {
1046 decl: DeclIndex,1100 decl: DeclIndex,
1047 runtime_index: RuntimeIndex,1101 runtime_index: RuntimeIndex,
...@@ -1222,10 +1276,11 @@ pub const Key = union(enum) {...@@ -1222,10 +1276,11 @@ pub const Key = union(enum) {
1222 .ptr => |ptr| {1276 .ptr => |ptr| {
1223 // Int-to-ptr pointers are hashed separately than decl-referencing pointers.1277 // Int-to-ptr pointers are hashed separately than decl-referencing pointers.
1224 // This is sound due to pointer provenance rules.1278 // This is sound due to pointer provenance rules.
1225 const addr: @typeInfo(Key.Ptr.Addr).Union.tag_type.? = ptr.addr;1279 const addr_tag: Key.Ptr.BaseAddr.Tag = ptr.base_addr;
1226 const seed2 = seed + @intFromEnum(addr);1280 const seed2 = seed + @intFromEnum(addr_tag);
1227 const common = asBytes(&ptr.ty);1281 const big_offset: i128 = ptr.byte_offset;
1228 return switch (ptr.addr) {1282 const common = asBytes(&ptr.ty) ++ asBytes(&big_offset);
1283 return switch (ptr.base_addr) {
1229 inline .decl,1284 inline .decl,
1230 .comptime_alloc,1285 .comptime_alloc,
1231 .anon_decl,1286 .anon_decl,
...@@ -1235,7 +1290,7 @@ pub const Key = union(enum) {...@@ -1235,7 +1290,7 @@ pub const Key = union(enum) {
1235 .comptime_field,1290 .comptime_field,
1236 => |x| Hash.hash(seed2, common ++ asBytes(&x)),1291 => |x| Hash.hash(seed2, common ++ asBytes(&x)),
12371292
1238 .elem, .field => |x| Hash.hash(1293 .arr_elem, .field => |x| Hash.hash(
1239 seed2,1294 seed2,
1240 common ++ asBytes(&x.base) ++ asBytes(&x.index),1295 common ++ asBytes(&x.base) ++ asBytes(&x.index),
1241 ),1296 ),
...@@ -1494,21 +1549,21 @@ pub const Key = union(enum) {...@@ -1494,21 +1549,21 @@ pub const Key = union(enum) {
1494 .ptr => |a_info| {1549 .ptr => |a_info| {
1495 const b_info = b.ptr;1550 const b_info = b.ptr;
1496 if (a_info.ty != b_info.ty) return false;1551 if (a_info.ty != b_info.ty) return false;
14971552 if (a_info.byte_offset != b_info.byte_offset) return false;
1498 const AddrTag = @typeInfo(Key.Ptr.Addr).Union.tag_type.?;1553
1499 if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false;1554 if (@as(Key.Ptr.BaseAddr.Tag, a_info.base_addr) != @as(Key.Ptr.BaseAddr.Tag, b_info.base_addr)) return false;
15001555
1501 return switch (a_info.addr) {1556 return switch (a_info.base_addr) {
1502 .decl => |a_decl| a_decl == b_info.addr.decl,1557 .decl => |a_decl| a_decl == b_info.base_addr.decl,
1503 .comptime_alloc => |a_alloc| a_alloc == b_info.addr.comptime_alloc,1558 .comptime_alloc => |a_alloc| a_alloc == b_info.base_addr.comptime_alloc,
1504 .anon_decl => |ad| ad.val == b_info.addr.anon_decl.val and1559 .anon_decl => |ad| ad.val == b_info.base_addr.anon_decl.val and
1505 ad.orig_ty == b_info.addr.anon_decl.orig_ty,1560 ad.orig_ty == b_info.base_addr.anon_decl.orig_ty,
1506 .int => |a_int| a_int == b_info.addr.int,1561 .int => true,
1507 .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload,1562 .eu_payload => |a_eu_payload| a_eu_payload == b_info.base_addr.eu_payload,
1508 .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload,1563 .opt_payload => |a_opt_payload| a_opt_payload == b_info.base_addr.opt_payload,
1509 .comptime_field => |a_comptime_field| a_comptime_field == b_info.addr.comptime_field,1564 .comptime_field => |a_comptime_field| a_comptime_field == b_info.base_addr.comptime_field,
1510 .elem => |a_elem| std.meta.eql(a_elem, b_info.addr.elem),1565 .arr_elem => |a_elem| std.meta.eql(a_elem, b_info.base_addr.arr_elem),
1511 .field => |a_field| std.meta.eql(a_field, b_info.addr.field),1566 .field => |a_field| std.meta.eql(a_field, b_info.base_addr.field),
1512 };1567 };
1513 },1568 },
15141569
...@@ -2271,6 +2326,46 @@ pub const LoadedStructType = struct {...@@ -2271,6 +2326,46 @@ pub const LoadedStructType = struct {
2271 .struct_type = s,2326 .struct_type = s,
2272 };2327 };
2273 }2328 }
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 }
2274};2369};
22752370
2276pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {2371pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
...@@ -2836,7 +2931,7 @@ pub const Index = enum(u32) {...@@ -2836,7 +2931,7 @@ pub const Index = enum(u32) {
2836 ptr_anon_decl: struct { data: *PtrAnonDecl },2931 ptr_anon_decl: struct { data: *PtrAnonDecl },
2837 ptr_anon_decl_aligned: struct { data: *PtrAnonDeclAligned },2932 ptr_anon_decl_aligned: struct { data: *PtrAnonDeclAligned },
2838 ptr_comptime_field: struct { data: *PtrComptimeField },2933 ptr_comptime_field: struct { data: *PtrComptimeField },
2839 ptr_int: struct { data: *PtrBase },2934 ptr_int: struct { data: *PtrInt },
2840 ptr_eu_payload: struct { data: *PtrBase },2935 ptr_eu_payload: struct { data: *PtrBase },
2841 ptr_opt_payload: struct { data: *PtrBase },2936 ptr_opt_payload: struct { data: *PtrBase },
2842 ptr_elem: struct { data: *PtrBaseIndex },2937 ptr_elem: struct { data: *PtrBaseIndex },
...@@ -3304,7 +3399,7 @@ pub const Tag = enum(u8) {...@@ -3304,7 +3399,7 @@ pub const Tag = enum(u8) {
3304 /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value.3399 /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value.
3305 ptr_comptime_field,3400 ptr_comptime_field,
3306 /// A pointer with an integer value.3401 /// 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).
3308 /// Only pointer types are allowed to have this encoding. Optional types must use3403 /// Only pointer types are allowed to have this encoding. Optional types must use
3309 /// `opt_payload` or `opt_null`.3404 /// `opt_payload` or `opt_null`.
3310 ptr_int,3405 ptr_int,
...@@ -3497,7 +3592,7 @@ pub const Tag = enum(u8) {...@@ -3497,7 +3592,7 @@ pub const Tag = enum(u8) {
3497 .ptr_anon_decl => PtrAnonDecl,3592 .ptr_anon_decl => PtrAnonDecl,
3498 .ptr_anon_decl_aligned => PtrAnonDeclAligned,3593 .ptr_anon_decl_aligned => PtrAnonDeclAligned,
3499 .ptr_comptime_field => PtrComptimeField,3594 .ptr_comptime_field => PtrComptimeField,
3500 .ptr_int => PtrBase,3595 .ptr_int => PtrInt,
3501 .ptr_eu_payload => PtrBase,3596 .ptr_eu_payload => PtrBase,
3502 .ptr_opt_payload => PtrBase,3597 .ptr_opt_payload => PtrBase,
3503 .ptr_elem => PtrBaseIndex,3598 .ptr_elem => PtrBaseIndex,
...@@ -4153,11 +4248,37 @@ pub const PackedU64 = packed struct(u64) {...@@ -4153,11 +4248,37 @@ pub const PackedU64 = packed struct(u64) {
4153pub const PtrDecl = struct {4248pub const PtrDecl = struct {
4154 ty: Index,4249 ty: Index,
4155 decl: DeclIndex,4250 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 }
4156};4264};
41574265
4158pub const PtrAnonDecl = struct {4266pub const PtrAnonDecl = struct {
4159 ty: Index,4267 ty: Index,
4160 val: Index,4268 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 }
4161};4282};
41624283
4163pub const PtrAnonDeclAligned = struct {4284pub const PtrAnonDeclAligned = struct {
...@@ -4165,27 +4286,110 @@ pub const PtrAnonDeclAligned = struct {...@@ -4165,27 +4286,110 @@ pub const PtrAnonDeclAligned = struct {
4165 val: Index,4286 val: Index,
4166 /// Must be nonequal to `ty`. Only the alignment from this value is important.4287 /// Must be nonequal to `ty`. Only the alignment from this value is important.
4167 orig_ty: Index,4288 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 }
4168};4303};
41694304
4170pub const PtrComptimeAlloc = struct {4305pub const PtrComptimeAlloc = struct {
4171 ty: Index,4306 ty: Index,
4172 index: ComptimeAllocIndex,4307 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 }
4173};4321};
41744322
4175pub const PtrComptimeField = struct {4323pub const PtrComptimeField = struct {
4176 ty: Index,4324 ty: Index,
4177 field_val: Index,4325 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 }
4178};4339};
41794340
4180pub const PtrBase = struct {4341pub const PtrBase = struct {
4181 ty: Index,4342 ty: Index,
4182 base: Index,4343 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 }
4183};4357};
41844358
4185pub const PtrBaseIndex = struct {4359pub const PtrBaseIndex = struct {
4186 ty: Index,4360 ty: Index,
4187 base: Index,4361 base: Index,
4188 index: Index,4362 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 }
4189};4393};
41904394
4191pub const PtrSlice = struct {4395pub const PtrSlice = struct {
...@@ -4569,78 +4773,55 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -4569,78 +4773,55 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
4569 },4773 },
4570 .ptr_decl => {4774 .ptr_decl => {
4571 const info = ip.extraData(PtrDecl, data);4775 const info = ip.extraData(PtrDecl, data);
4572 return .{ .ptr = .{4776 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .decl = info.decl }, .byte_offset = info.byteOffset() } };
4573 .ty = info.ty,
4574 .addr = .{ .decl = info.decl },
4575 } };
4576 },4777 },
4577 .ptr_comptime_alloc => {4778 .ptr_comptime_alloc => {
4578 const info = ip.extraData(PtrComptimeAlloc, data);4779 const info = ip.extraData(PtrComptimeAlloc, data);
4579 return .{ .ptr = .{4780 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .comptime_alloc = info.index }, .byte_offset = info.byteOffset() } };
4580 .ty = info.ty,
4581 .addr = .{ .comptime_alloc = info.index },
4582 } };
4583 },4781 },
4584 .ptr_anon_decl => {4782 .ptr_anon_decl => {
4585 const info = ip.extraData(PtrAnonDecl, data);4783 const info = ip.extraData(PtrAnonDecl, data);
4586 return .{ .ptr = .{4784 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .anon_decl = .{
4587 .ty = info.ty,4785 .val = info.val,
4588 .addr = .{ .anon_decl = .{4786 .orig_ty = info.ty,
4589 .val = info.val,4787 } }, .byte_offset = info.byteOffset() } };
4590 .orig_ty = info.ty,
4591 } },
4592 } };
4593 },4788 },
4594 .ptr_anon_decl_aligned => {4789 .ptr_anon_decl_aligned => {
4595 const info = ip.extraData(PtrAnonDeclAligned, data);4790 const info = ip.extraData(PtrAnonDeclAligned, data);
4596 return .{ .ptr = .{4791 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .anon_decl = .{
4597 .ty = info.ty,4792 .val = info.val,
4598 .addr = .{ .anon_decl = .{4793 .orig_ty = info.orig_ty,
4599 .val = info.val,4794 } }, .byte_offset = info.byteOffset() } };
4600 .orig_ty = info.orig_ty,
4601 } },
4602 } };
4603 },4795 },
4604 .ptr_comptime_field => {4796 .ptr_comptime_field => {
4605 const info = ip.extraData(PtrComptimeField, data);4797 const info = ip.extraData(PtrComptimeField, data);
4606 return .{ .ptr = .{4798 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .comptime_field = info.field_val }, .byte_offset = info.byteOffset() } };
4607 .ty = info.ty,
4608 .addr = .{ .comptime_field = info.field_val },
4609 } };
4610 },4799 },
4611 .ptr_int => {4800 .ptr_int => {
4612 const info = ip.extraData(PtrBase, data);4801 const info = ip.extraData(PtrInt, data);
4613 return .{ .ptr = .{4802 return .{ .ptr = .{
4614 .ty = info.ty,4803 .ty = info.ty,
4615 .addr = .{ .int = info.base },4804 .base_addr = .int,
4805 .byte_offset = info.byteOffset(),
4616 } };4806 } };
4617 },4807 },
4618 .ptr_eu_payload => {4808 .ptr_eu_payload => {
4619 const info = ip.extraData(PtrBase, data);4809 const info = ip.extraData(PtrBase, data);
4620 return .{ .ptr = .{4810 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .eu_payload = info.base }, .byte_offset = info.byteOffset() } };
4621 .ty = info.ty,
4622 .addr = .{ .eu_payload = info.base },
4623 } };
4624 },4811 },
4625 .ptr_opt_payload => {4812 .ptr_opt_payload => {
4626 const info = ip.extraData(PtrBase, data);4813 const info = ip.extraData(PtrBase, data);
4627 return .{ .ptr = .{4814 return .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .opt_payload = info.base }, .byte_offset = info.byteOffset() } };
4628 .ty = info.ty,
4629 .addr = .{ .opt_payload = info.base },
4630 } };
4631 },4815 },
4632 .ptr_elem => {4816 .ptr_elem => {
4633 // Avoid `indexToKey` recursion by asserting the tag encoding.4817 // Avoid `indexToKey` recursion by asserting the tag encoding.
4634 const info = ip.extraData(PtrBaseIndex, data);4818 const info = ip.extraData(PtrBaseIndex, data);
4635 const index_item = ip.items.get(@intFromEnum(info.index));4819 const index_item = ip.items.get(@intFromEnum(info.index));
4636 return switch (index_item.tag) {4820 return switch (index_item.tag) {
4637 .int_usize => .{ .ptr = .{4821 .int_usize => .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .arr_elem = .{
4638 .ty = info.ty,4822 .base = info.base,
4639 .addr = .{ .elem = .{4823 .index = index_item.data,
4640 .base = info.base,4824 } }, .byte_offset = info.byteOffset() } },
4641 .index = index_item.data,
4642 } },
4643 } },
4644 .int_positive => @panic("TODO"), // implement along with behavior test coverage4825 .int_positive => @panic("TODO"), // implement along with behavior test coverage
4645 else => unreachable,4826 else => unreachable,
4646 };4827 };
...@@ -4650,13 +4831,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -4650,13 +4831,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
4650 const info = ip.extraData(PtrBaseIndex, data);4831 const info = ip.extraData(PtrBaseIndex, data);
4651 const index_item = ip.items.get(@intFromEnum(info.index));4832 const index_item = ip.items.get(@intFromEnum(info.index));
4652 return switch (index_item.tag) {4833 return switch (index_item.tag) {
4653 .int_usize => .{ .ptr = .{4834 .int_usize => .{ .ptr = .{ .ty = info.ty, .base_addr = .{ .field = .{
4654 .ty = info.ty,4835 .base = info.base,
4655 .addr = .{ .field = .{4836 .index = index_item.data,
4656 .base = info.base,4837 } }, .byte_offset = info.byteOffset() } },
4657 .index = index_item.data,
4658 } },
4659 } },
4660 .int_positive => @panic("TODO"), // implement along with behavior test coverage4838 .int_positive => @panic("TODO"), // implement along with behavior test coverage
4661 else => unreachable,4839 else => unreachable,
4662 };4840 };
...@@ -5211,57 +5389,40 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -5211,57 +5389,40 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
5211 .ptr => |ptr| {5389 .ptr => |ptr| {
5212 const ptr_type = ip.indexToKey(ptr.ty).ptr_type;5390 const ptr_type = ip.indexToKey(ptr.ty).ptr_type;
5213 assert(ptr_type.flags.size != .Slice);5391 assert(ptr_type.flags.size != .Slice);
5214 ip.items.appendAssumeCapacity(switch (ptr.addr) {5392 ip.items.appendAssumeCapacity(switch (ptr.base_addr) {
5215 .decl => |decl| .{5393 .decl => |decl| .{
5216 .tag = .ptr_decl,5394 .tag = .ptr_decl,
5217 .data = try ip.addExtra(gpa, PtrDecl{5395 .data = try ip.addExtra(gpa, PtrDecl.init(ptr.ty, decl, ptr.byte_offset)),
5218 .ty = ptr.ty,
5219 .decl = decl,
5220 }),
5221 },5396 },
5222 .comptime_alloc => |alloc_index| .{5397 .comptime_alloc => |alloc_index| .{
5223 .tag = .ptr_comptime_alloc,5398 .tag = .ptr_comptime_alloc,
5224 .data = try ip.addExtra(gpa, PtrComptimeAlloc{5399 .data = try ip.addExtra(gpa, PtrComptimeAlloc.init(ptr.ty, alloc_index, ptr.byte_offset)),
5225 .ty = ptr.ty,
5226 .index = alloc_index,
5227 }),
5228 },5400 },
5229 .anon_decl => |anon_decl| if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) item: {5401 .anon_decl => |anon_decl| if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) item: {
5230 if (ptr.ty != anon_decl.orig_ty) {5402 if (ptr.ty != anon_decl.orig_ty) {
5231 _ = ip.map.pop();5403 _ = ip.map.pop();
5232 var new_key = key;5404 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;
5234 const new_gop = try ip.map.getOrPutAdapted(gpa, new_key, adapter);5406 const new_gop = try ip.map.getOrPutAdapted(gpa, new_key, adapter);
5235 if (new_gop.found_existing) return @enumFromInt(new_gop.index);5407 if (new_gop.found_existing) return @enumFromInt(new_gop.index);
5236 }5408 }
5237 break :item .{5409 break :item .{
5238 .tag = .ptr_anon_decl,5410 .tag = .ptr_anon_decl,
5239 .data = try ip.addExtra(gpa, PtrAnonDecl{5411 .data = try ip.addExtra(gpa, PtrAnonDecl.init(ptr.ty, anon_decl.val, ptr.byte_offset)),
5240 .ty = ptr.ty,
5241 .val = anon_decl.val,
5242 }),
5243 };5412 };
5244 } else .{5413 } else .{
5245 .tag = .ptr_anon_decl_aligned,5414 .tag = .ptr_anon_decl_aligned,
5246 .data = try ip.addExtra(gpa, PtrAnonDeclAligned{5415 .data = try ip.addExtra(gpa, PtrAnonDeclAligned.init(ptr.ty, anon_decl.val, anon_decl.orig_ty, ptr.byte_offset)),
5247 .ty = ptr.ty,
5248 .val = anon_decl.val,
5249 .orig_ty = anon_decl.orig_ty,
5250 }),
5251 },5416 },
5252 .comptime_field => |field_val| item: {5417 .comptime_field => |field_val| item: {
5253 assert(field_val != .none);5418 assert(field_val != .none);
5254 break :item .{5419 break :item .{
5255 .tag = .ptr_comptime_field,5420 .tag = .ptr_comptime_field,
5256 .data = try ip.addExtra(gpa, PtrComptimeField{5421 .data = try ip.addExtra(gpa, PtrComptimeField.init(ptr.ty, field_val, ptr.byte_offset)),
5257 .ty = ptr.ty,
5258 .field_val = field_val,
5259 }),
5260 };5422 };
5261 },5423 },
5262 .int, .eu_payload, .opt_payload => |base| item: {5424 .eu_payload, .opt_payload => |base| item: {
5263 switch (ptr.addr) {5425 switch (ptr.base_addr) {
5264 .int => assert(ip.typeOf(base) == .usize_type),
5265 .eu_payload => assert(ip.indexToKey(5426 .eu_payload => assert(ip.indexToKey(
5266 ip.indexToKey(ip.typeOf(base)).ptr_type.child,5427 ip.indexToKey(ip.typeOf(base)).ptr_type.child,
5267 ) == .error_union_type),5428 ) == .error_union_type),
...@@ -5271,40 +5432,40 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -5271,40 +5432,40 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
5271 else => unreachable,5432 else => unreachable,
5272 }5433 }
5273 break :item .{5434 break :item .{
5274 .tag = switch (ptr.addr) {5435 .tag = switch (ptr.base_addr) {
5275 .int => .ptr_int,
5276 .eu_payload => .ptr_eu_payload,5436 .eu_payload => .ptr_eu_payload,
5277 .opt_payload => .ptr_opt_payload,5437 .opt_payload => .ptr_opt_payload,
5278 else => unreachable,5438 else => unreachable,
5279 },5439 },
5280 .data = try ip.addExtra(gpa, PtrBase{5440 .data = try ip.addExtra(gpa, PtrBase.init(ptr.ty, base, ptr.byte_offset)),
5281 .ty = ptr.ty,
5282 .base = base,
5283 }),
5284 };5441 };
5285 },5442 },
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: {
5287 const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type;5448 const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type;
5288 switch (ptr.addr) {5449 switch (ptr.base_addr) {
5289 .elem => assert(base_ptr_type.flags.size == .Many),5450 .arr_elem => assert(base_ptr_type.flags.size == .Many),
5290 .field => {5451 .field => {
5291 assert(base_ptr_type.flags.size == .One);5452 assert(base_ptr_type.flags.size == .One);
5292 switch (ip.indexToKey(base_ptr_type.child)) {5453 switch (ip.indexToKey(base_ptr_type.child)) {
5293 .anon_struct_type => |anon_struct_type| {5454 .anon_struct_type => |anon_struct_type| {
5294 assert(ptr.addr == .field);5455 assert(ptr.base_addr == .field);
5295 assert(base_index.index < anon_struct_type.types.len);5456 assert(base_index.index < anon_struct_type.types.len);
5296 },5457 },
5297 .struct_type => {5458 .struct_type => {
5298 assert(ptr.addr == .field);5459 assert(ptr.base_addr == .field);
5299 assert(base_index.index < ip.loadStructType(base_ptr_type.child).field_types.len);5460 assert(base_index.index < ip.loadStructType(base_ptr_type.child).field_types.len);
5300 },5461 },
5301 .union_type => {5462 .union_type => {
5302 const union_type = ip.loadUnionType(base_ptr_type.child);5463 const union_type = ip.loadUnionType(base_ptr_type.child);
5303 assert(ptr.addr == .field);5464 assert(ptr.base_addr == .field);
5304 assert(base_index.index < union_type.field_types.len);5465 assert(base_index.index < union_type.field_types.len);
5305 },5466 },
5306 .ptr_type => |slice_type| {5467 .ptr_type => |slice_type| {
5307 assert(ptr.addr == .field);5468 assert(ptr.base_addr == .field);
5308 assert(slice_type.flags.size == .Slice);5469 assert(slice_type.flags.size == .Slice);
5309 assert(base_index.index < 2);5470 assert(base_index.index < 2);
5310 },5471 },
...@@ -5321,16 +5482,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -5321,16 +5482,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
5321 assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);5482 assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);
5322 try ip.items.ensureUnusedCapacity(gpa, 1);5483 try ip.items.ensureUnusedCapacity(gpa, 1);
5323 break :item .{5484 break :item .{
5324 .tag = switch (ptr.addr) {5485 .tag = switch (ptr.base_addr) {
5325 .elem => .ptr_elem,5486 .arr_elem => .ptr_elem,
5326 .field => .ptr_field,5487 .field => .ptr_field,
5327 else => unreachable,5488 else => unreachable,
5328 },5489 },
5329 .data = try ip.addExtra(gpa, PtrBaseIndex{5490 .data = try ip.addExtra(gpa, PtrBaseIndex.init(ptr.ty, base_index.base, index_index, ptr.byte_offset)),
5330 .ty = ptr.ty,
5331 .base = base_index.base,
5332 .index = index_index,
5333 }),
5334 };5491 };
5335 },5492 },
5336 });5493 });
...@@ -7584,13 +7741,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al...@@ -7584,13 +7741,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
7584 if (ip.isPointerType(new_ty)) switch (ip.indexToKey(new_ty).ptr_type.flags.size) {7741 if (ip.isPointerType(new_ty)) switch (ip.indexToKey(new_ty).ptr_type.flags.size) {
7585 .One, .Many, .C => return ip.get(gpa, .{ .ptr = .{7742 .One, .Many, .C => return ip.get(gpa, .{ .ptr = .{
7586 .ty = new_ty,7743 .ty = new_ty,
7587 .addr = .{ .int = .zero_usize },7744 .base_addr = .int,
7745 .byte_offset = 0,
7588 } }),7746 } }),
7589 .Slice => return ip.get(gpa, .{ .slice = .{7747 .Slice => return ip.get(gpa, .{ .slice = .{
7590 .ty = new_ty,7748 .ty = new_ty,
7591 .ptr = try ip.get(gpa, .{ .ptr = .{7749 .ptr = try ip.get(gpa, .{ .ptr = .{
7592 .ty = ip.slicePtrType(new_ty),7750 .ty = ip.slicePtrType(new_ty),
7593 .addr = .{ .int = .zero_usize },7751 .base_addr = .int,
7752 .byte_offset = 0,
7594 } }),7753 } }),
7595 .len = try ip.get(gpa, .{ .undef = .usize_type }),7754 .len = try ip.get(gpa, .{ .undef = .usize_type }),
7596 } }),7755 } }),
...@@ -7630,10 +7789,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al...@@ -7630,10 +7789,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
7630 .ty = new_ty,7789 .ty = new_ty,
7631 .int = try ip.getCoerced(gpa, val, ip.loadEnumType(new_ty).tag_ty),7790 .int = try ip.getCoerced(gpa, val, ip.loadEnumType(new_ty).tag_ty),
7632 } }),7791 } }),
7633 .ptr_type => return ip.get(gpa, .{ .ptr = .{7792 .ptr_type => switch (int.storage) {
7634 .ty = new_ty,7793 inline .u64, .i64 => |int_val| return ip.get(gpa, .{ .ptr = .{
7635 .addr = .{ .int = try ip.getCoerced(gpa, val, .usize_type) },7794 .ty = new_ty,
7636 } }),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 },
7637 else => if (ip.isIntegerType(new_ty))7801 else => if (ip.isIntegerType(new_ty))
7638 return getCoercedInts(ip, gpa, int, new_ty),7802 return getCoercedInts(ip, gpa, int, new_ty),
7639 },7803 },
...@@ -7684,11 +7848,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al...@@ -7684,11 +7848,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
7684 .ptr => |ptr| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size != .Slice)7848 .ptr => |ptr| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size != .Slice)
7685 return ip.get(gpa, .{ .ptr = .{7849 return ip.get(gpa, .{ .ptr = .{
7686 .ty = new_ty,7850 .ty = new_ty,
7687 .addr = ptr.addr,7851 .base_addr = ptr.base_addr,
7852 .byte_offset = ptr.byte_offset,
7688 } })7853 } })
7689 else if (ip.isIntegerType(new_ty))7854 else if (ip.isIntegerType(new_ty))
7690 switch (ptr.addr) {7855 switch (ptr.base_addr) {
7691 .int => |int| return ip.getCoerced(gpa, int, new_ty),7856 .int => return ip.get(gpa, .{ .int = .{
7857 .ty = .usize_type,
7858 .storage = .{ .u64 = @intCast(ptr.byte_offset) },
7859 } }),
7692 else => {},7860 else => {},
7693 },7861 },
7694 .opt => |opt| switch (ip.indexToKey(new_ty)) {7862 .opt => |opt| switch (ip.indexToKey(new_ty)) {
...@@ -7696,13 +7864,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al...@@ -7696,13 +7864,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
7696 .none => switch (ptr_type.flags.size) {7864 .none => switch (ptr_type.flags.size) {
7697 .One, .Many, .C => try ip.get(gpa, .{ .ptr = .{7865 .One, .Many, .C => try ip.get(gpa, .{ .ptr = .{
7698 .ty = new_ty,7866 .ty = new_ty,
7699 .addr = .{ .int = .zero_usize },7867 .base_addr = .int,
7868 .byte_offset = 0,
7700 } }),7869 } }),
7701 .Slice => try ip.get(gpa, .{ .slice = .{7870 .Slice => try ip.get(gpa, .{ .slice = .{
7702 .ty = new_ty,7871 .ty = new_ty,
7703 .ptr = try ip.get(gpa, .{ .ptr = .{7872 .ptr = try ip.get(gpa, .{ .ptr = .{
7704 .ty = ip.slicePtrType(new_ty),7873 .ty = ip.slicePtrType(new_ty),
7705 .addr = .{ .int = .zero_usize },7874 .base_addr = .int,
7875 .byte_offset = 0,
7706 } }),7876 } }),
7707 .len = try ip.get(gpa, .{ .undef = .usize_type }),7877 .len = try ip.get(gpa, .{ .undef = .usize_type }),
7708 } }),7878 } }),
...@@ -8181,7 +8351,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -8181,7 +8351,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
8181 .ptr_anon_decl => @sizeOf(PtrAnonDecl),8351 .ptr_anon_decl => @sizeOf(PtrAnonDecl),
8182 .ptr_anon_decl_aligned => @sizeOf(PtrAnonDeclAligned),8352 .ptr_anon_decl_aligned => @sizeOf(PtrAnonDeclAligned),
8183 .ptr_comptime_field => @sizeOf(PtrComptimeField),8353 .ptr_comptime_field => @sizeOf(PtrComptimeField),
8184 .ptr_int => @sizeOf(PtrBase),8354 .ptr_int => @sizeOf(PtrInt),
8185 .ptr_eu_payload => @sizeOf(PtrBase),8355 .ptr_eu_payload => @sizeOf(PtrBase),
8186 .ptr_opt_payload => @sizeOf(PtrBase),8356 .ptr_opt_payload => @sizeOf(PtrBase),
8187 .ptr_elem => @sizeOf(PtrBaseIndex),8357 .ptr_elem => @sizeOf(PtrBaseIndex),
...@@ -8854,13 +9024,15 @@ pub fn getBackingDecl(ip: *const InternPool, val: Index) OptionalDeclIndex {...@@ -8854,13 +9024,15 @@ pub fn getBackingDecl(ip: *const InternPool, val: Index) OptionalDeclIndex {
8854 }9024 }
8855}9025}
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 {
8858 var base = @intFromEnum(val);9028 var base = @intFromEnum(val);
8859 while (true) {9029 while (true) {
8860 switch (ip.items.items(.tag)[base]) {9030 switch (ip.items.items(.tag)[base]) {
8861 .ptr_decl => return .decl,9031 .ptr_decl => return .decl,
8862 .ptr_comptime_alloc => return .comptime_alloc,9032 .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,
8864 .ptr_comptime_field => return .comptime_field,9036 .ptr_comptime_field => return .comptime_field,
8865 .ptr_int => return .int,9037 .ptr_int => return .int,
8866 inline .ptr_eu_payload,9038 inline .ptr_eu_payload,
src/Module.zig+38-22
...@@ -528,21 +528,6 @@ pub const Decl = struct {...@@ -528,21 +528,6 @@ pub const Decl = struct {
528 return zcu.namespacePtrUnwrap(decl.getInnerNamespaceIndex(zcu));528 return zcu.namespacePtrUnwrap(decl.getInnerNamespaceIndex(zcu));
529 }529 }
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
546 pub fn getFileScope(decl: Decl, zcu: *Zcu) *File {531 pub fn getFileScope(decl: Decl, zcu: *Zcu) *File {
547 return zcu.namespacePtr(decl.src_namespace).file_scope;532 return zcu.namespacePtr(decl.src_namespace).file_scope;
548 }533 }
...@@ -660,6 +645,22 @@ pub const Decl = struct {...@@ -660,6 +645,22 @@ pub const Decl = struct {
660 },645 },
661 };646 };
662 }647 }
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 }
663};664};
664665
665/// This state is attached to every Decl when Module emit_h is non-null.666/// 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 {...@@ -3535,6 +3536,10 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3535 }3536 }
35363537
3537 log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)});3538 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
3539 const old_has_tv = decl.has_tv;3544 const old_has_tv = decl.has_tv;
3540 // The following values are ignored if `!old_has_tv`3545 // The following values are ignored if `!old_has_tv`
...@@ -4122,10 +4127,11 @@ fn newEmbedFile(...@@ -4122,10 +4127,11 @@ fn newEmbedFile(
4122 })).toIntern();4127 })).toIntern();
4123 const ptr_val = try ip.get(gpa, .{ .ptr = .{4128 const ptr_val = try ip.get(gpa, .{ .ptr = .{
4124 .ty = ptr_ty,4129 .ty = ptr_ty,
4125 .addr = .{ .anon_decl = .{4130 .base_addr = .{ .anon_decl = .{
4126 .val = array_val,4131 .val = array_val,
4127 .orig_ty = ptr_ty,4132 .orig_ty = ptr_ty,
4128 } },4133 } },
4134 .byte_offset = 0,
4129 } });4135 } });
41304136
4131 result.* = new_file;4137 result.* = new_file;
...@@ -4489,6 +4495,11 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -4489,6 +4495,11 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
4489 const decl_index = func.owner_decl;4495 const decl_index = func.owner_decl;
4490 const decl = mod.declPtr(decl_index);4496 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
4492 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));4503 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
44934504
4494 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);4505 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
...@@ -5332,7 +5343,7 @@ pub fn populateTestFunctions(...@@ -5332,7 +5343,7 @@ pub fn populateTestFunctions(
5332 const decl = mod.declPtr(decl_index);5343 const decl = mod.declPtr(decl_index);
5333 const test_fn_ty = decl.typeOf(mod).slicePtrFieldType(mod).childType(mod);5344 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: {
5336 // Add mod.test_functions to an array decl then make the test_functions5347 // Add mod.test_functions to an array decl then make the test_functions
5337 // decl reference it as a slice.5348 // decl reference it as a slice.
5338 const test_fn_vals = try gpa.alloc(InternPool.Index, mod.test_functions.count());5349 const test_fn_vals = try gpa.alloc(InternPool.Index, mod.test_functions.count());
...@@ -5342,7 +5353,7 @@ pub fn populateTestFunctions(...@@ -5342,7 +5353,7 @@ pub fn populateTestFunctions(
5342 const test_decl = mod.declPtr(test_decl_index);5353 const test_decl = mod.declPtr(test_decl_index);
5343 const test_decl_name = try test_decl.fullyQualifiedName(mod);5354 const test_decl_name = try test_decl.fullyQualifiedName(mod);
5344 const test_decl_name_len = test_decl_name.length(ip);5355 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: {
5346 const test_name_ty = try mod.arrayType(.{5357 const test_name_ty = try mod.arrayType(.{
5347 .len = test_decl_name_len,5358 .len = test_decl_name_len,
5348 .child = .u8_type,5359 .child = .u8_type,
...@@ -5363,7 +5374,8 @@ pub fn populateTestFunctions(...@@ -5363,7 +5374,8 @@ pub fn populateTestFunctions(
5363 .ty = .slice_const_u8_type,5374 .ty = .slice_const_u8_type,
5364 .ptr = try mod.intern(.{ .ptr = .{5375 .ptr = try mod.intern(.{ .ptr = .{
5365 .ty = .manyptr_const_u8_type,5376 .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,
5367 } }),5379 } }),
5368 .len = try mod.intern(.{ .int = .{5380 .len = try mod.intern(.{ .int = .{
5369 .ty = .usize_type,5381 .ty = .usize_type,
...@@ -5378,7 +5390,8 @@ pub fn populateTestFunctions(...@@ -5378,7 +5390,8 @@ pub fn populateTestFunctions(
5378 .is_const = true,5390 .is_const = true,
5379 },5391 },
5380 } }),5392 } }),
5381 .addr = .{ .decl = test_decl_index },5393 .base_addr = .{ .decl = test_decl_index },
5394 .byte_offset = 0,
5382 } }),5395 } }),
5383 };5396 };
5384 test_fn_val.* = try mod.intern(.{ .aggregate = .{5397 test_fn_val.* = try mod.intern(.{ .aggregate = .{
...@@ -5415,7 +5428,8 @@ pub fn populateTestFunctions(...@@ -5415,7 +5428,8 @@ pub fn populateTestFunctions(
5415 .ty = new_ty.toIntern(),5428 .ty = new_ty.toIntern(),
5416 .ptr = try mod.intern(.{ .ptr = .{5429 .ptr = try mod.intern(.{ .ptr = .{
5417 .ty = new_ty.slicePtrFieldType(mod).toIntern(),5430 .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,
5419 } }),5433 } }),
5420 .len = (try mod.intValue(Type.usize, mod.test_functions.count())).toIntern(),5434 .len = (try mod.intValue(Type.usize, mod.test_functions.count())).toIntern(),
5421 } });5435 } });
...@@ -5680,9 +5694,11 @@ pub fn errorSetFromUnsortedNames(...@@ -5680,9 +5694,11 @@ pub fn errorSetFromUnsortedNames(
5680/// Supports only pointers, not pointer-like optionals.5694/// Supports only pointers, not pointer-like optionals.
5681pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {5695pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
5682 assert(ty.zigTypeTag(mod) == .Pointer and !ty.isSlice(mod));5696 assert(ty.zigTypeTag(mod) == .Pointer and !ty.isSlice(mod));
5697 assert(x != 0 or ty.isAllowzeroPtr(mod));
5683 const i = try intern(mod, .{ .ptr = .{5698 const i = try intern(mod, .{ .ptr = .{
5684 .ty = ty.toIntern(),5699 .ty = ty.toIntern(),
5685 .addr = .{ .int = (try mod.intValue_u64(Type.usize, x)).toIntern() },5700 .base_addr = .int,
5701 .byte_offset = x,
5686 } });5702 } });
5687 return Value.fromInterned(i);5703 return Value.fromInterned(i);
5688}5704}
src/Sema.zig+841-1569
...@@ -126,16 +126,14 @@ const MaybeComptimeAlloc = struct {...@@ -126,16 +126,14 @@ const MaybeComptimeAlloc = struct {
126 runtime_index: Value.RuntimeIndex,126 runtime_index: Value.RuntimeIndex,
127 /// Backed by sema.arena. Tracks all comptime-known stores to this `alloc`. Due to127 /// Backed by sema.arena. Tracks all comptime-known stores to this `alloc`. Due to
128 /// RLS, a single comptime-known allocation may have arbitrarily many stores.128 /// 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`.
130 stores: std.MultiArrayList(struct {132 stores: std.MultiArrayList(struct {
131 inst: Air.Inst.Index,133 inst: Air.Inst.Index,
132 src_decl: InternPool.DeclIndex,134 src_decl: InternPool.DeclIndex,
133 src: LazySrcLoc,135 src: LazySrcLoc,
134 }) = .{},136 }) = .{},
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) = .{},
139};137};
140138
141const ComptimeAlloc = struct {139const ComptimeAlloc = struct {
...@@ -177,7 +175,8 @@ const MutableValue = @import("mutable_value.zig").MutableValue;...@@ -177,7 +175,8 @@ const MutableValue = @import("mutable_value.zig").MutableValue;
177const Type = @import("type.zig").Type;175const Type = @import("type.zig").Type;
178const Air = @import("Air.zig");176const Air = @import("Air.zig");
179const Zir = std.zig.Zir;177const Zir = std.zig.Zir;
180const Module = @import("Module.zig");178const Zcu = @import("Module.zig");
179const Module = Zcu;
181const trace = @import("tracy.zig").trace;180const trace = @import("tracy.zig").trace;
182const Namespace = Module.Namespace;181const Namespace = Module.Namespace;
183const CompileError = Module.CompileError;182const CompileError = Module.CompileError;
...@@ -2138,7 +2137,7 @@ fn resolveValueIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {...@@ -2138,7 +2137,7 @@ fn resolveValueIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
2138 if (sema.mod.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) {2137 if (sema.mod.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) {
2139 .decl, .anon_decl, .comptime_alloc, .comptime_field => return null,2138 .decl, .anon_decl, .comptime_alloc, .comptime_field => return null,
2140 .int => {},2139 .int => {},
2141 .eu_payload, .opt_payload, .elem, .field => unreachable,2140 .eu_payload, .opt_payload, .arr_elem, .field => unreachable,
2142 };2141 };
2143 return try sema.resolveLazyValue(val);2142 return try sema.resolveLazyValue(val);
2144}2143}
...@@ -2268,11 +2267,11 @@ fn failWithErrorSetCodeMissing(...@@ -2268,11 +2267,11 @@ fn failWithErrorSetCodeMissing(
2268}2267}
22692268
2270fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError {2269fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError {
2271 const mod = sema.mod;2270 const zcu = sema.mod;
2272 if (int_ty.zigTypeTag(mod) == .Vector) {2271 if (int_ty.zigTypeTag(zcu) == .Vector) {
2273 const msg = msg: {2272 const msg = msg: {
2274 const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{2273 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),
2276 });2275 });
2277 errdefer msg.destroy(sema.gpa);2276 errdefer msg.destroy(sema.gpa);
2278 try sema.errNote(block, src, msg, "when computing vector element at index '{d}'", .{vector_index});2277 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:...@@ -2281,7 +2280,7 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty:
2281 return sema.failWithOwnedErrorMsg(block, msg);2280 return sema.failWithOwnedErrorMsg(block, msg);
2282 }2281 }
2283 return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{2282 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),
2285 });2284 });
2286}2285}
22872286
...@@ -2440,7 +2439,7 @@ fn addFieldErrNote(...@@ -2440,7 +2439,7 @@ fn addFieldErrNote(
2440 try mod.errNoteNonLazy(field_src, parent, format, args);2439 try mod.errNoteNonLazy(field_src, parent, format, args);
2441}2440}
24422441
2443fn errMsg(2442pub fn errMsg(
2444 sema: *Sema,2443 sema: *Sema,
2445 block: *Block,2444 block: *Block,
2446 src: LazySrcLoc,2445 src: LazySrcLoc,
...@@ -2469,7 +2468,7 @@ pub fn fail(...@@ -2469,7 +2468,7 @@ pub fn fail(
2469 return sema.failWithOwnedErrorMsg(block, err_msg);2468 return sema.failWithOwnedErrorMsg(block, err_msg);
2470}2469}
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 } {
2473 @setCold(true);2472 @setCold(true);
2474 const gpa = sema.gpa;2473 const gpa = sema.gpa;
2475 const mod = sema.mod;2474 const mod = sema.mod;
...@@ -2922,7 +2921,7 @@ fn createAnonymousDeclTypeNamed(...@@ -2922,7 +2921,7 @@ fn createAnonymousDeclTypeNamed(
2922 return sema.createAnonymousDeclTypeNamed(block, src, val, .anon, anon_prefix, null);2921 return sema.createAnonymousDeclTypeNamed(block, src, val, .anon, anon_prefix, null);
29232922
2924 if (arg_i != 0) try writer.writeByte(',');2923 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
2927 arg_i += 1;2926 arg_i += 1;
2928 continue;2927 continue;
...@@ -3193,7 +3192,7 @@ fn zirEnumDecl(...@@ -3193,7 +3192,7 @@ fn zirEnumDecl(
3193 }).lazy;3192 }).lazy;
3194 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;3193 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
3195 const msg = msg: {3194 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)});
3197 errdefer msg.destroy(gpa);3196 errdefer msg.destroy(gpa);
3198 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});3197 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
3199 break :msg msg;3198 break :msg msg;
...@@ -3213,7 +3212,7 @@ fn zirEnumDecl(...@@ -3213,7 +3212,7 @@ fn zirEnumDecl(
3213 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;3212 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
3214 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;3213 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
3215 const msg = msg: {3214 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)});
3217 errdefer msg.destroy(gpa);3216 errdefer msg.destroy(gpa);
3218 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});3217 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
3219 break :msg msg;3218 break :msg msg;
...@@ -3235,7 +3234,7 @@ fn zirEnumDecl(...@@ -3235,7 +3234,7 @@ fn zirEnumDecl(
3235 .range = if (has_tag_value) .value else .name,3234 .range = if (has_tag_value) .value else .name,
3236 }).lazy;3235 }).lazy;
3237 const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{3236 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),
3239 });3238 });
3240 return sema.failWithOwnedErrorMsg(block, msg);3239 return sema.failWithOwnedErrorMsg(block, msg);
3241 }3240 }
...@@ -3766,7 +3765,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -3766,7 +3765,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
3766 // If this was a comptime inferred alloc, then `storeToInferredAllocComptime`3765 // If this was a comptime inferred alloc, then `storeToInferredAllocComptime`
3767 // might have already done our job and created an anon decl ref.3766 // might have already done our job and created an anon decl ref.
3768 switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {3767 switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
3769 .ptr => |ptr| switch (ptr.addr) {3768 .ptr => |ptr| switch (ptr.base_addr) {
3770 .anon_decl => {3769 .anon_decl => {
3771 // The comptime-ification was already done for us.3770 // The comptime-ification was already done for us.
3772 // Just make sure the pointer is const.3771 // Just make sure the pointer is const.
...@@ -3778,22 +3777,25 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -3778,22 +3777,25 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
3778 }3777 }
37793778
3780 if (!sema.isComptimeMutablePtr(ptr_val)) break :already_ct;3779 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;
3782 const ct_alloc = sema.getComptimeAlloc(alloc_index);3783 const ct_alloc = sema.getComptimeAlloc(alloc_index);
3783 const interned = try ct_alloc.val.intern(mod, sema.arena);3784 const interned = try ct_alloc.val.intern(mod, sema.arena);
3784 if (Value.fromInterned(interned).canMutateComptimeVarState(mod)) {3785 if (interned.canMutateComptimeVarState(mod)) {
3785 // Preserve the comptime alloc, just make the pointer const.3786 // Preserve the comptime alloc, just make the pointer const.
3786 ct_alloc.val = .{ .interned = interned };3787 ct_alloc.val = .{ .interned = interned.toIntern() };
3787 ct_alloc.is_const = true;3788 ct_alloc.is_const = true;
3788 return sema.makePtrConst(block, alloc);3789 return sema.makePtrConst(block, alloc);
3789 } else {3790 } else {
3790 // Promote the constant to an anon decl.3791 // Promote the constant to an anon decl.
3791 const new_mut_ptr = Air.internedToRef(try mod.intern(.{ .ptr = .{3792 const new_mut_ptr = Air.internedToRef(try mod.intern(.{ .ptr = .{
3792 .ty = alloc_ty.toIntern(),3793 .ty = alloc_ty.toIntern(),
3793 .addr = .{ .anon_decl = .{3794 .base_addr = .{ .anon_decl = .{
3794 .val = interned,3795 .val = interned.toIntern(),
3795 .orig_ty = alloc_ty.toIntern(),3796 .orig_ty = alloc_ty.toIntern(),
3796 } },3797 } },
3798 .byte_offset = 0,
3797 } }));3799 } }));
3798 return sema.makePtrConst(block, new_mut_ptr);3800 return sema.makePtrConst(block, new_mut_ptr);
3799 }3801 }
...@@ -3818,10 +3820,10 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -3818,10 +3820,10 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
3818/// If `alloc` is an inferred allocation, `resolved_inferred_ty` is taken to be its resolved3820/// If `alloc` is an inferred allocation, `resolved_inferred_ty` is taken to be its resolved
3819/// type. Otherwise, it may be `null`, and the type will be inferred from `alloc`.3821/// type. Otherwise, it may be `null`, and the type will be inferred from `alloc`.
3820fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, resolved_alloc_ty: ?Type) CompileError!?InternPool.Index {3822fn 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
3823 const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc);3825 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);
3825 const elem_ty = Type.fromInterned(ptr_info.child);3827 const elem_ty = Type.fromInterned(ptr_info.child);
38263828
3827 const alloc_inst = alloc.toIndex() orelse return null;3829 const alloc_inst = alloc.toIndex() orelse return null;
...@@ -3843,12 +3845,16 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -3843,12 +3845,16 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
38433845
3844 simple: {3846 simple: {
3845 if (stores.len != 1) break :simple;3847 if (stores.len != 1) break :simple;
3846 const store_inst = stores[0];3848 const store_inst = sema.air_instructions.get(@intFromEnum(stores[0]));
3847 const store_data = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;3849 switch (store_inst.tag) {
3848 if (store_data.lhs != alloc) break :simple;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().?;3856 const val = store_inst.data.bin_op.rhs.toInterned().?;
3851 assert(mod.intern_pool.typeOf(val) == elem_ty.toIntern());3857 assert(zcu.intern_pool.typeOf(val) == elem_ty.toIntern());
3852 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value);3858 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value);
3853 }3859 }
38543860
...@@ -3857,9 +3863,10 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -3857,9 +3863,10 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
38573863
3858 const ct_alloc = try sema.newComptimeAlloc(block, elem_ty, ptr_info.flags.alignment);3864 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 = .{
3861 .ty = alloc_ty.toIntern(),3867 .ty = alloc_ty.toIntern(),
3862 .addr = .{ .comptime_alloc = ct_alloc },3868 .base_addr = .{ .comptime_alloc = ct_alloc },
3869 .byte_offset = 0,
3863 } });3870 } });
38643871
3865 // Maps from pointers into the runtime allocs, to comptime-mutable pointers into the comptime alloc3872 // 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,...@@ -3867,10 +3874,18 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
3867 try ptr_mapping.ensureTotalCapacity(@intCast(stores.len));3874 try ptr_mapping.ensureTotalCapacity(@intCast(stores.len));
3868 ptr_mapping.putAssumeCapacity(alloc_inst, alloc_ptr);3875 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.
3870 var to_map = try std.ArrayList(Air.Inst.Index).initCapacity(sema.arena, stores.len);3879 var to_map = try std.ArrayList(Air.Inst.Index).initCapacity(sema.arena, stores.len);
3871 for (stores) |store_inst| {3880 for (stores) |store_inst_idx| {
3872 const bin_op = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;3881 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
3873 to_map.appendAssumeCapacity(bin_op.lhs.toIndex().?);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);
3874 }3889 }
38753890
3876 const tmp_air = sema.getTmpAir();3891 const tmp_air = sema.getTmpAir();
...@@ -3950,53 +3965,68 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -3950,53 +3965,68 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
3950 try to_map.appendSlice(&.{ air_ptr, air_parent_ptr.toIndex().? });3965 try to_map.appendSlice(&.{ air_ptr, air_parent_ptr.toIndex().? });
3951 continue;3966 continue;
3952 };3967 };
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();
3954 const new_ptr = switch (method) {3969 const new_ptr = switch (method) {
3955 .same_addr => try mod.intern_pool.getCoerced(sema.gpa, decl_parent_ptr, new_ptr_ty),3970 .same_addr => try zcu.intern_pool.getCoerced(sema.gpa, decl_parent_ptr, new_ptr_ty),
3956 .opt_payload => try mod.intern(.{ .ptr = .{3971 .opt_payload => ptr: {
3957 .ty = new_ptr_ty,3972 // Set the optional to non-null at comptime.
3958 .addr = .{ .opt_payload = decl_parent_ptr },3973 // If the payload is OPV, we must use that value instead of undef.
3959 } }),3974 const opt_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);
3960 .eu_payload => try mod.intern(.{ .ptr = .{3975 const payload_ty = opt_ty.optionalChild(zcu);
3961 .ty = new_ptr_ty,3976 const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try zcu.undefValue(payload_ty);
3962 .addr = .{ .eu_payload = decl_parent_ptr },3977 const opt_val = try zcu.intern(.{ .opt = .{
3963 } }),3978 .ty = opt_ty.toIntern(),
3964 .field => |field_idx| try mod.intern(.{ .ptr = .{3979 .val = payload_val.toIntern(),
3965 .ty = new_ptr_ty,3980 } });
3966 .addr = .{ .field = .{3981 try sema.storePtrVal(block, .unneeded, Value.fromInterned(decl_parent_ptr), Value.fromInterned(opt_val), opt_ty);
3967 .base = decl_parent_ptr,3982 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrOptPayload(sema)).toIntern();
3968 .index = field_idx,3983 },
3969 } },3984 .eu_payload => ptr: {
3970 } }),3985 // Set the error union to non-error at comptime.
3971 .elem => |elem_idx| (try Value.fromInterned(decl_parent_ptr).elemPtr(Type.fromInterned(new_ptr_ty), @intCast(elem_idx), mod)).toIntern(),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(),
3972 };4012 };
3973 try ptr_mapping.put(air_ptr, new_ptr);4013 try ptr_mapping.put(air_ptr, new_ptr);
3974 }4014 }
39754015
3976 // We have a correlation between AIR pointers and decl pointers. Perform all stores at comptime.4016 // We have a correlation between AIR pointers and decl pointers. Perform all stores at comptime.
39774017 // Any implicit stores performed by `optional_payload_ptr_set`, `errunion_payload_ptr_set`, or
3978 for (stores) |store_inst| {4018 // `set_union_tag` instructions were already done above.
3979 switch (sema.air_instructions.items(.tag)[@intFromEnum(store_inst)]) {4019
3980 .set_union_tag => {4020 for (stores) |store_inst_idx| {
3981 // If this tag has an OPV payload, there won't be a corresponding4021 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
3982 // store instruction, so we must set the union payload now.4022 switch (store_inst.tag) {
3983 const bin_op = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;4023 .set_union_tag => {}, // Handled implicitly by field pointers above
3984 const air_ptr_inst = bin_op.lhs.toIndex().?;4024 .optional_payload_ptr_set, .errunion_payload_ptr_set => {}, // Handled explicitly above
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 },
3994 .store, .store_safe => {4025 .store, .store_safe => {
3995 const bin_op = sema.air_instructions.items(.data)[@intFromEnum(store_inst)].bin_op;4026 const air_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;
3996 const air_ptr_inst = bin_op.lhs.toIndex().?;4027 const store_val = (try sema.resolveValue(store_inst.data.bin_op.rhs)).?;
3997 const store_val = (try sema.resolveValue(bin_op.rhs)).?;
3998 const new_ptr = ptr_mapping.get(air_ptr_inst).?;4028 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())));
4000 },4030 },
4001 else => unreachable,4031 else => unreachable,
4002 }4032 }
...@@ -4040,9 +4070,6 @@ fn finishResolveComptimeKnownAllocPtr(...@@ -4040,9 +4070,6 @@ fn finishResolveComptimeKnownAllocPtr(
4040 for (comptime_info.stores.items(.inst)) |store_inst| {4070 for (comptime_info.stores.items(.inst)) |store_inst| {
4041 sema.air_instructions.set(@intFromEnum(store_inst), nop_inst);4071 sema.air_instructions.set(@intFromEnum(store_inst), nop_inst);
4042 }4072 }
4043 for (comptime_info.non_elideable_pointers.items) |ptr_inst| {
4044 sema.air_instructions.set(@intFromEnum(ptr_inst), nop_inst);
4045 }
40464073
4047 if (Value.fromInterned(result_val).canMutateComptimeVarState(zcu)) {4074 if (Value.fromInterned(result_val).canMutateComptimeVarState(zcu)) {
4048 const alloc_index = existing_comptime_alloc orelse a: {4075 const alloc_index = existing_comptime_alloc orelse a: {
...@@ -4054,15 +4081,17 @@ fn finishResolveComptimeKnownAllocPtr(...@@ -4054,15 +4081,17 @@ fn finishResolveComptimeKnownAllocPtr(
4054 sema.getComptimeAlloc(alloc_index).is_const = true;4081 sema.getComptimeAlloc(alloc_index).is_const = true;
4055 return try zcu.intern(.{ .ptr = .{4082 return try zcu.intern(.{ .ptr = .{
4056 .ty = alloc_ty.toIntern(),4083 .ty = alloc_ty.toIntern(),
4057 .addr = .{ .comptime_alloc = alloc_index },4084 .base_addr = .{ .comptime_alloc = alloc_index },
4085 .byte_offset = 0,
4058 } });4086 } });
4059 } else {4087 } else {
4060 return try zcu.intern(.{ .ptr = .{4088 return try zcu.intern(.{ .ptr = .{
4061 .ty = alloc_ty.toIntern(),4089 .ty = alloc_ty.toIntern(),
4062 .addr = .{ .anon_decl = .{4090 .base_addr = .{ .anon_decl = .{
4063 .orig_ty = alloc_ty.toIntern(),4091 .orig_ty = alloc_ty.toIntern(),
4064 .val = result_val,4092 .val = result_val,
4065 } },4093 } },
4094 .byte_offset = 0,
4066 } });4095 } });
4067 }4096 }
4068}4097}
...@@ -4207,11 +4236,11 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4207,11 +4236,11 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4207 sema.air_instructions.set(@intFromEnum(ptr_inst), .{ .tag = undefined, .data = undefined });4236 sema.air_instructions.set(@intFromEnum(ptr_inst), .{ .tag = undefined, .data = undefined });
4208 }4237 }
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) {
4211 .anon_decl => |a| a.val,4240 .anon_decl => |a| a.val,
4212 .comptime_alloc => |i| val: {4241 .comptime_alloc => |i| val: {
4213 const alloc = sema.getComptimeAlloc(i);4242 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();
4215 },4244 },
4216 else => unreachable,4245 else => unreachable,
4217 };4246 };
...@@ -4388,10 +4417,10 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -4388,10 +4417,10 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
4388 .input_index = len_idx,4417 .input_index = len_idx,
4389 } };4418 } };
4390 try sema.errNote(block, a_src, msg, "length {} here", .{4419 try sema.errNote(block, a_src, msg, "length {} here", .{
4391 v.fmtValue(sema.mod),4420 v.fmtValue(sema.mod, sema),
4392 });4421 });
4393 try sema.errNote(block, arg_src, msg, "length {} here", .{4422 try sema.errNote(block, arg_src, msg, "length {} here", .{
4394 arg_val.fmtValue(sema.mod),4423 arg_val.fmtValue(sema.mod, sema),
4395 });4424 });
4396 break :msg msg;4425 break :msg msg;
4397 };4426 };
...@@ -4869,7 +4898,7 @@ fn validateUnionInit(...@@ -4869,7 +4898,7 @@ fn validateUnionInit(
48694898
4870 const new_tag = Air.internedToRef(tag_val.toIntern());4899 const new_tag = Air.internedToRef(tag_val.toIntern());
4871 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, new_tag);4900 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
4873}4902}
48744903
4875fn validateStructInit(4904fn validateStructInit(
...@@ -5331,7 +5360,7 @@ fn zirValidatePtrArrayInit(...@@ -5331,7 +5360,7 @@ fn zirValidatePtrArrayInit(
5331 if (array_is_comptime) {5360 if (array_is_comptime) {
5332 if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| {5361 if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| {
5333 switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {5362 switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
5334 .ptr => |ptr| switch (ptr.addr) {5363 .ptr => |ptr| switch (ptr.base_addr) {
5335 .comptime_field => return, // This store was validated by the individual elem ptrs.5364 .comptime_field => return, // This store was validated by the individual elem ptrs.
5336 else => {},5365 else => {},
5337 },5366 },
...@@ -5619,17 +5648,19 @@ fn storeToInferredAllocComptime(...@@ -5619,17 +5648,19 @@ fn storeToInferredAllocComptime(
5619 if (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)) {5648 if (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)) {
5620 iac.ptr = try zcu.intern(.{ .ptr = .{5649 iac.ptr = try zcu.intern(.{ .ptr = .{
5621 .ty = alloc_ty.toIntern(),5650 .ty = alloc_ty.toIntern(),
5622 .addr = .{ .anon_decl = .{5651 .base_addr = .{ .anon_decl = .{
5623 .val = operand_val.toIntern(),5652 .val = operand_val.toIntern(),
5624 .orig_ty = alloc_ty.toIntern(),5653 .orig_ty = alloc_ty.toIntern(),
5625 } },5654 } },
5655 .byte_offset = 0,
5626 } });5656 } });
5627 } else {5657 } else {
5628 const alloc_index = try sema.newComptimeAlloc(block, operand_ty, iac.alignment);5658 const alloc_index = try sema.newComptimeAlloc(block, operand_ty, iac.alignment);
5629 sema.getComptimeAlloc(alloc_index).val = .{ .interned = operand_val.toIntern() };5659 sema.getComptimeAlloc(alloc_index).val = .{ .interned = operand_val.toIntern() };
5630 iac.ptr = try zcu.intern(.{ .ptr = .{5660 iac.ptr = try zcu.intern(.{ .ptr = .{
5631 .ty = alloc_ty.toIntern(),5661 .ty = alloc_ty.toIntern(),
5632 .addr = .{ .comptime_alloc = alloc_index },5662 .base_addr = .{ .comptime_alloc = alloc_index },
5663 .byte_offset = 0,
5633 } });5664 } });
5634 }5665 }
5635}5666}
...@@ -5724,10 +5755,11 @@ fn refValue(sema: *Sema, val: InternPool.Index) CompileError!InternPool.Index {...@@ -5724,10 +5755,11 @@ fn refValue(sema: *Sema, val: InternPool.Index) CompileError!InternPool.Index {
5724 })).toIntern();5755 })).toIntern();
5725 return mod.intern(.{ .ptr = .{5756 return mod.intern(.{ .ptr = .{
5726 .ty = ptr_ty,5757 .ty = ptr_ty,
5727 .addr = .{ .anon_decl = .{5758 .base_addr = .{ .anon_decl = .{
5728 .val = val,5759 .val = val,
5729 .orig_ty = ptr_ty,5760 .orig_ty = ptr_ty,
5730 } },5761 } },
5762 .byte_offset = 0,
5731 } });5763 } });
5732}5764}
57335765
...@@ -5813,7 +5845,7 @@ fn zirCompileLog(...@@ -5813,7 +5845,7 @@ fn zirCompileLog(
5813 const arg_ty = sema.typeOf(arg);5845 const arg_ty = sema.typeOf(arg);
5814 if (try sema.resolveValueResolveLazy(arg)) |val| {5846 if (try sema.resolveValueResolveLazy(arg)) |val| {
5815 try writer.print("@as({}, {})", .{5847 try writer.print("@as({}, {})", .{
5816 arg_ty.fmt(mod), val.fmtValue(mod),5848 arg_ty.fmt(mod), val.fmtValue(mod, sema),
5817 });5849 });
5818 } else {5850 } else {
5819 try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(mod)});5851 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...@@ -6404,7 +6436,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
6404 else => |e| return e,6436 else => |e| return e,
6405 };6437 };
6406 {6438 {
6407 try mod.ensureDeclAnalyzed(decl_index);6439 try sema.ensureDeclAnalyzed(decl_index);
6408 const exported_decl = mod.declPtr(decl_index);6440 const exported_decl = mod.declPtr(decl_index);
6409 if (exported_decl.val.getFunction(mod)) |function| {6441 if (exported_decl.val.getFunction(mod)) |function| {
6410 return sema.analyzeExport(block, src, options, function.owner_decl);6442 return sema.analyzeExport(block, src, options, function.owner_decl);
...@@ -6457,7 +6489,7 @@ pub fn analyzeExport(...@@ -6457,7 +6489,7 @@ pub fn analyzeExport(
6457 if (options.linkage == .internal)6489 if (options.linkage == .internal)
6458 return;6490 return;
64596491
6460 try mod.ensureDeclAnalyzed(exported_decl_index);6492 try sema.ensureDeclAnalyzed(exported_decl_index);
6461 const exported_decl = mod.declPtr(exported_decl_index);6493 const exported_decl = mod.declPtr(exported_decl_index);
6462 const export_ty = exported_decl.typeOf(mod);6494 const export_ty = exported_decl.typeOf(mod);
64636495
...@@ -6880,8 +6912,8 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl {...@@ -6880,8 +6912,8 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl {
6880 const owner_decl_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {6912 const owner_decl_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
6881 .extern_func => |extern_func| extern_func.decl,6913 .extern_func => |extern_func| extern_func.decl,
6882 .func => |func| func.owner_decl,6914 .func => |func| func.owner_decl,
6883 .ptr => |ptr| switch (ptr.addr) {6915 .ptr => |ptr| switch (ptr.base_addr) {
6884 .decl => |decl| mod.declPtr(decl).val.getFunction(mod).?.owner_decl,6916 .decl => |decl| if (ptr.byte_offset == 0) mod.declPtr(decl).val.getFunction(mod).?.owner_decl else return null,
6885 else => return null,6917 else => return null,
6886 },6918 },
6887 else => return null,6919 else => return null,
...@@ -7638,22 +7670,23 @@ fn analyzeCall(...@@ -7638,22 +7670,23 @@ fn analyzeCall(
7638 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),7670 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
7639 }),7671 }),
7640 .func => func_val.toIntern(),7672 .func => func_val.toIntern(),
7641 .ptr => |ptr| switch (ptr.addr) {7673 .ptr => |ptr| blk: {
7642 .decl => |decl| blk: {7674 switch (ptr.base_addr) {
7643 const func_val_ptr = mod.declPtr(decl).val.toIntern();7675 .decl => |decl| if (ptr.byte_offset == 0) {
7644 const intern_index = mod.intern_pool.indexToKey(func_val_ptr);7676 const func_val_ptr = mod.declPtr(decl).val.toIntern();
7645 if (intern_index == .extern_func or (intern_index == .variable and intern_index.variable.is_extern))7677 const intern_index = mod.intern_pool.indexToKey(func_val_ptr);
7646 return sema.fail(block, call_src, "{s} call of extern function pointer", .{7678 if (intern_index == .extern_func or (intern_index == .variable and intern_index.variable.is_extern))
7647 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),7679 return sema.fail(block, call_src, "{s} call of extern function pointer", .{
7648 });7680 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
7649 break :blk func_val_ptr;7681 });
7650 },7682 break :blk func_val_ptr;
7651 else => {7683 },
7652 assert(callee_ty.isPtrAtRuntime(mod));7684 else => {},
7653 return sema.fail(block, call_src, "{s} call of function pointer", .{7685 }
7654 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),7686 assert(callee_ty.isPtrAtRuntime(mod));
7655 });7687 return sema.fail(block, call_src, "{s} call of function pointer", .{
7656 },7688 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
7689 });
7657 },7690 },
7658 else => unreachable,7691 else => unreachable,
7659 };7692 };
...@@ -7971,7 +8004,7 @@ fn analyzeCall(...@@ -7971,7 +8004,7 @@ fn analyzeCall(
7971 if (try sema.resolveValue(func)) |func_val| {8004 if (try sema.resolveValue(func)) |func_val| {
7972 switch (mod.intern_pool.indexToKey(func_val.toIntern())) {8005 switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
7973 .func => break :skip_safety,8006 .func => break :skip_safety,
7974 .ptr => |ptr| switch (ptr.addr) {8007 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
7975 .decl => |decl| if (!mod.declPtr(decl).isExtern(mod)) break :skip_safety,8008 .decl => |decl| if (!mod.declPtr(decl).isExtern(mod)) break :skip_safety,
7976 else => {},8009 else => {},
7977 },8010 },
...@@ -8167,7 +8200,7 @@ fn instantiateGenericCall(...@@ -8167,7 +8200,7 @@ fn instantiateGenericCall(
8167 });8200 });
8168 const generic_owner = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {8201 const generic_owner = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
8169 .func => func_val.toIntern(),8202 .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(),
8171 else => unreachable,8204 else => unreachable,
8172 };8205 };
8173 const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func;8206 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...@@ -8919,7 +8952,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8919 return Air.internedToRef((try mod.getCoerced(int_val, dest_ty)).toIntern());8952 return Air.internedToRef((try mod.getCoerced(int_val, dest_ty)).toIntern());
8920 }8953 }
8921 return sema.fail(block, src, "int value '{}' out of range of non-exhaustive enum '{}'", .{8954 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),
8923 });8956 });
8924 }8957 }
8925 if (int_val.isUndef(mod)) {8958 if (int_val.isUndef(mod)) {
...@@ -8927,7 +8960,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8927,7 +8960,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8927 }8960 }
8928 if (!(try sema.enumHasInt(dest_ty, int_val))) {8961 if (!(try sema.enumHasInt(dest_ty, int_val))) {
8929 return sema.fail(block, src, "enum '{}' has no tag with value '{}'", .{8962 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),
8931 });8964 });
8932 }8965 }
8933 return Air.internedToRef((try mod.getCoerced(int_val, dest_ty)).toIntern());8966 return Air.internedToRef((try mod.getCoerced(int_val, dest_ty)).toIntern());
...@@ -8984,47 +9017,47 @@ fn analyzeOptionalPayloadPtr(...@@ -8984,47 +9017,47 @@ fn analyzeOptionalPayloadPtr(
8984 safety_check: bool,9017 safety_check: bool,
8985 initializing: bool,9018 initializing: bool,
8986) CompileError!Air.Inst.Ref {9019) CompileError!Air.Inst.Ref {
8987 const mod = sema.mod;9020 const zcu = sema.mod;
8988 const optional_ptr_ty = sema.typeOf(optional_ptr);9021 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);9024 const opt_type = optional_ptr_ty.childType(zcu);
8992 if (opt_type.zigTypeTag(mod) != .Optional) {9025 if (opt_type.zigTypeTag(zcu) != .Optional) {
8993 return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(mod)});9026 return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(zcu)});
8994 }9027 }
89959028
8996 const child_type = opt_type.optionalChild(mod);9029 const child_type = opt_type.optionalChild(zcu);
8997 const child_pointer = try sema.ptrType(.{9030 const child_pointer = try sema.ptrType(.{
8998 .child = child_type.toIntern(),9031 .child = child_type.toIntern(),
8999 .flags = .{9032 .flags = .{
9000 .is_const = optional_ptr_ty.isConstPtr(mod),9033 .is_const = optional_ptr_ty.isConstPtr(zcu),
9001 .address_space = optional_ptr_ty.ptrAddressSpace(mod),9034 .address_space = optional_ptr_ty.ptrAddressSpace(zcu),
9002 },9035 },
9003 });9036 });
90049037
9005 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| {9038 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| {
9006 if (initializing) {9039 if (initializing) {
9007 if (!sema.isComptimeMutablePtr(ptr_val)) {9040 if (sema.isComptimeMutablePtr(ptr_val)) {
9008 // If the pointer resulting from this function was stored at comptime,9041 // Set the optional to non-null at comptime.
9009 // the optional non-null bit would be set that way. But in this case,9042 // If the payload is OPV, we must use that value instead of undef.
9010 // we need to emit a runtime instruction to do it.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.
9011 const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);9051 const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
9012 try sema.checkKnownAllocPtr(block, optional_ptr, opt_payload_ptr);9052 try sema.checkKnownAllocPtr(block, optional_ptr, opt_payload_ptr);
9013 }9053 }
9014 return Air.internedToRef((try mod.intern(.{ .ptr = .{9054 return Air.internedToRef((try ptr_val.ptrOptPayload(sema)).toIntern());
9015 .ty = child_pointer.toIntern(),
9016 .addr = .{ .opt_payload = ptr_val.toIntern() },
9017 } })));
9018 }9055 }
9019 if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| {9056 if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| {
9020 if (val.isNull(mod)) {9057 if (val.isNull(zcu)) {
9021 return sema.fail(block, src, "unable to unwrap null", .{});9058 return sema.fail(block, src, "unable to unwrap null", .{});
9022 }9059 }
9023 // The same Value represents the pointer to the optional and the payload.9060 return Air.internedToRef((try ptr_val.ptrOptPayload(sema)).toIntern());
9024 return Air.internedToRef((try mod.intern(.{ .ptr = .{
9025 .ty = child_pointer.toIntern(),
9026 .addr = .{ .opt_payload = ptr_val.toIntern() },
9027 } })));
9028 }9061 }
9029 }9062 }
90309063
...@@ -9173,49 +9206,50 @@ fn analyzeErrUnionPayloadPtr(...@@ -9173,49 +9206,50 @@ fn analyzeErrUnionPayloadPtr(
9173 safety_check: bool,9206 safety_check: bool,
9174 initializing: bool,9207 initializing: bool,
9175) CompileError!Air.Inst.Ref {9208) CompileError!Air.Inst.Ref {
9176 const mod = sema.mod;9209 const zcu = sema.mod;
9177 const operand_ty = sema.typeOf(operand);9210 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) {
9181 return sema.fail(block, src, "expected error union type, found '{}'", .{9214 return sema.fail(block, src, "expected error union type, found '{}'", .{
9182 operand_ty.childType(mod).fmt(mod),9215 operand_ty.childType(zcu).fmt(zcu),
9183 });9216 });
9184 }9217 }
91859218
9186 const err_union_ty = operand_ty.childType(mod);9219 const err_union_ty = operand_ty.childType(zcu);
9187 const payload_ty = err_union_ty.errorUnionPayload(mod);9220 const payload_ty = err_union_ty.errorUnionPayload(zcu);
9188 const operand_pointer_ty = try sema.ptrType(.{9221 const operand_pointer_ty = try sema.ptrType(.{
9189 .child = payload_ty.toIntern(),9222 .child = payload_ty.toIntern(),
9190 .flags = .{9223 .flags = .{
9191 .is_const = operand_ty.isConstPtr(mod),9224 .is_const = operand_ty.isConstPtr(zcu),
9192 .address_space = operand_ty.ptrAddressSpace(mod),9225 .address_space = operand_ty.ptrAddressSpace(zcu),
9193 },9226 },
9194 });9227 });
91959228
9196 if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| {9229 if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| {
9197 if (initializing) {9230 if (initializing) {
9198 if (!sema.isComptimeMutablePtr(ptr_val)) {9231 if (sema.isComptimeMutablePtr(ptr_val)) {
9199 // If the pointer resulting from this function was stored at comptime,9232 // Set the error union to non-error at comptime.
9200 // the error union error code would be set that way. But in this case,9233 // If the payload is OPV, we must use that value instead of undef.
9201 // we need to emit a runtime instruction to do it.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.
9202 try sema.requireRuntimeBlock(block, src, null);9242 try sema.requireRuntimeBlock(block, src, null);
9203 const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);9243 const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);
9204 try sema.checkKnownAllocPtr(block, operand, eu_payload_ptr);9244 try sema.checkKnownAllocPtr(block, operand, eu_payload_ptr);
9205 }9245 }
9206 return Air.internedToRef((try mod.intern(.{ .ptr = .{9246 return Air.internedToRef((try ptr_val.ptrEuPayload(sema)).toIntern());
9207 .ty = operand_pointer_ty.toIntern(),
9208 .addr = .{ .eu_payload = ptr_val.toIntern() },
9209 } })));
9210 }9247 }
9211 if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| {9248 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| {
9213 return sema.failWithComptimeErrorRetTrace(block, src, name);9250 return sema.failWithComptimeErrorRetTrace(block, src, name);
9214 }9251 }
9215 return Air.internedToRef((try mod.intern(.{ .ptr = .{9252 return Air.internedToRef((try ptr_val.ptrEuPayload(sema)).toIntern());
9216 .ty = operand_pointer_ty.toIntern(),
9217 .addr = .{ .eu_payload = ptr_val.toIntern() },
9218 } })));
9219 }9253 }
9220 }9254 }
92219255
...@@ -9223,7 +9257,7 @@ fn analyzeErrUnionPayloadPtr(...@@ -9223,7 +9257,7 @@ fn analyzeErrUnionPayloadPtr(
92239257
9224 // If the error set has no fields then no safety check is needed.9258 // If the error set has no fields then no safety check is needed.
9225 if (safety_check and block.wantSafety() and9259 if (safety_check and block.wantSafety() and
9226 !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod))9260 !err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu))
9227 {9261 {
9228 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);9262 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
9229 }9263 }
...@@ -10186,49 +10220,56 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -10186,49 +10220,56 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
10186 const tracy = trace(@src());10220 const tracy = trace(@src());
10187 defer tracy.end();10221 defer tracy.end();
1018810222
10189 const mod = sema.mod;10223 const zcu = sema.mod;
10190 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;10224 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
10191 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };10225 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
10192 const operand = try sema.resolveInst(inst_data.operand);10226 const operand = try sema.resolveInst(inst_data.operand);
10193 const operand_ty = sema.typeOf(operand);10227 const operand_ty = sema.typeOf(operand);
10194 const ptr_ty = operand_ty.scalarType(mod);10228 const ptr_ty = operand_ty.scalarType(zcu);
10195 const is_vector = operand_ty.zigTypeTag(mod) == .Vector;10229 const is_vector = operand_ty.zigTypeTag(zcu) == .Vector;
10196 if (!ptr_ty.isPtrAtRuntime(mod)) {10230 if (!ptr_ty.isPtrAtRuntime(zcu)) {
10197 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(mod)});10231 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(zcu)});
10198 }10232 }
10199 const pointee_ty = ptr_ty.childType(mod);10233 const pointee_ty = ptr_ty.childType(zcu);
10200 if (try sema.typeRequiresComptime(ptr_ty)) {10234 if (try sema.typeRequiresComptime(ptr_ty)) {
10201 const msg = msg: {10235 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)});
10203 errdefer msg.destroy(sema.gpa);10237 errdefer msg.destroy(sema.gpa);
10204 const src_decl = mod.declPtr(block.src_decl);10238 const src_decl = zcu.declPtr(block.src_decl);
10205 try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(ptr_src, mod), pointee_ty);10239 try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(ptr_src, zcu), pointee_ty);
10206 break :msg msg;10240 break :msg msg;
10207 };10241 };
10208 return sema.failWithOwnedErrorMsg(block, msg);10242 return sema.failWithOwnedErrorMsg(block, msg);
10209 }10243 }
10210 if (try sema.resolveValueIntable(operand)) |operand_val| ct: {10244 if (try sema.resolveValueIntable(operand)) |operand_val| ct: {
10211 if (!is_vector) {10245 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(
10213 Type.usize,10250 Type.usize,
10214 (try operand_val.getUnsignedIntAdvanced(mod, sema)).?,10251 (try operand_val.getUnsignedIntAdvanced(zcu, sema)).?,
10215 )).toIntern());10252 )).toIntern());
10216 }10253 }
10217 const len = operand_ty.vectorLen(mod);10254 const len = operand_ty.vectorLen(zcu);
10218 const dest_ty = try mod.vectorType(.{ .child = .usize_type, .len = len });10255 const dest_ty = try zcu.vectorType(.{ .child = .usize_type, .len = len });
10219 const new_elems = try sema.arena.alloc(InternPool.Index, len);10256 const new_elems = try sema.arena.alloc(InternPool.Index, len);
10220 for (new_elems, 0..) |*new_elem, i| {10257 for (new_elems, 0..) |*new_elem, i| {
10221 const ptr_val = try operand_val.elemValue(mod, i);10258 const ptr_val = try operand_val.elemValue(zcu, i);
10222 const addr = try ptr_val.getUnsignedIntAdvanced(mod, sema) orelse {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 {
10223 // A vector element wasn't an integer pointer. This is a runtime operation.10264 // A vector element wasn't an integer pointer. This is a runtime operation.
10224 break :ct;10265 break :ct;
10225 };10266 };
10226 new_elem.* = (try mod.intValue(10267 new_elem.* = (try zcu.intValue(
10227 Type.usize,10268 Type.usize,
10228 addr,10269 addr,
10229 )).toIntern();10270 )).toIntern();
10230 }10271 }
10231 return Air.internedToRef(try mod.intern(.{ .aggregate = .{10272 return Air.internedToRef(try zcu.intern(.{ .aggregate = .{
10232 .ty = dest_ty.toIntern(),10273 .ty = dest_ty.toIntern(),
10233 .storage = .{ .elems = new_elems },10274 .storage = .{ .elems = new_elems },
10234 } }));10275 } }));
...@@ -10238,11 +10279,11 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -10238,11 +10279,11 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
10238 if (!is_vector) {10279 if (!is_vector) {
10239 return block.addUnOp(.int_from_ptr, operand);10280 return block.addUnOp(.int_from_ptr, operand);
10240 }10281 }
10241 const len = operand_ty.vectorLen(mod);10282 const len = operand_ty.vectorLen(zcu);
10242 const dest_ty = try mod.vectorType(.{ .child = .usize_type, .len = len });10283 const dest_ty = try zcu.vectorType(.{ .child = .usize_type, .len = len });
10243 const new_elems = try sema.arena.alloc(Air.Inst.Ref, len);10284 const new_elems = try sema.arena.alloc(Air.Inst.Ref, len);
10244 for (new_elems, 0..) |*new_elem, i| {10285 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);
10246 const old_elem = try block.addBinOp(.array_elem_val, operand, idx_ref);10287 const old_elem = try block.addBinOp(.array_elem_val, operand, idx_ref);
10247 new_elem.* = try block.addUnOp(.int_from_ptr, old_elem);10288 new_elem.* = try block.addUnOp(.int_from_ptr, old_elem);
10248 }10289 }
...@@ -11077,8 +11118,8 @@ const SwitchProngAnalysis = struct {...@@ -11077,8 +11118,8 @@ const SwitchProngAnalysis = struct {
11077 inline_case_capture: Air.Inst.Ref,11118 inline_case_capture: Air.Inst.Ref,
11078 ) CompileError!Air.Inst.Ref {11119 ) CompileError!Air.Inst.Ref {
11079 const sema = spa.sema;11120 const sema = spa.sema;
11080 const mod = sema.mod;11121 const zcu = sema.mod;
11081 const ip = &mod.intern_pool;11122 const ip = &zcu.intern_pool;
1108211123
11083 const zir_datas = sema.code.instructions.items(.data);11124 const zir_datas = sema.code.instructions.items(.data);
11084 const switch_node_offset = zir_datas[@intFromEnum(spa.switch_block_inst)].pl_node.src_node;11125 const switch_node_offset = zir_datas[@intFromEnum(spa.switch_block_inst)].pl_node.src_node;
...@@ -11089,27 +11130,21 @@ const SwitchProngAnalysis = struct {...@@ -11089,27 +11130,21 @@ const SwitchProngAnalysis = struct {
1108911130
11090 if (inline_case_capture != .none) {11131 if (inline_case_capture != .none) {
11091 const item_val = sema.resolveConstDefinedValue(block, .unneeded, inline_case_capture, undefined) catch unreachable;11132 const item_val = sema.resolveConstDefinedValue(block, .unneeded, inline_case_capture, undefined) catch unreachable;
11092 if (operand_ty.zigTypeTag(mod) == .Union) {11133 if (operand_ty.zigTypeTag(zcu) == .Union) {
11093 const field_index: u32 = @intCast(operand_ty.unionTagFieldIndex(item_val, mod).?);11134 const field_index: u32 = @intCast(operand_ty.unionTagFieldIndex(item_val, zcu).?);
11094 const union_obj = mod.typeToUnion(operand_ty).?;11135 const union_obj = zcu.typeToUnion(operand_ty).?;
11095 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);11136 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
11096 if (capture_byref) {11137 if (capture_byref) {
11097 const ptr_field_ty = try sema.ptrType(.{11138 const ptr_field_ty = try sema.ptrType(.{
11098 .child = field_ty.toIntern(),11139 .child = field_ty.toIntern(),
11099 .flags = .{11140 .flags = .{
11100 .is_const = !operand_ptr_ty.ptrIsMutable(mod),11141 .is_const = !operand_ptr_ty.ptrIsMutable(zcu),
11101 .is_volatile = operand_ptr_ty.isVolatilePtr(mod),11142 .is_volatile = operand_ptr_ty.isVolatilePtr(zcu),
11102 .address_space = operand_ptr_ty.ptrAddressSpace(mod),11143 .address_space = operand_ptr_ty.ptrAddressSpace(zcu),
11103 },11144 },
11104 });11145 });
11105 if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |union_ptr| {11146 if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |union_ptr| {
11106 return Air.internedToRef((try mod.intern(.{ .ptr = .{11147 return Air.internedToRef((try union_ptr.ptrField(field_index, sema)).toIntern());
11107 .ty = ptr_field_ty.toIntern(),
11108 .addr = .{ .field = .{
11109 .base = union_ptr.toIntern(),
11110 .index = field_index,
11111 } },
11112 } })));
11113 }11148 }
11114 return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty);11149 return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty);
11115 } else {11150 } else {
...@@ -11131,7 +11166,7 @@ const SwitchProngAnalysis = struct {...@@ -11131,7 +11166,7 @@ const SwitchProngAnalysis = struct {
11131 return spa.operand_ptr;11166 return spa.operand_ptr;
11132 }11167 }
1113311168
11134 switch (operand_ty.zigTypeTag(mod)) {11169 switch (operand_ty.zigTypeTag(zcu)) {
11135 .ErrorSet => if (spa.else_error_ty) |ty| {11170 .ErrorSet => if (spa.else_error_ty) |ty| {
11136 return sema.bitCast(block, ty, spa.operand, operand_src, null);11171 return sema.bitCast(block, ty, spa.operand, operand_src, null);
11137 } else {11172 } else {
...@@ -11142,25 +11177,25 @@ const SwitchProngAnalysis = struct {...@@ -11142,25 +11177,25 @@ const SwitchProngAnalysis = struct {
11142 }11177 }
11143 }11178 }
1114411179
11145 switch (operand_ty.zigTypeTag(mod)) {11180 switch (operand_ty.zigTypeTag(zcu)) {
11146 .Union => {11181 .Union => {
11147 const union_obj = mod.typeToUnion(operand_ty).?;11182 const union_obj = zcu.typeToUnion(operand_ty).?;
11148 const first_item_val = sema.resolveConstDefinedValue(block, .unneeded, case_vals[0], undefined) catch unreachable;11183 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).?;
11151 const first_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[first_field_index]);11186 const first_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[first_field_index]);
1115211187
11153 const field_indices = try sema.arena.alloc(u32, case_vals.len);11188 const field_indices = try sema.arena.alloc(u32, case_vals.len);
11154 for (case_vals, field_indices) |item, *field_idx| {11189 for (case_vals, field_indices) |item, *field_idx| {
11155 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item, undefined) catch unreachable;11190 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).?;
11157 }11192 }
1115811193
11159 // Fast path: if all the operands are the same type already, we don't need to hit11194 // Fast path: if all the operands are the same type already, we don't need to hit
11160 // PTR! This will also allow us to emit simpler code.11195 // PTR! This will also allow us to emit simpler code.
11161 const same_types = for (field_indices[1..]) |field_idx| {11196 const same_types = for (field_indices[1..]) |field_idx| {
11162 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]);11197 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;
11164 } else true;11199 } else true;
1116511200
11166 const capture_ty = if (same_types) first_field_ty else capture_ty: {11201 const capture_ty = if (same_types) first_field_ty else capture_ty: {
...@@ -11168,7 +11203,7 @@ const SwitchProngAnalysis = struct {...@@ -11168,7 +11203,7 @@ const SwitchProngAnalysis = struct {
11168 const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len);11203 const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len);
11169 for (dummy_captures, field_indices) |*dummy, field_idx| {11204 for (dummy_captures, field_indices) |*dummy, field_idx| {
11170 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]);11205 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);
11172 }11207 }
1117311208
11174 const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len);11209 const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len);
...@@ -11178,12 +11213,12 @@ const SwitchProngAnalysis = struct {...@@ -11178,12 +11213,12 @@ const SwitchProngAnalysis = struct {
11178 error.NeededSourceLocation => {11213 error.NeededSourceLocation => {
11179 // This must be a multi-prong so this must be a `multi_capture` src11214 // This must be a multi-prong so this must be a `multi_capture` src
11180 const multi_idx = raw_capture_src.multi_capture;11215 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);
11182 for (case_srcs, 0..) |*case_src, i| {11217 for (case_srcs, 0..) |*case_src, i| {
11183 const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(i) } };11218 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);
11185 }11220 }
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);
11187 _ = sema.resolvePeerTypes(block, capture_src, dummy_captures, .{ .override = case_srcs }) catch |err1| switch (err1) {11222 _ = sema.resolvePeerTypes(block, capture_src, dummy_captures, .{ .override = case_srcs }) catch |err1| switch (err1) {
11188 error.AnalysisFail => {11223 error.AnalysisFail => {
11189 const msg = sema.err orelse return error.AnalysisFail;11224 const msg = sema.err orelse return error.AnalysisFail;
...@@ -11200,7 +11235,7 @@ const SwitchProngAnalysis = struct {...@@ -11200,7 +11235,7 @@ const SwitchProngAnalysis = struct {
1120011235
11201 // By-reference captures have some further restrictions which make them easier to emit11236 // By-reference captures have some further restrictions which make them easier to emit
11202 if (capture_byref) {11237 if (capture_byref) {
11203 const operand_ptr_info = operand_ptr_ty.ptrInfo(mod);11238 const operand_ptr_info = operand_ptr_ty.ptrInfo(zcu);
11204 const capture_ptr_ty = resolve: {11239 const capture_ptr_ty = resolve: {
11205 // By-ref captures of hetereogeneous types are only allowed if all field11240 // By-ref captures of hetereogeneous types are only allowed if all field
11206 // pointer types are peer resolvable to each other.11241 // pointer types are peer resolvable to each other.
...@@ -11217,7 +11252,7 @@ const SwitchProngAnalysis = struct {...@@ -11217,7 +11252,7 @@ const SwitchProngAnalysis = struct {
11217 .alignment = union_obj.fieldAlign(ip, field_idx),11252 .alignment = union_obj.fieldAlign(ip, field_idx),
11218 },11253 },
11219 });11254 });
11220 dummy.* = try mod.undefRef(field_ptr_ty);11255 dummy.* = try zcu.undefRef(field_ptr_ty);
11221 }11256 }
11222 const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len);11257 const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len);
11223 @memset(case_srcs, .unneeded);11258 @memset(case_srcs, .unneeded);
...@@ -11226,12 +11261,12 @@ const SwitchProngAnalysis = struct {...@@ -11226,12 +11261,12 @@ const SwitchProngAnalysis = struct {
11226 error.NeededSourceLocation => {11261 error.NeededSourceLocation => {
11227 // This must be a multi-prong so this must be a `multi_capture` src11262 // This must be a multi-prong so this must be a `multi_capture` src
11228 const multi_idx = raw_capture_src.multi_capture;11263 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);
11230 for (case_srcs, 0..) |*case_src, i| {11265 for (case_srcs, 0..) |*case_src, i| {
11231 const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(i) } };11266 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);
11233 }11268 }
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);
11235 _ = sema.resolvePeerTypes(block, capture_src, dummy_captures, .{ .override = case_srcs }) catch |err1| switch (err1) {11270 _ = sema.resolvePeerTypes(block, capture_src, dummy_captures, .{ .override = case_srcs }) catch |err1| switch (err1) {
11236 error.AnalysisFail => {11271 error.AnalysisFail => {
11237 const msg = sema.err orelse return error.AnalysisFail;11272 const msg = sema.err orelse return error.AnalysisFail;
...@@ -11248,14 +11283,9 @@ const SwitchProngAnalysis = struct {...@@ -11248,14 +11283,9 @@ const SwitchProngAnalysis = struct {
11248 };11283 };
1124911284
11250 if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |op_ptr_val| {11285 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);11286 if (op_ptr_val.isUndef(zcu)) return zcu.undefRef(capture_ptr_ty);
11252 return Air.internedToRef((try mod.intern(.{ .ptr = .{11287 const field_ptr_val = try op_ptr_val.ptrField(first_field_index, sema);
11253 .ty = capture_ptr_ty.toIntern(),11288 return Air.internedToRef((try zcu.getCoerced(field_ptr_val, capture_ptr_ty)).toIntern());
11254 .addr = .{ .field = .{
11255 .base = op_ptr_val.toIntern(),
11256 .index = first_field_index,
11257 } },
11258 } })));
11259 }11289 }
1126011290
11261 try sema.requireRuntimeBlock(block, operand_src, null);11291 try sema.requireRuntimeBlock(block, operand_src, null);
...@@ -11263,9 +11293,9 @@ const SwitchProngAnalysis = struct {...@@ -11263,9 +11293,9 @@ const SwitchProngAnalysis = struct {
11263 }11293 }
1126411294
11265 if (try sema.resolveDefinedValue(block, operand_src, spa.operand)) |operand_val| {11295 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);
11267 const union_val = ip.indexToKey(operand_val.toIntern()).un;11297 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);
11269 const uncoerced = Air.internedToRef(union_val.val);11299 const uncoerced = Air.internedToRef(union_val.val);
11270 return sema.coerce(block, capture_ty, uncoerced, operand_src);11300 return sema.coerce(block, capture_ty, uncoerced, operand_src);
11271 }11301 }
...@@ -11281,7 +11311,7 @@ const SwitchProngAnalysis = struct {...@@ -11281,7 +11311,7 @@ const SwitchProngAnalysis = struct {
11281 const first_non_imc = in_mem: {11311 const first_non_imc = in_mem: {
11282 for (field_indices, 0..) |field_idx, i| {11312 for (field_indices, 0..) |field_idx, i| {
11283 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]);11313 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)) {
11285 break :in_mem i;11315 break :in_mem i;
11286 }11316 }
11287 }11317 }
...@@ -11304,7 +11334,7 @@ const SwitchProngAnalysis = struct {...@@ -11304,7 +11334,7 @@ const SwitchProngAnalysis = struct {
11304 const next = first_non_imc + 1;11334 const next = first_non_imc + 1;
11305 for (field_indices[next..], next..) |field_idx, i| {11335 for (field_indices[next..], next..) |field_idx, i| {
11306 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]);11336 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)) {
11308 in_mem_coercible.unset(i);11338 in_mem_coercible.unset(i);
11309 }11339 }
11310 }11340 }
...@@ -11339,9 +11369,9 @@ const SwitchProngAnalysis = struct {...@@ -11339,9 +11369,9 @@ const SwitchProngAnalysis = struct {
11339 const coerced = sema.coerce(&coerce_block, capture_ty, uncoerced, .unneeded) catch |err| switch (err) {11369 const coerced = sema.coerce(&coerce_block, capture_ty, uncoerced, .unneeded) catch |err| switch (err) {
11340 error.NeededSourceLocation => {11370 error.NeededSourceLocation => {
11341 const multi_idx = raw_capture_src.multi_capture;11371 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);
11343 const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(idx) } };11373 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);
11345 _ = try sema.coerce(&coerce_block, capture_ty, uncoerced, case_src);11375 _ = try sema.coerce(&coerce_block, capture_ty, uncoerced, case_src);
11346 unreachable;11376 unreachable;
11347 },11377 },
...@@ -11400,7 +11430,7 @@ const SwitchProngAnalysis = struct {...@@ -11400,7 +11430,7 @@ const SwitchProngAnalysis = struct {
11400 },11430 },
11401 .ErrorSet => {11431 .ErrorSet => {
11402 if (capture_byref) {11432 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);
11404 return sema.fail(11434 return sema.fail(
11405 block,11435 block,
11406 capture_src,11436 capture_src,
...@@ -11411,7 +11441,7 @@ const SwitchProngAnalysis = struct {...@@ -11411,7 +11441,7 @@ const SwitchProngAnalysis = struct {
1141111441
11412 if (case_vals.len == 1) {11442 if (case_vals.len == 1) {
11413 const item_val = sema.resolveConstDefinedValue(block, .unneeded, case_vals[0], undefined) catch unreachable;11443 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().?);
11415 return sema.bitCast(block, item_ty, spa.operand, operand_src, null);11445 return sema.bitCast(block, item_ty, spa.operand, operand_src, null);
11416 }11446 }
1141711447
...@@ -11419,9 +11449,9 @@ const SwitchProngAnalysis = struct {...@@ -11419,9 +11449,9 @@ const SwitchProngAnalysis = struct {
11419 try names.ensureUnusedCapacity(sema.arena, case_vals.len);11449 try names.ensureUnusedCapacity(sema.arena, case_vals.len);
11420 for (case_vals) |err| {11450 for (case_vals) |err| {
11421 const err_val = sema.resolveConstDefinedValue(block, .unneeded, err, undefined) catch unreachable;11451 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().?, {});
11423 }11453 }
11424 const error_ty = try mod.errorSetFromUnsortedNames(names.keys());11454 const error_ty = try zcu.errorSetFromUnsortedNames(names.keys());
11425 return sema.bitCast(block, error_ty, spa.operand, operand_src, null);11455 return sema.bitCast(block, error_ty, spa.operand, operand_src, null);
11426 },11456 },
11427 else => {11457 else => {
...@@ -13989,7 +14019,7 @@ fn zirShl(...@@ -13989,7 +14019,7 @@ fn zirShl(
13989 const rhs_elem = try rhs_val.elemValue(mod, i);14019 const rhs_elem = try rhs_val.elemValue(mod, i);
13990 if (rhs_elem.compareHetero(.gte, bit_value, mod)) {14020 if (rhs_elem.compareHetero(.gte, bit_value, mod)) {
13991 return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{14021 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),
13993 i,14023 i,
13994 scalar_ty.fmt(mod),14024 scalar_ty.fmt(mod),
13995 });14025 });
...@@ -13997,7 +14027,7 @@ fn zirShl(...@@ -13997,7 +14027,7 @@ fn zirShl(
13997 }14027 }
13998 } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {14028 } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {
13999 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{14029 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),
14001 scalar_ty.fmt(mod),14031 scalar_ty.fmt(mod),
14002 });14032 });
14003 }14033 }
...@@ -14008,14 +14038,14 @@ fn zirShl(...@@ -14008,14 +14038,14 @@ fn zirShl(
14008 const rhs_elem = try rhs_val.elemValue(mod, i);14038 const rhs_elem = try rhs_val.elemValue(mod, i);
14009 if (rhs_elem.compareHetero(.lt, try mod.intValue(scalar_rhs_ty, 0), mod)) {14039 if (rhs_elem.compareHetero(.lt, try mod.intValue(scalar_rhs_ty, 0), mod)) {
14010 return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{14040 return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
14011 rhs_elem.fmtValue(mod),14041 rhs_elem.fmtValue(mod, sema),
14012 i,14042 i,
14013 });14043 });
14014 }14044 }
14015 }14045 }
14016 } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {14046 } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {
14017 return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{14047 return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
14018 rhs_val.fmtValue(mod),14048 rhs_val.fmtValue(mod, sema),
14019 });14049 });
14020 }14050 }
14021 }14051 }
...@@ -14154,7 +14184,7 @@ fn zirShr(...@@ -14154,7 +14184,7 @@ fn zirShr(
14154 const rhs_elem = try rhs_val.elemValue(mod, i);14184 const rhs_elem = try rhs_val.elemValue(mod, i);
14155 if (rhs_elem.compareHetero(.gte, bit_value, mod)) {14185 if (rhs_elem.compareHetero(.gte, bit_value, mod)) {
14156 return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{14186 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),
14158 i,14188 i,
14159 scalar_ty.fmt(mod),14189 scalar_ty.fmt(mod),
14160 });14190 });
...@@ -14162,7 +14192,7 @@ fn zirShr(...@@ -14162,7 +14192,7 @@ fn zirShr(
14162 }14192 }
14163 } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {14193 } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {
14164 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{14194 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),
14166 scalar_ty.fmt(mod),14196 scalar_ty.fmt(mod),
14167 });14197 });
14168 }14198 }
...@@ -14173,14 +14203,14 @@ fn zirShr(...@@ -14173,14 +14203,14 @@ fn zirShr(
14173 const rhs_elem = try rhs_val.elemValue(mod, i);14203 const rhs_elem = try rhs_val.elemValue(mod, i);
14174 if (rhs_elem.compareHetero(.lt, try mod.intValue(rhs_ty.childType(mod), 0), mod)) {14204 if (rhs_elem.compareHetero(.lt, try mod.intValue(rhs_ty.childType(mod), 0), mod)) {
14175 return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{14205 return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
14176 rhs_elem.fmtValue(mod),14206 rhs_elem.fmtValue(mod, sema),
14177 i,14207 i,
14178 });14208 });
14179 }14209 }
14180 }14210 }
14181 } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {14211 } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {
14182 return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{14212 return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
14183 rhs_val.fmtValue(mod),14213 rhs_val.fmtValue(mod, sema),
14184 });14214 });
14185 }14215 }
14186 if (maybe_lhs_val) |lhs_val| {14216 if (maybe_lhs_val) |lhs_val| {
...@@ -15101,7 +15131,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -15101,7 +15131,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
15101 block,15131 block,
15102 src,15132 src,
15103 "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'",15133 "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) },
15105 );15135 );
15106 }15136 }
15107 }15137 }
...@@ -16903,21 +16933,14 @@ fn analyzePtrArithmetic(...@@ -16903,21 +16933,14 @@ fn analyzePtrArithmetic(
1690316933
16904 const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntAdvanced(sema));16934 const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntAdvanced(sema));
16905 if (offset_int == 0) return ptr;16935 if (offset_int == 0) return ptr;
16906 if (try ptr_val.getUnsignedIntAdvanced(mod, sema)) |addr| {16936 if (air_tag == .ptr_sub) {
16907 const elem_size = try sema.typeAbiSize(Type.fromInterned(ptr_info.child));16937 const elem_size = try sema.typeAbiSize(Type.fromInterned(ptr_info.child));
16908 const new_addr = switch (air_tag) {16938 const new_ptr_val = try sema.ptrSubtract(block, op_src, ptr_val, offset_int * elem_size, new_ptr_ty);
16909 .ptr_add => addr + elem_size * offset_int,16939 return Air.internedToRef(new_ptr_val.toIntern());
16910 .ptr_sub => addr - elem_size * offset_int,16940 } else {
16911 else => unreachable,16941 const new_ptr_val = try mod.getCoerced(try ptr_val.ptrElem(offset_int, sema), new_ptr_ty);
16912 };
16913 const new_ptr_val = try mod.ptrIntValue(new_ptr_ty, new_addr);
16914 return Air.internedToRef(new_ptr_val.toIntern());16942 return Air.internedToRef(new_ptr_val.toIntern());
16915 }16943 }
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());
16921 } else break :rs offset_src;16944 } else break :rs offset_src;
16922 } else break :rs ptr_src;16945 } else break :rs ptr_src;
16923 };16946 };
...@@ -17611,13 +17634,14 @@ fn zirBuiltinSrc(...@@ -17611,13 +17634,14 @@ fn zirBuiltinSrc(
17611 .ty = .slice_const_u8_sentinel_0_type,17634 .ty = .slice_const_u8_sentinel_0_type,
17612 .ptr = try ip.get(gpa, .{ .ptr = .{17635 .ptr = try ip.get(gpa, .{ .ptr = .{
17613 .ty = .manyptr_const_u8_sentinel_0_type,17636 .ty = .manyptr_const_u8_sentinel_0_type,
17614 .addr = .{ .anon_decl = .{17637 .base_addr = .{ .anon_decl = .{
17615 .orig_ty = .slice_const_u8_sentinel_0_type,17638 .orig_ty = .slice_const_u8_sentinel_0_type,
17616 .val = try ip.get(gpa, .{ .aggregate = .{17639 .val = try ip.get(gpa, .{ .aggregate = .{
17617 .ty = array_ty,17640 .ty = array_ty,
17618 .storage = .{ .bytes = fn_owner_decl.name.toString() },17641 .storage = .{ .bytes = fn_owner_decl.name.toString() },
17619 } }),17642 } }),
17620 } },17643 } },
17644 .byte_offset = 0,
17621 } }),17645 } }),
17622 .len = (try mod.intValue(Type.usize, func_name_len)).toIntern(),17646 .len = (try mod.intValue(Type.usize, func_name_len)).toIntern(),
17623 } });17647 } });
...@@ -17635,7 +17659,7 @@ fn zirBuiltinSrc(...@@ -17635,7 +17659,7 @@ fn zirBuiltinSrc(
17635 .ty = .slice_const_u8_sentinel_0_type,17659 .ty = .slice_const_u8_sentinel_0_type,
17636 .ptr = try ip.get(gpa, .{ .ptr = .{17660 .ptr = try ip.get(gpa, .{ .ptr = .{
17637 .ty = .manyptr_const_u8_sentinel_0_type,17661 .ty = .manyptr_const_u8_sentinel_0_type,
17638 .addr = .{ .anon_decl = .{17662 .base_addr = .{ .anon_decl = .{
17639 .orig_ty = .slice_const_u8_sentinel_0_type,17663 .orig_ty = .slice_const_u8_sentinel_0_type,
17640 .val = try ip.get(gpa, .{ .aggregate = .{17664 .val = try ip.get(gpa, .{ .aggregate = .{
17641 .ty = array_ty,17665 .ty = array_ty,
...@@ -17644,6 +17668,7 @@ fn zirBuiltinSrc(...@@ -17644,6 +17668,7 @@ fn zirBuiltinSrc(
17644 },17668 },
17645 } }),17669 } }),
17646 } },17670 } },
17671 .byte_offset = 0,
17647 } }),17672 } }),
17648 .len = (try mod.intValue(Type.usize, file_name.len)).toIntern(),17673 .len = (try mod.intValue(Type.usize, file_name.len)).toIntern(),
17649 } });17674 } });
...@@ -17766,10 +17791,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17766,10 +17791,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17766 .ty = slice_ty,17791 .ty = slice_ty,
17767 .ptr = try mod.intern(.{ .ptr = .{17792 .ptr = try mod.intern(.{ .ptr = .{
17768 .ty = manyptr_ty,17793 .ty = manyptr_ty,
17769 .addr = .{ .anon_decl = .{17794 .base_addr = .{ .anon_decl = .{
17770 .orig_ty = manyptr_ty,17795 .orig_ty = manyptr_ty,
17771 .val = new_decl_val,17796 .val = new_decl_val,
17772 } },17797 } },
17798 .byte_offset = 0,
17773 } }),17799 } }),
17774 .len = (try mod.intValue(Type.usize, param_vals.len)).toIntern(),17800 .len = (try mod.intValue(Type.usize, param_vals.len)).toIntern(),
17775 } });17801 } });
...@@ -18046,10 +18072,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18046,10 +18072,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18046 .ty = .slice_const_u8_sentinel_0_type,18072 .ty = .slice_const_u8_sentinel_0_type,
18047 .ptr = try mod.intern(.{ .ptr = .{18073 .ptr = try mod.intern(.{ .ptr = .{
18048 .ty = .manyptr_const_u8_sentinel_0_type,18074 .ty = .manyptr_const_u8_sentinel_0_type,
18049 .addr = .{ .anon_decl = .{18075 .base_addr = .{ .anon_decl = .{
18050 .val = new_decl_val,18076 .val = new_decl_val,
18051 .orig_ty = .slice_const_u8_sentinel_0_type,18077 .orig_ty = .slice_const_u8_sentinel_0_type,
18052 } },18078 } },
18079 .byte_offset = 0,
18053 } }),18080 } }),
18054 .len = (try mod.intValue(Type.usize, error_name_len)).toIntern(),18081 .len = (try mod.intValue(Type.usize, error_name_len)).toIntern(),
18055 } });18082 } });
...@@ -18092,10 +18119,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18092,10 +18119,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18092 .ty = slice_errors_ty.toIntern(),18119 .ty = slice_errors_ty.toIntern(),
18093 .ptr = try mod.intern(.{ .ptr = .{18120 .ptr = try mod.intern(.{ .ptr = .{
18094 .ty = manyptr_errors_ty,18121 .ty = manyptr_errors_ty,
18095 .addr = .{ .anon_decl = .{18122 .base_addr = .{ .anon_decl = .{
18096 .orig_ty = manyptr_errors_ty,18123 .orig_ty = manyptr_errors_ty,
18097 .val = new_decl_val,18124 .val = new_decl_val,
18098 } },18125 } },
18126 .byte_offset = 0,
18099 } }),18127 } }),
18100 .len = (try mod.intValue(Type.usize, vals.len)).toIntern(),18128 .len = (try mod.intValue(Type.usize, vals.len)).toIntern(),
18101 } });18129 } });
...@@ -18184,10 +18212,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18184,10 +18212,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18184 .ty = .slice_const_u8_sentinel_0_type,18212 .ty = .slice_const_u8_sentinel_0_type,
18185 .ptr = try mod.intern(.{ .ptr = .{18213 .ptr = try mod.intern(.{ .ptr = .{
18186 .ty = .manyptr_const_u8_sentinel_0_type,18214 .ty = .manyptr_const_u8_sentinel_0_type,
18187 .addr = .{ .anon_decl = .{18215 .base_addr = .{ .anon_decl = .{
18188 .val = new_decl_val,18216 .val = new_decl_val,
18189 .orig_ty = .slice_const_u8_sentinel_0_type,18217 .orig_ty = .slice_const_u8_sentinel_0_type,
18190 } },18218 } },
18219 .byte_offset = 0,
18191 } }),18220 } }),
18192 .len = (try mod.intValue(Type.usize, tag_name_len)).toIntern(),18221 .len = (try mod.intValue(Type.usize, tag_name_len)).toIntern(),
18193 } });18222 } });
...@@ -18226,10 +18255,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18226,10 +18255,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18226 .ty = slice_ty,18255 .ty = slice_ty,
18227 .ptr = try mod.intern(.{ .ptr = .{18256 .ptr = try mod.intern(.{ .ptr = .{
18228 .ty = manyptr_ty,18257 .ty = manyptr_ty,
18229 .addr = .{ .anon_decl = .{18258 .base_addr = .{ .anon_decl = .{
18230 .val = new_decl_val,18259 .val = new_decl_val,
18231 .orig_ty = manyptr_ty,18260 .orig_ty = manyptr_ty,
18232 } },18261 } },
18262 .byte_offset = 0,
18233 } }),18263 } }),
18234 .len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(),18264 .len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(),
18235 } });18265 } });
...@@ -18318,10 +18348,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18318,10 +18348,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18318 .ty = .slice_const_u8_sentinel_0_type,18348 .ty = .slice_const_u8_sentinel_0_type,
18319 .ptr = try mod.intern(.{ .ptr = .{18349 .ptr = try mod.intern(.{ .ptr = .{
18320 .ty = .manyptr_const_u8_sentinel_0_type,18350 .ty = .manyptr_const_u8_sentinel_0_type,
18321 .addr = .{ .anon_decl = .{18351 .base_addr = .{ .anon_decl = .{
18322 .val = new_decl_val,18352 .val = new_decl_val,
18323 .orig_ty = .slice_const_u8_sentinel_0_type,18353 .orig_ty = .slice_const_u8_sentinel_0_type,
18324 } },18354 } },
18355 .byte_offset = 0,
18325 } }),18356 } }),
18326 .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),18357 .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),
18327 } });18358 } });
...@@ -18368,10 +18399,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18368,10 +18399,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18368 .ty = slice_ty,18399 .ty = slice_ty,
18369 .ptr = try mod.intern(.{ .ptr = .{18400 .ptr = try mod.intern(.{ .ptr = .{
18370 .ty = manyptr_ty,18401 .ty = manyptr_ty,
18371 .addr = .{ .anon_decl = .{18402 .base_addr = .{ .anon_decl = .{
18372 .orig_ty = manyptr_ty,18403 .orig_ty = manyptr_ty,
18373 .val = new_decl_val,18404 .val = new_decl_val,
18374 } },18405 } },
18406 .byte_offset = 0,
18375 } }),18407 } }),
18376 .len = (try mod.intValue(Type.usize, union_field_vals.len)).toIntern(),18408 .len = (try mod.intValue(Type.usize, union_field_vals.len)).toIntern(),
18377 } });18409 } });
...@@ -18471,10 +18503,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18471,10 +18503,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18471 .ty = .slice_const_u8_sentinel_0_type,18503 .ty = .slice_const_u8_sentinel_0_type,
18472 .ptr = try mod.intern(.{ .ptr = .{18504 .ptr = try mod.intern(.{ .ptr = .{
18473 .ty = .manyptr_const_u8_sentinel_0_type,18505 .ty = .manyptr_const_u8_sentinel_0_type,
18474 .addr = .{ .anon_decl = .{18506 .base_addr = .{ .anon_decl = .{
18475 .val = new_decl_val,18507 .val = new_decl_val,
18476 .orig_ty = .slice_const_u8_sentinel_0_type,18508 .orig_ty = .slice_const_u8_sentinel_0_type,
18477 } },18509 } },
18510 .byte_offset = 0,
18478 } }),18511 } }),
18479 .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),18512 .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),
18480 } });18513 } });
...@@ -18534,10 +18567,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18534,10 +18567,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18534 .ty = .slice_const_u8_sentinel_0_type,18567 .ty = .slice_const_u8_sentinel_0_type,
18535 .ptr = try mod.intern(.{ .ptr = .{18568 .ptr = try mod.intern(.{ .ptr = .{
18536 .ty = .manyptr_const_u8_sentinel_0_type,18569 .ty = .manyptr_const_u8_sentinel_0_type,
18537 .addr = .{ .anon_decl = .{18570 .base_addr = .{ .anon_decl = .{
18538 .val = new_decl_val,18571 .val = new_decl_val,
18539 .orig_ty = .slice_const_u8_sentinel_0_type,18572 .orig_ty = .slice_const_u8_sentinel_0_type,
18540 } },18573 } },
18574 .byte_offset = 0,
18541 } }),18575 } }),
18542 .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),18576 .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),
18543 } });18577 } });
...@@ -18594,10 +18628,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18594,10 +18628,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18594 .ty = slice_ty,18628 .ty = slice_ty,
18595 .ptr = try mod.intern(.{ .ptr = .{18629 .ptr = try mod.intern(.{ .ptr = .{
18596 .ty = manyptr_ty,18630 .ty = manyptr_ty,
18597 .addr = .{ .anon_decl = .{18631 .base_addr = .{ .anon_decl = .{
18598 .orig_ty = manyptr_ty,18632 .orig_ty = manyptr_ty,
18599 .val = new_decl_val,18633 .val = new_decl_val,
18600 } },18634 } },
18635 .byte_offset = 0,
18601 } }),18636 } }),
18602 .len = (try mod.intValue(Type.usize, struct_field_vals.len)).toIntern(),18637 .len = (try mod.intValue(Type.usize, struct_field_vals.len)).toIntern(),
18603 } });18638 } });
...@@ -18733,10 +18768,11 @@ fn typeInfoDecls(...@@ -18733,10 +18768,11 @@ fn typeInfoDecls(
18733 .ty = slice_ty,18768 .ty = slice_ty,
18734 .ptr = try mod.intern(.{ .ptr = .{18769 .ptr = try mod.intern(.{ .ptr = .{
18735 .ty = manyptr_ty,18770 .ty = manyptr_ty,
18736 .addr = .{ .anon_decl = .{18771 .base_addr = .{ .anon_decl = .{
18737 .orig_ty = manyptr_ty,18772 .orig_ty = manyptr_ty,
18738 .val = new_decl_val,18773 .val = new_decl_val,
18739 } },18774 } },
18775 .byte_offset = 0,
18740 } }),18776 } }),
18741 .len = (try mod.intValue(Type.usize, decl_vals.items.len)).toIntern(),18777 .len = (try mod.intValue(Type.usize, decl_vals.items.len)).toIntern(),
18742 } });18778 } });
...@@ -18765,7 +18801,7 @@ fn typeInfoNamespaceDecls(...@@ -18765,7 +18801,7 @@ fn typeInfoNamespaceDecls(
18765 if (!decl.is_pub) continue;18801 if (!decl.is_pub) continue;
18766 if (decl.kind == .@"usingnamespace") {18802 if (decl.kind == .@"usingnamespace") {
18767 if (decl.analysis == .in_progress) continue;18803 if (decl.analysis == .in_progress) continue;
18768 try mod.ensureDeclAnalyzed(decl_index);18804 try sema.ensureDeclAnalyzed(decl_index);
18769 try sema.typeInfoNamespaceDecls(block, decl.val.toType().getNamespaceIndex(mod), declaration_ty, decl_vals, seen_namespaces);18805 try sema.typeInfoNamespaceDecls(block, decl.val.toType().getNamespaceIndex(mod), declaration_ty, decl_vals, seen_namespaces);
18770 continue;18806 continue;
18771 }18807 }
...@@ -18785,10 +18821,11 @@ fn typeInfoNamespaceDecls(...@@ -18785,10 +18821,11 @@ fn typeInfoNamespaceDecls(
18785 .ty = .slice_const_u8_sentinel_0_type,18821 .ty = .slice_const_u8_sentinel_0_type,
18786 .ptr = try mod.intern(.{ .ptr = .{18822 .ptr = try mod.intern(.{ .ptr = .{
18787 .ty = .manyptr_const_u8_sentinel_0_type,18823 .ty = .manyptr_const_u8_sentinel_0_type,
18788 .addr = .{ .anon_decl = .{18824 .base_addr = .{ .anon_decl = .{
18789 .orig_ty = .slice_const_u8_sentinel_0_type,18825 .orig_ty = .slice_const_u8_sentinel_0_type,
18790 .val = new_decl_val,18826 .val = new_decl_val,
18791 } },18827 } },
18828 .byte_offset = 0,
18792 } }),18829 } }),
18793 .len = (try mod.intValue(Type.usize, decl_name_len)).toIntern(),18830 .len = (try mod.intValue(Type.usize, decl_name_len)).toIntern(),
18794 } });18831 } });
...@@ -19907,6 +19944,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -19907,6 +19944,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
19907 }19944 }
19908 }19945 }
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
19910 const ty = try sema.ptrType(.{19957 const ty = try sema.ptrType(.{
19911 .child = elem_ty.toIntern(),19958 .child = elem_ty.toIntern(),
19912 .sentinel = sentinel,19959 .sentinel = sentinel,
...@@ -21176,7 +21223,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -21176,7 +21223,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
21176 const enum_decl = mod.declPtr(enum_decl_index);21223 const enum_decl = mod.declPtr(enum_decl_index);
21177 const msg = msg: {21224 const msg = msg: {
21178 const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{}'", .{21225 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),
21180 });21227 });
21181 errdefer msg.destroy(sema.gpa);21228 errdefer msg.destroy(sema.gpa);
21182 try mod.errNoteNonLazy(enum_decl.srcLoc(mod), msg, "declared here", .{});21229 try mod.errNoteNonLazy(enum_decl.srcLoc(mod), msg, "declared here", .{});
...@@ -21811,7 +21858,7 @@ fn reifyEnum(...@@ -21811,7 +21858,7 @@ fn reifyEnum(
21811 // TODO: better source location21858 // TODO: better source location
21812 return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{21859 return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{
21813 field_name.fmt(ip),21860 field_name.fmt(ip),
21814 field_value_val.fmtValue(mod),21861 field_value_val.fmtValue(mod, sema),
21815 tag_ty.fmt(mod),21862 tag_ty.fmt(mod),
21816 });21863 });
21817 }21864 }
...@@ -21827,7 +21874,7 @@ fn reifyEnum(...@@ -21827,7 +21874,7 @@ fn reifyEnum(
21827 break :msg msg;21874 break :msg msg;
21828 },21875 },
21829 .value => msg: {21876 .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)});
21831 errdefer msg.destroy(gpa);21878 errdefer msg.destroy(gpa);
21832 _ = conflict.prev_field_idx; // TODO: this note is incorrect21879 _ = conflict.prev_field_idx; // TODO: this note is incorrect
21833 try sema.errNote(block, src, msg, "other enum tag value here", .{});21880 try sema.errNote(block, src, msg, "other enum tag value here", .{});
...@@ -22681,19 +22728,25 @@ fn ptrFromIntVal(...@@ -22681,19 +22728,25 @@ fn ptrFromIntVal(
22681 ptr_ty: Type,22728 ptr_ty: Type,
22682 ptr_align: Alignment,22729 ptr_align: Alignment,
22683) !Value {22730) !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 }
22685 const addr = try operand_val.toUnsignedIntAdvanced(sema);22738 const addr = try operand_val.toUnsignedIntAdvanced(sema);
22686 if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)22739 if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0)
22687 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)});22740 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(zcu)});
22688 if (addr != 0 and ptr_align != .none and !ptr_align.check(addr))22741 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)) {22744 return switch (ptr_ty.zigTypeTag(zcu)) {
22692 .Optional => Value.fromInterned((try mod.intern(.{ .opt = .{22745 .Optional => Value.fromInterned((try zcu.intern(.{ .opt = .{
22693 .ty = ptr_ty.toIntern(),22746 .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(),
22695 } }))),22748 } }))),
22696 .Pointer => try mod.ptrIntValue(ptr_ty, addr),22749 .Pointer => try zcu.ptrIntValue(ptr_ty, addr),
22697 else => unreachable,22750 else => unreachable,
22698 };22751 };
22699}22752}
...@@ -22980,12 +23033,12 @@ fn ptrCastFull(...@@ -22980,12 +23033,12 @@ fn ptrCastFull(
22980 return sema.failWithOwnedErrorMsg(block, msg: {23033 return sema.failWithOwnedErrorMsg(block, msg: {
22981 const msg = if (src_info.sentinel == .none) blk: {23034 const msg = if (src_info.sentinel == .none) blk: {
22982 break :blk try sema.errMsg(block, src, "destination pointer requires '{}' sentinel", .{23035 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),
22984 });23037 });
22985 } else blk: {23038 } else blk: {
22986 break :blk try sema.errMsg(block, src, "pointer sentinel '{}' cannot coerce into pointer sentinel '{}'", .{23039 break :blk try sema.errMsg(block, src, "pointer sentinel '{}' cannot coerce into pointer sentinel '{}'", .{
22987 Value.fromInterned(src_info.sentinel).fmtValue(mod),23040 Value.fromInterned(src_info.sentinel).fmtValue(mod, sema),
22988 Value.fromInterned(dest_info.sentinel).fmtValue(mod),23041 Value.fromInterned(dest_info.sentinel).fmtValue(mod, sema),
22989 });23042 });
22990 };23043 };
22991 errdefer msg.destroy(sema.gpa);23044 errdefer msg.destroy(sema.gpa);
...@@ -23159,11 +23212,13 @@ fn ptrCastFull(...@@ -23159,11 +23212,13 @@ fn ptrCastFull(
23159 if (dest_info.flags.size == .Slice and src_info.flags.size != .Slice) {23212 if (dest_info.flags.size == .Slice and src_info.flags.size != .Slice) {
23160 if (ptr_val.isUndef(mod)) return mod.undefRef(dest_ty);23213 if (ptr_val.isUndef(mod)) return mod.undefRef(dest_ty);
23161 const arr_len = try mod.intValue(Type.usize, Type.fromInterned(src_info.child).arrayLen(mod));23214 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;
23162 return Air.internedToRef((try mod.intern(.{ .slice = .{23216 return Air.internedToRef((try mod.intern(.{ .slice = .{
23163 .ty = dest_ty.toIntern(),23217 .ty = dest_ty.toIntern(),
23164 .ptr = try mod.intern(.{ .ptr = .{23218 .ptr = try mod.intern(.{ .ptr = .{
23165 .ty = dest_ty.slicePtrFieldType(mod).toIntern(),23219 .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,
23167 } }),23222 } }),
23168 .len = arr_len.toIntern(),23223 .len = arr_len.toIntern(),
23169 } })));23224 } })));
...@@ -23834,36 +23889,6 @@ fn checkPtrIsNotComptimeMutable(...@@ -23834,36 +23889,6 @@ fn checkPtrIsNotComptimeMutable(
23834 }23889 }
23835}23890}
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
23867fn checkIntOrVector(23892fn checkIntOrVector(
23868 sema: *Sema,23893 sema: *Sema,
23869 block: *Block,23894 block: *Block,
...@@ -24926,8 +24951,8 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -24926,8 +24951,8 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
24926}24951}
2492724952
24928fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {24953fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
24929 const mod = sema.mod;24954 const zcu = sema.mod;
24930 const ip = &mod.intern_pool;24955 const ip = &zcu.intern_pool;
2493124956
24932 const extra = sema.code.extraData(Zir.Inst.FieldParentPtr, extended.operand).data;24957 const extra = sema.code.extraData(Zir.Inst.FieldParentPtr, extended.operand).data;
24933 const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).Struct.backing_integer.?;24958 const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).Struct.backing_integer.?;
...@@ -24939,23 +24964,23 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24939,23 +24964,23 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2493924964
24940 const parent_ptr_ty = try sema.resolveDestType(block, inst_src, extra.parent_ptr_type, .remove_eu, "@fieldParentPtr");24965 const parent_ptr_ty = try sema.resolveDestType(block, inst_src, extra.parent_ptr_type, .remove_eu, "@fieldParentPtr");
24941 try sema.checkPtrType(block, inst_src, parent_ptr_ty, true);24966 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);
24943 if (parent_ptr_info.flags.size != .One) {24968 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)});
24945 }24970 }
24946 const parent_ty = Type.fromInterned(parent_ptr_info.child);24971 const parent_ty = Type.fromInterned(parent_ptr_info.child);
24947 switch (parent_ty.zigTypeTag(mod)) {24972 switch (parent_ty.zigTypeTag(zcu)) {
24948 .Struct, .Union => {},24973 .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)}),
24950 }24975 }
24951 try sema.resolveTypeLayout(parent_ty);24976 try sema.resolveTypeLayout(parent_ty);
2495224977
24953 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{24978 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{
24954 .needed_comptime_reason = "field name must be comptime-known",24979 .needed_comptime_reason = "field name must be comptime-known",
24955 });24980 });
24956 const field_index = switch (parent_ty.zigTypeTag(mod)) {24981 const field_index = switch (parent_ty.zigTypeTag(zcu)) {
24957 .Struct => blk: {24982 .Struct => blk: {
24958 if (parent_ty.isTuple(mod)) {24983 if (parent_ty.isTuple(zcu)) {
24959 if (field_name.eqlSlice("len", ip)) {24984 if (field_name.eqlSlice("len", ip)) {
24960 return sema.fail(block, inst_src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});24985 return sema.fail(block, inst_src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});
24961 }24986 }
...@@ -24967,19 +24992,19 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24967,19 +24992,19 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
24967 .Union => try sema.unionFieldIndex(block, parent_ty, field_name, field_name_src),24992 .Union => try sema.unionFieldIndex(block, parent_ty, field_name, field_name_src),
24968 else => unreachable,24993 else => unreachable,
24969 };24994 };
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)) {
24971 return sema.fail(block, field_name_src, "cannot get @fieldParentPtr of a comptime field", .{});24996 return sema.fail(block, field_name_src, "cannot get @fieldParentPtr of a comptime field", .{});
24972 }24997 }
2497324998
24974 const field_ptr = try sema.resolveInst(extra.field_ptr);24999 const field_ptr = try sema.resolveInst(extra.field_ptr);
24975 const field_ptr_ty = sema.typeOf(field_ptr);25000 const field_ptr_ty = sema.typeOf(field_ptr);
24976 try sema.checkPtrOperand(block, field_ptr_src, field_ptr_ty);25001 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
24979 var actual_parent_ptr_info: InternPool.Key.PtrType = .{25004 var actual_parent_ptr_info: InternPool.Key.PtrType = .{
24980 .child = parent_ty.toIntern(),25005 .child = parent_ty.toIntern(),
24981 .flags = .{25006 .flags = .{
24982 .alignment = try parent_ptr_ty.ptrAlignmentAdvanced(mod, sema),25007 .alignment = try parent_ptr_ty.ptrAlignmentAdvanced(zcu, sema),
24983 .is_const = field_ptr_info.flags.is_const,25008 .is_const = field_ptr_info.flags.is_const,
24984 .is_volatile = field_ptr_info.flags.is_volatile,25009 .is_volatile = field_ptr_info.flags.is_volatile,
24985 .is_allowzero = field_ptr_info.flags.is_allowzero,25010 .is_allowzero = field_ptr_info.flags.is_allowzero,
...@@ -24987,11 +25012,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24987,11 +25012,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
24987 },25012 },
24988 .packed_offset = parent_ptr_info.packed_offset,25013 .packed_offset = parent_ptr_info.packed_offset,
24989 };25014 };
24990 const field_ty = parent_ty.structFieldType(field_index, mod);25015 const field_ty = parent_ty.structFieldType(field_index, zcu);
24991 var actual_field_ptr_info: InternPool.Key.PtrType = .{25016 var actual_field_ptr_info: InternPool.Key.PtrType = .{
24992 .child = field_ty.toIntern(),25017 .child = field_ty.toIntern(),
24993 .flags = .{25018 .flags = .{
24994 .alignment = try field_ptr_ty.ptrAlignmentAdvanced(mod, sema),25019 .alignment = try field_ptr_ty.ptrAlignmentAdvanced(zcu, sema),
24995 .is_const = field_ptr_info.flags.is_const,25020 .is_const = field_ptr_info.flags.is_const,
24996 .is_volatile = field_ptr_info.flags.is_volatile,25021 .is_volatile = field_ptr_info.flags.is_volatile,
24997 .is_allowzero = field_ptr_info.flags.is_allowzero,25022 .is_allowzero = field_ptr_info.flags.is_allowzero,
...@@ -24999,14 +25024,14 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24999,14 +25024,14 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
24999 },25024 },
25000 .packed_offset = field_ptr_info.packed_offset,25025 .packed_offset = field_ptr_info.packed_offset,
25001 };25026 };
25002 switch (parent_ty.containerLayout(mod)) {25027 switch (parent_ty.containerLayout(zcu)) {
25003 .auto => {25028 .auto => {
25004 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(25029 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(
25006 struct_obj.fieldAlign(ip, field_index),25031 struct_obj.fieldAlign(ip, field_index),
25007 field_ty,25032 field_ty,
25008 struct_obj.layout,25033 struct_obj.layout,
25009 ) else if (mod.typeToUnion(parent_ty)) |union_obj|25034 ) else if (zcu.typeToUnion(parent_ty)) |union_obj|
25010 try sema.unionFieldAlignment(union_obj, field_index)25035 try sema.unionFieldAlignment(union_obj, field_index)
25011 else25036 else
25012 actual_field_ptr_info.flags.alignment,25037 actual_field_ptr_info.flags.alignment,
...@@ -25016,7 +25041,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -25016,7 +25041,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
25016 actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };25041 actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
25017 },25042 },
25018 .@"extern" => {25043 .@"extern" => {
25019 const field_offset = parent_ty.structFieldOffset(field_index, mod);25044 const field_offset = parent_ty.structFieldOffset(field_index, zcu);
25020 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (field_offset > 0)25045 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (field_offset > 0)
25021 Alignment.fromLog2Units(@ctz(field_offset))25046 Alignment.fromLog2Units(@ctz(field_offset))
25022 else25047 else
...@@ -25027,7 +25052,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -25027,7 +25052,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
25027 },25052 },
25028 .@"packed" => {25053 .@"packed" => {
25029 const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) +25054 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) -
25031 actual_field_ptr_info.packed_offset.bit_offset), 8) catch25056 actual_field_ptr_info.packed_offset.bit_offset), 8) catch
25032 return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{});25057 return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{});
25033 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (byte_offset > 0)25058 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...@@ -25040,18 +25065,60 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
25040 const actual_field_ptr_ty = try sema.ptrType(actual_field_ptr_info);25065 const actual_field_ptr_ty = try sema.ptrType(actual_field_ptr_info);
25041 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src);25066 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src);
25042 const actual_parent_ptr_ty = try sema.ptrType(actual_parent_ptr_info);25067 const actual_parent_ptr_ty = try sema.ptrType(actual_parent_ptr_info);
25068
25043 const result = if (try sema.resolveDefinedValue(block, field_ptr_src, casted_field_ptr)) |field_ptr_val| result: {25069 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())) {25070 switch (parent_ty.zigTypeTag(zcu)) {
25045 .ptr => |ptr| switch (ptr.addr) {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) {
25046 .field => |field| field,25106 .field => |field| field,
25047 else => null,25107 else => null,
25048 },25108 };
25049 else => null,25109 };
25050 } orelse return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{});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
25052 if (field.index != field_index) {25119 if (field.index != field_index) {
25053 return sema.fail(block, inst_src, "field '{}' has index '{d}' but pointer value is index '{d}' of struct '{}'", .{25120 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),
25055 });25122 });
25056 }25123 }
25057 break :result try sema.coerce(block, actual_parent_ptr_ty, Air.internedToRef(field.base), inst_src);25124 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...@@ -25072,6 +25139,27 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
25072 return sema.ptrCastFull(block, flags, inst_src, result, inst_src, parent_ptr_ty, "@fieldParentPtr");25139 return sema.ptrCastFull(block, flags, inst_src, result, inst_src, parent_ptr_ty, "@fieldParentPtr");
25073}25140}
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
25075fn zirMinMax(25163fn zirMinMax(
25076 sema: *Sema,25164 sema: *Sema,
25077 block: *Block,25165 block: *Block,
...@@ -25424,10 +25512,10 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -25424,10 +25512,10 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
25424 const msg = try sema.errMsg(block, src, "non-matching @memcpy lengths", .{});25512 const msg = try sema.errMsg(block, src, "non-matching @memcpy lengths", .{});
25425 errdefer msg.destroy(sema.gpa);25513 errdefer msg.destroy(sema.gpa);
25426 try sema.errNote(block, dest_src, msg, "length {} here", .{25514 try sema.errNote(block, dest_src, msg, "length {} here", .{
25427 dest_len_val.fmtValue(sema.mod),25515 dest_len_val.fmtValue(sema.mod, sema),
25428 });25516 });
25429 try sema.errNote(block, src_src, msg, "length {} here", .{25517 try sema.errNote(block, src_src, msg, "length {} here", .{
25430 src_len_val.fmtValue(sema.mod),25518 src_len_val.fmtValue(sema.mod, sema),
25431 });25519 });
25432 break :msg msg;25520 break :msg msg;
25433 };25521 };
...@@ -26340,7 +26428,8 @@ fn zirBuiltinExtern(...@@ -26340,7 +26428,8 @@ fn zirBuiltinExtern(
26340 .opt_type => |child_type| child_type,26428 .opt_type => |child_type| child_type,
26341 else => unreachable,26429 else => unreachable,
26342 },26430 },
26343 .addr = .{ .decl = new_decl_index },26431 .base_addr = .{ .decl = new_decl_index },
26432 .byte_offset = 0,
26344 } }))), ty)).toIntern());26433 } }))), ty)).toIntern());
26345}26434}
2634626435
...@@ -26745,8 +26834,8 @@ fn explainWhyTypeIsNotExtern(...@@ -26745,8 +26834,8 @@ fn explainWhyTypeIsNotExtern(
26745/// Returns true if `ty` is allowed in packed types.26834/// Returns true if `ty` is allowed in packed types.
26746/// Does not require `ty` to be resolved in any way, but may resolve whether it is comptime-only.26835/// Does not require `ty` to be resolved in any way, but may resolve whether it is comptime-only.
26747fn validatePackedType(sema: *Sema, ty: Type) !bool {26836fn validatePackedType(sema: *Sema, ty: Type) !bool {
26748 const mod = sema.mod;26837 const zcu = sema.mod;
26749 switch (ty.zigTypeTag(mod)) {26838 return switch (ty.zigTypeTag(zcu)) {
26750 .Type,26839 .Type,
26751 .ComptimeFloat,26840 .ComptimeFloat,
26752 .ComptimeInt,26841 .ComptimeInt,
...@@ -26761,18 +26850,21 @@ fn validatePackedType(sema: *Sema, ty: Type) !bool {...@@ -26761,18 +26850,21 @@ fn validatePackedType(sema: *Sema, ty: Type) !bool {
26761 .AnyFrame,26850 .AnyFrame,
26762 .Fn,26851 .Fn,
26763 .Array,26852 .Array,
26764 => return false,26853 => false,
26765 .Optional => return ty.isPtrLikeOptional(mod),26854 .Optional => return ty.isPtrLikeOptional(zcu),
26766 .Void,26855 .Void,
26767 .Bool,26856 .Bool,
26768 .Float,26857 .Float,
26769 .Int,26858 .Int,
26770 .Vector,26859 .Vector,
26771 .Enum,26860 => true,
26772 => return true,26861 .Enum => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).tag_mode) {
26773 .Pointer => return !ty.isSlice(mod) and !try sema.typeRequiresComptime(ty),26862 .auto => false,
26774 .Struct, .Union => return ty.containerLayout(mod) == .@"packed",26863 .explicit, .nonexhaustive => true,
26775 }26864 },
26865 .Pointer => !ty.isSlice(zcu) and !try sema.typeRequiresComptime(ty),
26866 .Struct, .Union => ty.containerLayout(zcu) == .@"packed",
26867 };
26776}26868}
2677726869
26778fn explainWhyTypeIsNotPacked(26870fn explainWhyTypeIsNotPacked(
...@@ -27443,13 +27535,7 @@ fn fieldPtr(...@@ -27443,13 +27535,7 @@ fn fieldPtr(
27443 });27535 });
2744427536
27445 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {27537 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
27446 return Air.internedToRef((try mod.intern(.{ .ptr = .{27538 return Air.internedToRef((try val.ptrField(Value.slice_ptr_index, sema)).toIntern());
27447 .ty = result_ty.toIntern(),
27448 .addr = .{ .field = .{
27449 .base = val.toIntern(),
27450 .index = Value.slice_ptr_index,
27451 } },
27452 } })));
27453 }27539 }
27454 try sema.requireRuntimeBlock(block, src, null);27540 try sema.requireRuntimeBlock(block, src, null);
2745527541
...@@ -27467,13 +27553,7 @@ fn fieldPtr(...@@ -27467,13 +27553,7 @@ fn fieldPtr(
27467 });27553 });
2746827554
27469 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {27555 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
27470 return Air.internedToRef((try mod.intern(.{ .ptr = .{27556 return Air.internedToRef((try val.ptrField(Value.slice_len_index, sema)).toIntern());
27471 .ty = result_ty.toIntern(),
27472 .addr = .{ .field = .{
27473 .base = val.toIntern(),
27474 .index = Value.slice_len_index,
27475 } },
27476 } })));
27477 }27557 }
27478 try sema.requireRuntimeBlock(block, src, null);27558 try sema.requireRuntimeBlock(block, src, null);
2747927559
...@@ -27785,13 +27865,8 @@ fn finishFieldCallBind(...@@ -27785,13 +27865,8 @@ fn finishFieldCallBind(
27785 }27865 }
2778627866
27787 if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {27867 if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {
27788 const pointer = Air.internedToRef((try mod.intern(.{ .ptr = .{27868 const ptr_val = try struct_ptr_val.ptrField(field_index, sema);
27789 .ty = ptr_field_ty.toIntern(),27869 const pointer = Air.internedToRef(ptr_val.toIntern());
27790 .addr = .{ .field = .{
27791 .base = struct_ptr_val.toIntern(),
27792 .index = field_index,
27793 } },
27794 } })));
27795 return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) };27870 return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) };
27796 }27871 }
2779727872
...@@ -27903,6 +27978,11 @@ fn structFieldPtrByIndex(...@@ -27903,6 +27978,11 @@ fn structFieldPtrByIndex(
27903 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);27978 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);
27904 }27979 }
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
27906 const struct_type = mod.typeToStruct(struct_ty).?;27986 const struct_type = mod.typeToStruct(struct_ty).?;
27907 const field_ty = struct_type.field_types.get(ip)[field_index];27987 const field_ty = struct_type.field_types.get(ip)[field_index];
27908 const struct_ptr_ty = sema.typeOf(struct_ptr);27988 const struct_ptr_ty = sema.typeOf(struct_ptr);
...@@ -27917,57 +27997,20 @@ fn structFieldPtrByIndex(...@@ -27917,57 +27997,20 @@ fn structFieldPtrByIndex(
27917 },27997 },
27918 };27998 };
2791927999
27920 const target = mod.getTarget();
27921
27922 const parent_align = if (struct_ptr_ty_info.flags.alignment != .none)28000 const parent_align = if (struct_ptr_ty_info.flags.alignment != .none)
27923 struct_ptr_ty_info.flags.alignment28001 struct_ptr_ty_info.flags.alignment
27924 else28002 else
27925 try sema.typeAbiAlignment(Type.fromInterned(struct_ptr_ty_info.child));28003 try sema.typeAbiAlignment(Type.fromInterned(struct_ptr_ty_info.child));
2792628004
27927 if (struct_type.layout == .@"packed") {28005 if (struct_type.layout == .@"packed") {
27928 comptime assert(Type.packed_struct_layout_version == 2);28006 switch (struct_ty.packedStructFieldPtrInfo(struct_ptr_ty, field_index, mod)) {
2792928007 .bit_ptr => |packed_offset| {
27930 var running_bits: u16 = 0;28008 ptr_ty_data.flags.alignment = parent_align;
27931 for (0..struct_type.field_types.len) |i| {28009 ptr_ty_data.packed_offset = packed_offset;
27932 const f_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);28010 },
27933 if (!(try sema.typeHasRuntimeBits(f_ty))) continue;28011 .byte_ptr => |ptr_info| {
2793428012 ptr_ty_data.flags.alignment = ptr_info.alignment;
27935 if (i == field_index) {28013 },
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 }
27971 }28014 }
27972 } else if (struct_type.layout == .@"extern") {28015 } else if (struct_type.layout == .@"extern") {
27973 // For extern structs, field alignment might be bigger than type's28016 // For extern structs, field alignment might be bigger than type's
...@@ -27997,18 +28040,8 @@ fn structFieldPtrByIndex(...@@ -27997,18 +28040,8 @@ fn structFieldPtrByIndex(
27997 try sema.resolveStructFieldInits(struct_ty);28040 try sema.resolveStructFieldInits(struct_ty);
27998 const val = try mod.intern(.{ .ptr = .{28041 const val = try mod.intern(.{ .ptr = .{
27999 .ty = ptr_field_ty.toIntern(),28042 .ty = ptr_field_ty.toIntern(),
28000 .addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },28043 .base_addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },
28001 } });28044 .byte_offset = 0,
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 } },
28012 } });28045 } });
28013 return Air.internedToRef(val);28046 return Air.internedToRef(val);
28014 }28047 }
...@@ -28206,7 +28239,13 @@ fn unionFieldPtr(...@@ -28206,7 +28239,13 @@ fn unionFieldPtr(
2820628239
28207 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {28240 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
28208 switch (union_obj.getLayout(ip)) {28241 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 {
28210 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse28249 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse
28211 break :ct;28250 break :ct;
28212 if (union_val.isUndef(mod)) {28251 if (union_val.isUndef(mod)) {
...@@ -28232,13 +28271,8 @@ fn unionFieldPtr(...@@ -28232,13 +28271,8 @@ fn unionFieldPtr(
28232 },28271 },
28233 .@"packed", .@"extern" => {},28272 .@"packed", .@"extern" => {},
28234 }28273 }
28235 return Air.internedToRef((try mod.intern(.{ .ptr = .{28274 const field_ptr_val = try union_ptr_val.ptrField(field_index, sema);
28236 .ty = ptr_field_ty.toIntern(),28275 return Air.internedToRef(field_ptr_val.toIntern());
28237 .addr = .{ .field = .{
28238 .base = union_ptr_val.toIntern(),
28239 .index = field_index,
28240 } },
28241 } })));
28242 }28276 }
2824328277
28244 try sema.requireRuntimeBlock(block, src, null);28278 try sema.requireRuntimeBlock(block, src, null);
...@@ -28268,21 +28302,21 @@ fn unionFieldVal(...@@ -28268,21 +28302,21 @@ fn unionFieldVal(
28268 field_name_src: LazySrcLoc,28302 field_name_src: LazySrcLoc,
28269 union_ty: Type,28303 union_ty: Type,
28270) CompileError!Air.Inst.Ref {28304) CompileError!Air.Inst.Ref {
28271 const mod = sema.mod;28305 const zcu = sema.mod;
28272 const ip = &mod.intern_pool;28306 const ip = &zcu.intern_pool;
28273 assert(union_ty.zigTypeTag(mod) == .Union);28307 assert(union_ty.zigTypeTag(zcu) == .Union);
2827428308
28275 try sema.resolveTypeFields(union_ty);28309 try sema.resolveTypeFields(union_ty);
28276 const union_obj = mod.typeToUnion(union_ty).?;28310 const union_obj = zcu.typeToUnion(union_ty).?;
28277 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);28311 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
28278 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);28312 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
28281 if (try sema.resolveValue(union_byval)) |union_val| {28315 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
28284 const un = ip.indexToKey(union_val.toIntern()).un;28318 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);
28286 const tag_matches = un.tag == field_tag.toIntern();28320 const tag_matches = un.tag == field_tag.toIntern();
28287 switch (union_obj.getLayout(ip)) {28321 switch (union_obj.getLayout(ip)) {
28288 .auto => {28322 .auto => {
...@@ -28290,8 +28324,8 @@ fn unionFieldVal(...@@ -28290,8 +28324,8 @@ fn unionFieldVal(
28290 return Air.internedToRef(un.val);28324 return Air.internedToRef(un.val);
28291 } else {28325 } else {
28292 const msg = msg: {28326 const msg = msg: {
28293 const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), mod).?;28327 const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
28294 const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, mod);28328 const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu);
28295 const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{28329 const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{
28296 field_name.fmt(ip), active_field_name.fmt(ip),28330 field_name.fmt(ip), active_field_name.fmt(ip),
28297 });28331 });
...@@ -28302,33 +28336,31 @@ fn unionFieldVal(...@@ -28302,33 +28336,31 @@ fn unionFieldVal(
28302 return sema.failWithOwnedErrorMsg(block, msg);28336 return sema.failWithOwnedErrorMsg(block, msg);
28303 }28337 }
28304 },28338 },
28305 .@"packed", .@"extern" => |layout| {28339 .@"extern" => if (tag_matches) {
28306 if (tag_matches) {28340 // Fast path - no need to use bitcast logic.
28307 return Air.internedToRef(un.val);28341 return Air.internedToRef(un.val);
28308 } else {28342 } else if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| {
28309 const old_ty = if (un.tag == .none)28343 return Air.internedToRef(field_val.toIntern());
28310 Type.fromInterned(ip.typeOf(un.val))28344 },
28311 else28345 .@"packed" => if (tag_matches) {
28312 union_ty.unionFieldType(Value.fromInterned(un.tag), mod).?;28346 // Fast path - no need to use bitcast logic.
2831328347 return Air.internedToRef(un.val);
28314 if (try sema.bitCastUnionFieldVal(block, src, Value.fromInterned(un.val), old_ty, field_ty, layout)) |new_val| {28348 } else if (try sema.bitCastVal(union_val, field_ty, 0, try union_ty.bitSizeAdvanced(zcu, sema), 0)) |field_val| {
28315 return Air.internedToRef(new_val.toIntern());28349 return Air.internedToRef(field_val.toIntern());
28316 }
28317 }
28318 },28350 },
28319 }28351 }
28320 }28352 }
2832128353
28322 try sema.requireRuntimeBlock(block, src, null);28354 try sema.requireRuntimeBlock(block, src, null);
28323 if (union_obj.getLayout(ip) == .auto and block.wantSafety() and28355 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)
28325 {28357 {
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);
28327 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());28359 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
28328 const active_tag = try block.addTyOp(.get_union_tag, Type.fromInterned(union_obj.enum_tag_ty), union_byval);28360 const active_tag = try block.addTyOp(.get_union_tag, Type.fromInterned(union_obj.enum_tag_ty), union_byval);
28329 try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag);28361 try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag);
28330 }28362 }
28331 if (field_ty.zigTypeTag(mod) == .NoReturn) {28363 if (field_ty.zigTypeTag(zcu) == .NoReturn) {
28332 _ = try block.addNoOp(.unreach);28364 _ = try block.addNoOp(.unreach);
28333 return .unreachable_value;28365 return .unreachable_value;
28334 }28366 }
...@@ -28402,8 +28434,7 @@ fn elemPtrOneLayerOnly(...@@ -28402,8 +28434,7 @@ fn elemPtrOneLayerOnly(
28402 const ptr_val = maybe_ptr_val orelse break :rs indexable_src;28434 const ptr_val = maybe_ptr_val orelse break :rs indexable_src;
28403 const index_val = maybe_index_val orelse break :rs elem_index_src;28435 const index_val = maybe_index_val orelse break :rs elem_index_src;
28404 const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));28436 const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
28405 const result_ty = try sema.elemPtrType(indexable_ty, index);28437 const elem_ptr = try ptr_val.ptrElem(index, sema);
28406 const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod);
28407 return Air.internedToRef(elem_ptr.toIntern());28438 return Air.internedToRef(elem_ptr.toIntern());
28408 };28439 };
28409 const result_ty = try sema.elemPtrType(indexable_ty, null);28440 const result_ty = try sema.elemPtrType(indexable_ty, null);
...@@ -28465,7 +28496,7 @@ fn elemVal(...@@ -28465,7 +28496,7 @@ fn elemVal(
28465 const many_ptr_ty = try mod.manyConstPtrType(elem_ty);28496 const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
28466 const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty);28497 const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty);
28467 const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);28498 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);
28469 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {28500 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
28470 return Air.internedToRef((try mod.getCoerced(elem_val, elem_ty)).toIntern());28501 return Air.internedToRef((try mod.getCoerced(elem_val, elem_ty)).toIntern());
28471 }28502 }
...@@ -28571,21 +28602,18 @@ fn tupleFieldPtr(...@@ -28571,21 +28602,18 @@ fn tupleFieldPtr(
2857128602
28572 if (tuple_ty.structFieldIsComptime(field_index, mod))28603 if (tuple_ty.structFieldIsComptime(field_index, mod))
28573 try sema.resolveStructFieldInits(tuple_ty);28604 try sema.resolveStructFieldInits(tuple_ty);
28605
28574 if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| {28606 if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| {
28575 return Air.internedToRef((try mod.intern(.{ .ptr = .{28607 return Air.internedToRef((try mod.intern(.{ .ptr = .{
28576 .ty = ptr_field_ty.toIntern(),28608 .ty = ptr_field_ty.toIntern(),
28577 .addr = .{ .comptime_field = default_val.toIntern() },28609 .base_addr = .{ .comptime_field = default_val.toIntern() },
28610 .byte_offset = 0,
28578 } })));28611 } })));
28579 }28612 }
2858028613
28581 if (try sema.resolveValue(tuple_ptr)) |tuple_ptr_val| {28614 if (try sema.resolveValue(tuple_ptr)) |tuple_ptr_val| {
28582 return Air.internedToRef((try mod.intern(.{ .ptr = .{28615 const field_ptr_val = try tuple_ptr_val.ptrField(field_index, sema);
28583 .ty = ptr_field_ty.toIntern(),28616 return Air.internedToRef(field_ptr_val.toIntern());
28584 .addr = .{ .field = .{
28585 .base = tuple_ptr_val.toIntern(),
28586 .index = field_index,
28587 } },
28588 } })));
28589 }28617 }
2859028618
28591 if (!init) {28619 if (!init) {
...@@ -28747,7 +28775,7 @@ fn elemPtrArray(...@@ -28747,7 +28775,7 @@ fn elemPtrArray(
28747 return mod.undefRef(elem_ptr_ty);28775 return mod.undefRef(elem_ptr_ty);
28748 }28776 }
28749 if (offset) |index| {28777 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);
28751 return Air.internedToRef(elem_ptr.toIntern());28779 return Air.internedToRef(elem_ptr.toIntern());
28752 }28780 }
28753 }28781 }
...@@ -28804,7 +28832,7 @@ fn elemValSlice(...@@ -28804,7 +28832,7 @@ fn elemValSlice(
28804 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });28832 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
28805 }28833 }
28806 const elem_ptr_ty = try sema.elemPtrType(slice_ty, index);28834 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);
28808 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {28836 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
28809 return Air.internedToRef(elem_val.toIntern());28837 return Air.internedToRef(elem_val.toIntern());
28810 }28838 }
...@@ -28864,7 +28892,7 @@ fn elemPtrSlice(...@@ -28864,7 +28892,7 @@ fn elemPtrSlice(
28864 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";28892 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
28865 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });28893 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
28866 }28894 }
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);
28868 return Air.internedToRef(elem_ptr_val.toIntern());28896 return Air.internedToRef(elem_ptr_val.toIntern());
28869 }28897 }
28870 }28898 }
...@@ -28943,14 +28971,14 @@ fn coerceExtra(...@@ -28943,14 +28971,14 @@ fn coerceExtra(
28943 opts: CoerceOpts,28971 opts: CoerceOpts,
28944) CoersionError!Air.Inst.Ref {28972) CoersionError!Air.Inst.Ref {
28945 if (dest_ty.isGenericPoison()) return inst;28973 if (dest_ty.isGenericPoison()) return inst;
28946 const mod = sema.mod;28974 const zcu = sema.mod;
28947 const dest_ty_src = inst_src; // TODO better source location28975 const dest_ty_src = inst_src; // TODO better source location
28948 try sema.resolveTypeFields(dest_ty);28976 try sema.resolveTypeFields(dest_ty);
28949 const inst_ty = sema.typeOf(inst);28977 const inst_ty = sema.typeOf(inst);
28950 try sema.resolveTypeFields(inst_ty);28978 try sema.resolveTypeFields(inst_ty);
28951 const target = mod.getTarget();28979 const target = zcu.getTarget();
28952 // If the types are the same, we can return the operand.28980 // 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))
28954 return inst;28982 return inst;
2895528983
28956 const maybe_inst_val = try sema.resolveValue(inst);28984 const maybe_inst_val = try sema.resolveValue(inst);
...@@ -28967,17 +28995,17 @@ fn coerceExtra(...@@ -28967,17 +28995,17 @@ fn coerceExtra(
28967 return new_val;28995 return new_val;
28968 }28996 }
2896928997
28970 switch (dest_ty.zigTypeTag(mod)) {28998 switch (dest_ty.zigTypeTag(zcu)) {
28971 .Optional => optional: {28999 .Optional => optional: {
28972 if (maybe_inst_val) |val| {29000 if (maybe_inst_val) |val| {
28973 // undefined sets the optional bit also to undefined.29001 // undefined sets the optional bit also to undefined.
28974 if (val.toIntern() == .undef) {29002 if (val.toIntern() == .undef) {
28975 return mod.undefRef(dest_ty);29003 return zcu.undefRef(dest_ty);
28976 }29004 }
2897729005
28978 // null to ?T29006 // null to ?T
28979 if (val.toIntern() == .null_value) {29007 if (val.toIntern() == .null_value) {
28980 return Air.internedToRef((try mod.intern(.{ .opt = .{29008 return Air.internedToRef((try zcu.intern(.{ .opt = .{
28981 .ty = dest_ty.toIntern(),29009 .ty = dest_ty.toIntern(),
28982 .val = .none,29010 .val = .none,
28983 } })));29011 } })));
...@@ -28986,13 +29014,13 @@ fn coerceExtra(...@@ -28986,13 +29014,13 @@ fn coerceExtra(
2898629014
28987 // cast from ?*T and ?[*]T to ?*anyopaque29015 // cast from ?*T and ?[*]T to ?*anyopaque
28988 // but don't do it if the source type is a double pointer29016 // but don't do it if the source type is a double pointer
28989 if (dest_ty.isPtrLikeOptional(mod) and29017 if (dest_ty.isPtrLikeOptional(zcu) and
28990 dest_ty.elemType2(mod).toIntern() == .anyopaque_type and29018 dest_ty.elemType2(zcu).toIntern() == .anyopaque_type and
28991 inst_ty.isPtrAtRuntime(mod))29019 inst_ty.isPtrAtRuntime(zcu))
28992 anyopaque_check: {29020 anyopaque_check: {
28993 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;29021 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;
28994 const elem_ty = inst_ty.elemType2(mod);29022 const elem_ty = inst_ty.elemType2(zcu);
28995 if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) {29023 if (elem_ty.zigTypeTag(zcu) == .Pointer or elem_ty.isPtrLikeOptional(zcu)) {
28996 in_memory_result = .{ .double_ptr_to_anyopaque = .{29024 in_memory_result = .{ .double_ptr_to_anyopaque = .{
28997 .actual = inst_ty,29025 .actual = inst_ty,
28998 .wanted = dest_ty,29026 .wanted = dest_ty,
...@@ -29001,12 +29029,12 @@ fn coerceExtra(...@@ -29001,12 +29029,12 @@ fn coerceExtra(
29001 }29029 }
29002 // Let the logic below handle wrapping the optional now that29030 // Let the logic below handle wrapping the optional now that
29003 // it has been checked to correctly coerce.29031 // 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;
29005 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);29033 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
29006 }29034 }
2900729035
29008 // T to ?T29036 // T to ?T
29009 const child_type = dest_ty.optionalChild(mod);29037 const child_type = dest_ty.optionalChild(zcu);
29010 const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {29038 const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
29011 error.NotCoercible => {29039 error.NotCoercible => {
29012 if (in_memory_result == .no_match) {29040 if (in_memory_result == .no_match) {
...@@ -29020,12 +29048,12 @@ fn coerceExtra(...@@ -29020,12 +29048,12 @@ fn coerceExtra(
29020 return try sema.wrapOptional(block, dest_ty, intermediate, inst_src);29048 return try sema.wrapOptional(block, dest_ty, intermediate, inst_src);
29021 },29049 },
29022 .Pointer => pointer: {29050 .Pointer => pointer: {
29023 const dest_info = dest_ty.ptrInfo(mod);29051 const dest_info = dest_ty.ptrInfo(zcu);
2902429052
29025 // Function body to function pointer.29053 // Function body to function pointer.
29026 if (inst_ty.zigTypeTag(mod) == .Fn) {29054 if (inst_ty.zigTypeTag(zcu) == .Fn) {
29027 const fn_val = try sema.resolveConstDefinedValue(block, .unneeded, inst, undefined);29055 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).?;
29029 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);29057 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);
29030 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);29058 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
29031 }29059 }
...@@ -29033,13 +29061,13 @@ fn coerceExtra(...@@ -29033,13 +29061,13 @@ fn coerceExtra(
29033 // *T to *[1]T29061 // *T to *[1]T
29034 single_item: {29062 single_item: {
29035 if (dest_info.flags.size != .One) break :single_item;29063 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;
29037 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;29065 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);
29039 const array_ty = Type.fromInterned(dest_info.child);29067 const array_ty = Type.fromInterned(dest_info.child);
29040 if (array_ty.zigTypeTag(mod) != .Array) break :single_item;29068 if (array_ty.zigTypeTag(zcu) != .Array) break :single_item;
29041 const array_elem_ty = array_ty.childType(mod);29069 const array_elem_ty = array_ty.childType(zcu);
29042 if (array_ty.arrayLen(mod) != 1) break :single_item;29070 if (array_ty.arrayLen(zcu) != 1) break :single_item;
29043 const dest_is_mut = !dest_info.flags.is_const;29071 const dest_is_mut = !dest_info.flags.is_const;
29044 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {29072 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
29045 .ok => {},29073 .ok => {},
...@@ -29050,11 +29078,11 @@ fn coerceExtra(...@@ -29050,11 +29078,11 @@ fn coerceExtra(
2905029078
29051 // Coercions where the source is a single pointer to an array.29079 // Coercions where the source is a single pointer to an array.
29052 src_array_ptr: {29080 src_array_ptr: {
29053 if (!inst_ty.isSinglePointer(mod)) break :src_array_ptr;29081 if (!inst_ty.isSinglePointer(zcu)) break :src_array_ptr;
29054 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;29082 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
29055 const array_ty = inst_ty.childType(mod);29083 const array_ty = inst_ty.childType(zcu);
29056 if (array_ty.zigTypeTag(mod) != .Array) break :src_array_ptr;29084 if (array_ty.zigTypeTag(zcu) != .Array) break :src_array_ptr;
29057 const array_elem_type = array_ty.childType(mod);29085 const array_elem_type = array_ty.childType(zcu);
29058 const dest_is_mut = !dest_info.flags.is_const;29086 const dest_is_mut = !dest_info.flags.is_const;
2905929087
29060 const dst_elem_type = Type.fromInterned(dest_info.child);29088 const dst_elem_type = Type.fromInterned(dest_info.child);
...@@ -29072,7 +29100,7 @@ fn coerceExtra(...@@ -29072,7 +29100,7 @@ fn coerceExtra(
29072 }29100 }
2907329101
29074 if (dest_info.sentinel != .none) {29102 if (dest_info.sentinel != .none) {
29075 if (array_ty.sentinel(mod)) |inst_sent| {29103 if (array_ty.sentinel(zcu)) |inst_sent| {
29076 if (Air.internedToRef(dest_info.sentinel) !=29104 if (Air.internedToRef(dest_info.sentinel) !=
29077 try sema.coerceInMemory(inst_sent, dst_elem_type))29105 try sema.coerceInMemory(inst_sent, dst_elem_type))
29078 {29106 {
...@@ -29111,12 +29139,12 @@ fn coerceExtra(...@@ -29111,12 +29139,12 @@ fn coerceExtra(
29111 }29139 }
2911229140
29113 // coercion from C pointer29141 // coercion from C pointer
29114 if (inst_ty.isCPtr(mod)) src_c_ptr: {29142 if (inst_ty.isCPtr(zcu)) src_c_ptr: {
29115 if (dest_info.flags.size == .Slice) break :src_c_ptr;29143 if (dest_info.flags.size == .Slice) break :src_c_ptr;
29116 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr;29144 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr;
29117 // In this case we must add a safety check because the C pointer29145 // In this case we must add a safety check because the C pointer
29118 // could be null.29146 // could be null.
29119 const src_elem_ty = inst_ty.childType(mod);29147 const src_elem_ty = inst_ty.childType(zcu);
29120 const dest_is_mut = !dest_info.flags.is_const;29148 const dest_is_mut = !dest_info.flags.is_const;
29121 const dst_elem_type = Type.fromInterned(dest_info.child);29149 const dst_elem_type = Type.fromInterned(dest_info.child);
29122 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {29150 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(...@@ -29128,18 +29156,18 @@ fn coerceExtra(
2912829156
29129 // cast from *T and [*]T to *anyopaque29157 // cast from *T and [*]T to *anyopaque
29130 // but don't do it if the source type is a double pointer29158 // 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: {
29132 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;29160 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
29133 const elem_ty = inst_ty.elemType2(mod);29161 const elem_ty = inst_ty.elemType2(zcu);
29134 if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) {29162 if (elem_ty.zigTypeTag(zcu) == .Pointer or elem_ty.isPtrLikeOptional(zcu)) {
29135 in_memory_result = .{ .double_ptr_to_anyopaque = .{29163 in_memory_result = .{ .double_ptr_to_anyopaque = .{
29136 .actual = inst_ty,29164 .actual = inst_ty,
29137 .wanted = dest_ty,29165 .wanted = dest_ty,
29138 } };29166 } };
29139 break :pointer;29167 break :pointer;
29140 }29168 }
29141 if (dest_ty.isSlice(mod)) break :to_anyopaque;29169 if (dest_ty.isSlice(zcu)) break :to_anyopaque;
29142 if (inst_ty.isSlice(mod)) {29170 if (inst_ty.isSlice(zcu)) {
29143 in_memory_result = .{ .slice_to_anyopaque = .{29171 in_memory_result = .{ .slice_to_anyopaque = .{
29144 .actual = inst_ty,29172 .actual = inst_ty,
29145 .wanted = dest_ty,29173 .wanted = dest_ty,
...@@ -29151,10 +29179,11 @@ fn coerceExtra(...@@ -29151,10 +29179,11 @@ fn coerceExtra(
2915129179
29152 switch (dest_info.flags.size) {29180 switch (dest_info.flags.size) {
29153 // coercion to C pointer29181 // coercion to C pointer
29154 .C => switch (inst_ty.zigTypeTag(mod)) {29182 .C => switch (inst_ty.zigTypeTag(zcu)) {
29155 .Null => return Air.internedToRef(try mod.intern(.{ .ptr = .{29183 .Null => return Air.internedToRef(try zcu.intern(.{ .ptr = .{
29156 .ty = dest_ty.toIntern(),29184 .ty = dest_ty.toIntern(),
29157 .addr = .{ .int = .zero_usize },29185 .base_addr = .int,
29186 .byte_offset = 0,
29158 } })),29187 } })),
29159 .ComptimeInt => {29188 .ComptimeInt => {
29160 const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {29189 const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
...@@ -29164,7 +29193,7 @@ fn coerceExtra(...@@ -29164,7 +29193,7 @@ fn coerceExtra(
29164 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);29193 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
29165 },29194 },
29166 .Int => {29195 .Int => {
29167 const ptr_size_ty = switch (inst_ty.intInfo(mod).signedness) {29196 const ptr_size_ty = switch (inst_ty.intInfo(zcu).signedness) {
29168 .signed => Type.isize,29197 .signed => Type.isize,
29169 .unsigned => Type.usize,29198 .unsigned => Type.usize,
29170 };29199 };
...@@ -29180,7 +29209,7 @@ fn coerceExtra(...@@ -29180,7 +29209,7 @@ fn coerceExtra(
29180 },29209 },
29181 .Pointer => p: {29210 .Pointer => p: {
29182 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;29211 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);
29184 switch (try sema.coerceInMemoryAllowed(29213 switch (try sema.coerceInMemoryAllowed(
29185 block,29214 block,
29186 Type.fromInterned(dest_info.child),29215 Type.fromInterned(dest_info.child),
...@@ -29196,7 +29225,7 @@ fn coerceExtra(...@@ -29196,7 +29225,7 @@ fn coerceExtra(
29196 if (inst_info.flags.size == .Slice) {29225 if (inst_info.flags.size == .Slice) {
29197 assert(dest_info.sentinel == .none);29226 assert(dest_info.sentinel == .none);
29198 if (inst_info.sentinel == .none or29227 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())
29200 break :p;29229 break :p;
2920129230
29202 const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);29231 const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
...@@ -29206,11 +29235,11 @@ fn coerceExtra(...@@ -29206,11 +29235,11 @@ fn coerceExtra(
29206 },29235 },
29207 else => {},29236 else => {},
29208 },29237 },
29209 .One => switch (Type.fromInterned(dest_info.child).zigTypeTag(mod)) {29238 .One => switch (Type.fromInterned(dest_info.child).zigTypeTag(zcu)) {
29210 .Union => {29239 .Union => {
29211 // pointer to anonymous struct to pointer to union29240 // pointer to anonymous struct to pointer to union
29212 if (inst_ty.isSinglePointer(mod) and29241 if (inst_ty.isSinglePointer(zcu) and
29213 inst_ty.childType(mod).isAnonStruct(mod) and29242 inst_ty.childType(zcu).isAnonStruct(zcu) and
29214 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))29243 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
29215 {29244 {
29216 return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);29245 return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
...@@ -29218,8 +29247,8 @@ fn coerceExtra(...@@ -29218,8 +29247,8 @@ fn coerceExtra(
29218 },29247 },
29219 .Struct => {29248 .Struct => {
29220 // pointer to anonymous struct to pointer to struct29249 // pointer to anonymous struct to pointer to struct
29221 if (inst_ty.isSinglePointer(mod) and29250 if (inst_ty.isSinglePointer(zcu) and
29222 inst_ty.childType(mod).isAnonStruct(mod) and29251 inst_ty.childType(zcu).isAnonStruct(zcu) and
29223 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))29252 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
29224 {29253 {
29225 return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) {29254 return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) {
...@@ -29230,8 +29259,8 @@ fn coerceExtra(...@@ -29230,8 +29259,8 @@ fn coerceExtra(
29230 },29259 },
29231 .Array => {29260 .Array => {
29232 // pointer to tuple to pointer to array29261 // pointer to tuple to pointer to array
29233 if (inst_ty.isSinglePointer(mod) and29262 if (inst_ty.isSinglePointer(zcu) and
29234 inst_ty.childType(mod).isTuple(mod) and29263 inst_ty.childType(zcu).isTuple(zcu) and
29235 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))29264 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
29236 {29265 {
29237 return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src);29266 return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
...@@ -29240,50 +29269,38 @@ fn coerceExtra(...@@ -29240,50 +29269,38 @@ fn coerceExtra(
29240 else => {},29269 else => {},
29241 },29270 },
29242 .Slice => to_slice: {29271 .Slice => to_slice: {
29243 if (inst_ty.zigTypeTag(mod) == .Array) {29272 if (inst_ty.zigTypeTag(zcu) == .Array) {
29244 return sema.fail(29273 return sema.fail(
29245 block,29274 block,
29246 inst_src,29275 inst_src,
29247 "array literal requires address-of operator (&) to coerce to slice type '{}'",29276 "array literal requires address-of operator (&) to coerce to slice type '{}'",
29248 .{dest_ty.fmt(mod)},29277 .{dest_ty.fmt(zcu)},
29249 );29278 );
29250 }29279 }
2925129280
29252 if (!inst_ty.isSinglePointer(mod)) break :to_slice;29281 if (!inst_ty.isSinglePointer(zcu)) break :to_slice;
29253 const inst_child_ty = inst_ty.childType(mod);29282 const inst_child_ty = inst_ty.childType(zcu);
29254 if (!inst_child_ty.isTuple(mod)) break :to_slice;29283 if (!inst_child_ty.isTuple(zcu)) break :to_slice;
2925529284
29256 // empty tuple to zero-length slice29285 // empty tuple to zero-length slice
29257 // note that this allows coercing to a mutable slice.29286 // note that this allows coercing to a mutable slice.
29258 if (inst_child_ty.structFieldCount(mod) == 0) {29287 if (inst_child_ty.structFieldCount(zcu) == 0) {
29259 // Optional slice is represented with a null pointer so29288 const align_val = try dest_ty.ptrAlignmentAdvanced(zcu, sema);
29260 // we use a dummy pointer value with the required alignment.29289 return Air.internedToRef(try zcu.intern(.{ .slice = .{
29261 return Air.internedToRef((try mod.intern(.{ .slice = .{
29262 .ty = dest_ty.toIntern(),29290 .ty = dest_ty.toIntern(),
29263 .ptr = try mod.intern(.{ .ptr = .{29291 .ptr = try zcu.intern(.{ .ptr = .{
29264 .ty = dest_ty.slicePtrFieldType(mod).toIntern(),29292 .ty = dest_ty.slicePtrFieldType(zcu).toIntern(),
29265 .addr = .{ .int = if (dest_info.flags.alignment != .none)29293 .base_addr = .int,
29266 (try mod.intValue(29294 .byte_offset = align_val.toByteUnits().?,
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 ) },
29278 } }),29295 } }),
29279 .len = (try mod.intValue(Type.usize, 0)).toIntern(),29296 .len = .zero_usize,
29280 } })));29297 } }));
29281 }29298 }
2928229299
29283 // pointer to tuple to slice29300 // pointer to tuple to slice
29284 if (!dest_info.flags.is_const) {29301 if (!dest_info.flags.is_const) {
29285 const err_msg = err_msg: {29302 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)});
29287 errdefer err_msg.destroy(sema.gpa);29304 errdefer err_msg.destroy(sema.gpa);
29288 try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{});29305 try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{});
29289 break :err_msg err_msg;29306 break :err_msg err_msg;
...@@ -29293,9 +29310,9 @@ fn coerceExtra(...@@ -29293,9 +29310,9 @@ fn coerceExtra(
29293 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);29310 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
29294 },29311 },
29295 .Many => p: {29312 .Many => p: {
29296 if (!inst_ty.isSlice(mod)) break :p;29313 if (!inst_ty.isSlice(zcu)) break :p;
29297 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;29314 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
29300 switch (try sema.coerceInMemoryAllowed(29317 switch (try sema.coerceInMemoryAllowed(
29301 block,29318 block,
...@@ -29320,10 +29337,10 @@ fn coerceExtra(...@@ -29320,10 +29337,10 @@ fn coerceExtra(
29320 },29337 },
29321 }29338 }
29322 },29339 },
29323 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) {29340 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(zcu)) {
29324 .Float, .ComptimeFloat => float: {29341 .Float, .ComptimeFloat => float: {
29325 const val = maybe_inst_val orelse {29342 const val = maybe_inst_val orelse {
29326 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {29343 if (dest_ty.zigTypeTag(zcu) == .ComptimeInt) {
29327 if (!opts.report_err) return error.NotCoercible;29344 if (!opts.report_err) return error.NotCoercible;
29328 return sema.failWithNeededComptime(block, inst_src, .{29345 return sema.failWithNeededComptime(block, inst_src, .{
29329 .needed_comptime_reason = "value being casted to 'comptime_int' must be comptime-known",29346 .needed_comptime_reason = "value being casted to 'comptime_int' must be comptime-known",
...@@ -29339,17 +29356,17 @@ fn coerceExtra(...@@ -29339,17 +29356,17 @@ fn coerceExtra(
29339 // comptime-known integer to other number29356 // comptime-known integer to other number
29340 if (!(try sema.intFitsInType(val, dest_ty, null))) {29357 if (!(try sema.intFitsInType(val, dest_ty, null))) {
29341 if (!opts.report_err) return error.NotCoercible;29358 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) });
29343 }29360 }
29344 return switch (mod.intern_pool.indexToKey(val.toIntern())) {29361 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
29345 .undef => try mod.undefRef(dest_ty),29362 .undef => try zcu.undefRef(dest_ty),
29346 .int => |int| Air.internedToRef(29363 .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()),
29348 ),29365 ),
29349 else => unreachable,29366 else => unreachable,
29350 };29367 };
29351 }29368 }
29352 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {29369 if (dest_ty.zigTypeTag(zcu) == .ComptimeInt) {
29353 if (!opts.report_err) return error.NotCoercible;29370 if (!opts.report_err) return error.NotCoercible;
29354 if (opts.no_cast_to_comptime_int) return inst;29371 if (opts.no_cast_to_comptime_int) return inst;
29355 return sema.failWithNeededComptime(block, inst_src, .{29372 return sema.failWithNeededComptime(block, inst_src, .{
...@@ -29358,8 +29375,8 @@ fn coerceExtra(...@@ -29358,8 +29375,8 @@ fn coerceExtra(
29358 }29375 }
2935929376
29360 // integer widening29377 // integer widening
29361 const dst_info = dest_ty.intInfo(mod);29378 const dst_info = dest_ty.intInfo(zcu);
29362 const src_info = inst_ty.intInfo(mod);29379 const src_info = inst_ty.intInfo(zcu);
29363 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or29380 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or
29364 // small enough unsigned ints can get casted to large enough signed ints29381 // small enough unsigned ints can get casted to large enough signed ints
29365 (dst_info.signedness == .signed and dst_info.bits > src_info.bits))29382 (dst_info.signedness == .signed and dst_info.bits > src_info.bits))
...@@ -29370,25 +29387,25 @@ fn coerceExtra(...@@ -29370,25 +29387,25 @@ fn coerceExtra(
29370 },29387 },
29371 else => {},29388 else => {},
29372 },29389 },
29373 .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) {29390 .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(zcu)) {
29374 .ComptimeFloat => {29391 .ComptimeFloat => {
29375 const val = try sema.resolveConstDefinedValue(block, .unneeded, inst, undefined);29392 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);
29377 return Air.internedToRef(result_val.toIntern());29394 return Air.internedToRef(result_val.toIntern());
29378 },29395 },
29379 .Float => {29396 .Float => {
29380 if (maybe_inst_val) |val| {29397 if (maybe_inst_val) |val| {
29381 const result_val = try val.floatCast(dest_ty, mod);29398 const result_val = try val.floatCast(dest_ty, zcu);
29382 if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) {29399 if (!val.eql(try result_val.floatCast(inst_ty, zcu), inst_ty, zcu)) {
29383 return sema.fail(29400 return sema.fail(
29384 block,29401 block,
29385 inst_src,29402 inst_src,
29386 "type '{}' cannot represent float value '{}'",29403 "type '{}' cannot represent float value '{}'",
29387 .{ dest_ty.fmt(mod), val.fmtValue(mod) },29404 .{ dest_ty.fmt(zcu), val.fmtValue(zcu, sema) },
29388 );29405 );
29389 }29406 }
29390 return Air.internedToRef(result_val.toIntern());29407 return Air.internedToRef(result_val.toIntern());
29391 } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {29408 } else if (dest_ty.zigTypeTag(zcu) == .ComptimeFloat) {
29392 if (!opts.report_err) return error.NotCoercible;29409 if (!opts.report_err) return error.NotCoercible;
29393 return sema.failWithNeededComptime(block, inst_src, .{29410 return sema.failWithNeededComptime(block, inst_src, .{
29394 .needed_comptime_reason = "value being casted to 'comptime_float' must be comptime-known",29411 .needed_comptime_reason = "value being casted to 'comptime_float' must be comptime-known",
...@@ -29405,7 +29422,7 @@ fn coerceExtra(...@@ -29405,7 +29422,7 @@ fn coerceExtra(
29405 },29422 },
29406 .Int, .ComptimeInt => int: {29423 .Int, .ComptimeInt => int: {
29407 const val = maybe_inst_val orelse {29424 const val = maybe_inst_val orelse {
29408 if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {29425 if (dest_ty.zigTypeTag(zcu) == .ComptimeFloat) {
29409 if (!opts.report_err) return error.NotCoercible;29426 if (!opts.report_err) return error.NotCoercible;
29410 return sema.failWithNeededComptime(block, inst_src, .{29427 return sema.failWithNeededComptime(block, inst_src, .{
29411 .needed_comptime_reason = "value being casted to 'comptime_float' must be comptime-known",29428 .needed_comptime_reason = "value being casted to 'comptime_float' must be comptime-known",
...@@ -29413,52 +29430,52 @@ fn coerceExtra(...@@ -29413,52 +29430,52 @@ fn coerceExtra(
29413 }29430 }
29414 break :int;29431 break :int;
29415 };29432 };
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);
29417 // TODO implement this compile error29434 // TODO implement this compile error
29418 //const int_again_val = try result_val.intFromFloat(sema.arena, inst_ty);29435 //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)) {
29420 // return sema.fail(29437 // return sema.fail(
29421 // block,29438 // block,
29422 // inst_src,29439 // inst_src,
29423 // "type '{}' cannot represent integer value '{}'",29440 // "type '{}' cannot represent integer value '{}'",
29424 // .{ dest_ty.fmt(mod), val },29441 // .{ dest_ty.fmt(zcu), val },
29425 // );29442 // );
29426 //}29443 //}
29427 return Air.internedToRef(result_val.toIntern());29444 return Air.internedToRef(result_val.toIntern());
29428 },29445 },
29429 else => {},29446 else => {},
29430 },29447 },
29431 .Enum => switch (inst_ty.zigTypeTag(mod)) {29448 .Enum => switch (inst_ty.zigTypeTag(zcu)) {
29432 .EnumLiteral => {29449 .EnumLiteral => {
29433 // enum literal to enum29450 // enum literal to enum
29434 const val = try sema.resolveConstDefinedValue(block, .unneeded, inst, undefined);29451 const val = try sema.resolveConstDefinedValue(block, .unneeded, inst, undefined);
29435 const string = mod.intern_pool.indexToKey(val.toIntern()).enum_literal;29452 const string = zcu.intern_pool.indexToKey(val.toIntern()).enum_literal;
29436 const field_index = dest_ty.enumFieldIndex(string, mod) orelse {29453 const field_index = dest_ty.enumFieldIndex(string, zcu) orelse {
29437 return sema.fail(block, inst_src, "no field named '{}' in enum '{}'", .{29454 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),
29439 });29456 });
29440 };29457 };
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());
29442 },29459 },
29443 .Union => blk: {29460 .Union => blk: {
29444 // union to its own tag type29461 // union to its own tag type
29445 const union_tag_ty = inst_ty.unionTagType(mod) orelse break :blk;29462 const union_tag_ty = inst_ty.unionTagType(zcu) orelse break :blk;
29446 if (union_tag_ty.eql(dest_ty, mod)) {29463 if (union_tag_ty.eql(dest_ty, zcu)) {
29447 return sema.unionToTag(block, dest_ty, inst, inst_src);29464 return sema.unionToTag(block, dest_ty, inst, inst_src);
29448 }29465 }
29449 },29466 },
29450 else => {},29467 else => {},
29451 },29468 },
29452 .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) {29469 .ErrorUnion => switch (inst_ty.zigTypeTag(zcu)) {
29453 .ErrorUnion => eu: {29470 .ErrorUnion => eu: {
29454 if (maybe_inst_val) |inst_val| {29471 if (maybe_inst_val) |inst_val| {
29455 switch (inst_val.toIntern()) {29472 switch (inst_val.toIntern()) {
29456 .undef => return mod.undefRef(dest_ty),29473 .undef => return zcu.undefRef(dest_ty),
29457 else => switch (mod.intern_pool.indexToKey(inst_val.toIntern())) {29474 else => switch (zcu.intern_pool.indexToKey(inst_val.toIntern())) {
29458 .error_union => |error_union| switch (error_union.val) {29475 .error_union => |error_union| switch (error_union.val) {
29459 .err_name => |err_name| {29476 .err_name => |err_name| {
29460 const error_set_ty = inst_ty.errorUnionSet(mod);29477 const error_set_ty = inst_ty.errorUnionSet(zcu);
29461 const error_set_val = Air.internedToRef((try mod.intern(.{ .err = .{29478 const error_set_val = Air.internedToRef((try zcu.intern(.{ .err = .{
29462 .ty = error_set_ty.toIntern(),29479 .ty = error_set_ty.toIntern(),
29463 .name = err_name,29480 .name = err_name,
29464 } })));29481 } })));
...@@ -29489,31 +29506,54 @@ fn coerceExtra(...@@ -29489,31 +29506,54 @@ fn coerceExtra(
29489 };29506 };
29490 },29507 },
29491 },29508 },
29492 .Union => switch (inst_ty.zigTypeTag(mod)) {29509 .Union => switch (inst_ty.zigTypeTag(zcu)) {
29493 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),29510 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),
29494 .Struct => {29511 .Struct => {
29495 if (inst_ty.isAnonStruct(mod)) {29512 if (inst_ty.isAnonStruct(zcu)) {
29496 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);29513 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
29497 }29514 }
29498 },29515 },
29499 else => {},29516 else => {},
29500 },29517 },
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 },
29502 .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),29542 .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
29503 .Struct => {29543 .Struct => {
29504 if (inst == .empty_struct) {29544 if (inst == .empty_struct) {
29505 return sema.arrayInitEmpty(block, inst_src, dest_ty);29545 return sema.arrayInitEmpty(block, inst_src, dest_ty);
29506 }29546 }
29507 if (inst_ty.isTuple(mod)) {29547 if (inst_ty.isTuple(zcu)) {
29508 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);29548 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
29509 }29549 }
29510 },29550 },
29511 else => {},29551 else => {},
29512 },29552 },
29513 .Vector => switch (inst_ty.zigTypeTag(mod)) {29553 .Vector => switch (inst_ty.zigTypeTag(zcu)) {
29514 .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),29554 .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
29515 .Struct => {29555 .Struct => {
29516 if (inst_ty.isTuple(mod)) {29556 if (inst_ty.isTuple(zcu)) {
29517 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);29557 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
29518 }29558 }
29519 },29559 },
...@@ -29523,7 +29563,7 @@ fn coerceExtra(...@@ -29523,7 +29563,7 @@ fn coerceExtra(
29523 if (inst == .empty_struct) {29563 if (inst == .empty_struct) {
29524 return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src);29564 return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src);
29525 }29565 }
29526 if (inst_ty.isTupleOrAnonStruct(mod)) {29566 if (inst_ty.isTupleOrAnonStruct(zcu)) {
29527 return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) {29567 return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) {
29528 error.NotCoercible => break :blk,29568 error.NotCoercible => break :blk,
29529 else => |e| return e,29569 else => |e| return e,
...@@ -29536,38 +29576,38 @@ fn coerceExtra(...@@ -29536,38 +29576,38 @@ fn coerceExtra(
29536 // undefined to anything. We do this after the big switch above so that29576 // undefined to anything. We do this after the big switch above so that
29537 // special logic has a chance to run first, such as `*[N]T` to `[]T` which29577 // special logic has a chance to run first, such as `*[N]T` to `[]T` which
29538 // should initialize the length field of the slice.29578 // 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
29541 if (!opts.report_err) return error.NotCoercible;29581 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) {
29544 const msg = msg: {29584 const msg = msg: {
29545 const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{});29585 const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{});
29546 errdefer msg.destroy(sema.gpa);29586 errdefer msg.destroy(sema.gpa);
2954729587
29548 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };29588 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
29549 const src_decl = mod.funcOwnerDeclPtr(sema.func_index);29589 const src_decl = zcu.funcOwnerDeclPtr(sema.func_index);
29550 try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "'noreturn' declared here", .{});29590 try zcu.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, zcu), msg, "'noreturn' declared here", .{});
29551 break :msg msg;29591 break :msg msg;
29552 };29592 };
29553 return sema.failWithOwnedErrorMsg(block, msg);29593 return sema.failWithOwnedErrorMsg(block, msg);
29554 }29594 }
2955529595
29556 const msg = msg: {29596 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) });
29558 errdefer msg.destroy(sema.gpa);29598 errdefer msg.destroy(sema.gpa);
2955929599
29560 // E!T to T29600 // E!T to T
29561 if (inst_ty.zigTypeTag(mod) == .ErrorUnion and29601 if (inst_ty.zigTypeTag(zcu) == .ErrorUnion and
29562 (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)29602 (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(zcu), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
29563 {29603 {
29564 try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{});29604 try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{});
29565 try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{});29605 try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{});
29566 }29606 }
2956729607
29568 // ?T to T29608 // ?T to T
29569 if (inst_ty.zigTypeTag(mod) == .Optional and29609 if (inst_ty.zigTypeTag(zcu) == .Optional and
29570 (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)29610 (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(zcu), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
29571 {29611 {
29572 try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{});29612 try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{});
29573 try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{});29613 try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{});
...@@ -29577,19 +29617,19 @@ fn coerceExtra(...@@ -29577,19 +29617,19 @@ fn coerceExtra(
2957729617
29578 // Add notes about function return type29618 // Add notes about function return type
29579 if (opts.is_ret and29619 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)
29581 {29621 {
29582 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };29622 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
29583 const src_decl = mod.funcOwnerDeclPtr(sema.func_index);29623 const src_decl = zcu.funcOwnerDeclPtr(sema.func_index);
29584 if (inst_ty.isError(mod) and !dest_ty.isError(mod)) {29624 if (inst_ty.isError(zcu) and !dest_ty.isError(zcu)) {
29585 try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "function cannot return an error", .{});29625 try zcu.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, zcu), msg, "function cannot return an error", .{});
29586 } else {29626 } 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", .{});
29588 }29628 }
29589 }29629 }
2959029630
29591 if (try opts.param_src.get(sema)) |param_src| {29631 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", .{});
29593 }29633 }
2959429634
29595 // TODO maybe add "cannot store an error in type '{}'" note29635 // TODO maybe add "cannot store an error in type '{}'" note
...@@ -29755,11 +29795,11 @@ const InMemoryCoercionResult = union(enum) {...@@ -29755,11 +29795,11 @@ const InMemoryCoercionResult = union(enum) {
29755 .array_sentinel => |sentinel| {29795 .array_sentinel => |sentinel| {
29756 if (sentinel.actual.toIntern() != .unreachable_value) {29796 if (sentinel.actual.toIntern() != .unreachable_value) {
29757 try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{29797 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),
29759 });29799 });
29760 } else {29800 } else {
29761 try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{29801 try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{
29762 sentinel.wanted.fmtValue(mod),29802 sentinel.wanted.fmtValue(mod, sema),
29763 });29803 });
29764 }29804 }
29765 break;29805 break;
...@@ -29881,11 +29921,11 @@ const InMemoryCoercionResult = union(enum) {...@@ -29881,11 +29921,11 @@ const InMemoryCoercionResult = union(enum) {
29881 .ptr_sentinel => |sentinel| {29921 .ptr_sentinel => |sentinel| {
29882 if (sentinel.actual.toIntern() != .unreachable_value) {29922 if (sentinel.actual.toIntern() != .unreachable_value) {
29883 try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{29923 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),
29885 });29925 });
29886 } else {29926 } else {
29887 try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{29927 try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{
29888 sentinel.wanted.fmtValue(mod),29928 sentinel.wanted.fmtValue(mod, sema),
29889 });29929 });
29890 }29930 }
29891 break;29931 break;
...@@ -29972,7 +30012,7 @@ fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 {...@@ -29972,7 +30012,7 @@ fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 {
29972/// * bit offset attributes must match exactly30012/// * bit offset attributes must match exactly
29973/// * `*`/`[*]` must match exactly, but `[*c]` matches either one30013/// * `*`/`[*]` must match exactly, but `[*c]` matches either one
29974/// * sentinel-terminated pointers can coerce into `[*]`30014/// * sentinel-terminated pointers can coerce into `[*]`
29975fn coerceInMemoryAllowed(30015pub fn coerceInMemoryAllowed(
29976 sema: *Sema,30016 sema: *Sema,
29977 block: *Block,30017 block: *Block,
29978 dest_ty: Type,30018 dest_ty: Type,
...@@ -30082,8 +30122,9 @@ fn coerceInMemoryAllowed(...@@ -30082,8 +30122,9 @@ fn coerceInMemoryAllowed(
30082 .wanted = dest_info.elem_type,30122 .wanted = dest_info.elem_type,
30083 } };30123 } };
30084 }30124 }
30085 const ok_sent = dest_info.sentinel == null or30125 const ok_sent = (dest_info.sentinel == null and src_info.sentinel == null) or
30086 (src_info.sentinel != null and30126 (src_info.sentinel != null and
30127 dest_info.sentinel != null and
30087 dest_info.sentinel.?.eql(30128 dest_info.sentinel.?.eql(
30088 try mod.getCoerced(src_info.sentinel.?, dest_info.elem_type),30129 try mod.getCoerced(src_info.sentinel.?, dest_info.elem_type),
30089 dest_info.elem_type,30130 dest_info.elem_type,
...@@ -30420,9 +30461,9 @@ fn coerceInMemoryAllowedPtrs(...@@ -30420,9 +30461,9 @@ fn coerceInMemoryAllowedPtrs(
30420 dest_src: LazySrcLoc,30461 dest_src: LazySrcLoc,
30421 src_src: LazySrcLoc,30462 src_src: LazySrcLoc,
30422) !InMemoryCoercionResult {30463) !InMemoryCoercionResult {
30423 const mod = sema.mod;30464 const zcu = sema.mod;
30424 const dest_info = dest_ptr_ty.ptrInfo(mod);30465 const dest_info = dest_ptr_ty.ptrInfo(zcu);
30425 const src_info = src_ptr_ty.ptrInfo(mod);30466 const src_info = src_ptr_ty.ptrInfo(zcu);
3042630467
30427 const ok_ptr_size = src_info.flags.size == dest_info.flags.size or30468 const ok_ptr_size = src_info.flags.size == dest_info.flags.size or
30428 src_info.flags.size == .C or dest_info.flags.size == .C;30469 src_info.flags.size == .C or dest_info.flags.size == .C;
...@@ -30453,8 +30494,18 @@ fn coerceInMemoryAllowedPtrs(...@@ -30453,8 +30494,18 @@ fn coerceInMemoryAllowedPtrs(
30453 } };30494 } };
30454 }30495 }
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);30497 const dest_child = Type.fromInterned(dest_info.child);
30457 if (child != .ok) {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 }
30458 return InMemoryCoercionResult{ .ptr_child = .{30509 return InMemoryCoercionResult{ .ptr_child = .{
30459 .child = try child.dupe(sema.arena),30510 .child = try child.dupe(sema.arena),
30460 .actual = Type.fromInterned(src_info.child),30511 .actual = Type.fromInterned(src_info.child),
...@@ -30462,8 +30513,8 @@ fn coerceInMemoryAllowedPtrs(...@@ -30462,8 +30513,8 @@ fn coerceInMemoryAllowedPtrs(
30462 } };30513 } };
30463 }30514 }
3046430515
30465 const dest_allow_zero = dest_ty.ptrAllowsZero(mod);30516 const dest_allow_zero = dest_ty.ptrAllowsZero(zcu);
30466 const src_allow_zero = src_ty.ptrAllowsZero(mod);30517 const src_allow_zero = src_ty.ptrAllowsZero(zcu);
3046730518
30468 const ok_allows_zero = (dest_allow_zero and30519 const ok_allows_zero = (dest_allow_zero and
30469 (src_allow_zero or !dest_is_mut)) or30520 (src_allow_zero or !dest_is_mut)) or
...@@ -30488,7 +30539,7 @@ fn coerceInMemoryAllowedPtrs(...@@ -30488,7 +30539,7 @@ fn coerceInMemoryAllowedPtrs(
3048830539
30489 const ok_sent = dest_info.sentinel == .none or src_info.flags.size == .C or30540 const ok_sent = dest_info.sentinel == .none or src_info.flags.size == .C or
30490 (src_info.sentinel != .none and30541 (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));
30492 if (!ok_sent) {30543 if (!ok_sent) {
30493 return InMemoryCoercionResult{ .ptr_sentinel = .{30544 return InMemoryCoercionResult{ .ptr_sentinel = .{
30494 .actual = switch (src_info.sentinel) {30545 .actual = switch (src_info.sentinel) {
...@@ -30787,7 +30838,18 @@ fn checkKnownAllocPtr(sema: *Sema, block: *Block, base_ptr: Air.Inst.Ref, new_pt...@@ -30787,7 +30838,18 @@ fn checkKnownAllocPtr(sema: *Sema, block: *Block, base_ptr: Air.Inst.Ref, new_pt
30787 switch (sema.air_instructions.items(.tag)[@intFromEnum(new_ptr_inst)]) {30838 switch (sema.air_instructions.items(.tag)[@intFromEnum(new_ptr_inst)]) {
30788 .optional_payload_ptr_set, .errunion_payload_ptr_set => {30839 .optional_payload_ptr_set, .errunion_payload_ptr_set => {
30789 const maybe_comptime_alloc = sema.maybe_comptime_allocs.getPtr(alloc_inst) orelse return;30840 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 });
30791 },30853 },
30792 .ptr_elem_ptr => {30854 .ptr_elem_ptr => {
30793 const tmp_air = sema.getTmpAir();30855 const tmp_air = sema.getTmpAir();
...@@ -30812,6 +30874,12 @@ fn markMaybeComptimeAllocRuntime(sema: *Sema, block: *Block, alloc_inst: Air.Ins...@@ -30812,6 +30874,12 @@ fn markMaybeComptimeAllocRuntime(sema: *Sema, block: *Block, alloc_inst: Air.Ins
30812 const mod = sema.mod;30874 const mod = sema.mod;
30813 const slice = maybe_comptime_alloc.stores.slice();30875 const slice = maybe_comptime_alloc.stores.slice();
30814 for (slice.items(.inst), slice.items(.src_decl), slice.items(.src)) |other_inst, other_src_decl, other_src| {30876 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 }
30815 const other_data = sema.air_instructions.items(.data)[@intFromEnum(other_inst)].bin_op;30883 const other_data = sema.air_instructions.items(.data)[@intFromEnum(other_inst)].bin_op;
30816 const other_operand = other_data.rhs;30884 const other_operand = other_data.rhs;
30817 if (!sema.checkRuntimeValue(other_operand)) {30885 if (!sema.checkRuntimeValue(other_operand)) {
...@@ -30866,748 +30934,46 @@ fn storePtrVal(...@@ -30866,748 +30934,46 @@ fn storePtrVal(
30866 operand_val: Value,30934 operand_val: Value,
30867 operand_ty: Type,30935 operand_ty: Type,
30868) !void {30936) !void {
30869 const mod = sema.mod;30937 const zcu = sema.mod;
30870 var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty);30938 const ip = &zcu.intern_pool;
30871 switch (mut_kit.root) {30939 // TODO: audit use sites to eliminate this coercion
30872 .alloc => |a| try sema.checkComptimeVarStore(block, src, a),30940 const coerced_operand_val = try zcu.getCoerced(operand_val, operand_ty);
30873 .comptime_field => {},30941 // TODO: audit use sites to eliminate this coercion
30874 }30942 const ptr_ty = try zcu.ptrType(info: {
3087530943 var info = ptr_val.typeOf(zcu).ptrInfo(zcu);
30876 try sema.resolveTypeLayout(operand_ty);30944 info.child = operand_ty.toIntern();
30877 switch (mut_kit.pointee) {30945 break :info info;
30878 .opv => {},30946 });
30879 .direct => |val_ptr| {30947 const coerced_ptr_val = try zcu.getCoerced(ptr_val, ptr_ty);
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 };
3160430948
31605 if (deref.pointee) |val| {30949 switch (try sema.storeComptimePtr(block, src, coerced_ptr_val, coerced_operand_val)) {
31606 if (deref.parent == null and val.typeOf(mod).hasWellDefinedLayout(mod)) {30950 .success => {},
31607 deref.parent = .{ .val = val, .byte_offset = 0 };30951 .runtime_store => unreachable, // use sites check this
31608 }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", .{}),
31609 }30976 }
31610 return deref;
31611}30977}
3161230978
31613fn bitCast(30979fn bitCast(
...@@ -31618,28 +30984,33 @@ fn bitCast(...@@ -31618,28 +30984,33 @@ fn bitCast(
31618 inst_src: LazySrcLoc,30984 inst_src: LazySrcLoc,
31619 operand_src: ?LazySrcLoc,30985 operand_src: ?LazySrcLoc,
31620) CompileError!Air.Inst.Ref {30986) CompileError!Air.Inst.Ref {
31621 const mod = sema.mod;30987 const zcu = sema.mod;
31622 try sema.resolveTypeLayout(dest_ty);30988 try sema.resolveTypeLayout(dest_ty);
3162330989
31624 const old_ty = sema.typeOf(inst);30990 const old_ty = sema.typeOf(inst);
31625 try sema.resolveTypeLayout(old_ty);30991 try sema.resolveTypeLayout(old_ty);
3162630992
31627 const dest_bits = dest_ty.bitSize(mod);30993 const dest_bits = dest_ty.bitSize(zcu);
31628 const old_bits = old_ty.bitSize(mod);30994 const old_bits = old_ty.bitSize(zcu);
3162930995
31630 if (old_bits != dest_bits) {30996 if (old_bits != dest_bits) {
31631 return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{30997 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),
31633 dest_bits,30999 dest_bits,
31634 old_ty.fmt(mod),31000 old_ty.fmt(zcu),
31635 old_bits,31001 old_bits,
31636 });31002 });
31637 }31003 }
3163831004
31639 if (try sema.resolveValue(inst)) |val| {31005 if (try sema.resolveValue(inst)) |val| {
31640 if (val.isUndef(mod))31006 if (val.isUndef(zcu))
31641 return mod.undefRef(dest_ty);31007 return zcu.undefRef(dest_ty);
31642 if (try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0)) |result_val| {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| {
31643 return Air.internedToRef(result_val.toIntern());31014 return Air.internedToRef(result_val.toIntern());
31644 }31015 }
31645 }31016 }
...@@ -31648,98 +31019,6 @@ fn bitCast(...@@ -31648,98 +31019,6 @@ fn bitCast(
31648 return block.addBitCast(dest_ty, inst);31019 return block.addBitCast(dest_ty, inst);
31649}31020}
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
31743fn coerceArrayPtrToSlice(31022fn coerceArrayPtrToSlice(
31744 sema: *Sema,31023 sema: *Sema,
31745 block: *Block,31024 block: *Block,
...@@ -31885,7 +31164,7 @@ fn coerceEnumToUnion(...@@ -31885,7 +31164,7 @@ fn coerceEnumToUnion(
31885 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {31164 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
31886 const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse {31165 const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse {
31887 return sema.fail(block, inst_src, "union '{}' has no tag with value '{}'", .{31166 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),
31889 });31168 });
31890 };31169 };
3189131170
...@@ -32595,7 +31874,7 @@ fn addReferencedBy(...@@ -32595,7 +31874,7 @@ fn addReferencedBy(
32595 });31874 });
32596}31875}
3259731876
32598fn ensureDeclAnalyzed(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!void {31877pub fn ensureDeclAnalyzed(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!void {
32599 const mod = sema.mod;31878 const mod = sema.mod;
32600 const ip = &mod.intern_pool;31879 const ip = &mod.intern_pool;
32601 const decl = mod.declPtr(decl_index);31880 const decl = mod.declPtr(decl_index);
...@@ -32673,7 +31952,8 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn...@@ -32673,7 +31952,8 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
32673 }31952 }
32674 return Air.internedToRef((try mod.intern(.{ .ptr = .{31953 return Air.internedToRef((try mod.intern(.{ .ptr = .{
32675 .ty = ptr_ty.toIntern(),31954 .ty = ptr_ty.toIntern(),
32676 .addr = .{ .decl = decl_index },31955 .base_addr = .{ .decl = decl_index },
31956 .byte_offset = 0,
32677 } })));31957 } })));
32678}31958}
3267931959
...@@ -33102,8 +32382,8 @@ fn analyzeSlice(...@@ -33102,8 +32382,8 @@ fn analyzeSlice(
33102 msg,32382 msg,
33103 "expected '{}', found '{}'",32383 "expected '{}', found '{}'",
33104 .{32384 .{
33105 Value.zero_comptime_int.fmtValue(mod),32385 Value.zero_comptime_int.fmtValue(mod, sema),
33106 start_value.fmtValue(mod),32386 start_value.fmtValue(mod, sema),
33107 },32387 },
33108 );32388 );
33109 break :msg msg;32389 break :msg msg;
...@@ -33119,8 +32399,8 @@ fn analyzeSlice(...@@ -33119,8 +32399,8 @@ fn analyzeSlice(
33119 msg,32399 msg,
33120 "expected '{}', found '{}'",32400 "expected '{}', found '{}'",
33121 .{32401 .{
33122 Value.one_comptime_int.fmtValue(mod),32402 Value.one_comptime_int.fmtValue(mod, sema),
33123 end_value.fmtValue(mod),32403 end_value.fmtValue(mod, sema),
33124 },32404 },
33125 );32405 );
33126 break :msg msg;32406 break :msg msg;
...@@ -33133,7 +32413,7 @@ fn analyzeSlice(...@@ -33133,7 +32413,7 @@ fn analyzeSlice(
33133 block,32413 block,
33134 end_src,32414 end_src,
33135 "end index {} out of bounds for slice of single-item pointer",32415 "end index {} out of bounds for slice of single-item pointer",
33136 .{end_value.fmtValue(mod)},32416 .{end_value.fmtValue(mod, sema)},
33137 );32417 );
33138 }32418 }
33139 }32419 }
...@@ -33228,8 +32508,8 @@ fn analyzeSlice(...@@ -33228,8 +32508,8 @@ fn analyzeSlice(
33228 end_src,32508 end_src,
33229 "end index {} out of bounds for array of length {}{s}",32509 "end index {} out of bounds for array of length {}{s}",
33230 .{32510 .{
33231 end_val.fmtValue(mod),32511 end_val.fmtValue(mod, sema),
33232 len_val.fmtValue(mod),32512 len_val.fmtValue(mod, sema),
33233 sentinel_label,32513 sentinel_label,
33234 },32514 },
33235 );32515 );
...@@ -33273,7 +32553,7 @@ fn analyzeSlice(...@@ -33273,7 +32553,7 @@ fn analyzeSlice(
33273 end_src,32553 end_src,
33274 "end index {} out of bounds for slice of length {d}{s}",32554 "end index {} out of bounds for slice of length {d}{s}",
33275 .{32555 .{
33276 end_val.fmtValue(mod),32556 end_val.fmtValue(mod, sema),
33277 try slice_val.sliceLen(sema),32557 try slice_val.sliceLen(sema),
33278 sentinel_label,32558 sentinel_label,
33279 },32559 },
...@@ -33333,8 +32613,8 @@ fn analyzeSlice(...@@ -33333,8 +32613,8 @@ fn analyzeSlice(
33333 start_src,32613 start_src,
33334 "start index {} is larger than end index {}",32614 "start index {} is larger than end index {}",
33335 .{32615 .{
33336 start_val.fmtValue(mod),32616 start_val.fmtValue(mod, sema),
33337 end_val.fmtValue(mod),32617 end_val.fmtValue(mod, sema),
33338 },32618 },
33339 );32619 );
33340 }32620 }
...@@ -33347,16 +32627,15 @@ fn analyzeSlice(...@@ -33347,16 +32627,15 @@ fn analyzeSlice(
3334732627
33348 const many_ptr_ty = try mod.manyConstPtrType(elem_ty);32628 const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
33349 const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty);32629 const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty);
33350 const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);32630 const elem_ptr = try many_ptr_val.ptrElem(sentinel_index, sema);
33351 const elem_ptr = try many_ptr_val.elemPtr(elem_ptr_ty, sentinel_index, mod);32631 const res = try sema.pointerDerefExtra(block, src, elem_ptr);
33352 const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty);
33353 const actual_sentinel = switch (res) {32632 const actual_sentinel = switch (res) {
33354 .runtime_load => break :sentinel_check,32633 .runtime_load => break :sentinel_check,
33355 .val => |v| v,32634 .val => |v| v,
33356 .needed_well_defined => |ty| return sema.fail(32635 .needed_well_defined => |ty| return sema.fail(
33357 block,32636 block,
33358 src,32637 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",
33360 .{ty.fmt(mod)},32639 .{ty.fmt(mod)},
33361 ),32640 ),
33362 .out_of_bounds => |ty| return sema.fail(32641 .out_of_bounds => |ty| return sema.fail(
...@@ -33372,8 +32651,8 @@ fn analyzeSlice(...@@ -33372,8 +32651,8 @@ fn analyzeSlice(
33372 const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});32651 const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});
33373 errdefer msg.destroy(sema.gpa);32652 errdefer msg.destroy(sema.gpa);
33374 try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{32653 try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{
33375 expected_sentinel.fmtValue(mod),32654 expected_sentinel.fmtValue(mod, sema),
33376 actual_sentinel.fmtValue(mod),32655 actual_sentinel.fmtValue(mod, sema),
33377 });32656 });
3337832657
33379 break :msg msg;32658 break :msg msg;
...@@ -35599,8 +34878,8 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {...@@ -35599,8 +34878,8 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
35599 } }));34878 } }));
35600 },34879 },
35601 .ptr => |ptr| {34880 .ptr => |ptr| {
35602 switch (ptr.addr) {34881 switch (ptr.base_addr) {
35603 .decl, .comptime_alloc, .anon_decl => return val,34882 .decl, .comptime_alloc, .anon_decl, .int => return val,
35604 .comptime_field => |field_val| {34883 .comptime_field => |field_val| {
35605 const resolved_field_val =34884 const resolved_field_val =
35606 (try sema.resolveLazyValue(Value.fromInterned(field_val))).toIntern();34885 (try sema.resolveLazyValue(Value.fromInterned(field_val))).toIntern();
...@@ -35609,17 +34888,8 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {...@@ -35609,17 +34888,8 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
35609 else34888 else
35610 Value.fromInterned((try mod.intern(.{ .ptr = .{34889 Value.fromInterned((try mod.intern(.{ .ptr = .{
35611 .ty = ptr.ty,34890 .ty = ptr.ty,
35612 .addr = .{ .comptime_field = resolved_field_val },34891 .base_addr = .{ .comptime_field = resolved_field_val },
35613 } })));34892 .byte_offset = ptr.byte_offset,
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 },
35623 } })));34893 } })));
35624 },34894 },
35625 .eu_payload, .opt_payload => |base| {34895 .eu_payload, .opt_payload => |base| {
...@@ -35629,22 +34899,23 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {...@@ -35629,22 +34899,23 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
35629 else34899 else
35630 Value.fromInterned((try mod.intern(.{ .ptr = .{34900 Value.fromInterned((try mod.intern(.{ .ptr = .{
35631 .ty = ptr.ty,34901 .ty = ptr.ty,
35632 .addr = switch (ptr.addr) {34902 .base_addr = switch (ptr.base_addr) {
35633 .eu_payload => .{ .eu_payload = resolved_base },34903 .eu_payload => .{ .eu_payload = resolved_base },
35634 .opt_payload => .{ .opt_payload = resolved_base },34904 .opt_payload => .{ .opt_payload = resolved_base },
35635 else => unreachable,34905 else => unreachable,
35636 },34906 },
34907 .byte_offset = ptr.byte_offset,
35637 } })));34908 } })));
35638 },34909 },
35639 .elem, .field => |base_index| {34910 .arr_elem, .field => |base_index| {
35640 const resolved_base = (try sema.resolveLazyValue(Value.fromInterned(base_index.base))).toIntern();34911 const resolved_base = (try sema.resolveLazyValue(Value.fromInterned(base_index.base))).toIntern();
35641 return if (resolved_base == base_index.base)34912 return if (resolved_base == base_index.base)
35642 val34913 val
35643 else34914 else
35644 Value.fromInterned((try mod.intern(.{ .ptr = .{34915 Value.fromInterned((try mod.intern(.{ .ptr = .{
35645 .ty = ptr.ty,34916 .ty = ptr.ty,
35646 .addr = switch (ptr.addr) {34917 .base_addr = switch (ptr.base_addr) {
35647 .elem => .{ .elem = .{34918 .arr_elem => .{ .arr_elem = .{
35648 .base = resolved_base,34919 .base = resolved_base,
35649 .index = base_index.index,34920 .index = base_index.index,
35650 } },34921 } },
...@@ -35654,6 +34925,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {...@@ -35654,6 +34925,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
35654 } },34925 } },
35655 else => unreachable,34926 else => unreachable,
35656 },34927 },
34928 .byte_offset = ptr.byte_offset,
35657 } })));34929 } })));
35658 },34930 },
35659 }34931 }
...@@ -36166,7 +35438,8 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -36166,7 +35438,8 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
36166 var max_align: Alignment = .@"1";35438 var max_align: Alignment = .@"1";
36167 for (0..union_type.field_types.len) |field_index| {35439 for (0..union_type.field_types.len) |field_index| {
36168 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);35440 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
36171 max_size = @max(max_size, sema.typeAbiSize(field_ty) catch |err| switch (err) {35444 max_size = @max(max_size, sema.typeAbiSize(field_ty) catch |err| switch (err) {
36172 error.AnalysisFail => {35445 error.AnalysisFail => {
...@@ -36496,7 +35769,15 @@ pub fn resolveTypeFieldsStruct(...@@ -36496,7 +35769,15 @@ pub fn resolveTypeFieldsStruct(
36496 }35769 }
36497 defer struct_type.clearTypesWip(ip);35770 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 };
36500}35781}
3650135782
36502pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {35783pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {
...@@ -36521,7 +35802,15 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {...@@ -36521,7 +35802,15 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {
36521 }35802 }
36522 defer struct_type.clearInitsWip(ip);35803 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 };
36525 struct_type.setHaveFieldInits(ip);35814 struct_type.setHaveFieldInits(ip);
36526}35815}
3652735816
...@@ -36560,7 +35849,15 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Load...@@ -36560,7 +35849,15 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Load
3656035849
36561 union_type.flagsPtr(ip).status = .field_types_wip;35850 union_type.flagsPtr(ip).status = .field_types_wip;
36562 errdefer union_type.flagsPtr(ip).status = .none;35851 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 };
36564 union_type.flagsPtr(ip).status = .have_field_types;35861 union_type.flagsPtr(ip).status = .have_field_types;
36565}35862}
3656635863
...@@ -37391,7 +36688,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded...@@ -37391,7 +36688,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
37391 const field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = field_i }).lazy;36688 const field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = field_i }).lazy;
37392 const other_field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = gop.index }).lazy;36689 const other_field_src = mod.fieldSrcLoc(union_type.decl, .{ .index = gop.index }).lazy;
37393 const msg = msg: {36690 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)});
37395 errdefer msg.destroy(gpa);36692 errdefer msg.destroy(gpa);
37396 try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{});36693 try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{});
37397 break :msg msg;36694 break :msg msg;
...@@ -38158,7 +37455,8 @@ fn analyzeComptimeAlloc(...@@ -38158,7 +37455,8 @@ fn analyzeComptimeAlloc(
3815837455
38159 return Air.internedToRef((try mod.intern(.{ .ptr = .{37456 return Air.internedToRef((try mod.intern(.{ .ptr = .{
38160 .ty = ptr_type.toIntern(),37457 .ty = ptr_type.toIntern(),
38161 .addr = .{ .comptime_alloc = alloc },37458 .base_addr = .{ .comptime_alloc = alloc },
37459 .byte_offset = 0,
38162 } })));37460 } })));
38163}37461}
3816437462
...@@ -38247,16 +37545,15 @@ pub fn analyzeAsAddressSpace(...@@ -38247,16 +37545,15 @@ pub fn analyzeAsAddressSpace(
38247/// Asserts the value is a pointer and dereferences it.37545/// Asserts the value is a pointer and dereferences it.
38248/// Returns `null` if the pointer contents cannot be loaded at comptime.37546/// Returns `null` if the pointer contents cannot be loaded at comptime.
38249fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value {37547fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value {
38250 const mod = sema.mod;37548 // TODO: audit use sites to eliminate this coercion
38251 const load_ty = ptr_ty.childType(mod);37549 const coerced_ptr_val = try sema.mod.getCoerced(ptr_val, ptr_ty);
38252 const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty);37550 switch (try sema.pointerDerefExtra(block, src, coerced_ptr_val)) {
38253 switch (res) {
38254 .runtime_load => return null,37551 .runtime_load => return null,
38255 .val => |v| return v,37552 .val => |v| return v,
38256 .needed_well_defined => |ty| return sema.fail(37553 .needed_well_defined => |ty| return sema.fail(
38257 block,37554 block,
38258 src,37555 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",
38260 .{ty.fmt(sema.mod)},37557 .{ty.fmt(sema.mod)},
38261 ),37558 ),
38262 .out_of_bounds => |ty| return sema.fail(37559 .out_of_bounds => |ty| return sema.fail(
...@@ -38275,68 +37572,19 @@ const DerefResult = union(enum) {...@@ -38275,68 +37572,19 @@ const DerefResult = union(enum) {
38275 out_of_bounds: Type,37572 out_of_bounds: Type,
38276};37573};
3827737574
38278fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type) CompileError!DerefResult {37575fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value) CompileError!DerefResult {
38279 const mod = sema.mod;37576 const zcu = sema.mod;
38280 const target = mod.getTarget();37577 const ip = &zcu.intern_pool;
38281 const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) {37578 switch (try sema.loadComptimePtr(block, src, ptr_val)) {
38282 error.RuntimeLoad => return DerefResult{ .runtime_load = {} },37579 .success => |mv| return .{ .val = try mv.intern(zcu, sema.arena) },
38283 else => |e| return e,37580 .runtime_load => return .runtime_load,
38284 };37581 .undef => return sema.failWithUseOfUndef(block, src),
3828537582 .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {}", .{err_name.fmt(ip)}),
38286 if (deref.pointee) |pointee| {37583 .null_payload => return sema.fail(block, src, "attempt to use null value", .{}),
38287 const uncoerced_val = Value.fromInterned(try pointee.intern(mod, sema.arena));37584 .inactive_union_field => return sema.fail(block, src, "access of inactive union field", .{}),
38288 const ty = Type.fromInterned(mod.intern_pool.typeOf(uncoerced_val.toIntern()));37585 .needed_well_defined => |ty| return .{ .needed_well_defined = ty },
38289 const coerce_in_mem_ok =37586 .out_of_bounds => |ty| return .{ .out_of_bounds = ty },
38290 (try sema.coerceInMemoryAllowed(block, load_ty, ty, false, target, src, src)) == .ok or37587 .exceeds_host_size => return sema.fail(block, src, "bit-pointer target exceeds host size", .{}),
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 };
38340 }37588 }
38341}37589}
3834237590
...@@ -38394,18 +37642,18 @@ pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {...@@ -38394,18 +37642,18 @@ pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
38394 };37642 };
38395}37643}
3839637644
38397fn typeAbiSize(sema: *Sema, ty: Type) !u64 {37645pub fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
38398 try sema.resolveTypeLayout(ty);37646 try sema.resolveTypeLayout(ty);
38399 return ty.abiSize(sema.mod);37647 return ty.abiSize(sema.mod);
38400}37648}
3840137649
38402fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {37650pub fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {
38403 return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar;37651 return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar;
38404}37652}
3840537653
38406/// Not valid to call for packed unions.37654/// Not valid to call for packed unions.
38407/// Keep implementation in sync with `Module.unionFieldNormalAlignment`.37655/// 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 {
38409 const mod = sema.mod;37657 const mod = sema.mod;
38410 const ip = &mod.intern_pool;37658 const ip = &mod.intern_pool;
38411 const field_align = u.fieldAlign(ip, field_index);37659 const field_align = u.fieldAlign(ip, field_index);
...@@ -38416,7 +37664,7 @@ fn unionFieldAlignment(sema: *Sema, u: InternPool.LoadedUnionType, field_index:...@@ -38416,7 +37664,7 @@ fn unionFieldAlignment(sema: *Sema, u: InternPool.LoadedUnionType, field_index:
38416}37664}
3841737665
38418/// Keep implementation in sync with `Module.structFieldAlignment`.37666/// Keep implementation in sync with `Module.structFieldAlignment`.
38419fn structFieldAlignment(37667pub fn structFieldAlignment(
38420 sema: *Sema,37668 sema: *Sema,
38421 explicit_alignment: InternPool.Alignment,37669 explicit_alignment: InternPool.Alignment,
38422 field_ty: Type,37670 field_ty: Type,
...@@ -38724,6 +37972,13 @@ fn intSubWithOverflowScalar(...@@ -38724,6 +37972,13 @@ fn intSubWithOverflowScalar(
38724 const mod = sema.mod;37972 const mod = sema.mod;
38725 const info = ty.intInfo(mod);37973 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
38727 var lhs_space: Value.BigIntSpace = undefined;37982 var lhs_space: Value.BigIntSpace = undefined;
38728 var rhs_space: Value.BigIntSpace = undefined;37983 var rhs_space: Value.BigIntSpace = undefined;
38729 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);37984 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
...@@ -38808,7 +38063,7 @@ fn intFromFloatScalar(...@@ -38808,7 +38063,7 @@ fn intFromFloatScalar(
38808 block,38063 block,
38809 src,38064 src,
38810 "fractional component prevents float value '{}' from coercion to type '{}'",38065 "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) },
38812 );38067 );
3881338068
38814 const float = val.toFloat(f128, mod);38069 const float = val.toFloat(f128, mod);
...@@ -38830,7 +38085,7 @@ fn intFromFloatScalar(...@@ -38830,7 +38085,7 @@ fn intFromFloatScalar(
3883038085
38831 if (!(try sema.intFitsInType(cti_result, int_ty, null))) {38086 if (!(try sema.intFitsInType(cti_result, int_ty, null))) {
38832 return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{38087 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),
38834 });38089 });
38835 }38090 }
38836 return mod.getCoerced(cti_result, int_ty);38091 return mod.getCoerced(cti_result, int_ty);
...@@ -38975,6 +38230,13 @@ fn intAddWithOverflowScalar(...@@ -38975,6 +38230,13 @@ fn intAddWithOverflowScalar(
38975 const mod = sema.mod;38230 const mod = sema.mod;
38976 const info = ty.intInfo(mod);38231 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
38978 var lhs_space: Value.BigIntSpace = undefined;38240 var lhs_space: Value.BigIntSpace = undefined;
38979 var rhs_space: Value.BigIntSpace = undefined;38241 var rhs_space: Value.BigIntSpace = undefined;
38980 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);38242 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
...@@ -39070,12 +38332,14 @@ fn compareVector(...@@ -39070,12 +38332,14 @@ fn compareVector(
3907038332
39071/// Returns the type of a pointer to an element.38333/// Returns the type of a pointer to an element.
39072/// Asserts that the type is a pointer, and that the element type is indexable.38334/// 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
39073/// For *[N]T, return *T38337/// For *[N]T, return *T
39074/// For [*]T, returns *T38338/// For [*]T, returns *T
39075/// For []T, returns *T38339/// For []T, returns *T
39076/// Handles const-ness and address spaces in particular.38340/// Handles const-ness and address spaces in particular.
39077/// This code is duplicated in `analyzePtrArithmetic`.38341/// 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 {
39079 const mod = sema.mod;38343 const mod = sema.mod;
39080 const ptr_info = ptr_ty.ptrInfo(mod);38344 const ptr_info = ptr_ty.ptrInfo(mod);
39081 const elem_ty = ptr_ty.elemType2(mod);38345 const elem_ty = ptr_ty.elemType2(mod);
...@@ -39180,7 +38444,7 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool...@@ -39180,7 +38444,7 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool
39180 return sema.typeOf(ref).zigTypeTag(sema.mod) == tag;38444 return sema.typeOf(ref).zigTypeTag(sema.mod) == tag;
39181}38445}
3918238446
39183fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {38447pub fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {
39184 if (info.flags.alignment != .none) {38448 if (info.flags.alignment != .none) {
39185 _ = try sema.typeAbiAlignment(Type.fromInterned(info.child));38449 _ = try sema.typeAbiAlignment(Type.fromInterned(info.child));
39186 }38450 }
...@@ -39210,12 +38474,12 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {...@@ -39210,12 +38474,12 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
39210fn isComptimeMutablePtr(sema: *Sema, val: Value) bool {38474fn isComptimeMutablePtr(sema: *Sema, val: Value) bool {
39211 return switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {38475 return switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {
39212 .slice => |slice| sema.isComptimeMutablePtr(Value.fromInterned(slice.ptr)),38476 .slice => |slice| sema.isComptimeMutablePtr(Value.fromInterned(slice.ptr)),
39213 .ptr => |ptr| switch (ptr.addr) {38477 .ptr => |ptr| switch (ptr.base_addr) {
39214 .anon_decl, .decl, .int => false,38478 .anon_decl, .decl, .int => false,
39215 .comptime_field => true,38479 .comptime_field => true,
39216 .comptime_alloc => |alloc_index| !sema.getComptimeAlloc(alloc_index).is_const,38480 .comptime_alloc => |alloc_index| !sema.getComptimeAlloc(alloc_index).is_const,
39217 .eu_payload, .opt_payload => |base| sema.isComptimeMutablePtr(Value.fromInterned(base)),38481 .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)),
39219 },38483 },
39220 else => false,38484 else => false,
39221 };38485 };
...@@ -39321,3 +38585,11 @@ fn maybeDerefSliceAsArray(...@@ -39321,3 +38585,11 @@ fn maybeDerefSliceAsArray(
39321 const casted_ptr = try zcu.getCoerced(Value.fromInterned(slice.ptr), ptr_ty);38585 const casted_ptr = try zcu.getCoerced(Value.fromInterned(slice.ptr), ptr_ty);
39322 return sema.pointerDeref(block, src, casted_ptr, ptr_ty);38586 return sema.pointerDeref(block, src, casted_ptr, ptr_ty);
39323}38587}
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) {...@@ -39,10 +39,11 @@ pub fn fmtDebug(val: Value) std.fmt.Formatter(dump) {
39 return .{ .data = val };39 return .{ .data = val };
40}40}
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) {
43 return .{ .data = .{43 return .{ .data = .{
44 .val = val,44 .val = val,
45 .mod = mod,45 .mod = mod,
46 .opt_sema = opt_sema,
46 } };47 } };
47}48}
4849
...@@ -246,18 +247,13 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64...@@ -246,18 +247,13 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64
246 else247 else
247 Type.fromInterned(ty).abiSize(mod),248 Type.fromInterned(ty).abiSize(mod),
248 },249 },
249 .ptr => |ptr| switch (ptr.addr) {250 .ptr => |ptr| switch (ptr.base_addr) {
250 .int => |int| Value.fromInterned(int).getUnsignedIntAdvanced(mod, opt_sema),251 .int => ptr.byte_offset,
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 },
256 .field => |field| {252 .field => |field| {
257 const base_addr = (try Value.fromInterned(field.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null;253 const base_addr = (try Value.fromInterned(field.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null;
258 const struct_ty = Value.fromInterned(field.base).typeOf(mod).childType(mod);254 const struct_ty = Value.fromInterned(field.base).typeOf(mod).childType(mod);
259 if (opt_sema) |sema| try sema.resolveTypeLayout(struct_ty);255 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;
261 },257 },
262 else => null,258 else => null,
263 },259 },
...@@ -309,11 +305,11 @@ pub fn toBool(val: Value) bool {...@@ -309,11 +305,11 @@ pub fn toBool(val: Value) bool {
309fn ptrHasIntAddr(val: Value, mod: *Module) bool {305fn ptrHasIntAddr(val: Value, mod: *Module) bool {
310 var check = val;306 var check = val;
311 while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) {307 while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) {
312 .ptr => |ptr| switch (ptr.addr) {308 .ptr => |ptr| switch (ptr.base_addr) {
313 .decl, .comptime_alloc, .comptime_field, .anon_decl => return false,309 .decl, .comptime_alloc, .comptime_field, .anon_decl => return false,
314 .int => return true,310 .int => return true,
315 .eu_payload, .opt_payload => |base| check = Value.fromInterned(base),311 .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),
317 },313 },
318 else => unreachable,314 else => unreachable,
319 };315 };
...@@ -473,7 +469,9 @@ pub fn writeToPackedMemory(...@@ -473,7 +469,9 @@ pub fn writeToPackedMemory(
473 const endian = target.cpu.arch.endian();469 const endian = target.cpu.arch.endian();
474 if (val.isUndef(mod)) {470 if (val.isUndef(mod)) {
475 const bit_size: usize = @intCast(ty.bitSize(mod));471 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 }
477 return;475 return;
478 }476 }
479 switch (ty.zigTypeTag(mod)) {477 switch (ty.zigTypeTag(mod)) {
...@@ -731,7 +729,8 @@ pub fn readFromMemory(...@@ -731,7 +729,8 @@ pub fn readFromMemory(
731 const int_val = try readFromMemory(Type.usize, mod, buffer, arena);729 const int_val = try readFromMemory(Type.usize, mod, buffer, arena);
732 return Value.fromInterned((try mod.intern(.{ .ptr = .{730 return Value.fromInterned((try mod.intern(.{ .ptr = .{
733 .ty = ty.toIntern(),731 .ty = ty.toIntern(),
734 .addr = .{ .int = int_val.toIntern() },732 .base_addr = .int,
733 .byte_offset = int_val.toUnsignedInt(mod),
735 } })));734 } })));
736 },735 },
737 .Optional => {736 .Optional => {
...@@ -869,12 +868,25 @@ pub fn readFromPackedMemory(...@@ -869,12 +868,25 @@ pub fn readFromPackedMemory(
869 },868 },
870 .Pointer => {869 .Pointer => {
871 assert(!ty.isSlice(mod)); // No well defined layout.870 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 } }));
873 },877 },
874 .Optional => {878 .Optional => {
875 assert(ty.isPtrLikeOptional(mod));879 assert(ty.isPtrLikeOptional(mod));
876 const child = ty.optionalChild(mod);880 const child_ty = ty.optionalChild(mod);
877 return readFromPackedMemory(child, mod, buffer, bit_offset, arena);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 } }));
878 },890 },
879 else => @panic("TODO implement readFromPackedMemory for more types"),891 else => @panic("TODO implement readFromPackedMemory for more types"),
880 }892 }
...@@ -983,16 +995,17 @@ pub fn intBitCountTwosComp(self: Value, mod: *Module) usize {...@@ -983,16 +995,17 @@ pub fn intBitCountTwosComp(self: Value, mod: *Module) usize {
983995
984/// Converts an integer or a float to a float. May result in a loss of information.996/// Converts an integer or a float to a float. May result in a loss of information.
985/// Caller can find out by equality checking the result against the operand.997/// Caller can find out by equality checking the result against the operand.
986pub fn floatCast(self: Value, dest_ty: Type, mod: *Module) !Value {998pub fn floatCast(val: Value, dest_ty: Type, zcu: *Zcu) !Value {
987 const target = mod.getTarget();999 const target = zcu.getTarget();
988 return Value.fromInterned((try mod.intern(.{ .float = .{1000 if (val.isUndef(zcu)) return zcu.undefValue(dest_ty);
1001 return Value.fromInterned((try zcu.intern(.{ .float = .{
989 .ty = dest_ty.toIntern(),1002 .ty = dest_ty.toIntern(),
990 .storage = switch (dest_ty.floatBits(target)) {1003 .storage = switch (dest_ty.floatBits(target)) {
991 16 => .{ .f16 = self.toFloat(f16, mod) },1004 16 => .{ .f16 = val.toFloat(f16, zcu) },
992 32 => .{ .f32 = self.toFloat(f32, mod) },1005 32 => .{ .f32 = val.toFloat(f32, zcu) },
993 64 => .{ .f64 = self.toFloat(f64, mod) },1006 64 => .{ .f64 = val.toFloat(f64, zcu) },
994 80 => .{ .f80 = self.toFloat(f80, mod) },1007 80 => .{ .f80 = val.toFloat(f80, zcu) },
995 128 => .{ .f128 = self.toFloat(f128, mod) },1008 128 => .{ .f128 = val.toFloat(f128, zcu) },
996 else => unreachable,1009 else => unreachable,
997 },1010 },
998 } })));1011 } })));
...@@ -1021,14 +1034,9 @@ pub fn orderAgainstZeroAdvanced(...@@ -1021,14 +1034,9 @@ pub fn orderAgainstZeroAdvanced(
1021 .bool_false => .eq,1034 .bool_false => .eq,
1022 .bool_true => .gt,1035 .bool_true => .gt,
1023 else => switch (mod.intern_pool.indexToKey(lhs.toIntern())) {1036 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) {
1025 .decl, .comptime_alloc, .comptime_field => .gt,1038 .decl, .comptime_alloc, .comptime_field => .gt,
1026 .int => |int| Value.fromInterned(int).orderAgainstZeroAdvanced(mod, opt_sema),1039 .int => .eq,
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 },
1032 else => unreachable,1040 else => unreachable,
1033 },1041 },
1034 .int => |int| switch (int.storage) {1042 .int => |int| switch (int.storage) {
...@@ -1158,6 +1166,7 @@ pub fn compareScalar(...@@ -1158,6 +1166,7 @@ pub fn compareScalar(
11581166
1159/// Asserts the value is comparable.1167/// Asserts the value is comparable.
1160/// For vectors, returns true if comparison is true for ALL elements.1168/// For vectors, returns true if comparison is true for ALL elements.
1169/// Returns `false` if the value or any vector element is undefined.
1161///1170///
1162/// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`1171/// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`
1163pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, mod: *Module) bool {1172pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, mod: *Module) bool {
...@@ -1200,6 +1209,7 @@ pub fn compareAllWithZeroAdvancedExtra(...@@ -1200,6 +1209,7 @@ pub fn compareAllWithZeroAdvancedExtra(
1200 } else true,1209 } else true,
1201 .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, opt_sema),1210 .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, opt_sema),
1202 },1211 },
1212 .undef => return false,
1203 else => {},1213 else => {},
1204 }1214 }
1205 return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op);1215 return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op);
...@@ -1217,14 +1227,14 @@ pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool {...@@ -1217,14 +1227,14 @@ pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool {
1217 .err_name => false,1227 .err_name => false,
1218 .payload => |payload| Value.fromInterned(payload).canMutateComptimeVarState(zcu),1228 .payload => |payload| Value.fromInterned(payload).canMutateComptimeVarState(zcu),
1219 },1229 },
1220 .ptr => |ptr| switch (ptr.addr) {1230 .ptr => |ptr| switch (ptr.base_addr) {
1221 .decl => false, // The value of a Decl can never reference a comptime alloc.1231 .decl => false, // The value of a Decl can never reference a comptime alloc.
1222 .int => false,1232 .int => false,
1223 .comptime_alloc => true, // A comptime alloc is either mutable or references comptime-mutable memory.1233 .comptime_alloc => true, // A comptime alloc is either mutable or references comptime-mutable memory.
1224 .comptime_field => true, // Comptime field pointers are comptime-mutable, albeit only to the "correct" value.1234 .comptime_field => true, // Comptime field pointers are comptime-mutable, albeit only to the "correct" value.
1225 .eu_payload, .opt_payload => |base| Value.fromInterned(base).canMutateComptimeVarState(zcu),1235 .eu_payload, .opt_payload => |base| Value.fromInterned(base).canMutateComptimeVarState(zcu),
1226 .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).canMutateComptimeVarState(zcu),1236 .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),
1228 },1238 },
1229 .slice => |slice| return Value.fromInterned(slice.ptr).canMutateComptimeVarState(zcu),1239 .slice => |slice| return Value.fromInterned(slice.ptr).canMutateComptimeVarState(zcu),
1230 .opt => |opt| switch (opt.val) {1240 .opt => |opt| switch (opt.val) {
...@@ -1247,10 +1257,10 @@ pub fn pointerDecl(val: Value, mod: *Module) ?InternPool.DeclIndex {...@@ -1247,10 +1257,10 @@ pub fn pointerDecl(val: Value, mod: *Module) ?InternPool.DeclIndex {
1247 .variable => |variable| variable.decl,1257 .variable => |variable| variable.decl,
1248 .extern_func => |extern_func| extern_func.decl,1258 .extern_func => |extern_func| extern_func.decl,
1249 .func => |func| func.owner_decl,1259 .func => |func| func.owner_decl,
1250 .ptr => |ptr| switch (ptr.addr) {1260 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
1251 .decl => |decl| decl,1261 .decl => |decl| decl,
1252 else => null,1262 else => null,
1253 },1263 } else null,
1254 else => null,1264 else => null,
1255 };1265 };
1256}1266}
...@@ -1386,44 +1396,6 @@ pub fn unionValue(val: Value, mod: *Module) Value {...@@ -1386,44 +1396,6 @@ pub fn unionValue(val: Value, mod: *Module) Value {
1386 };1396 };
1387}1397}
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
1427pub fn isUndef(val: Value, mod: *Module) bool {1399pub fn isUndef(val: Value, mod: *Module) bool {
1428 return mod.intern_pool.isUndef(val.toIntern());1400 return mod.intern_pool.isUndef(val.toIntern());
1429}1401}
...@@ -1444,11 +1416,8 @@ pub fn isNull(val: Value, mod: *Module) bool {...@@ -1444,11 +1416,8 @@ pub fn isNull(val: Value, mod: *Module) bool {
1444 .null_value => true,1416 .null_value => true,
1445 else => return switch (mod.intern_pool.indexToKey(val.toIntern())) {1417 else => return switch (mod.intern_pool.indexToKey(val.toIntern())) {
1446 .undef => unreachable,1418 .undef => unreachable,
1447 .ptr => |ptr| switch (ptr.addr) {1419 .ptr => |ptr| switch (ptr.base_addr) {
1448 .int => {1420 .int => ptr.byte_offset == 0,
1449 var buf: BigIntSpace = undefined;
1450 return val.toBigInt(&buf, mod).eqlZero();
1451 },
1452 else => false,1421 else => false,
1453 },1422 },
1454 .opt => |opt| opt.val == .none,1423 .opt => |opt| opt.val == .none,
...@@ -1725,6 +1694,13 @@ pub fn intMulWithOverflowScalar(...@@ -1725,6 +1694,13 @@ pub fn intMulWithOverflowScalar(
1725) !OverflowArithmeticResult {1694) !OverflowArithmeticResult {
1726 const info = ty.intInfo(mod);1695 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
1728 var lhs_space: Value.BigIntSpace = undefined;1704 var lhs_space: Value.BigIntSpace = undefined;
1729 var rhs_space: Value.BigIntSpace = undefined;1705 var rhs_space: Value.BigIntSpace = undefined;
1730 const lhs_bigint = lhs.toBigInt(&lhs_space, mod);1706 const lhs_bigint = lhs.toBigInt(&lhs_space, mod);
...@@ -1941,16 +1917,29 @@ pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *...@@ -1941,16 +1917,29 @@ pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *
1941}1917}
19421918
1943/// operands must be integers; handles undefined.1919/// operands must be integers; handles undefined.
1944pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value {1920pub fn bitwiseAndScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Allocator, zcu: *Zcu) !Value {
1945 if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.fromInterned((try mod.intern(.{ .undef = ty.toIntern() })));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
1946 if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() and rhs.toBool());1935 if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() and rhs.toBool());
19471936
1948 // TODO is this a performance issue? maybe we should try the operation without1937 // TODO is this a performance issue? maybe we should try the operation without
1949 // resorting to BigInt first.1938 // resorting to BigInt first.
1950 var lhs_space: Value.BigIntSpace = undefined;1939 var lhs_space: Value.BigIntSpace = undefined;
1951 var rhs_space: Value.BigIntSpace = undefined;1940 var rhs_space: Value.BigIntSpace = undefined;
1952 const lhs_bigint = lhs.toBigInt(&lhs_space, mod);1941 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
1953 const rhs_bigint = rhs.toBigInt(&rhs_space, mod);1942 const rhs_bigint = rhs.toBigInt(&rhs_space, zcu);
1954 const limbs = try arena.alloc(1943 const limbs = try arena.alloc(
1955 std.math.big.Limb,1944 std.math.big.Limb,
1956 // + 1 for negatives1945 // + 1 for negatives
...@@ -1958,7 +1947,25 @@ pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod:...@@ -1958,7 +1947,25 @@ pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod:
1958 );1947 );
1959 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };1948 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
1960 result_bigint.bitAnd(lhs_bigint, rhs_bigint);1949 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());
1962}1969}
19631970
1964/// operands must be (vectors of) integers; handles undefined scalars.1971/// 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...@@ -2008,23 +2015,36 @@ pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *M
2008}2015}
20092016
2010/// operands must be integers; handles undefined.2017/// operands must be integers; handles undefined.
2011pub fn bitwiseOrScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value {2018pub fn bitwiseOrScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Allocator, zcu: *Zcu) !Value {
2012 if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.fromInterned((try mod.intern(.{ .undef = ty.toIntern() })));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
2013 if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() or rhs.toBool());2033 if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() or rhs.toBool());
20142034
2015 // TODO is this a performance issue? maybe we should try the operation without2035 // TODO is this a performance issue? maybe we should try the operation without
2016 // resorting to BigInt first.2036 // resorting to BigInt first.
2017 var lhs_space: Value.BigIntSpace = undefined;2037 var lhs_space: Value.BigIntSpace = undefined;
2018 var rhs_space: Value.BigIntSpace = undefined;2038 var rhs_space: Value.BigIntSpace = undefined;
2019 const lhs_bigint = lhs.toBigInt(&lhs_space, mod);2039 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
2020 const rhs_bigint = rhs.toBigInt(&rhs_space, mod);2040 const rhs_bigint = rhs.toBigInt(&rhs_space, zcu);
2021 const limbs = try arena.alloc(2041 const limbs = try arena.alloc(
2022 std.math.big.Limb,2042 std.math.big.Limb,
2023 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),2043 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
2024 );2044 );
2025 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };2045 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
2026 result_bigint.bitOr(lhs_bigint, rhs_bigint);2046 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());
2028}2048}
20292049
2030/// operands must be (vectors of) integers; handles undefined scalars.2050/// operands must be (vectors of) integers; handles undefined scalars.
...@@ -2439,12 +2459,14 @@ pub fn intTruncScalar(...@@ -2439,12 +2459,14 @@ pub fn intTruncScalar(
2439 allocator: Allocator,2459 allocator: Allocator,
2440 signedness: std.builtin.Signedness,2460 signedness: std.builtin.Signedness,
2441 bits: u16,2461 bits: u16,
2442 mod: *Module,2462 zcu: *Zcu,
2443) !Value {2463) !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
2446 var val_space: Value.BigIntSpace = undefined;2468 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
2449 const limbs = try allocator.alloc(2471 const limbs = try allocator.alloc(
2450 std.math.big.Limb,2472 std.math.big.Limb,
...@@ -2453,7 +2475,7 @@ pub fn intTruncScalar(...@@ -2453,7 +2475,7 @@ pub fn intTruncScalar(
2453 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };2475 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
24542476
2455 result_bigint.truncate(val_bigint, signedness, bits);2477 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());
2457}2479}
24582480
2459pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value {2481pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value {
...@@ -3585,3 +3607,660 @@ pub fn makeBool(x: bool) Value {...@@ -3585,3 +3607,660 @@ pub fn makeBool(x: bool) Value {
3585}3607}
35863608
3587pub const RuntimeIndex = InternPool.RuntimeIndex;3609pub 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...@@ -2206,7 +2206,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
2206 );2206 );
2207 break :blk extern_func.decl;2207 break :blk extern_func.decl;
2208 } else switch (mod.intern_pool.indexToKey(func_val.ip_index)) {2208 } 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) {
2210 .decl => |decl| {2210 .decl => |decl| {
2211 _ = try func.bin_file.getOrCreateAtomForDecl(decl);2211 _ = try func.bin_file.getOrCreateAtomForDecl(decl);
2212 break :blk decl;2212 break :blk decl;
...@@ -3058,72 +3058,59 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {...@@ -3058,72 +3058,59 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
3058 return WValue{ .stack = {} };3058 return WValue{ .stack = {} };
3059}3059}
30603060
3061fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue {3061fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {
3062 const mod = func.bin_file.base.comp.module.?;3062 const zcu = func.bin_file.base.comp.module.?;
3063 const ptr = mod.intern_pool.indexToKey(ptr_val.ip_index).ptr;3063 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
3064 switch (ptr.addr) {3064 const offset: u64 = prev_offset + ptr.byte_offset;
3065 .decl => |decl_index| {3065 return switch (ptr.base_addr) {
3066 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);3066 .decl => |decl| return func.lowerDeclRefValue(decl, @intCast(offset)),
3067 },3067 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, @intCast(offset)),
3068 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, offset),3068 .int => return func.lowerConstant(try zcu.intValue(Type.usize, offset), Type.usize),
3069 .eu_payload => |tag| return func.fail("TODO: Implement lowerParentPtr for {}", .{tag}),3069 .eu_payload => return func.fail("Wasm TODO: lower error union payload pointer", .{}),
3070 .int => |base| return func.lowerConstant(Value.fromInterned(base), Type.usize),3070 .opt_payload => |opt_ptr| return func.lowerPtr(opt_ptr, offset),
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 },
3079 .field => |field| {3071 .field => |field| {
3080 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(field.base));3072 const base_ptr = Value.fromInterned(field.base);
3081 const parent_ty = parent_ptr_ty.childType(mod);3073 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
3082 const field_index: u32 = @intCast(field.index);3074 const field_off: u64 = switch (base_ty.zigTypeTag(zcu)) {
30833075 .Pointer => off: {
3084 const field_offset = switch (parent_ty.zigTypeTag(mod)) {3076 assert(base_ty.isSlice(zcu));
3085 .Struct => blk: {3077 break :off switch (field.index) {
3086 if (mod.typeToPackedStruct(parent_ty)) |struct_type| {3078 Value.slice_ptr_index => 0,
3087 if (Type.fromInterned(ptr.ty).ptrInfo(mod).packed_offset.host_size == 0)3079 Value.slice_len_index => @divExact(zcu.getTarget().ptrBitWidth(), 8),
3088 break :blk @divExact(mod.structPackedFieldBitOffset(struct_type, field_index) + parent_ptr_ty.ptrInfo(mod).packed_offset.bit_offset, 8)3080 else => unreachable,
3089 else3081 };
3090 break :blk 0;
3091 }
3092 break :blk parent_ty.structFieldOffset(field_index, mod);
3093 },3082 },
3094 .Union => switch (parent_ty.containerLayout(mod)) {3083 .Struct => switch (base_ty.containerLayout(zcu)) {
3095 .@"packed" => 0,3084 .auto => base_ty.structFieldOffset(@intCast(field.index), zcu),
3096 else => blk: {3085 .@"extern", .@"packed" => unreachable,
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 },
3104 },3086 },
3105 .Pointer => switch (parent_ty.ptrSize(mod)) {3087 .Union => switch (base_ty.containerLayout(zcu)) {
3106 .Slice => switch (field.index) {3088 .auto => off: {
3107 0 => 0,3089 // Keep in sync with the `un` case of `generateSymbol`.
3108 1 => func.ptrSize(),3090 const layout = base_ty.unionGetLayout(zcu);
3109 else => unreachable,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 }
3110 },3100 },
3111 else => unreachable,3101 .@"extern", .@"packed" => unreachable,
3112 },3102 },
3113 else => unreachable,3103 else => unreachable,
3114 };3104 };
3115 return func.lowerParentPtr(Value.fromInterned(field.base), @as(u32, @intCast(offset + field_offset)));3105 return func.lowerPtr(field.base, offset + field_off);
3116 },3106 },
3117 }3107 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
3118}3108 };
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);
3122}3109}
31233110
3124fn lowerAnonDeclRef(3111fn lowerAnonDeclRef(
3125 func: *CodeGen,3112 func: *CodeGen,
3126 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,3113 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
3127 offset: u32,3114 offset: u32,
3128) InnerError!WValue {3115) InnerError!WValue {
3129 const mod = func.bin_file.base.comp.module.?;3116 const mod = func.bin_file.base.comp.module.?;
...@@ -3153,7 +3140,7 @@ fn lowerAnonDeclRef(...@@ -3153,7 +3140,7 @@ fn lowerAnonDeclRef(
3153 } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } };3140 } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } };
3154}3141}
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 {
3157 const mod = func.bin_file.base.comp.module.?;3144 const mod = func.bin_file.base.comp.module.?;
31583145
3159 const decl = mod.declPtr(decl_index);3146 const decl = mod.declPtr(decl_index);
...@@ -3161,11 +3148,11 @@ fn lowerDeclRefValue(func: *CodeGen, val: Value, decl_index: InternPool.DeclInde...@@ -3161,11 +3148,11 @@ fn lowerDeclRefValue(func: *CodeGen, val: Value, decl_index: InternPool.DeclInde
3161 // want to lower the actual decl, rather than the alias itself.3148 // want to lower the actual decl, rather than the alias itself.
3162 if (decl.val.getFunction(mod)) |func_val| {3149 if (decl.val.getFunction(mod)) |func_val| {
3163 if (func_val.owner_decl != decl_index) {3150 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);
3165 }3152 }
3166 } else if (decl.val.getExternFunc(mod)) |func_val| {3153 } else if (decl.val.getExternFunc(mod)) |func_val| {
3167 if (func_val.decl != decl_index) {3154 if (func_val.decl != decl_index) {
3168 return func.lowerDeclRefValue(val, func_val.decl, offset);3155 return func.lowerDeclRefValue(func_val.decl, offset);
3169 }3156 }
3170 }3157 }
3171 const decl_ty = decl.typeOf(mod);3158 const decl_ty = decl.typeOf(mod);
...@@ -3309,23 +3296,16 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3309,23 +3296,16 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3309 },3296 },
3310 .slice => |slice| {3297 .slice => |slice| {
3311 var ptr = ip.indexToKey(slice.ptr).ptr;3298 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) {
3313 .decl => |decl| break decl,3300 .decl => |decl| break decl,
3314 .int, .anon_decl => return func.fail("Wasm TODO: lower slice where ptr is not owned by decl", .{}),3301 .int, .anon_decl => return func.fail("Wasm TODO: lower slice where ptr is not owned by decl", .{}),
3315 .opt_payload, .eu_payload => |base| ptr = ip.indexToKey(base).ptr,3302 .opt_payload, .eu_payload => |base| ptr = ip.indexToKey(base).ptr,
3316 .elem, .field => |base_index| ptr = ip.indexToKey(base_index.base).ptr,3303 .field => |base_index| ptr = ip.indexToKey(base_index.base).ptr,
3317 .comptime_field, .comptime_alloc => unreachable,3304 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
3318 };3305 };
3319 return .{ .memory = try func.bin_file.lowerUnnamedConst(val, owner_decl) };3306 return .{ .memory = try func.bin_file.lowerUnnamedConst(val, owner_decl) };
3320 },3307 },
3321 .ptr => |ptr| switch (ptr.addr) {3308 .ptr => return func.lowerPtr(val.toIntern(), 0),
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 },
3329 .opt => if (ty.optionalReprIsPayload(mod)) {3309 .opt => if (ty.optionalReprIsPayload(mod)) {
3330 const pl_ty = ty.optionalChild(mod);3310 const pl_ty = ty.optionalChild(mod);
3331 if (val.optionalValue(mod)) |payload| {3311 if (val.optionalValue(mod)) |payload| {
...@@ -3435,7 +3415,10 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 {...@@ -3435,7 +3415,10 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 {
3435 else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {3415 else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {
3436 .enum_tag => |enum_tag| intIndexAsI32(&mod.intern_pool, enum_tag.int, mod),3416 .enum_tag => |enum_tag| intIndexAsI32(&mod.intern_pool, enum_tag.int, mod),
3437 .int => |int| intStorageAsI32(int.storage, mod),3417 .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 },
3439 .err => |err| @as(i32, @bitCast(@as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(err.name).?)))),3422 .err => |err| @as(i32, @bitCast(@as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(err.name).?)))),
3440 else => unreachable,3423 else => unreachable,
3441 },3424 },
src/arch/x86_64/CodeGen.zig+4-4
...@@ -12249,10 +12249,10 @@ fn genCall(self: *Self, info: union(enum) {...@@ -12249,10 +12249,10 @@ fn genCall(self: *Self, info: union(enum) {
12249 const func_key = mod.intern_pool.indexToKey(func_value.ip_index);12249 const func_key = mod.intern_pool.indexToKey(func_value.ip_index);
12250 switch (switch (func_key) {12250 switch (switch (func_key) {
12251 else => func_key,12251 else => func_key,
12252 .ptr => |ptr| switch (ptr.addr) {12252 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
12253 .decl => |decl| mod.intern_pool.indexToKey(mod.declPtr(decl).val.toIntern()),12253 .decl => |decl| mod.intern_pool.indexToKey(mod.declPtr(decl).val.toIntern()),
12254 else => func_key,12254 else => func_key,
12255 },12255 } else func_key,
12256 }) {12256 }) {
12257 .func => |func| {12257 .func => |func| {
12258 if (self.bin_file.cast(link.File.Elf)) |elf_file| {12258 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
...@@ -17877,8 +17877,8 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {...@@ -17877,8 +17877,8 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
1787717877
17878 break :result null;17878 break :result null;
17879 }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{17879 }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{
17880 lhs_ty.fmt(mod), rhs_ty.fmt(mod), dst_ty.fmt(mod),17880 lhs_ty.fmt(mod), rhs_ty.fmt(mod), dst_ty.fmt(mod),
17881 Value.fromInterned(extra.mask).fmtValue(mod),17881 Value.fromInterned(extra.mask).fmtValue(mod, null),
17882 });17882 });
17883 return self.finishAir(inst, result, .{ extra.a, extra.b, .none });17883 return self.finishAir(inst, result, .{ extra.a, extra.b, .none });
17884}17884}
src/codegen.zig+52-82
...@@ -16,7 +16,8 @@ const Compilation = @import("Compilation.zig");...@@ -16,7 +16,8 @@ const Compilation = @import("Compilation.zig");
16const ErrorMsg = Module.ErrorMsg;16const ErrorMsg = Module.ErrorMsg;
17const InternPool = @import("InternPool.zig");17const InternPool = @import("InternPool.zig");
18const Liveness = @import("Liveness.zig");18const Liveness = @import("Liveness.zig");
19const Module = @import("Module.zig");19const Zcu = @import("Module.zig");
20const Module = Zcu;
20const Target = std.Target;21const Target = std.Target;
21const Type = @import("type.zig").Type;22const Type = @import("type.zig").Type;
22const Value = @import("Value.zig");23const Value = @import("Value.zig");
...@@ -185,7 +186,7 @@ pub fn generateSymbol(...@@ -185,7 +186,7 @@ pub fn generateSymbol(
185 const target = mod.getTarget();186 const target = mod.getTarget();
186 const endian = target.cpu.arch.endian();187 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
190 if (val.isUndefDeep(mod)) {191 if (val.isUndefDeep(mod)) {
191 const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow;192 const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow;
...@@ -314,7 +315,7 @@ pub fn generateSymbol(...@@ -314,7 +315,7 @@ pub fn generateSymbol(
314 },315 },
315 .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(16)),316 .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(16)),
316 },317 },
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)) {
318 .ok => {},319 .ok => {},
319 .fail => |em| return .{ .fail = em },320 .fail => |em| return .{ .fail = em },
320 },321 },
...@@ -614,111 +615,79 @@ pub fn generateSymbol(...@@ -614,111 +615,79 @@ pub fn generateSymbol(
614 return .ok;615 return .ok;
615}616}
616617
617fn lowerParentPtr(618fn lowerPtr(
618 bin_file: *link.File,619 bin_file: *link.File,
619 src_loc: Module.SrcLoc,620 src_loc: Module.SrcLoc,
620 parent_ptr: InternPool.Index,621 ptr_val: InternPool.Index,
621 code: *std.ArrayList(u8),622 code: *std.ArrayList(u8),
622 debug_output: DebugInfoOutput,623 debug_output: DebugInfoOutput,
623 reloc_info: RelocInfo,624 reloc_info: RelocInfo,
625 prev_offset: u64,
624) CodeGenError!Result {626) CodeGenError!Result {
625 const mod = bin_file.comp.module.?;627 const zcu = bin_file.comp.module.?;
626 const ip = &mod.intern_pool;628 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
627 const ptr = ip.indexToKey(parent_ptr).ptr;629 const offset: u64 = prev_offset + ptr.byte_offset;
628 return switch (ptr.addr) {630 return switch (ptr.base_addr) {
629 .decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info),631 .decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info, offset),
630 .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info),632 .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info, offset),
631 .int => |int| try generateSymbol(bin_file, src_loc, Value.fromInterned(int), code, debug_output, reloc_info),633 .int => try generateSymbol(bin_file, src_loc, try zcu.intValue(Type.usize, offset), code, debug_output, reloc_info),
632 .eu_payload => |eu_payload| try lowerParentPtr(634 .eu_payload => |eu_ptr| try lowerPtr(
633 bin_file,635 bin_file,
634 src_loc,636 src_loc,
635 eu_payload,637 eu_ptr,
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,
647 code,638 code,
648 debug_output,639 debug_output,
649 reloc_info,640 reloc_info,
641 offset + errUnionPayloadOffset(
642 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu).errorUnionPayload(zcu),
643 zcu,
644 ),
650 ),645 ),
651 .elem => |elem| try lowerParentPtr(646 .opt_payload => |opt_ptr| try lowerPtr(
652 bin_file,647 bin_file,
653 src_loc,648 src_loc,
654 elem.base,649 opt_ptr,
655 code,650 code,
656 debug_output,651 debug_output,
657 reloc_info.offset(@intCast(elem.index *652 reloc_info,
658 Type.fromInterned(ip.typeOf(elem.base)).elemType2(mod).abiSize(mod))),653 offset,
659 ),654 ),
660 .field => |field| {655 .field => |field| {
661 const base_ptr_ty = ip.typeOf(field.base);656 const base_ptr = Value.fromInterned(field.base);
662 const base_ty = ip.indexToKey(base_ptr_ty).ptr_type.child;657 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
663 return lowerParentPtr(658 const field_off: u64 = switch (base_ty.zigTypeTag(zcu)) {
664 bin_file,659 .Pointer => off: {
665 src_loc,660 assert(base_ty.isSlice(zcu));
666 field.base,661 break :off switch (field.index) {
667 code,662 Value.slice_ptr_index => 0,
668 debug_output,663 Value.slice_len_index => @divExact(zcu.getTarget().ptrBitWidth(), 8),
669 reloc_info.offset(switch (ip.indexToKey(base_ty)) {664 else => unreachable,
670 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {665 };
671 .One, .Many, .C => unreachable,666 },
672 .Slice => switch (field.index) {667 .Struct, .Union => switch (base_ty.containerLayout(zcu)) {
673 0 => 0,668 .auto => base_ty.structFieldOffset(@intCast(field.index), zcu),
674 1 => @divExact(mod.getTarget().ptrBitWidth(), 8),669 .@"extern", .@"packed" => unreachable,
675 else => unreachable,670 },
676 },671 else => unreachable,
677 },672 };
678 .struct_type,673 return lowerPtr(bin_file, src_loc, field.base, code, debug_output, reloc_info, offset + field_off);
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 );
701 },674 },
702 .comptime_field, .comptime_alloc => unreachable,675 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
703 };676 };
704}677}
705678
706const RelocInfo = struct {679const RelocInfo = struct {
707 parent_atom_index: u32,680 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 }
713};681};
714682
715fn lowerAnonDeclRef(683fn lowerAnonDeclRef(
716 lf: *link.File,684 lf: *link.File,
717 src_loc: Module.SrcLoc,685 src_loc: Module.SrcLoc,
718 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,686 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
719 code: *std.ArrayList(u8),687 code: *std.ArrayList(u8),
720 debug_output: DebugInfoOutput,688 debug_output: DebugInfoOutput,
721 reloc_info: RelocInfo,689 reloc_info: RelocInfo,
690 offset: u64,
722) CodeGenError!Result {691) CodeGenError!Result {
723 _ = debug_output;692 _ = debug_output;
724 const zcu = lf.comp.module.?;693 const zcu = lf.comp.module.?;
...@@ -745,7 +714,7 @@ fn lowerAnonDeclRef(...@@ -745,7 +714,7 @@ fn lowerAnonDeclRef(
745 const vaddr = try lf.getAnonDeclVAddr(decl_val, .{714 const vaddr = try lf.getAnonDeclVAddr(decl_val, .{
746 .parent_atom_index = reloc_info.parent_atom_index,715 .parent_atom_index = reloc_info.parent_atom_index,
747 .offset = code.items.len,716 .offset = code.items.len,
748 .addend = reloc_info.addend orelse 0,717 .addend = @intCast(offset),
749 });718 });
750 const endian = target.cpu.arch.endian();719 const endian = target.cpu.arch.endian();
751 switch (ptr_width_bytes) {720 switch (ptr_width_bytes) {
...@@ -765,6 +734,7 @@ fn lowerDeclRef(...@@ -765,6 +734,7 @@ fn lowerDeclRef(
765 code: *std.ArrayList(u8),734 code: *std.ArrayList(u8),
766 debug_output: DebugInfoOutput,735 debug_output: DebugInfoOutput,
767 reloc_info: RelocInfo,736 reloc_info: RelocInfo,
737 offset: u64,
768) CodeGenError!Result {738) CodeGenError!Result {
769 _ = src_loc;739 _ = src_loc;
770 _ = debug_output;740 _ = debug_output;
...@@ -783,7 +753,7 @@ fn lowerDeclRef(...@@ -783,7 +753,7 @@ fn lowerDeclRef(
783 const vaddr = try lf.getDeclVAddr(decl_index, .{753 const vaddr = try lf.getDeclVAddr(decl_index, .{
784 .parent_atom_index = reloc_info.parent_atom_index,754 .parent_atom_index = reloc_info.parent_atom_index,
785 .offset = code.items.len,755 .offset = code.items.len,
786 .addend = reloc_info.addend orelse 0,756 .addend = @intCast(offset),
787 });757 });
788 const endian = target.cpu.arch.endian();758 const endian = target.cpu.arch.endian();
789 switch (ptr_width) {759 switch (ptr_width) {
...@@ -861,7 +831,7 @@ fn genDeclRef(...@@ -861,7 +831,7 @@ fn genDeclRef(
861 const zcu = lf.comp.module.?;831 const zcu = lf.comp.module.?;
862 const ip = &zcu.intern_pool;832 const ip = &zcu.intern_pool;
863 const ty = val.typeOf(zcu);833 const ty = val.typeOf(zcu);
864 log.debug("genDeclRef: val = {}", .{val.fmtValue(zcu)});834 log.debug("genDeclRef: val = {}", .{val.fmtValue(zcu, null)});
865835
866 const ptr_decl = zcu.declPtr(ptr_decl_index);836 const ptr_decl = zcu.declPtr(ptr_decl_index);
867 const namespace = zcu.namespacePtr(ptr_decl.src_namespace);837 const namespace = zcu.namespacePtr(ptr_decl.src_namespace);
...@@ -966,7 +936,7 @@ fn genUnnamedConst(...@@ -966,7 +936,7 @@ fn genUnnamedConst(
966) CodeGenError!GenResult {936) CodeGenError!GenResult {
967 const zcu = lf.comp.module.?;937 const zcu = lf.comp.module.?;
968 const gpa = lf.comp.gpa;938 const gpa = lf.comp.gpa;
969 log.debug("genUnnamedConst: val = {}", .{val.fmtValue(zcu)});939 log.debug("genUnnamedConst: val = {}", .{val.fmtValue(zcu, null)});
970940
971 const local_sym_index = lf.lowerUnnamedConst(val, owner_decl_index) catch |err| {941 const local_sym_index = lf.lowerUnnamedConst(val, owner_decl_index) catch |err| {
972 return GenResult.fail(gpa, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)});942 return GenResult.fail(gpa, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)});
...@@ -1007,7 +977,7 @@ pub fn genTypedValue(...@@ -1007,7 +977,7 @@ pub fn genTypedValue(
1007 const ip = &zcu.intern_pool;977 const ip = &zcu.intern_pool;
1008 const ty = val.typeOf(zcu);978 const ty = val.typeOf(zcu);
1009979
1010 log.debug("genTypedValue: val = {}", .{val.fmtValue(zcu)});980 log.debug("genTypedValue: val = {}", .{val.fmtValue(zcu, null)});
1011981
1012 if (val.isUndef(zcu))982 if (val.isUndef(zcu))
1013 return GenResult.mcv(.undef);983 return GenResult.mcv(.undef);
...@@ -1018,7 +988,7 @@ pub fn genTypedValue(...@@ -1018,7 +988,7 @@ pub fn genTypedValue(
1018 const ptr_bits = target.ptrBitWidth();988 const ptr_bits = target.ptrBitWidth();
1019989
1020 if (!ty.isSlice(zcu)) switch (ip.indexToKey(val.toIntern())) {990 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) {
1022 .decl => |decl| return genDeclRef(lf, src_loc, val, decl),992 .decl => |decl| return genDeclRef(lf, src_loc, val, decl),
1023 else => {},993 else => {},
1024 },994 },
src/codegen/c.zig+96-124
...@@ -646,8 +646,7 @@ pub const DeclGen = struct {...@@ -646,8 +646,7 @@ pub const DeclGen = struct {
646 fn renderAnonDeclValue(646 fn renderAnonDeclValue(
647 dg: *DeclGen,647 dg: *DeclGen,
648 writer: anytype,648 writer: anytype,
649 ptr_val: Value,649 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
650 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
651 location: ValueRenderLocation,650 location: ValueRenderLocation,
652 ) error{ OutOfMemory, AnalysisFail }!void {651 ) error{ OutOfMemory, AnalysisFail }!void {
653 const zcu = dg.zcu;652 const zcu = dg.zcu;
...@@ -657,16 +656,16 @@ pub const DeclGen = struct {...@@ -657,16 +656,16 @@ pub const DeclGen = struct {
657 const decl_ty = decl_val.typeOf(zcu);656 const decl_ty = decl_val.typeOf(zcu);
658657
659 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.658 // 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);
661 if (ptr_ty.isPtrAtRuntime(zcu) and !decl_ty.isFnOrHasRuntimeBits(zcu)) {660 if (ptr_ty.isPtrAtRuntime(zcu) and !decl_ty.isFnOrHasRuntimeBits(zcu)) {
662 return dg.writeCValue(writer, .{ .undef = ptr_ty });661 return dg.writeCValue(writer, .{ .undef = ptr_ty });
663 }662 }
664663
665 // Chase function values in order to be able to reference the original function.664 // Chase function values in order to be able to reference the original function.
666 if (decl_val.getFunction(zcu)) |func|665 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);
668 if (decl_val.getExternFunc(zcu)) |extern_func|667 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
671 assert(decl_val.getVariable(zcu) == null);670 assert(decl_val.getVariable(zcu) == null);
672671
...@@ -712,7 +711,6 @@ pub const DeclGen = struct {...@@ -712,7 +711,6 @@ pub const DeclGen = struct {
712 fn renderDeclValue(711 fn renderDeclValue(
713 dg: *DeclGen,712 dg: *DeclGen,
714 writer: anytype,713 writer: anytype,
715 val: Value,
716 decl_index: InternPool.DeclIndex,714 decl_index: InternPool.DeclIndex,
717 location: ValueRenderLocation,715 location: ValueRenderLocation,
718 ) error{ OutOfMemory, AnalysisFail }!void {716 ) error{ OutOfMemory, AnalysisFail }!void {
...@@ -722,17 +720,17 @@ pub const DeclGen = struct {...@@ -722,17 +720,17 @@ pub const DeclGen = struct {
722 assert(decl.has_tv);720 assert(decl.has_tv);
723721
724 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.722 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
725 const ty = val.typeOf(zcu);
726 const decl_ty = decl.typeOf(zcu);723 const decl_ty = decl.typeOf(zcu);
727 if (ty.isPtrAtRuntime(zcu) and !decl_ty.isFnOrHasRuntimeBits(zcu)) {724 const ptr_ty = try decl.declPtrType(zcu);
728 return dg.writeCValue(writer, .{ .undef = ty });725 if (!decl_ty.isFnOrHasRuntimeBits(zcu)) {
726 return dg.writeCValue(writer, .{ .undef = ptr_ty });
729 }727 }
730728
731 // Chase function values in order to be able to reference the original function.729 // Chase function values in order to be able to reference the original function.
732 if (decl.val.getFunction(zcu)) |func| if (func.owner_decl != decl_index)730 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);
734 if (decl.val.getExternFunc(zcu)) |extern_func| if (extern_func.decl != decl_index)732 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
737 if (decl.val.getVariable(zcu)) |variable| try dg.renderFwdDecl(decl_index, variable, .tentative);735 if (decl.val.getVariable(zcu)) |variable| try dg.renderFwdDecl(decl_index, variable, .tentative);
738736
...@@ -740,7 +738,7 @@ pub const DeclGen = struct {...@@ -740,7 +738,7 @@ pub const DeclGen = struct {
740 // them). The analysis until now should ensure that the C function738 // them). The analysis until now should ensure that the C function
741 // pointers are compatible. If they are not, then there is a bug739 // pointers are compatible. If they are not, then there is a bug
742 // somewhere and we should let the C compiler tell us about it.740 // 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);
744 const elem_ctype = ctype.info(ctype_pool).pointer.elem_ctype;742 const elem_ctype = ctype.info(ctype_pool).pointer.elem_ctype;
745 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);743 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
746 const need_cast = !elem_ctype.eql(decl_ctype) and744 const need_cast = !elem_ctype.eql(decl_ctype) and
...@@ -755,125 +753,108 @@ pub const DeclGen = struct {...@@ -755,125 +753,108 @@ pub const DeclGen = struct {
755 if (need_cast) try writer.writeByte(')');753 if (need_cast) try writer.writeByte(')');
756 }754 }
757755
758 /// Renders a "parent" pointer by recursing to the root decl/variable756 fn renderPointer(
759 /// that its contents are defined with respect to.
760 fn renderParentPtr(
761 dg: *DeclGen,757 dg: *DeclGen,
762 writer: anytype,758 writer: anytype,
763 ptr_val: InternPool.Index,759 derivation: Value.PointerDeriveStep,
764 location: ValueRenderLocation,760 location: ValueRenderLocation,
765 ) error{ OutOfMemory, AnalysisFail }!void {761 ) error{ OutOfMemory, AnalysisFail }!void {
766 const zcu = dg.zcu;762 const zcu = dg.zcu;
767 const ip = &zcu.intern_pool;763 switch (derivation) {
768 const ptr_ty = Type.fromInterned(ip.typeOf(ptr_val));764 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
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),
775 .int => |int| {765 .int => |int| {
766 const ptr_ctype = try dg.ctypeFromType(int.ptr_ty, .complete);
767 const addr_val = try zcu.intValue(Type.usize, int.addr);
776 try writer.writeByte('(');768 try writer.writeByte('(');
777 try dg.renderCType(writer, ptr_ctype);769 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)});
779 },771 },
780 .eu_payload, .opt_payload => |base| {772
781 const ptr_base_ty = Type.fromInterned(ip.typeOf(base));773 .decl_ptr => |decl| try dg.renderDeclValue(writer, decl, location),
782 const base_ty = ptr_base_ty.childType(zcu);774 .anon_decl_ptr => |ad| try dg.renderAnonDeclValue(writer, ad, location),
783 // Ensure complete type definition is visible before accessing fields.775
784 _ = try dg.ctypeFromType(base_ty, .complete);776 inline .eu_payload_ptr, .opt_payload_ptr => |info| {
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 }
796 try writer.writeAll("&(");777 try writer.writeAll("&(");
797 try dg.renderParentPtr(writer, base, location);778 try dg.renderPointer(writer, info.parent.*, location);
798 try writer.writeAll(")->payload");779 try writer.writeAll(")->payload");
799 },780 },
800 .elem => |elem| {781
801 const ptr_base_ty = Type.fromInterned(ip.typeOf(elem.base));782 .field_ptr => |field| {
802 const elem_ty = ptr_base_ty.elemType2(zcu);783 const parent_ptr_ty = try field.parent.ptrType(zcu);
803 const elem_ctype = try dg.ctypeFromType(elem_ty, .forward);784
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);
818 // Ensure complete type definition is available before accessing fields.785 // Ensure complete type definition is available before accessing fields.
819 _ = try dg.ctypeFromType(base_ty, .complete);786 _ = try dg.ctypeFromType(parent_ptr_ty.childType(zcu), .complete);
820 switch (fieldLocation(ptr_base_ty, ptr_ty, @as(u32, @intCast(field.index)), zcu)) {787
788 switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, zcu)) {
821 .begin => {789 .begin => {
822 const ptr_base_ctype = try dg.ctypeFromType(ptr_base_ty, .complete);790 const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
823 if (!ptr_ctype.eql(ptr_base_ctype)) {791 try writer.writeByte('(');
824 try writer.writeByte('(');792 try dg.renderCType(writer, ptr_ctype);
825 try dg.renderCType(writer, ptr_ctype);793 try writer.writeByte(')');
826 try writer.writeByte(')');794 try dg.renderPointer(writer, field.parent.*, location);
827 }
828 try dg.renderParentPtr(writer, field.base, location);
829 },795 },
830 .field => |name| {796 .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 }
852 try writer.writeAll("&(");797 try writer.writeAll("&(");
853 try dg.renderParentPtr(writer, field.base, location);798 try dg.renderPointer(writer, field.parent.*, location);
854 try writer.writeAll(")->");799 try writer.writeAll(")->");
855 try dg.writeCValue(writer, name);800 try dg.writeCValue(writer, name);
856 },801 },
857 .byte_offset => |byte_offset| {802 .byte_offset => |byte_offset| {
858 const u8_ptr_ty = try zcu.adjustPtrTypeChild(ptr_ty, Type.u8);803 const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
859 const u8_ptr_ctype = try dg.ctypeFromType(u8_ptr_ty, .complete);804 try writer.writeByte('(');
860805 try dg.renderCType(writer, ptr_ctype);
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);
868 try writer.writeByte(')');806 try writer.writeByte(')');
869 try dg.renderParentPtr(writer, field.base, location);807 const offset_val = try zcu.intValue(Type.usize, byte_offset);
870 try writer.print(" + {})", .{808 try writer.writeAll("((char *)");
871 try dg.fmtIntLiteral(try zcu.intValue(Type.usize, byte_offset), .Other),809 try dg.renderPointer(writer, field.parent.*, location);
872 });810 try writer.print(" + {})", .{try dg.fmtIntLiteral(offset_val, .Other)});
873 },811 },
874 }812 }
875 },813 },
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 },
877 }858 }
878 }859 }
879860
...@@ -1103,20 +1084,11 @@ pub const DeclGen = struct {...@@ -1103,20 +1084,11 @@ pub const DeclGen = struct {
1103 }1084 }
1104 try writer.writeByte('}');1085 try writer.writeByte('}');
1105 },1086 },
1106 .ptr => |ptr| switch (ptr.addr) {1087 .ptr => {
1107 .decl => |d| try dg.renderDeclValue(writer, val, d, location),1088 var arena = std.heap.ArenaAllocator.init(zcu.gpa);
1108 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, val, decl_val, location),1089 defer arena.deinit();
1109 .int => |int| {1090 const derivation = try val.pointerDerivation(arena.allocator(), zcu);
1110 try writer.writeAll("((");1091 try dg.renderPointer(writer, derivation, location);
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,
1120 },1092 },
1121 .opt => |opt| switch (ctype.info(ctype_pool)) {1093 .opt => |opt| switch (ctype.info(ctype_pool)) {
1122 .basic => if (ctype.isBool()) try writer.writeAll(switch (opt.val) {1094 .basic => if (ctype.isBool()) try writer.writeAll(switch (opt.val) {
...@@ -4574,10 +4546,10 @@ fn airCall(...@@ -4574,10 +4546,10 @@ fn airCall(
4574 break :fn_decl switch (zcu.intern_pool.indexToKey(callee_val.toIntern())) {4546 break :fn_decl switch (zcu.intern_pool.indexToKey(callee_val.toIntern())) {
4575 .extern_func => |extern_func| extern_func.decl,4547 .extern_func => |extern_func| extern_func.decl,
4576 .func => |func| func.owner_decl,4548 .func => |func| func.owner_decl,
4577 .ptr => |ptr| switch (ptr.addr) {4549 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
4578 .decl => |decl| decl,4550 .decl => |decl| decl,
4579 else => break :known,4551 else => break :known,
4580 },4552 } else break :known,
4581 else => break :known,4553 else => break :known,
4582 };4554 };
4583 };4555 };
...@@ -5147,10 +5119,10 @@ fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool...@@ -5147,10 +5119,10 @@ fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool
5147 'I' => !target.cpu.arch.isArmOrThumb(),5119 'I' => !target.cpu.arch.isArmOrThumb(),
5148 else => switch (value) {5120 else => switch (value) {
5149 .constant => |val| switch (f.object.dg.zcu.intern_pool.indexToKey(val.toIntern())) {5121 .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) {
5151 .decl => false,5123 .decl => false,
5152 else => true,5124 else => true,
5153 },5125 } else true,
5154 else => true,5126 else => true,
5155 },5127 },
5156 else => false,5128 else => false,
src/codegen/llvm.zig+66-157
...@@ -3262,6 +3262,7 @@ pub const Object = struct {...@@ -3262,6 +3262,7 @@ pub const Object = struct {
3262 try o.lowerType(Type.fromInterned(vector_type.child)),3262 try o.lowerType(Type.fromInterned(vector_type.child)),
3263 ),3263 ),
3264 .opt_type => |child_ty| {3264 .opt_type => |child_ty| {
3265 // Must stay in sync with `opt_payload` logic in `lowerPtr`.
3265 if (!Type.fromInterned(child_ty).hasRuntimeBitsIgnoreComptime(mod)) return .i8;3266 if (!Type.fromInterned(child_ty).hasRuntimeBitsIgnoreComptime(mod)) return .i8;
32663267
3267 const payload_ty = try o.lowerType(Type.fromInterned(child_ty));3268 const payload_ty = try o.lowerType(Type.fromInterned(child_ty));
...@@ -3281,6 +3282,8 @@ pub const Object = struct {...@@ -3281,6 +3282,8 @@ pub const Object = struct {
3281 },3282 },
3282 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),3283 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
3283 .error_union_type => |error_union_type| {3284 .error_union_type => |error_union_type| {
3285 // Must stay in sync with `codegen.errUnionPayloadOffset`.
3286 // See logic in `lowerPtr`.
3284 const error_type = try o.errorIntType();3287 const error_type = try o.errorIntType();
3285 if (!Type.fromInterned(error_union_type.payload_type).hasRuntimeBitsIgnoreComptime(mod))3288 if (!Type.fromInterned(error_union_type.payload_type).hasRuntimeBitsIgnoreComptime(mod))
3286 return error_type;3289 return error_type;
...@@ -3792,17 +3795,7 @@ pub const Object = struct {...@@ -3792,17 +3795,7 @@ pub const Object = struct {
3792 128 => try o.builder.fp128Const(val.toFloat(f128, mod)),3795 128 => try o.builder.fp128Const(val.toFloat(f128, mod)),
3793 else => unreachable,3796 else => unreachable,
3794 },3797 },
3795 .ptr => |ptr| return switch (ptr.addr) {3798 .ptr => try o.lowerPtr(arg_val, 0),
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 },
3806 .slice => |slice| return o.builder.structConst(try o.lowerType(ty), &.{3799 .slice => |slice| return o.builder.structConst(try o.lowerType(ty), &.{
3807 try o.lowerValue(slice.ptr),3800 try o.lowerValue(slice.ptr),
3808 try o.lowerValue(slice.len),3801 try o.lowerValue(slice.len),
...@@ -4223,20 +4216,6 @@ pub const Object = struct {...@@ -4223,20 +4216,6 @@ pub const Object = struct {
4223 };4216 };
4224 }4217 }
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
4240 fn lowerBigInt(4219 fn lowerBigInt(
4241 o: *Object,4220 o: *Object,
4242 ty: Type,4221 ty: Type,
...@@ -4246,129 +4225,60 @@ pub const Object = struct {...@@ -4246,129 +4225,60 @@ pub const Object = struct {
4246 return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint);4225 return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint);
4247 }4226 }
42484227
4249 fn lowerParentPtrDecl(o: *Object, decl_index: InternPool.DeclIndex) Allocator.Error!Builder.Constant {4228 fn lowerPtr(
4250 const mod = o.module;4229 o: *Object,
4251 const decl = mod.declPtr(decl_index);4230 ptr_val: InternPool.Index,
4252 const ptr_ty = try mod.singleMutPtrType(decl.typeOf(mod));4231 prev_offset: u64,
4253 return o.lowerDeclRefValue(ptr_ty, decl_index);4232 ) Error!Builder.Constant {
4254 }4233 const zcu = o.module;
42554234 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
4256 fn lowerParentPtr(o: *Object, ptr_val: Value) Error!Builder.Constant {4235 const offset: u64 = prev_offset + ptr.byte_offset;
4257 const mod = o.module;4236 return switch (ptr.base_addr) {
4258 const ip = &mod.intern_pool;4237 .decl => |decl| {
4259 const ptr = ip.indexToKey(ptr_val.toIntern()).ptr;4238 const base_ptr = try o.lowerDeclRefValue(decl);
4260 return switch (ptr.addr) {4239 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
4261 .decl => |decl| try o.lowerParentPtrDecl(decl),4240 try o.builder.intConst(.i64, offset),
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),
4281 });4241 });
4282 },4242 },
4283 .opt_payload => |opt_ptr| {4243 .anon_decl => |ad| {
4284 const parent_ptr = try o.lowerParentPtr(Value.fromInterned(opt_ptr));4244 const base_ptr = try o.lowerAnonDeclRef(ad);
42854245 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
4286 const opt_ty = Type.fromInterned(ip.typeOf(opt_ptr)).childType(mod);4246 try o.builder.intConst(.i64, offset),
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),
4305 });4247 });
4306 },4248 },
4307 .field => |field_ptr| {4249 .int => try o.builder.castConst(
4308 const parent_ptr = try o.lowerParentPtr(Value.fromInterned(field_ptr.base));4250 .inttoptr,
4309 const parent_ptr_ty = Type.fromInterned(ip.typeOf(field_ptr.base));4251 try o.builder.intConst(try o.lowerType(Type.usize), offset),
4310 const parent_ty = parent_ptr_ty.childType(mod);4252 .ptr,
4311 const field_index: u32 = @intCast(field_ptr.index);4253 ),
4312 switch (parent_ty.zigTypeTag(mod)) {4254 .eu_payload => |eu_ptr| try o.lowerPtr(
4313 .Union => {4255 eu_ptr,
4314 if (parent_ty.containerLayout(mod) == .@"packed") {4256 offset + @import("../codegen.zig").errUnionPayloadOffset(
4315 return parent_ptr;4257 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),
4316 }4258 zcu,
43174259 ),
4318 const layout = parent_ty.unionGetLayout(mod);4260 ),
4319 if (layout.payload_size == 0) {4261 .opt_payload => |opt_ptr| try o.lowerPtr(opt_ptr, offset),
4320 // In this case a pointer to the union and a pointer to any4262 .field => |field| {
4321 // (void) payload is the same.4263 const agg_ty = Value.fromInterned(field.base).typeOf(zcu).childType(zcu);
4322 return parent_ptr;4264 const field_off: u64 = switch (agg_ty.zigTypeTag(zcu)) {
4323 }4265 .Pointer => off: {
43244266 assert(agg_ty.isSlice(zcu));
4325 const parent_llvm_ty = try o.lowerType(parent_ty);4267 break :off switch (field.index) {
4326 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{4268 Value.slice_ptr_index => 0,
4327 .@"0",4269 Value.slice_len_index => @divExact(zcu.getTarget().ptrBitWidth(), 8),
4328 try o.builder.intConst(.i32, @intFromBool(4270 else => unreachable,
4329 layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align),4271 };
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 );
4361 },4272 },
4362 .Pointer => {4273 .Struct, .Union => switch (agg_ty.containerLayout(zcu)) {
4363 assert(parent_ty.isSlice(mod));4274 .auto => agg_ty.structFieldOffset(@intCast(field.index), zcu),
4364 const parent_llvm_ty = try o.lowerType(parent_ty);4275 .@"extern", .@"packed" => unreachable,
4365 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4366 .@"0", try o.builder.intConst(.i32, field_index),
4367 });
4368 },4276 },
4369 else => unreachable,4277 else => unreachable,
4370 }4278 };
4279 return o.lowerPtr(field.base, offset + field_off);
4371 },4280 },
4281 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
4372 };4282 };
4373 }4283 }
43744284
...@@ -4376,8 +4286,7 @@ pub const Object = struct {...@@ -4376,8 +4286,7 @@ pub const Object = struct {
4376 /// Maybe the logic could be unified.4286 /// Maybe the logic could be unified.
4377 fn lowerAnonDeclRef(4287 fn lowerAnonDeclRef(
4378 o: *Object,4288 o: *Object,
4379 ptr_ty: Type,4289 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
4380 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
4381 ) Error!Builder.Constant {4290 ) Error!Builder.Constant {
4382 const mod = o.module;4291 const mod = o.module;
4383 const ip = &mod.intern_pool;4292 const ip = &mod.intern_pool;
...@@ -4393,6 +4302,8 @@ pub const Object = struct {...@@ -4393,6 +4302,8 @@ pub const Object = struct {
4393 @panic("TODO");4302 @panic("TODO");
4394 }4303 }
43954304
4305 const ptr_ty = Type.fromInterned(anon_decl.orig_ty);
4306
4396 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;4307 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
4397 if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or4308 if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or
4398 (is_fn_body and mod.typeToFunc(decl_ty).?.is_generic)) return o.lowerPtrToVoid(ptr_ty);4309 (is_fn_body and mod.typeToFunc(decl_ty).?.is_generic)) return o.lowerPtrToVoid(ptr_ty);
...@@ -4400,9 +4311,8 @@ pub const Object = struct {...@@ -4400,9 +4311,8 @@ pub const Object = struct {
4400 if (is_fn_body)4311 if (is_fn_body)
4401 @panic("TODO");4312 @panic("TODO");
44024313
4403 const orig_ty = Type.fromInterned(anon_decl.orig_ty);4314 const llvm_addr_space = toLlvmAddressSpace(ptr_ty.ptrAddressSpace(mod), target);
4404 const llvm_addr_space = toLlvmAddressSpace(orig_ty.ptrAddressSpace(mod), target);4315 const alignment = ptr_ty.ptrAlignment(mod);
4405 const alignment = orig_ty.ptrAlignment(mod);
4406 const llvm_global = (try o.resolveGlobalAnonDecl(decl_val, llvm_addr_space, alignment)).ptrConst(&o.builder).global;4316 const llvm_global = (try o.resolveGlobalAnonDecl(decl_val, llvm_addr_space, alignment)).ptrConst(&o.builder).global;
44074317
4408 const llvm_val = try o.builder.convConst(4318 const llvm_val = try o.builder.convConst(
...@@ -4411,13 +4321,10 @@ pub const Object = struct {...@@ -4411,13 +4321,10 @@ pub const Object = struct {
4411 try o.builder.ptrType(llvm_addr_space),4321 try o.builder.ptrType(llvm_addr_space),
4412 );4322 );
44134323
4414 return o.builder.convConst(if (ptr_ty.isAbiInt(mod)) switch (ptr_ty.intInfo(mod).signedness) {4324 return o.builder.convConst(.unneeded, llvm_val, try o.lowerType(ptr_ty));
4415 .signed => .signed,
4416 .unsigned => .unsigned,
4417 } else .unneeded, llvm_val, try o.lowerType(ptr_ty));
4418 }4325 }
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 {
4421 const mod = o.module;4328 const mod = o.module;
44224329
4423 // In the case of something like:4330 // In the case of something like:
...@@ -4428,18 +4335,23 @@ pub const Object = struct {...@@ -4428,18 +4335,23 @@ pub const Object = struct {
4428 const decl = mod.declPtr(decl_index);4335 const decl = mod.declPtr(decl_index);
4429 if (decl.val.getFunction(mod)) |func| {4336 if (decl.val.getFunction(mod)) |func| {
4430 if (func.owner_decl != decl_index) {4337 if (func.owner_decl != decl_index) {
4431 return o.lowerDeclRefValue(ty, func.owner_decl);4338 return o.lowerDeclRefValue(func.owner_decl);
4432 }4339 }
4433 } else if (decl.val.getExternFunc(mod)) |func| {4340 } else if (decl.val.getExternFunc(mod)) |func| {
4434 if (func.decl != decl_index) {4341 if (func.decl != decl_index) {
4435 return o.lowerDeclRefValue(ty, func.decl);4342 return o.lowerDeclRefValue(func.decl);
4436 }4343 }
4437 }4344 }
44384345
4439 const decl_ty = decl.typeOf(mod);4346 const decl_ty = decl.typeOf(mod);
4347 const ptr_ty = try decl.declPtrType(mod);
4348
4440 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;4349 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
4441 if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or4350 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
4444 const llvm_global = if (is_fn_body)4356 const llvm_global = if (is_fn_body)
4445 (try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global4357 (try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global
...@@ -4452,10 +4364,7 @@ pub const Object = struct {...@@ -4452,10 +4364,7 @@ pub const Object = struct {
4452 try o.builder.ptrType(toLlvmAddressSpace(decl.@"addrspace", mod.getTarget())),4364 try o.builder.ptrType(toLlvmAddressSpace(decl.@"addrspace", mod.getTarget())),
4453 );4365 );
44544366
4455 return o.builder.convConst(if (ty.isAbiInt(mod)) switch (ty.intInfo(mod).signedness) {4367 return o.builder.convConst(.unneeded, llvm_val, try o.lowerType(ptr_ty));
4456 .signed => .signed,
4457 .unsigned => .unsigned,
4458 } else .unneeded, llvm_val, try o.lowerType(ty));
4459 }4368 }
44604369
4461 fn lowerPtrToVoid(o: *Object, ptr_ty: Type) Allocator.Error!Builder.Constant {4370 fn lowerPtrToVoid(o: *Object, ptr_ty: Type) Allocator.Error!Builder.Constant {
src/codegen/spirv.zig+80-52
...@@ -863,7 +863,7 @@ const DeclGen = struct {...@@ -863,7 +863,7 @@ const DeclGen = struct {
863 const result_ty_id = try self.resolveType(ty, repr);863 const result_ty_id = try self.resolveType(ty, repr);
864 const ip = &mod.intern_pool;864 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) });
867 if (val.isUndefDeep(mod)) {867 if (val.isUndefDeep(mod)) {
868 return self.spv.constUndef(result_ty_id);868 return self.spv.constUndef(result_ty_id);
869 }869 }
...@@ -983,10 +983,10 @@ const DeclGen = struct {...@@ -983,10 +983,10 @@ const DeclGen = struct {
983 const int_ty = ty.intTagType(mod);983 const int_ty = ty.intTagType(mod);
984 break :cache try self.constant(int_ty, int_val, repr);984 break :cache try self.constant(int_ty, int_val, repr);
985 },985 },
986 .ptr => return self.constantPtr(ty, val),986 .ptr => return self.constantPtr(val),
987 .slice => |slice| {987 .slice => |slice| {
988 const ptr_ty = ty.slicePtrFieldType(mod);988 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));
990 const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);990 const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);
991 return self.constructStruct(991 return self.constructStruct(
992 ty,992 ty,
...@@ -1107,62 +1107,86 @@ const DeclGen = struct {...@@ -1107,62 +1107,86 @@ const DeclGen = struct {
1107 return cacheable_id;1107 return cacheable_id;
1108 }1108 }
11091109
1110 fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) Error!IdRef {1110 fn constantPtr(self: *DeclGen, ptr_val: Value) Error!IdRef {
1111 // TODO: Caching??1111 // TODO: Caching??
11121112
1113 const result_ty_id = try self.resolveType(ptr_ty, .direct);1113 const zcu = self.module;
1114 const mod = 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) {1124 const derivation = try ptr_val.pointerDerivation(arena.allocator(), zcu);
1119 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),1125 return self.derivePtr(derivation);
1120 .anon_decl => |anon_decl| return try self.constantAnonDeclRef(ptr_ty, anon_decl),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,
1121 .int => |int| {1132 .int => |int| {
1122 const ptr_id = self.spv.allocId();1133 const result_ty_id = try self.resolveType(int.ptr_ty, .direct);
1123 // TODO: This can probably be an OpSpecConstantOp Bitcast, but1134 // TODO: This can probably be an OpSpecConstantOp Bitcast, but
1124 // that is not implemented by Mesa yet. Therefore, just generate it1135 // that is not implemented by Mesa yet. Therefore, just generate it
1125 // as a runtime operation.1136 // as a runtime operation.
1137 const result_ptr_id = self.spv.allocId();
1126 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{1138 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
1127 .id_result_type = result_ty_id,1139 .id_result_type = result_ty_id,
1128 .id_result = ptr_id,1140 .id_result = result_ptr_id,
1129 .integer_value = try self.constant(Type.usize, Value.fromInterned(int), .direct),1141 .integer_value = try self.constant(Type.usize, try zcu.intValue(Type.usize, int.addr), .direct),
1130 });1142 });
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);
1132 },1148 },
1133 .eu_payload => unreachable, // TODO1149 .anon_decl_ptr => |ad| {
1134 .opt_payload => unreachable, // TODO1150 const result_ptr_ty = Type.fromInterned(ad.orig_ty);
1135 .comptime_field, .comptime_alloc => unreachable,1151 return self.constantAnonDeclRef(result_ptr_ty, ad);
1136 .elem => |elem_ptr| {1152 },
1137 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));1153 .eu_payload_ptr => @panic("TODO"),
1138 const parent_ptr_id = try self.constantPtr(parent_ptr_ty, Value.fromInterned(elem_ptr.base));1154 .opt_payload_ptr => @panic("TODO"),
1139 const index_id = try self.constInt(Type.usize, elem_ptr.index, .direct);1155 .field_ptr => |field| {
11401156 const parent_ptr_id = try self.derivePtr(field.parent.*);
1141 const elem_ptr_id = try self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);1157 const parent_ptr_ty = try field.parent.ptrType(zcu);
11421158 return self.structFieldPtr(field.result_ptr_ty, parent_ptr_ty, parent_ptr_id, field.field_idx);
1143 // TODO: Can we consolidate this in ptrElemPtr?1159 },
1144 const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T.1160 .elem_ptr => |elem| {
1145 const elem_ptr_ty_id = try self.ptrType(elem_ty, self.spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod)));1161 const parent_ptr_id = try self.derivePtr(elem.parent.*);
11461162 const parent_ptr_ty = try elem.parent.ptrType(zcu);
1147 // TODO: Can we remove this ID comparison?1163 const index_id = try self.constInt(Type.usize, elem.elem_idx, .direct);
1148 if (elem_ptr_ty_id == result_ty_id) {1164 return self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);
1149 return elem_ptr_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;
1150 }1185 }
1151 // This may happen when we have pointer-to-array and the result is1186 return self.fail("Cannot perform pointer cast: '{}' to '{}'", .{
1152 // another pointer-to-array instead of a pointer-to-element.1187 parent_ptr_ty.fmt(zcu),
1153 const result_id = self.spv.allocId();1188 oac.new_ptr_ty.fmt(zcu),
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,
1158 });1189 });
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);
1166 },1190 },
1167 }1191 }
1168 }1192 }
...@@ -1170,7 +1194,7 @@ const DeclGen = struct {...@@ -1170,7 +1194,7 @@ const DeclGen = struct {
1170 fn constantAnonDeclRef(1194 fn constantAnonDeclRef(
1171 self: *DeclGen,1195 self: *DeclGen,
1172 ty: Type,1196 ty: Type,
1173 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,1197 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
1174 ) !IdRef {1198 ) !IdRef {
1175 // TODO: Merge this function with constantDeclRef.1199 // TODO: Merge this function with constantDeclRef.
11761200
...@@ -4456,16 +4480,20 @@ const DeclGen = struct {...@@ -4456,16 +4480,20 @@ const DeclGen = struct {
4456 ) !IdRef {4480 ) !IdRef {
4457 const result_ty_id = try self.resolveType(result_ptr_ty, .direct);4481 const result_ty_id = try self.resolveType(result_ptr_ty, .direct);
44584482
4459 const mod = self.module;4483 const zcu = self.module;
4460 const object_ty = object_ptr_ty.childType(mod);4484 const object_ty = object_ptr_ty.childType(zcu);
4461 switch (object_ty.zigTypeTag(mod)) {4485 switch (object_ty.zigTypeTag(zcu)) {
4462 .Struct => switch (object_ty.containerLayout(mod)) {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)) {
4463 .@"packed" => unreachable, // TODO4491 .@"packed" => unreachable, // TODO
4464 else => {4492 else => {
4465 return try self.accessChain(result_ty_id, object_ptr, &.{field_index});4493 return try self.accessChain(result_ty_id, object_ptr, &.{field_index});
4466 },4494 },
4467 },4495 },
4468 .Union => switch (object_ty.containerLayout(mod)) {4496 .Union => switch (object_ty.containerLayout(zcu)) {
4469 .@"packed" => unreachable, // TODO4497 .@"packed" => unreachable, // TODO
4470 else => {4498 else => {
4471 const layout = self.unionLayout(object_ty);4499 const layout = self.unionLayout(object_ty);
...@@ -4475,7 +4503,7 @@ const DeclGen = struct {...@@ -4475,7 +4503,7 @@ const DeclGen = struct {
4475 return try self.spv.constUndef(result_ty_id);4503 return try self.spv.constUndef(result_ty_id);
4476 }4504 }
44774505
4478 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(mod));4506 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(zcu));
4479 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, storage_class);4507 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, storage_class);
4480 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});4508 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...@@ -539,7 +539,6 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, val: V
539 .none,539 .none,
540 .{540 .{
541 .parent_atom_index = @intFromEnum(atom.sym_index),541 .parent_atom_index = @intFromEnum(atom.sym_index),
542 .addend = null,
543 },542 },
544 );543 );
545 break :code switch (result) {544 break :code switch (result) {
src/mutable_value.zig+111-38
...@@ -54,22 +54,22 @@ pub const MutableValue = union(enum) {...@@ -54,22 +54,22 @@ pub const MutableValue = union(enum) {
54 payload: *MutableValue,54 payload: *MutableValue,
55 };55 };
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 {
58 const ip = &zcu.intern_pool;58 const ip = &zcu.intern_pool;
59 const gpa = zcu.gpa;59 const gpa = zcu.gpa;
60 return switch (mv) {60 return Value.fromInterned(switch (mv) {
61 .interned => |ip_index| ip_index,61 .interned => |ip_index| ip_index,
62 .eu_payload => |sv| try ip.get(gpa, .{ .error_union = .{62 .eu_payload => |sv| try ip.get(gpa, .{ .error_union = .{
63 .ty = sv.ty,63 .ty = sv.ty,
64 .val = .{ .payload = try sv.child.intern(zcu, arena) },64 .val = .{ .payload = (try sv.child.intern(zcu, arena)).toIntern() },
65 } }),65 } }),
66 .opt_payload => |sv| try ip.get(gpa, .{ .opt = .{66 .opt_payload => |sv| try ip.get(gpa, .{ .opt = .{
67 .ty = sv.ty,67 .ty = sv.ty,
68 .val = try sv.child.intern(zcu, arena),68 .val = (try sv.child.intern(zcu, arena)).toIntern(),
69 } }),69 } }),
70 .repeated => |sv| try ip.get(gpa, .{ .aggregate = .{70 .repeated => |sv| try ip.get(gpa, .{ .aggregate = .{
71 .ty = sv.ty,71 .ty = sv.ty,
72 .storage = .{ .repeated_elem = try sv.child.intern(zcu, arena) },72 .storage = .{ .repeated_elem = (try sv.child.intern(zcu, arena)).toIntern() },
73 } }),73 } }),
74 .bytes => |b| try ip.get(gpa, .{ .aggregate = .{74 .bytes => |b| try ip.get(gpa, .{ .aggregate = .{
75 .ty = b.ty,75 .ty = b.ty,
...@@ -78,24 +78,24 @@ pub const MutableValue = union(enum) {...@@ -78,24 +78,24 @@ pub const MutableValue = union(enum) {
78 .aggregate => |a| {78 .aggregate => |a| {
79 const elems = try arena.alloc(InternPool.Index, a.elems.len);79 const elems = try arena.alloc(InternPool.Index, a.elems.len);
80 for (a.elems, elems) |mut_elem, *interned_elem| {80 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();
82 }82 }
83 return ip.get(gpa, .{ .aggregate = .{83 return Value.fromInterned(try ip.get(gpa, .{ .aggregate = .{
84 .ty = a.ty,84 .ty = a.ty,
85 .storage = .{ .elems = elems },85 .storage = .{ .elems = elems },
86 } });86 } }));
87 },87 },
88 .slice => |s| try ip.get(gpa, .{ .slice = .{88 .slice => |s| try ip.get(gpa, .{ .slice = .{
89 .ty = s.ty,89 .ty = s.ty,
90 .ptr = try s.ptr.intern(zcu, arena),90 .ptr = (try s.ptr.intern(zcu, arena)).toIntern(),
91 .len = try s.len.intern(zcu, arena),91 .len = (try s.len.intern(zcu, arena)).toIntern(),
92 } }),92 } }),
93 .un => |u| try ip.get(gpa, .{ .un = .{93 .un => |u| try ip.get(gpa, .{ .un = .{
94 .ty = u.ty,94 .ty = u.ty,
95 .tag = u.tag,95 .tag = u.tag,
96 .val = try u.payload.intern(zcu, arena),96 .val = (try u.payload.intern(zcu, arena)).toIntern(),
97 } }),97 } }),
98 };98 });
99 }99 }
100100
101 /// Un-interns the top level of this `MutableValue`, if applicable.101 /// Un-interns the top level of this `MutableValue`, if applicable.
...@@ -248,9 +248,11 @@ pub const MutableValue = union(enum) {...@@ -248,9 +248,11 @@ pub const MutableValue = union(enum) {
248 },248 },
249 .Union => {249 .Union => {
250 const payload = try arena.create(MutableValue);250 const payload = try arena.create(MutableValue);
251 // HACKHACK: this logic is silly, but Sema detects it and reverts the change where needed.251 const backing_ty = try Type.fromInterned(ty_ip).unionBackingType(zcu);
252 // See comment at the top of `Sema.beginComptimePtrMutationInner`.252 payload.* = .{ .interned = try ip.get(
253 payload.* = .{ .interned = .undef };253 gpa,
254 .{ .undef = backing_ty.toIntern() },
255 ) };
254 mv.* = .{ .un = .{256 mv.* = .{ .un = .{
255 .ty = ty_ip,257 .ty = ty_ip,
256 .tag = .none,258 .tag = .none,
...@@ -294,7 +296,6 @@ pub const MutableValue = union(enum) {...@@ -294,7 +296,6 @@ pub const MutableValue = union(enum) {
294 /// Get a pointer to the `MutableValue` associated with a field/element.296 /// Get a pointer to the `MutableValue` associated with a field/element.
295 /// The returned pointer can be safety mutated through to modify the field value.297 /// The returned pointer can be safety mutated through to modify the field value.
296 /// The returned pointer is valid until the representation of `mv` changes.298 /// The returned pointer is valid until the representation of `mv` changes.
297 /// This function does *not* support accessing the ptr/len field of slices.
298 pub fn elem(299 pub fn elem(
299 mv: *MutableValue,300 mv: *MutableValue,
300 zcu: *Zcu,301 zcu: *Zcu,
...@@ -304,18 +305,18 @@ pub const MutableValue = union(enum) {...@@ -304,18 +305,18 @@ pub const MutableValue = union(enum) {
304 const ip = &zcu.intern_pool;305 const ip = &zcu.intern_pool;
305 const gpa = zcu.gpa;306 const gpa = zcu.gpa;
306 // Convert to the `aggregate` representation.307 // Convert to the `aggregate` representation.
307 switch (mv) {308 switch (mv.*) {
308 .eu_payload, .opt_payload, .slice, .un => unreachable,309 .eu_payload, .opt_payload, .un => unreachable,
309 .interned => {310 .interned => {
310 try mv.unintern(zcu, arena, false, false);311 try mv.unintern(zcu, arena, false, false);
311 },312 },
312 .bytes => |bytes| {313 .bytes => |bytes| {
313 const elems = try arena.alloc(MutableValue, bytes.data.len);314 const elems = try arena.alloc(MutableValue, bytes.data.len);
314 for (bytes.data, elems) |byte, interned_byte| {315 for (bytes.data, elems) |byte, *interned_byte| {
315 interned_byte.* = try ip.get(gpa, .{ .int = .{316 interned_byte.* = .{ .interned = try ip.get(gpa, .{ .int = .{
316 .ty = .u8_type,317 .ty = .u8_type,
317 .storage = .{ .u64 = byte },318 .storage = .{ .u64 = byte },
318 } });319 } }) };
319 }320 }
320 mv.* = .{ .aggregate = .{321 mv.* = .{ .aggregate = .{
321 .ty = bytes.ty,322 .ty = bytes.ty,
...@@ -331,9 +332,17 @@ pub const MutableValue = union(enum) {...@@ -331,9 +332,17 @@ pub const MutableValue = union(enum) {
331 .elems = elems,332 .elems = elems,
332 } };333 } };
333 },334 },
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,
335 }345 }
336 return &mv.aggregate.elems[field_idx];
337 }346 }
338347
339 /// Modify a single field of a `MutableValue` which represents an aggregate or slice, leaving others348 /// Modify a single field of a `MutableValue` which represents an aggregate or slice, leaving others
...@@ -349,43 +358,44 @@ pub const MutableValue = union(enum) {...@@ -349,43 +358,44 @@ pub const MutableValue = union(enum) {
349 ) Allocator.Error!void {358 ) Allocator.Error!void {
350 const ip = &zcu.intern_pool;359 const ip = &zcu.intern_pool;
351 const is_trivial_int = field_val.isTrivialInt(zcu);360 const is_trivial_int = field_val.isTrivialInt(zcu);
352 try mv.unintern(arena, is_trivial_int, true);361 try mv.unintern(zcu, arena, is_trivial_int, true);
353 switch (mv) {362 switch (mv.*) {
354 .interned,363 .interned,
355 .eu_payload,364 .eu_payload,
356 .opt_payload,365 .opt_payload,
357 .un,366 .un,
358 => unreachable,367 => unreachable,
359 .slice => |*s| switch (field_idx) {368 .slice => |*s| switch (field_idx) {
360 Value.slice_ptr_index => s.ptr = field_val,369 Value.slice_ptr_index => s.ptr.* = field_val,
361 Value.slice_len_index => s.len = field_val,370 Value.slice_len_index => s.len.* = field_val,
371 else => unreachable,
362 },372 },
363 .bytes => |b| {373 .bytes => |b| {
364 assert(is_trivial_int);374 assert(is_trivial_int);
365 assert(field_val.typeOf() == Type.u8);375 assert(field_val.typeOf(zcu).toIntern() == .u8_type);
366 b.data[field_idx] = Value.fromInterned(field_val.interned).toUnsignedInt(zcu);376 b.data[field_idx] = @intCast(Value.fromInterned(field_val.interned).toUnsignedInt(zcu));
367 },377 },
368 .repeated => |r| {378 .repeated => |r| {
369 if (field_val.eqlTrivial(r.child.*)) return;379 if (field_val.eqlTrivial(r.child.*)) return;
370 // We must switch to either the `aggregate` or the `bytes` representation.380 // We must switch to either the `aggregate` or the `bytes` representation.
371 const len_inc_sent = ip.aggregateTypeLenIncludingSentinel(r.ty);381 const len_inc_sent = ip.aggregateTypeLenIncludingSentinel(r.ty);
372 if (ip.zigTypeTag(r.ty) != .Struct and382 if (Type.fromInterned(r.ty).zigTypeTag(zcu) != .Struct and
373 is_trivial_int and383 is_trivial_int and
374 Type.fromInterned(r.ty).childType(zcu) == .u8_type and384 Type.fromInterned(r.ty).childType(zcu).toIntern() == .u8_type and
375 r.child.isTrivialInt(zcu))385 r.child.isTrivialInt(zcu))
376 {386 {
377 // We can use the `bytes` representation.387 // We can use the `bytes` representation.
378 const bytes = try arena.alloc(u8, @intCast(len_inc_sent));388 const bytes = try arena.alloc(u8, @intCast(len_inc_sent));
379 const repeated_byte = Value.fromInterned(r.child.interned).getUnsignedInt(zcu);389 const repeated_byte = Value.fromInterned(r.child.interned).toUnsignedInt(zcu);
380 @memset(bytes, repeated_byte);390 @memset(bytes, @intCast(repeated_byte));
381 bytes[field_idx] = Value.fromInterned(field_val.interned).getUnsignedInt(zcu);391 bytes[field_idx] = @intCast(Value.fromInterned(field_val.interned).toUnsignedInt(zcu));
382 mv.* = .{ .bytes = .{392 mv.* = .{ .bytes = .{
383 .ty = r.ty,393 .ty = r.ty,
384 .data = bytes,394 .data = bytes,
385 } };395 } };
386 } else {396 } else {
387 // We must use the `aggregate` representation.397 // 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));
389 @memset(mut_elems, r.child.*);399 @memset(mut_elems, r.child.*);
390 mut_elems[field_idx] = field_val;400 mut_elems[field_idx] = field_val;
391 mv.* = .{ .aggregate = .{401 mv.* = .{ .aggregate = .{
...@@ -396,12 +406,12 @@ pub const MutableValue = union(enum) {...@@ -396,12 +406,12 @@ pub const MutableValue = union(enum) {
396 },406 },
397 .aggregate => |a| {407 .aggregate => |a| {
398 a.elems[field_idx] = field_val;408 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;
400 // Attempt to switch to a more efficient representation.410 // Attempt to switch to a more efficient representation.
401 const is_repeated = for (a.elems) |e| {411 const is_repeated = for (a.elems) |e| {
402 if (!e.eqlTrivial(field_val)) break false;412 if (!e.eqlTrivial(field_val)) break false;
403 } else true;413 } else true;
404 if (is_repeated) {414 if (!is_struct and is_repeated) {
405 // Switch to `repeated` repr415 // Switch to `repeated` repr
406 const mut_repeated = try arena.create(MutableValue);416 const mut_repeated = try arena.create(MutableValue);
407 mut_repeated.* = field_val;417 mut_repeated.* = field_val;
...@@ -425,7 +435,7 @@ pub const MutableValue = union(enum) {...@@ -425,7 +435,7 @@ pub const MutableValue = union(enum) {
425 } else {435 } else {
426 const bytes = try arena.alloc(u8, a.elems.len);436 const bytes = try arena.alloc(u8, a.elems.len);
427 for (a.elems, bytes) |elem_val, *b| {437 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));
429 }439 }
430 mv.* = .{ .bytes = .{440 mv.* = .{ .bytes = .{
431 .ty = a.ty,441 .ty = a.ty,
...@@ -505,4 +515,67 @@ pub const MutableValue = union(enum) {...@@ -505,4 +515,67 @@ pub const MutableValue = union(enum) {
505 inline else => |x| Type.fromInterned(x.ty),515 inline else => |x| Type.fromInterned(x.ty),
506 };516 };
507 }517 }
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 }
508};581};
src/print_air.zig+1-1
...@@ -951,7 +951,7 @@ const Writer = struct {...@@ -951,7 +951,7 @@ const Writer = struct {
951 const ty = Type.fromInterned(mod.intern_pool.indexToKey(ip_index).typeOf());951 const ty = Type.fromInterned(mod.intern_pool.indexToKey(ip_index).typeOf());
952 try s.print("<{}, {}>", .{952 try s.print("<{}, {}>", .{
953 ty.fmt(mod),953 ty.fmt(mod),
954 Value.fromInterned(ip_index).fmtValue(mod),954 Value.fromInterned(ip_index).fmtValue(mod, null),
955 });955 });
956 } else {956 } else {
957 return w.writeInstIndex(s, operand.toIndex().?, dies);957 return w.writeInstIndex(s, operand.toIndex().?, dies);
src/print_value.zig+87-86
...@@ -17,6 +17,7 @@ const max_string_len = 256;...@@ -17,6 +17,7 @@ const max_string_len = 256;
17const FormatContext = struct {17const FormatContext = struct {
18 val: Value,18 val: Value,
19 mod: *Module,19 mod: *Module,
20 opt_sema: ?*Sema,
20};21};
2122
22pub fn format(23pub fn format(
...@@ -27,10 +28,10 @@ pub fn format(...@@ -27,10 +28,10 @@ pub fn format(
27) !void {28) !void {
28 _ = options;29 _ = options;
29 comptime std.debug.assert(fmt.len == 0);30 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) {
31 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function32 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
32 error.ComptimeBreak, error.ComptimeReturn => unreachable,33 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
34 else => |e| return e,35 else => |e| return e,
35 };36 };
36}37}
...@@ -117,7 +118,7 @@ pub fn print(...@@ -117,7 +118,7 @@ pub fn print(
117 },118 },
118 .slice => |slice| {119 .slice => |slice| {
119 const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) {120 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,
121 .anon_decl, .comptime_alloc, .comptime_field => true,122 .anon_decl, .comptime_alloc, .comptime_field => true,
122 .decl, .int => false,123 .decl, .int => false,
123 };124 };
...@@ -125,7 +126,7 @@ pub fn print(...@@ -125,7 +126,7 @@ pub fn print(
125 // TODO: eventually we want to load the slice as an array with `opt_sema`, but that's126 // TODO: eventually we want to load the slice as an array with `opt_sema`, but that's
126 // currently not possible without e.g. triggering compile errors.127 // currently not possible without e.g. triggering compile errors.
127 }128 }
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);
129 try writer.writeAll("[0..");130 try writer.writeAll("[0..");
130 if (level == 0) {131 if (level == 0) {
131 try writer.writeAll("(...)");132 try writer.writeAll("(...)");
...@@ -136,7 +137,7 @@ pub fn print(...@@ -136,7 +137,7 @@ pub fn print(
136 },137 },
137 .ptr => {138 .ptr => {
138 const print_contents = switch (ip.getBackingAddrTag(val.toIntern()).?) {139 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,
140 .anon_decl, .comptime_alloc, .comptime_field => true,141 .anon_decl, .comptime_alloc, .comptime_field => true,
141 .decl, .int => false,142 .decl, .int => false,
142 };143 };
...@@ -144,13 +145,13 @@ pub fn print(...@@ -144,13 +145,13 @@ pub fn print(
144 // TODO: eventually we want to load the pointer with `opt_sema`, but that's145 // TODO: eventually we want to load the pointer with `opt_sema`, but that's
145 // currently not possible without e.g. triggering compile errors.146 // currently not possible without e.g. triggering compile errors.
146 }147 }
147 try printPtr(val.toIntern(), writer, false, false, 0, level, mod, opt_sema);148 try printPtr(val, writer, level, mod, opt_sema);
148 },149 },
149 .opt => |opt| switch (opt.val) {150 .opt => |opt| switch (opt.val) {
150 .none => try writer.writeAll("null"),151 .none => try writer.writeAll("null"),
151 else => |payload| try print(Value.fromInterned(payload), writer, level, mod, opt_sema),152 else => |payload| try print(Value.fromInterned(payload), writer, level, mod, opt_sema),
152 },153 },
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),
154 .un => |un| {155 .un => |un| {
155 if (level == 0) {156 if (level == 0) {
156 try writer.writeAll(".{ ... }");157 try writer.writeAll(".{ ... }");
...@@ -176,13 +177,14 @@ pub fn print(...@@ -176,13 +177,14 @@ pub fn print(
176fn printAggregate(177fn printAggregate(
177 val: Value,178 val: Value,
178 aggregate: InternPool.Key.Aggregate,179 aggregate: InternPool.Key.Aggregate,
180 is_ref: bool,
179 writer: anytype,181 writer: anytype,
180 level: u8,182 level: u8,
181 is_ref: bool,
182 zcu: *Zcu,183 zcu: *Zcu,
183 opt_sema: ?*Sema,184 opt_sema: ?*Sema,
184) (@TypeOf(writer).Error || Module.CompileError)!void {185) (@TypeOf(writer).Error || Module.CompileError)!void {
185 if (level == 0) {186 if (level == 0) {
187 if (is_ref) try writer.writeByte('&');
186 return writer.writeAll(".{ ... }");188 return writer.writeAll(".{ ... }");
187 }189 }
188 const ip = &zcu.intern_pool;190 const ip = &zcu.intern_pool;
...@@ -257,101 +259,87 @@ fn printAggregate(...@@ -257,101 +259,87 @@ fn printAggregate(
257 return writer.writeAll(" }");259 return writer.writeAll(" }");
258}260}
259261
260fn printPtr(262fn printPtr(ptr_val: Value, writer: anytype, level: u8, zcu: *Zcu, opt_sema: ?*Sema) (@TypeOf(writer).Error || Module.CompileError)!void {
261 ptr_val: InternPool.Index,263 const ptr = switch (zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
262 writer: anytype,264 .undef => return writer.writeAll("undefined"),
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 },
278 .ptr => |ptr| ptr,265 .ptr => |ptr| ptr,
279 else => unreachable,266 else => unreachable,
280 };267 };
281 if (level == 0) {268
282 return writer.writeAll("&...");269 if (ptr.base_addr == .anon_decl) {
283 }270 // If the value is an aggregate, we can potentially print it more nicely.
284 switch (ptr.addr) {271 switch (zcu.intern_pool.indexToKey(ptr.base_addr.anon_decl.val)) {
285 .int => |int| {272 .aggregate => |agg| return printAggregate(
286 if (force_addrof) try writer.writeAll("&");273 Value.fromInterned(ptr.base_addr.anon_decl.val),
287 try writer.writeByteNTimes('(', leading_parens);274 agg,
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,
309 true,275 true,
276 writer,
277 level,
310 zcu,278 zcu,
311 opt_sema,279 opt_sema,
312 ),280 ),
313 else => {281 else => {},
314 const ty = Type.fromInterned(ip.typeOf(anon.val));282 }
315 try writer.print("&@as({}, ", .{ty.fmt(zcu)});283 }
316 try print(Value.fromInterned(anon.val), writer, level - 1, zcu, opt_sema);284
317 try writer.writeAll(")");285 var arena = std.heap.ArenaAllocator.init(zcu.gpa);
318 },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);
319 },301 },
320 .comptime_field => |val| {302 .anon_decl_ptr => |anon| {
321 const ty = Type.fromInterned(ip.typeOf(val));303 const ty = Value.fromInterned(anon.val).typeOf(zcu);
322 try writer.print("&@as({}, ", .{ty.fmt(zcu)});304 try writer.print("@as({}, ", .{ty.fmt(zcu)});
323 try print(Value.fromInterned(val), writer, level - 1, zcu, opt_sema);305 try print(Value.fromInterned(anon.val), writer, level - 1, zcu, opt_sema);
324 try writer.writeAll(")");306 try writer.writeByte(')');
325 },307 },
326 .eu_payload => |base| {308 .comptime_alloc_ptr => |info| {
327 try printPtr(base, writer, true, true, leading_parens, level, zcu, opt_sema);309 try writer.print("@as({}, ", .{info.val.typeOf(zcu).fmt(zcu)});
328 try writer.writeAll(".?");310 try print(info.val, writer, level - 1, zcu, opt_sema);
311 try writer.writeByte(')');
329 },312 },
330 .opt_payload => |base| {313 .comptime_field_ptr => |val| {
331 try writer.writeAll("(");314 const ty = val.typeOf(zcu);
332 try printPtr(base, writer, true, true, leading_parens + 1, level, zcu, opt_sema);315 try writer.print("@as({}, ", .{ty.fmt(zcu)});
333 try writer.writeAll(" catch unreachable");316 try print(val, writer, level - 1, zcu, opt_sema);
317 try writer.writeByte(')');
334 },318 },
335 .elem => |elem| {319 .eu_payload_ptr => |info| {
336 try printPtr(elem.base, writer, true, true, leading_parens, level, zcu, opt_sema);320 try writer.writeByte('(');
337 try writer.print("[{d}]", .{elem.index});321 try printPtrDerivation(info.parent.*, writer, level, zcu, opt_sema);
322 try writer.writeAll(" catch unreachable)");
338 },323 },
339 .field => |field| {324 .opt_payload_ptr => |info| {
340 try printPtr(field.base, writer, true, true, leading_parens, level, zcu, opt_sema);325 try printPtrDerivation(info.parent.*, writer, level, zcu, opt_sema);
341 const base_ty = Type.fromInterned(ip.typeOf(field.base)).childType(zcu);326 try writer.writeAll(".?");
342 switch (base_ty.zigTypeTag(zcu)) {327 },
343 .Struct => if (base_ty.isTuple(zcu)) {328 .field_ptr => |field| {
344 try writer.print("[{d}]", .{field.index});329 try printPtrDerivation(field.parent.*, writer, level, zcu, opt_sema);
345 } else {330 const agg_ty = (try field.parent.ptrType(zcu)).childType(zcu);
346 const field_name = base_ty.structFieldName(@intCast(field.index), zcu).unwrap().?;331 switch (agg_ty.zigTypeTag(zcu)) {
332 .Struct => if (agg_ty.structFieldName(field.field_idx, zcu).unwrap()) |field_name| {
347 try writer.print(".{i}", .{field_name.fmt(ip)});333 try writer.print(".{i}", .{field_name.fmt(ip)});
334 } else {
335 try writer.print("[{d}]", .{field.field_idx});
348 },336 },
349 .Union => {337 .Union => {
350 const tag_ty = base_ty.unionTagTypeHypothetical(zcu);338 const tag_ty = agg_ty.unionTagTypeHypothetical(zcu);
351 const field_name = tag_ty.enumFieldName(@intCast(field.index), zcu);339 const field_name = tag_ty.enumFieldName(field.field_idx, zcu);
352 try writer.print(".{i}", .{field_name.fmt(ip)});340 try writer.print(".{i}", .{field_name.fmt(ip)});
353 },341 },
354 .Pointer => switch (field.index) {342 .Pointer => switch (field.field_idx) {
355 Value.slice_ptr_index => try writer.writeAll(".ptr"),343 Value.slice_ptr_index => try writer.writeAll(".ptr"),
356 Value.slice_len_index => try writer.writeAll(".len"),344 Value.slice_len_index => try writer.writeAll(".len"),
357 else => unreachable,345 else => unreachable,
...@@ -359,5 +347,18 @@ fn printPtr(...@@ -359,5 +347,18 @@ fn printPtr(
359 else => unreachable,347 else => unreachable,
360 }348 }
361 },349 },
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 },
362 }363 }
363}364}
src/type.zig+93-9
...@@ -172,6 +172,7 @@ pub const Type = struct {...@@ -172,6 +172,7 @@ pub const Type = struct {
172 }172 }
173173
174 /// Prints a name suitable for `@typeName`.174 /// Prints a name suitable for `@typeName`.
175 /// TODO: take an `opt_sema` to pass to `fmtValue` when printing sentinels.
175 pub fn print(ty: Type, writer: anytype, mod: *Module) @TypeOf(writer).Error!void {176 pub fn print(ty: Type, writer: anytype, mod: *Module) @TypeOf(writer).Error!void {
176 const ip = &mod.intern_pool;177 const ip = &mod.intern_pool;
177 switch (ip.indexToKey(ty.toIntern())) {178 switch (ip.indexToKey(ty.toIntern())) {
...@@ -187,8 +188,8 @@ pub const Type = struct {...@@ -187,8 +188,8 @@ pub const Type = struct {
187188
188 if (info.sentinel != .none) switch (info.flags.size) {189 if (info.sentinel != .none) switch (info.flags.size) {
189 .One, .C => unreachable,190 .One, .C => unreachable,
190 .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod)}),191 .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod, null)}),
191 .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod)}),192 .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod, null)}),
192 } else switch (info.flags.size) {193 } else switch (info.flags.size) {
193 .One => try writer.writeAll("*"),194 .One => try writer.writeAll("*"),
194 .Many => try writer.writeAll("[*]"),195 .Many => try writer.writeAll("[*]"),
...@@ -234,7 +235,7 @@ pub const Type = struct {...@@ -234,7 +235,7 @@ pub const Type = struct {
234 } else {235 } else {
235 try writer.print("[{d}:{}]", .{236 try writer.print("[{d}:{}]", .{
236 array_type.len,237 array_type.len,
237 Value.fromInterned(array_type.sentinel).fmtValue(mod),238 Value.fromInterned(array_type.sentinel).fmtValue(mod, null),
238 });239 });
239 try print(Type.fromInterned(array_type.child), writer, mod);240 try print(Type.fromInterned(array_type.child), writer, mod);
240 }241 }
...@@ -352,7 +353,7 @@ pub const Type = struct {...@@ -352,7 +353,7 @@ pub const Type = struct {
352 try print(Type.fromInterned(field_ty), writer, mod);353 try print(Type.fromInterned(field_ty), writer, mod);
353354
354 if (val != .none) {355 if (val != .none) {
355 try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(mod)});356 try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(mod, null)});
356 }357 }
357 }358 }
358 try writer.writeAll("}");359 try writer.writeAll("}");
...@@ -1965,6 +1966,12 @@ pub const Type = struct {...@@ -1965,6 +1966,12 @@ pub const Type = struct {
1965 return Type.fromInterned(union_fields[index]);1966 return Type.fromInterned(union_fields[index]);
1966 }1967 }
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
1968 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {1975 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
1969 const union_obj = mod.typeToUnion(ty).?;1976 const union_obj = mod.typeToUnion(ty).?;
1970 return mod.unionTagFieldIndex(union_obj, enum_tag);1977 return mod.unionTagFieldIndex(union_obj, enum_tag);
...@@ -3049,22 +3056,34 @@ pub const Type = struct {...@@ -3049,22 +3056,34 @@ pub const Type = struct {
3049 };3056 };
3050 }3057 }
30513058
3052 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) Alignment {3059 pub fn structFieldAlign(ty: Type, index: usize, zcu: *Zcu) Alignment {
3053 const ip = &mod.intern_pool;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;
3054 switch (ip.indexToKey(ty.toIntern())) {3065 switch (ip.indexToKey(ty.toIntern())) {
3055 .struct_type => {3066 .struct_type => {
3056 const struct_type = ip.loadStructType(ty.toIntern());3067 const struct_type = ip.loadStructType(ty.toIntern());
3057 assert(struct_type.layout != .@"packed");3068 assert(struct_type.layout != .@"packed");
3058 const explicit_align = struct_type.fieldAlign(ip, index);3069 const explicit_align = struct_type.fieldAlign(ip, index);
3059 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);3070 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 }
3061 },3076 },
3062 .anon_struct_type => |anon_struct| {3077 .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;
3064 },3079 },
3065 .union_type => {3080 .union_type => {
3066 const union_obj = ip.loadUnionType(ty.toIntern());3081 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 }
3068 },3087 },
3069 else => unreachable,3088 else => unreachable,
3070 }3089 }
...@@ -3301,6 +3320,71 @@ pub const Type = struct {...@@ -3301,6 +3320,71 @@ pub const Type = struct {
3301 };3320 };
3302 }3321 }
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
3304 pub const @"u1": Type = .{ .ip_index = .u1_type };3388 pub const @"u1": Type = .{ .ip_index = .u1_type };
3305 pub const @"u8": Type = .{ .ip_index = .u8_type };3389 pub const @"u8": Type = .{ .ip_index = .u8_type };
3306 pub const @"u16": Type = .{ .ip_index = .u16_type };3390 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" {...@@ -517,3 +517,61 @@ test "@bitCast of packed struct of bools all false" {
517 p.b3 = false;517 p.b3 = false;
518 try expect(@as(u8, @as(u4, @bitCast(p))) == 0);518 try expect(@as(u8, @as(u4, @bitCast(p))) == 0);
519}519}
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 {...@@ -139,8 +139,8 @@ const Piece = packed struct {
139 color: Color,139 color: Color,
140 type: Type,140 type: Type,
141141
142 const Type = enum { KING, QUEEN, BISHOP, KNIGHT, ROOK, PAWN };142 const Type = enum(u3) { KING, QUEEN, BISHOP, KNIGHT, ROOK, PAWN };
143 const Color = enum { WHITE, BLACK };143 const Color = enum(u1) { WHITE, BLACK };
144144
145 fn charToPiece(c: u8) !@This() {145 fn charToPiece(c: u8) !@This() {
146 return .{146 return .{
test/behavior/comptime_memory.zig+21-43
...@@ -32,32 +32,22 @@ test "type pun signed and unsigned as array pointer" {...@@ -32,32 +32,22 @@ test "type pun signed and unsigned as array pointer" {
32}32}
3333
34test "type pun signed and unsigned as offset many pointer" {34test "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
40 comptime {35 comptime {
41 var x: u32 = 0;36 var x: [11]u32 = undefined;
42 var y = @as([*]i32, @ptrCast(&x));37 var y: [*]i32 = @ptrCast(&x[10]);
43 y -= 10;38 y -= 10;
44 y[10] = -1;39 y[10] = -1;
45 try testing.expectEqual(@as(u32, 0xFFFFFFFF), x);40 try testing.expectEqual(@as(u32, 0xFFFFFFFF), x[10]);
46 }41 }
47}42}
4843
49test "type pun signed and unsigned as array pointer with pointer arithemtic" {44test "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
55 comptime {45 comptime {
56 var x: u32 = 0;46 var x: [11]u32 = undefined;
57 const y = @as([*]i32, @ptrCast(&x)) - 10;47 const y = @as([*]i32, @ptrCast(&x[10])) - 10;
58 const z: *[15]i32 = y[0..15];48 const z: *[15]i32 = y[0..15];
59 z[10] = -1;49 z[10] = -1;
60 try testing.expectEqual(@as(u32, 0xFFFFFFFF), x);50 try testing.expectEqual(@as(u32, 0xFFFFFFFF), x[10]);
61 }51 }
62}52}
6353
...@@ -171,10 +161,13 @@ fn doTypePunBitsTest(as_bits: *Bits) !void {...@@ -171,10 +161,13 @@ fn doTypePunBitsTest(as_bits: *Bits) !void {
171161
172test "type pun bits" {162test "type pun bits" {
173 if (true) {163 if (true) {
174 // TODO https://github.com/ziglang/zig/issues/9646164 // 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.
175 return error.SkipZigTest;169 return error.SkipZigTest;
176 }170 }
177
178 comptime {171 comptime {
179 var v: u32 = undefined;172 var v: u32 = undefined;
180 try doTypePunBitsTest(@as(*Bits, @ptrCast(&v)));173 try doTypePunBitsTest(@as(*Bits, @ptrCast(&v)));
...@@ -296,11 +289,6 @@ test "dance on linker values" {...@@ -296,11 +289,6 @@ test "dance on linker values" {
296}289}
297290
298test "offset array ptr by element size" {291test "offset array ptr by element size" {
299 if (true) {
300 // TODO https://github.com/ziglang/zig/issues/9646
301 return error.SkipZigTest;
302 }
303
304 comptime {292 comptime {
305 const VirtualStruct = struct { x: u32 };293 const VirtualStruct = struct { x: u32 };
306 var arr: [4]VirtualStruct = .{294 var arr: [4]VirtualStruct = .{
...@@ -310,15 +298,10 @@ test "offset array ptr by element size" {...@@ -310,15 +298,10 @@ test "offset array ptr by element size" {
310 .{ .x = bigToNativeEndian(u32, 0x03070b0f) },298 .{ .x = bigToNativeEndian(u32, 0x03070b0f) },
311 };299 };
312300
313 const address = @intFromPtr(&arr);301 const buf: [*]align(@alignOf(VirtualStruct)) u8 = @ptrCast(&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);
319302
320 const secondElement = @as(*VirtualStruct, @ptrFromInt(@intFromPtr(&arr[0]) + 2 * @sizeOf(VirtualStruct)));303 const second_element: *VirtualStruct = @ptrCast(buf + 2 * @sizeOf(VirtualStruct));
321 try testing.expectEqual(bigToNativeEndian(u32, 0x02060a0e), secondElement.x);304 try testing.expectEqual(bigToNativeEndian(u32, 0x02060a0e), second_element.x);
322 }305 }
323}306}
324307
...@@ -364,7 +347,7 @@ test "offset field ptr by enclosing array element size" {...@@ -364,7 +347,7 @@ test "offset field ptr by enclosing array element size" {
364347
365 var i: usize = 0;348 var i: usize = 0;
366 while (i < 4) : (i += 1) {349 while (i < 4) : (i += 1) {
367 var ptr: [*]u8 = @as([*]u8, @ptrCast(&arr[0]));350 var ptr: [*]u8 = @ptrCast(&arr[0]);
368 ptr += i;351 ptr += i;
369 ptr += @offsetOf(VirtualStruct, "x");352 ptr += @offsetOf(VirtualStruct, "x");
370 var j: usize = 0;353 var j: usize = 0;
...@@ -400,23 +383,18 @@ test "accessing reinterpreted memory of parent object" {...@@ -400,23 +383,18 @@ test "accessing reinterpreted memory of parent object" {
400}383}
401384
402test "bitcast packed union to integer" {385test "bitcast packed union to integer" {
403 if (true) {
404 // https://github.com/ziglang/zig/issues/19384
405 return error.SkipZigTest;
406 }
407 const U = packed union {386 const U = packed union {
408 x: u1,387 x: i2,
409 y: u2,388 y: u2,
410 };389 };
411390
412 comptime {391 comptime {
413 const a = U{ .x = 1 };392 const a: U = .{ .x = -1 };
414 const b = U{ .y = 2 };393 const b: U = .{ .y = 2 };
415 const cast_a = @as(u2, @bitCast(a));394 const cast_a: u2 = @bitCast(a);
416 const cast_b = @as(u2, @bitCast(b));395 const cast_b: u2 = @bitCast(b);
417396
418 // truncated because the upper bit is garbage memory that we don't care about397 try testing.expectEqual(@as(u2, 3), cast_a);
419 try testing.expectEqual(@as(u1, 1), @as(u1, @truncate(cast_a)));
420 try testing.expectEqual(@as(u2, 2), cast_b);398 try testing.expectEqual(@as(u2, 2), cast_b);
421 }399 }
422}400}
test/behavior/error.zig+23
...@@ -1054,3 +1054,26 @@ test "errorCast from error sets to error unions" {...@@ -1054,3 +1054,26 @@ test "errorCast from error sets to error unions" {
1054 const err_union: Set1!void = @errorCast(error.A);1054 const err_union: Set1!void = @errorCast(error.A);
1055 try expectError(error.A, err_union);1055 try expectError(error.A, err_union);
1056}1056}
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" {...@@ -1731,6 +1731,7 @@ test "@fieldParentPtr extern union" {
1731test "@fieldParentPtr packed union" {1731test "@fieldParentPtr packed union" {
1732 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;1732 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1733 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1733 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1734 if (builtin.target.cpu.arch.endian() == .big) return error.SkipZigTest; // TODO
17341735
1735 const C = packed union {1736 const C = packed union {
1736 a: bool,1737 a: bool,
test/behavior/optional.zig+29-7
...@@ -92,13 +92,11 @@ test "optional with zero-bit type" {...@@ -92,13 +92,11 @@ test "optional with zero-bit type" {
9292
93 var two: ?struct { ZeroBit, ZeroBit } = undefined;93 var two: ?struct { ZeroBit, ZeroBit } = undefined;
94 two = .{ with_runtime.zero_bit, with_runtime.zero_bit };94 two = .{ with_runtime.zero_bit, with_runtime.zero_bit };
95 if (!@inComptime()) {95 try expect(two != null);
96 try expect(two != null);96 try expect(two.?[0] == zero_bit);
97 try expect(two.?[0] == zero_bit);97 try expect(two.?[0] == with_runtime.zero_bit);
98 try expect(two.?[0] == with_runtime.zero_bit);98 try expect(two.?[1] == zero_bit);
99 try expect(two.?[1] == zero_bit);99 try expect(two.?[1] == with_runtime.zero_bit);
100 try expect(two.?[1] == with_runtime.zero_bit);
101 }
102 }100 }
103 };101 };
104102
...@@ -610,3 +608,27 @@ test "copied optional doesn't alias source" {...@@ -610,3 +608,27 @@ test "copied optional doesn't alias source" {
610608
611 try expect(x[0] == 0.0);609 try expect(x[0] == 0.0);
612}610}
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" {...@@ -1025,7 +1025,7 @@ test "modify nested packed struct aligned field" {
1025 pretty_print: packed struct {1025 pretty_print: packed struct {
1026 enabled: bool = false,1026 enabled: bool = false,
1027 num_spaces: u4 = 4,1027 num_spaces: u4 = 4,
1028 space_char: enum { space, tab } = .space,1028 space_char: enum(u1) { space, tab } = .space,
1029 indent: u8 = 0,1029 indent: u8 = 0,
1030 } = .{},1030 } = .{},
1031 baz: bool = false,1031 baz: bool = false,
test/behavior/packed-union.zig+14-1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;
3const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
45
5test "flags in packed union" {6test "flags in packed union" {
...@@ -106,7 +107,7 @@ test "packed union in packed struct" {...@@ -106,7 +107,7 @@ test "packed union in packed struct" {
106107
107fn testPackedUnionInPackedStruct() !void {108fn testPackedUnionInPackedStruct() !void {
108 const ReadRequest = packed struct { key: i32 };109 const ReadRequest = packed struct { key: i32 };
109 const RequestType = enum {110 const RequestType = enum(u1) {
110 read,111 read,
111 insert,112 insert,
112 };113 };
...@@ -169,3 +170,15 @@ test "assigning to non-active field at comptime" {...@@ -169,3 +170,15 @@ test "assigning to non-active field at comptime" {
169 test_bits.bits = .{};170 test_bits.bits = .{};
170 }171 }
171}172}
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" {...@@ -621,3 +621,39 @@ test "cast pointers with zero sized elements" {
621 const d: []u8 = c;621 const d: []u8 = c;
622 _ = d;622 _ = d;
623}623}
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 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const assert = std.debug.assert;
4const native_endian = builtin.target.cpu.arch.endian();5const native_endian = builtin.target.cpu.arch.endian();
56
6test "reinterpret bytes as integer with nonzero offset" {7test "reinterpret bytes as integer with nonzero offset" {
...@@ -277,7 +278,7 @@ test "@ptrCast undefined value at comptime" {...@@ -277,7 +278,7 @@ test "@ptrCast undefined value at comptime" {
277 }278 }
278 };279 };
279 comptime {280 comptime {
280 const x = S.transmute([]u8, i32, undefined);281 const x = S.transmute(u64, i32, undefined);
281 _ = x;282 _ = x;
282 }283 }
283}284}
...@@ -292,3 +293,60 @@ test "comptime @ptrCast with packed struct leaves value unmodified" {...@@ -292,3 +293,60 @@ test "comptime @ptrCast with packed struct leaves value unmodified" {
292 try expect(p.*[0] == 6);293 try expect(p.*[0] == 6);
293 try expect(st.three == 6);294 try expect(st.three == 6);
294}295}
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" {...@@ -758,3 +758,24 @@ test "matching captures causes opaque equivalence" {
758 comptime assert(@TypeOf(a) == @TypeOf(b));758 comptime assert(@TypeOf(a) == @TypeOf(b));
759 try testing.expect(a == b);759 try testing.expect(a == b);
760}760}
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" {...@@ -1532,7 +1532,7 @@ test "reinterpreting enum value inside packed union" {
1532 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1532 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
15331533
1534 const U = packed union {1534 const U = packed union {
1535 tag: enum { a, b },1535 tag: enum(u8) { a, b },
1536 val: u8,1536 val: u8,
15371537
1538 fn doTest() !void {1538 fn doTest() !void {
...@@ -1850,9 +1850,8 @@ test "reinterpret packed union" {...@@ -1850,9 +1850,8 @@ test "reinterpret packed union" {
18501850
1851 {1851 {
1852 // Union initialization1852 // Union initialization
1853 var u: U = .{1853 var u: U = .{ .baz = 0 }; // ensure all bits are defined
1854 .qux = 0xe2a,1854 u.qux = 0xe2a;
1855 };
1856 try expectEqual(@as(u8, 0x2a), u.foo);1855 try expectEqual(@as(u8, 0x2a), u.foo);
1857 try expectEqual(@as(u12, 0xe2a), u.qux);1856 try expectEqual(@as(u12, 0xe2a), u.qux);
1858 try expectEqual(@as(u29, 0xe2a), u.bar & 0xfff);1857 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 {...@@ -9,4 +9,4 @@ export fn entry() void {
9// :2:5: error: found compile log statement9// :2:5: error: found compile log statement
10//10//
11// Compile Log Output:11// 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 {...@@ -6,7 +6,7 @@ comptime {
66
7 const payload_ptr = &opt_ptr.?;7 const payload_ptr = &opt_ptr.?;
8 opt_ptr = null;8 opt_ptr = null;
9 _ = payload_ptr.*.*;9 _ = payload_ptr.*.*; // TODO: this case was regressed by #19630
10}10}
11comptime {11comptime {
12 var opt: ?u8 = 15;12 var opt: ?u8 = 15;
...@@ -28,6 +28,5 @@ comptime {...@@ -28,6 +28,5 @@ comptime {
28// backend=stage228// backend=stage2
29// target=native29// target=native
30//30//
31// :9:20: error: attempt to use null value
32// :16:20: error: attempt to use null value31// :16:20: error: attempt to use null value
33// :24:20: error: attempt to unwrap error: Foo32// :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 {...@@ -11,4 +11,5 @@ fn concat() [16]f32 {
11// target=native11// target=native
12//12//
13// :3:17: error: expected type '[4]f32', found '[16]f32'13// :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 414// :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 {...@@ -8,7 +8,5 @@ export fn foo_slice_len_increment_beyond_bounds() void {
8}8}
99
10// error10// error
11// backend=stage2
12// target=native
13//11//
14// :6:16: error: comptime store of index 8 out of bounds of array length 812// :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 {...@@ -30,7 +30,7 @@ export fn entry6() void {
30}30}
31export fn entry7() void {31export fn entry7() void {
32 _ = @sizeOf(packed struct {32 _ = @sizeOf(packed struct {
33 x: enum { A, B },33 x: enum(u1) { A, B },
34 });34 });
35}35}
36export fn entry8() void {36export fn entry8() void {
...@@ -70,6 +70,12 @@ export fn entry13() void {...@@ -70,6 +70,12 @@ export fn entry13() void {
70 x: *type,70 x: *type,
71 });71 });
72}72}
73export fn entry14() void {
74 const E = enum { implicit, backing, type };
75 _ = @sizeOf(packed struct {
76 x: E,
77 });
78}
7379
74// error80// error
75// backend=llvm81// backend=llvm
...@@ -97,3 +103,5 @@ export fn entry13() void {...@@ -97,3 +103,5 @@ export fn entry13() void {
97// :70:12: error: packed structs cannot contain fields of type '*type'103// :70:12: error: packed structs cannot contain fields of type '*type'
98// :70:12: note: comptime-only pointer has no guaranteed in-memory representation104// :70:12: note: comptime-only pointer has no guaranteed in-memory representation
99// :70:12: note: types are not available at runtime105// :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 {...@@ -5,9 +5,17 @@ comptime {
5 const deref = int_ptr.*;5 const deref = int_ptr.*;
6 _ = deref;6 _ = deref;
7}7}
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
9// error16// error
10// backend=stage217// backend=stage2
11// target=native18// target=native
12//19//
13// :5:26: error: dereference of '*const u24' exceeds bounds of containing decl of type '[4]u8'20// :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 {...@@ -7,4 +7,4 @@ export fn foo() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
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 {}...@@ -31,5 +31,5 @@ pub fn main() !void {}
31// :20:5: error: found compile log statement31// :20:5: error: found compile log statement
32//32//
33// Compile Log Output:33// Compile Log Output:
34// @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, &(comptime alloc).buf[0..2])35// @as([]i32, @as([*]i32, @ptrCast(@as(tmp.StructContainer, .{ .buf = .{ 3, 4 } }).buf[0]))[0..2])