| author | |
| committer | |
| log | 1fb23813166e768a59bc7468d09bcb2e8e0f8f03 |
| tree | ea6746763647264d62389f73768662184d32c82e |
| parent | 77abd3a96aa8c8c1277cdbb33d88149d4674d389 |
| parent | 23062a5bed285f72e35651dd1e8b4a125b83dba0 |
| signature |
compiler: rework comptime pointer representation and access46 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 | } |
| 234 | 234 | ||
| 235 | pub const ImageFormat = enum { | 235 | pub 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 | } |
| 273 | 273 | ||
| 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 later | 277 | @"win2.0", // Windows 2.0 or later |
| 278 | @"nt3.1", // Windows NT, 3.1x or later | 278 | @"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 | }; |
| 133 | 133 | ||
| 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, |
| 272 | 272 | ||
| 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) |
| 567 | pub const CaptureValue = packed struct(u32) { | 567 | pub 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, |
| 570 | 570 | ||
| 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, | ||
| 1031 | 1033 | ||
| 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.?; |
| 1034 | 1036 | ||
| 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, |
| 1044 | 1078 | ||
| 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)), |
| 1237 | 1292 | ||
| 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; |
| 1497 | 1552 | 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; |
| 1500 | 1555 | ||
| 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 and | 1559 | .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 | }, |
| 1514 | 1569 | ||
| ... | @@ -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 | }; |
| 2275 | 2370 | ||
| 2276 | pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { | 2371 | pub 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 use | 3403 | /// 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) { |
| 4153 | pub const PtrDecl = struct { | 4248 | pub 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 | }; |
| 4157 | 4265 | ||
| 4158 | pub const PtrAnonDecl = struct { | 4266 | pub 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 | }; |
| 4162 | 4283 | ||
| 4163 | pub const PtrAnonDeclAligned = struct { | 4284 | pub 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 | }; |
| 4169 | 4304 | ||
| 4170 | pub const PtrComptimeAlloc = struct { | 4305 | pub 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 | }; |
| 4174 | 4322 | ||
| 4175 | pub const PtrComptimeField = struct { | 4323 | pub 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 | }; |
| 4179 | 4340 | ||
| 4180 | pub const PtrBase = struct { | 4341 | pub 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 | }; |
| 4184 | 4358 | ||
| 4185 | pub const PtrBaseIndex = struct { | 4359 | pub 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 | |||
| 4379 | pub 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 | }; |
| 4190 | 4394 | ||
| 4191 | pub const PtrSlice = struct { | 4395 | pub 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 coverage | 4825 | .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 coverage | 4838 | .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 | } |
| 8856 | 9026 | ||
| 8857 | pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag { | 9027 | pub 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 | } |
| 530 | 530 | ||
| 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 | }; |
| 664 | 665 | ||
| 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 | } |
| 3536 | 3537 | ||
| 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 | } | ||
| 3538 | 3543 | ||
| 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 | } }); |
| 4130 | 4136 | ||
| 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); |
| 4491 | 4497 | ||
| 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 })); |
| 4493 | 4504 | ||
| 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); |
| 5334 | 5345 | ||
| 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_functions | 5347 | // 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. |
| 5681 | pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value { | 5695 | pub 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 to | 127 | /// 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 | }; |
| 140 | 138 | ||
| 141 | const ComptimeAlloc = struct { | 139 | const ComptimeAlloc = struct { |
| ... | @@ -177,7 +175,8 @@ const MutableValue = @import("mutable_value.zig").MutableValue; | ... | @@ -177,7 +175,8 @@ const MutableValue = @import("mutable_value.zig").MutableValue; |
| 177 | const Type = @import("type.zig").Type; | 175 | const Type = @import("type.zig").Type; |
| 178 | const Air = @import("Air.zig"); | 176 | const Air = @import("Air.zig"); |
| 179 | const Zir = std.zig.Zir; | 177 | const Zir = std.zig.Zir; |
| 180 | const Module = @import("Module.zig"); | 178 | const Zcu = @import("Module.zig"); |
| 179 | const Module = Zcu; | ||
| 181 | const trace = @import("tracy.zig").trace; | 180 | const trace = @import("tracy.zig").trace; |
| 182 | const Namespace = Module.Namespace; | 181 | const Namespace = Module.Namespace; |
| 183 | const CompileError = Module.CompileError; | 182 | const 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 | } |
| 2269 | 2268 | ||
| 2270 | fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError { | 2269 | fn 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 | } |
| 2287 | 2286 | ||
| ... | @@ -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 | } |
| 2442 | 2441 | ||
| 2443 | fn errMsg( | 2442 | pub 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 | } |
| 2471 | 2470 | ||
| 2472 | fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.ErrorMsg) error{ AnalysisFail, OutOfMemory } { | 2471 | pub 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); |
| 2923 | 2922 | ||
| 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)}); |
| 2926 | 2925 | ||
| 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 | } |
| 3779 | 3778 | ||
| 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 resolved | 3820 | /// 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`. |
| 3820 | fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, resolved_alloc_ty: ?Type) CompileError!?InternPool.Index { | 3822 | fn 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; |
| 3822 | 3824 | ||
| 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); |
| 3826 | 3828 | ||
| 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, |
| 3843 | 3845 | ||
| 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; | ||
| 3849 | 3855 | ||
| 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 | } |
| 3854 | 3860 | ||
| ... | @@ -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, |
| 3857 | 3863 | ||
| 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); |
| 3859 | 3865 | ||
| 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 | } }); |
| 3864 | 3871 | ||
| 3865 | // Maps from pointers into the runtime allocs, to comptime-mutable pointers into the comptime alloc | 3872 | // 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); |
| 3869 | 3876 | ||
| 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 | } |
| 3875 | 3890 | ||
| 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 | } |
| 3975 | 4015 | ||
| 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. |
| 3977 | 4017 | // 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 corresponding | 4021 | 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 | } | ||
| 4046 | 4073 | ||
| 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 | } |
| 4209 | 4238 | ||
| 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( |
| 4869 | 4898 | ||
| 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 | } |
| 4874 | 4903 | ||
| 4875 | fn validateStructInit( | 4904 | fn 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 | } |
| 5733 | 5765 | ||
| ... | @@ -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; |
| 6459 | 6491 | ||
| 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); |
| 6463 | 6495 | ||
| ... | @@ -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); |
| 8990 | 9023 | ||
| 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 | } |
| 8995 | 9028 | ||
| 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 | }); |
| 9004 | 9037 | ||
| 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 | } |
| 9030 | 9063 | ||
| ... | @@ -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); |
| 9179 | 9212 | ||
| 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 | } |
| 9185 | 9218 | ||
| 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 | }); |
| 9195 | 9228 | ||
| 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 | } |
| 9221 | 9255 | ||
| ... | @@ -9223,7 +9257,7 @@ fn analyzeErrUnionPayloadPtr( | ... | @@ -9223,7 +9257,7 @@ fn analyzeErrUnionPayloadPtr( |
| 9223 | 9257 | ||
| 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() and | 9259 | 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(); |
| 10188 | 10222 | ||
| 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; |
| 11082 | 11123 | ||
| 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 { |
| 11089 | 11130 | ||
| 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 | } |
| 11133 | 11168 | ||
| 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 | } |
| 11144 | 11179 | ||
| 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; |
| 11149 | 11184 | ||
| 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]); |
| 11152 | 11187 | ||
| 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 | } |
| 11158 | 11193 | ||
| 11159 | // Fast path: if all the operands are the same type already, we don't need to hit | 11194 | // 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; |
| 11165 | 11200 | ||
| 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 | } |
| 11173 | 11208 | ||
| 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` src | 11214 | // 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 { |
| 11200 | 11235 | ||
| 11201 | // By-reference captures have some further restrictions which make them easier to emit | 11236 | // 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 field | 11240 | // 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` src | 11262 | // 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 | }; |
| 11249 | 11284 | ||
| 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 | } |
| 11260 | 11290 | ||
| 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 | } |
| 11264 | 11294 | ||
| 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 { |
| 11411 | 11441 | ||
| 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 | } |
| 11417 | 11447 | ||
| ... | @@ -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( |
| 16903 | 16933 | ||
| 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 | } |
| 19909 | 19946 | ||
| 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 location | 21858 | // 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 incorrect | 21879 | _ = 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)}); |
| 22690 | 22743 | ||
| 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 | } |
| 23836 | 23891 | ||
| 23837 | fn 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 | |||
| 23867 | fn checkIntOrVector( | 23892 | fn 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 | } |
| 24927 | 24952 | ||
| 24928 | fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 24953 | fn 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; |
| 24931 | 24956 | ||
| 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 |
| 24939 | 24964 | ||
| 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); |
| 24952 | 24977 | ||
| 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 | } |
| 24973 | 24998 | ||
| 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); |
| 24978 | 25003 | ||
| 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 | else | 25036 | 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 | else | 25047 | 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) catch | 25056 | 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 | } | ||
| 25051 | 25118 | ||
| 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 | } |
| 25074 | 25141 | ||
| 25142 | fn 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 | |||
| 25075 | fn zirMinMax( | 25163 | fn 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 | } |
| 26346 | 26435 | ||
| ... | @@ -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. |
| 26747 | fn validatePackedType(sema: *Sema, ty: Type) !bool { | 26836 | fn 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 | } |
| 26777 | 26869 | ||
| 26778 | fn explainWhyTypeIsNotPacked( | 26870 | fn explainWhyTypeIsNotPacked( |
| ... | @@ -27443,13 +27535,7 @@ fn fieldPtr( | ... | @@ -27443,13 +27535,7 @@ fn fieldPtr( |
| 27443 | }); | 27535 | }); |
| 27444 | 27536 | ||
| 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); |
| 27455 | 27541 | ||
| ... | @@ -27467,13 +27553,7 @@ fn fieldPtr( | ... | @@ -27467,13 +27553,7 @@ fn fieldPtr( |
| 27467 | }); | 27553 | }); |
| 27468 | 27554 | ||
| 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); |
| 27479 | 27559 | ||
| ... | @@ -27785,13 +27865,8 @@ fn finishFieldCallBind( | ... | @@ -27785,13 +27865,8 @@ fn finishFieldCallBind( |
| 27785 | } | 27865 | } |
| 27786 | 27866 | ||
| 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 | } |
| 27797 | 27872 | ||
| ... | @@ -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 | } |
| 27905 | 27980 | ||
| 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 | }; |
| 27919 | 27999 | ||
| 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.alignment | 28001 | struct_ptr_ty_info.flags.alignment |
| 27924 | else | 28002 | else |
| 27925 | try sema.typeAbiAlignment(Type.fromInterned(struct_ptr_ty_info.child)); | 28003 | try sema.typeAbiAlignment(Type.fromInterned(struct_ptr_ty_info.child)); |
| 27926 | 28004 | ||
| 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)) { |
| 27929 | 28007 | .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| { |
| 27934 | 28012 | 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's | 28016 | // 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( |
| 28206 | 28239 | ||
| 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)) orelse | 28249 | 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 | } |
| 28243 | 28277 | ||
| 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); |
| 28274 | 28308 | ||
| 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).?); |
| 28280 | 28314 | ||
| 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); |
| 28283 | 28317 | ||
| 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 | else | 28345 | .@"packed" => if (tag_matches) { |
| 28312 | union_ty.unionFieldType(Value.fromInterned(un.tag), mod).?; | 28346 | // Fast path - no need to use bitcast logic. |
| 28313 | 28347 | 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 | } |
| 28321 | 28353 | ||
| 28322 | try sema.requireRuntimeBlock(block, src, null); | 28354 | try sema.requireRuntimeBlock(block, src, null); |
| 28323 | if (union_obj.getLayout(ip) == .auto and block.wantSafety() and | 28355 | 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( |
| 28571 | 28602 | ||
| 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 | } |
| 28580 | 28613 | ||
| 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 | } |
| 28590 | 28618 | ||
| 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 location | 28975 | 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; |
| 28955 | 28983 | ||
| 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 | } |
| 28969 | 28997 | ||
| 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 | } |
| 28977 | 29005 | ||
| 28978 | // null to ?T | 29006 | // 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( |
| 28986 | 29014 | ||
| 28987 | // cast from ?*T and ?[*]T to ?*anyopaque | 29015 | // cast from ?*T and ?[*]T to ?*anyopaque |
| 28988 | // but don't do it if the source type is a double pointer | 29016 | // but don't do it if the source type is a double pointer |
| 28989 | if (dest_ty.isPtrLikeOptional(mod) and | 29017 | if (dest_ty.isPtrLikeOptional(zcu) and |
| 28990 | dest_ty.elemType2(mod).toIntern() == .anyopaque_type and | 29018 | 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 that | 29030 | // 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 | } |
| 29007 | 29035 | ||
| 29008 | // T to ?T | 29036 | // 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); |
| 29024 | 29052 | ||
| 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]T | 29061 | // *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( |
| 29050 | 29078 | ||
| 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; |
| 29059 | 29087 | ||
| 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 | } |
| 29073 | 29101 | ||
| 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 | } |
| 29112 | 29140 | ||
| 29113 | // coercion from C pointer | 29141 | // 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 pointer | 29145 | // 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( |
| 29128 | 29156 | ||
| 29129 | // cast from *T and [*]T to *anyopaque | 29157 | // cast from *T and [*]T to *anyopaque |
| 29130 | // but don't do it if the source type is a double pointer | 29158 | // 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( |
| 29151 | 29179 | ||
| 29152 | switch (dest_info.flags.size) { | 29180 | switch (dest_info.flags.size) { |
| 29153 | // coercion to C pointer | 29181 | // 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 or | 29227 | 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; |
| 29201 | 29230 | ||
| 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 union | 29240 | // pointer to anonymous struct to pointer to union |
| 29212 | if (inst_ty.isSinglePointer(mod) and | 29241 | if (inst_ty.isSinglePointer(zcu) and |
| 29213 | inst_ty.childType(mod).isAnonStruct(mod) and | 29242 | 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 struct | 29249 | // pointer to anonymous struct to pointer to struct |
| 29221 | if (inst_ty.isSinglePointer(mod) and | 29250 | if (inst_ty.isSinglePointer(zcu) and |
| 29222 | inst_ty.childType(mod).isAnonStruct(mod) and | 29251 | 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 array | 29261 | // pointer to tuple to pointer to array |
| 29233 | if (inst_ty.isSinglePointer(mod) and | 29262 | if (inst_ty.isSinglePointer(zcu) and |
| 29234 | inst_ty.childType(mod).isTuple(mod) and | 29263 | 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 | } |
| 29251 | 29280 | ||
| 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; |
| 29255 | 29284 | ||
| 29256 | // empty tuple to zero-length slice | 29285 | // 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 so | 29288 | 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 | } |
| 29282 | 29299 | ||
| 29283 | // pointer to tuple to slice | 29300 | // 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); |
| 29299 | 29316 | ||
| 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 number | 29356 | // 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 | } |
| 29359 | 29376 | ||
| 29360 | // integer widening | 29377 | // 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) or | 29380 | 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 ints | 29381 | // 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 error | 29434 | // 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 enum | 29450 | // 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 type | 29461 | // 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 that | 29576 | // 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` which | 29577 | // 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); |
| 29540 | 29580 | ||
| 29541 | if (!opts.report_err) return error.NotCoercible; | 29581 | if (!opts.report_err) return error.NotCoercible; |
| 29542 | 29582 | ||
| 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); |
| 29547 | 29587 | ||
| 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 | } |
| 29555 | 29595 | ||
| 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); |
| 29559 | 29599 | ||
| 29560 | // E!T to T | 29600 | // E!T to T |
| 29561 | if (inst_ty.zigTypeTag(mod) == .ErrorUnion and | 29601 | 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 | } |
| 29567 | 29607 | ||
| 29568 | // ?T to T | 29608 | // ?T to T |
| 29569 | if (inst_ty.zigTypeTag(mod) == .Optional and | 29609 | 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( |
| 29577 | 29617 | ||
| 29578 | // Add notes about function return type | 29618 | // Add notes about function return type |
| 29579 | if (opts.is_ret and | 29619 | 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 | } |
| 29590 | 29630 | ||
| 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 | } |
| 29594 | 29634 | ||
| 29595 | // TODO maybe add "cannot store an error in type '{}'" note | 29635 | // 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 exactly | 30012 | /// * bit offset attributes must match exactly |
| 29973 | /// * `*`/`[*]` must match exactly, but `[*c]` matches either one | 30013 | /// * `*`/`[*]` must match exactly, but `[*c]` matches either one |
| 29974 | /// * sentinel-terminated pointers can coerce into `[*]` | 30014 | /// * sentinel-terminated pointers can coerce into `[*]` |
| 29975 | fn coerceInMemoryAllowed( | 30015 | pub 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 or | 30125 | const ok_sent = (dest_info.sentinel == null and src_info.sentinel == null) or |
| 30086 | (src_info.sentinel != null and | 30126 | (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); |
| 30426 | 30467 | ||
| 30427 | const ok_ptr_size = src_info.flags.size == dest_info.flags.size or | 30468 | 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 | } |
| 30455 | 30496 | ||
| 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 | } |
| 30464 | 30515 | ||
| 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); |
| 30467 | 30518 | ||
| 30468 | const ok_allows_zero = (dest_allow_zero and | 30519 | const ok_allows_zero = (dest_allow_zero and |
| 30469 | (src_allow_zero or !dest_is_mut)) or | 30520 | (src_allow_zero or !dest_is_mut)) or |
| ... | @@ -30488,7 +30539,7 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -30488,7 +30539,7 @@ fn coerceInMemoryAllowedPtrs( |
| 30488 | 30539 | ||
| 30489 | const ok_sent = dest_info.sentinel == .none or src_info.flags.size == .C or | 30540 | const ok_sent = dest_info.sentinel == .none or src_info.flags.size == .C or |
| 30490 | (src_info.sentinel != .none and | 30541 | (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: { |
| 30875 | 30943 | 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 | |||
| 30935 | const 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 | |||
| 30968 | fn 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 | |||
| 31302 | fn 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 | |||
| 31367 | const 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 | |||
| 31382 | const 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. | ||
| 31388 | fn 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 | }; | ||
| 31604 | 30948 | ||
| 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 | } |
| 31612 | 30978 | ||
| 31613 | fn bitCast( | 30979 | fn 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); |
| 31623 | 30989 | ||
| 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); |
| 31626 | 30992 | ||
| 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); |
| 31629 | 30995 | ||
| 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 | } |
| 31638 | 31004 | ||
| 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 | } |
| 31650 | 31021 | ||
| 31651 | fn 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 | |||
| 31683 | fn 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 | |||
| 31743 | fn coerceArrayPtrToSlice( | 31022 | fn 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 | }; |
| 31891 | 31170 | ||
| ... | @@ -32595,7 +31874,7 @@ fn addReferencedBy( | ... | @@ -32595,7 +31874,7 @@ fn addReferencedBy( |
| 32595 | }); | 31874 | }); |
| 32596 | } | 31875 | } |
| 32597 | 31876 | ||
| 32598 | fn ensureDeclAnalyzed(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!void { | 31877 | pub 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 | } |
| 32679 | 31959 | ||
| ... | @@ -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( |
| 33347 | 32627 | ||
| 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 | }); |
| 33378 | 32657 | ||
| 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 | else | 34888 | 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 | else | 34899 | 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 | val | 34913 | val |
| 35643 | else | 34914 | 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? | ||
| 36170 | 35443 | ||
| 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); |
| 36498 | 35771 | ||
| 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 | } |
| 36501 | 35782 | ||
| 36502 | pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void { | 35783 | pub 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); |
| 36523 | 35804 | ||
| 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 | } |
| 36527 | 35816 | ||
| ... | @@ -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 |
| 36560 | 35849 | ||
| 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 | } |
| 36566 | 35863 | ||
| ... | @@ -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( |
| 38158 | 37455 | ||
| 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 | } |
| 38164 | 37462 | ||
| ... | @@ -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. |
| 38249 | fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { | 37547 | fn 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 | }; |
| 38277 | 37574 | ||
| 38278 | fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type) CompileError!DerefResult { | 37575 | fn 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), |
| 38285 | 37582 | .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 or | 37587 | .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 | } |
| 38342 | 37590 | ||
| ... | @@ -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 | } |
| 38396 | 37644 | ||
| 38397 | fn typeAbiSize(sema: *Sema, ty: Type) !u64 { | 37645 | pub 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 | } |
| 38401 | 37649 | ||
| 38402 | fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment { | 37650 | pub 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 | } |
| 38405 | 37653 | ||
| 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`. |
| 38408 | fn unionFieldAlignment(sema: *Sema, u: InternPool.LoadedUnionType, field_index: u32) !Alignment { | 37656 | pub 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 | } |
| 38417 | 37665 | ||
| 38418 | /// Keep implementation in sync with `Module.structFieldAlignment`. | 37666 | /// Keep implementation in sync with `Module.structFieldAlignment`. |
| 38419 | fn structFieldAlignment( | 37667 | pub 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); |
| 38726 | 37974 | ||
| 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 | ); |
| 38813 | 38068 | ||
| 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( |
| 38830 | 38085 | ||
| 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); |
| 38977 | 38232 | ||
| 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( |
| 39070 | 38332 | ||
| 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 *T | 38337 | /// For *[N]T, return *T |
| 39074 | /// For [*]T, returns *T | 38338 | /// For [*]T, returns *T |
| 39075 | /// For []T, returns *T | 38339 | /// 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`. |
| 39078 | fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { | 38342 | pub 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 | } |
| 39182 | 38446 | ||
| 39183 | fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type { | 38447 | pub 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 { |
| 39210 | fn isComptimeMutablePtr(sema: *Sema, val: Value) bool { | 38474 | fn 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 | |||
| 38589 | pub const bitCastVal = @import("Sema/bitcast.zig").bitCast; | ||
| 38590 | pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice; | ||
| 38591 | |||
| 38592 | const loadComptimePtr = @import("Sema/comptime_ptr_access.zig").loadComptimePtr; | ||
| 38593 | const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadResult; | ||
| 38594 | const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr; | ||
| 38595 | const 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. | ||
| 19 | pub 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. | ||
| 46 | pub 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 | |||
| 62 | const BitCastError = CompileError || error{ ReinterpretDeclRef, IllDefinedMemoryLayout, Unimplemented }; | ||
| 63 | |||
| 64 | fn 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 | |||
| 126 | fn 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. | ||
| 211 | const 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. | ||
| 458 | const 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 | |||
| 763 | const std = @import("std"); | ||
| 764 | const Allocator = std.mem.Allocator; | ||
| 765 | const assert = std.debug.assert; | ||
| 766 | |||
| 767 | const Sema = @import("../Sema.zig"); | ||
| 768 | const Zcu = @import("../Module.zig"); | ||
| 769 | const InternPool = @import("../InternPool.zig"); | ||
| 770 | const Type = @import("../type.zig").Type; | ||
| 771 | const Value = @import("../Value.zig"); | ||
| 772 | const CompileError = Zcu.CompileError; | ||
src/Sema/comptime_ptr_access.zig created+1059| ... | @@ -0,0 +1,1059 @@ | ||
| 1 | pub 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 | |||
| 14 | pub 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 | |||
| 40 | pub 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. | ||
| 56 | pub 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. | ||
| 196 | fn 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 | |||
| 494 | const 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. | ||
| 557 | fn 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. | ||
| 912 | fn 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`. | ||
| 954 | fn 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. | ||
| 988 | fn 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 | |||
| 1018 | fn 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 | |||
| 1048 | const std = @import("std"); | ||
| 1049 | const assert = std.debug.assert; | ||
| 1050 | const Allocator = std.mem.Allocator; | ||
| 1051 | const LazySrcLoc = std.zig.LazySrcLoc; | ||
| 1052 | |||
| 1053 | const InternPool = @import("../InternPool.zig"); | ||
| 1054 | const ComptimeAllocIndex = InternPool.ComptimeAllocIndex; | ||
| 1055 | const Sema = @import("../Sema.zig"); | ||
| 1056 | const Block = Sema.Block; | ||
| 1057 | const MutableValue = @import("../mutable_value.zig").MutableValue; | ||
| 1058 | const Type = @import("../type.zig").Type; | ||
| 1059 | const 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 | } |
| 41 | 41 | ||
| 42 | pub fn fmtValue(val: Value, mod: *Module) std.fmt.Formatter(print_value.format) { | 42 | pub 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 | } |
| 48 | 49 | ||
| ... | @@ -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 | else | 247 | 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 { |
| 309 | fn ptrHasIntAddr(val: Value, mod: *Module) bool { | 305 | fn 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 { |
| 983 | 995 | ||
| 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. |
| 986 | pub fn floatCast(self: Value, dest_ty: Type, mod: *Module) !Value { | 998 | pub 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( |
| 1158 | 1166 | ||
| 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, ...)` |
| 1163 | pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, mod: *Module) bool { | 1172 | pub 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 | } |
| 1388 | 1398 | ||
| 1389 | /// Returns a pointer to the element value at the index. | ||
| 1390 | pub 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 | |||
| 1427 | pub fn isUndef(val: Value, mod: *Module) bool { | 1399 | pub 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); |
| 1727 | 1696 | ||
| 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 | } |
| 1942 | 1918 | ||
| 1943 | /// operands must be integers; handles undefined. | 1919 | /// operands must be integers; handles undefined. |
| 1944 | pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { | 1920 | pub 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()); |
| 1947 | 1936 | ||
| 1948 | // TODO is this a performance issue? maybe we should try the operation without | 1937 | // 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 negatives | 1945 | // + 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. | ||
| 1955 | fn 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 | } |
| 1963 | 1970 | ||
| 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 | } |
| 2009 | 2016 | ||
| 2010 | /// operands must be integers; handles undefined. | 2017 | /// operands must be integers; handles undefined. |
| 2011 | pub fn bitwiseOrScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { | 2018 | pub 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()); |
| 2014 | 2034 | ||
| 2015 | // TODO is this a performance issue? maybe we should try the operation without | 2035 | // 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 | } |
| 2029 | 2049 | ||
| 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); | ||
| 2445 | 2467 | ||
| 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); |
| 2448 | 2470 | ||
| 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 }; |
| 2454 | 2476 | ||
| 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 | } |
| 2458 | 2480 | ||
| 2459 | pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 2481 | pub 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 | } |
| 3586 | 3608 | ||
| 3587 | pub const RuntimeIndex = InternPool.RuntimeIndex; | 3609 | pub 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. | ||
| 3614 | pub 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. | ||
| 3649 | pub 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. | ||
| 3680 | pub 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. | ||
| 3832 | pub 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 | |||
| 3916 | fn 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 | |||
| 3947 | pub 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 | |||
| 3955 | pub 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 | |||
| 4008 | pub 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. | ||
| 4024 | pub 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 | } |
| 3060 | 3060 | ||
| 3061 | fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue { | 3061 | fn 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)) { |
| 3083 | 3075 | .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 | else | 3081 | }; |
| 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 | |||
| 3120 | fn 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 | } |
| 3123 | 3110 | ||
| 3124 | fn lowerAnonDeclRef( | 3111 | fn 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 | } |
| 3155 | 3142 | ||
| 3156 | fn lowerDeclRefValue(func: *CodeGen, val: Value, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue { | 3143 | fn 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.?; |
| 3158 | 3145 | ||
| 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 { |
| 17877 | 17877 | ||
| 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"); |
| 16 | const ErrorMsg = Module.ErrorMsg; | 16 | const ErrorMsg = Module.ErrorMsg; |
| 17 | const InternPool = @import("InternPool.zig"); | 17 | const InternPool = @import("InternPool.zig"); |
| 18 | const Liveness = @import("Liveness.zig"); | 18 | const Liveness = @import("Liveness.zig"); |
| 19 | const Module = @import("Module.zig"); | 19 | const Zcu = @import("Module.zig"); |
| 20 | const Module = Zcu; | ||
| 20 | const Target = std.Target; | 21 | const Target = std.Target; |
| 21 | const Type = @import("type.zig").Type; | 22 | const Type = @import("type.zig").Type; |
| 22 | const Value = @import("Value.zig"); | 23 | const 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(); |
| 187 | 188 | ||
| 188 | log.debug("generateSymbol: val = {}", .{val.fmtValue(mod)}); | 189 | log.debug("generateSymbol: val = {}", .{val.fmtValue(mod, null)}); |
| 189 | 190 | ||
| 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 | } |
| 616 | 617 | ||
| 617 | fn lowerParentPtr( | 618 | fn 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 | } |
| 705 | 678 | ||
| 706 | const RelocInfo = struct { | 679 | const 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 | }; |
| 714 | 682 | ||
| 715 | fn lowerAnonDeclRef( | 683 | fn 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)}); |
| 865 | 835 | ||
| 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)}); |
| 970 | 940 | ||
| 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); |
| 1009 | 979 | ||
| 1010 | log.debug("genTypedValue: val = {}", .{val.fmtValue(zcu)}); | 980 | log.debug("genTypedValue: val = {}", .{val.fmtValue(zcu, null)}); |
| 1011 | 981 | ||
| 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(); |
| 1019 | 989 | ||
| 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); |
| 658 | 657 | ||
| 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 | } |
| 664 | 663 | ||
| 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); |
| 670 | 669 | ||
| 671 | assert(decl_val.getVariable(zcu) == null); | 670 | assert(decl_val.getVariable(zcu) == null); |
| 672 | 671 | ||
| ... | @@ -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); |
| 723 | 721 | ||
| 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 | } |
| 730 | 728 | ||
| 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); |
| 736 | 734 | ||
| 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); |
| 738 | 736 | ||
| ... | @@ -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 function | 738 | // them). The analysis until now should ensure that the C function |
| 741 | // pointers are compatible. If they are not, then there is a bug | 739 | // 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) and | 744 | 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 | } |
| 757 | 755 | ||
| 758 | /// Renders a "parent" pointer by recursing to the root decl/variable | 756 | 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('('); |
| 860 | 805 | 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 | } |
| 879 | 860 | ||
| ... | @@ -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; |
| 3266 | 3267 | ||
| 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 | } |
| 4225 | 4218 | ||
| 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 | } |
| 4248 | 4227 | ||
| 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; |
| 4255 | 4234 | 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); |
| 4285 | 4245 | 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, |
| 4317 | 4259 | ), | |
| 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 any | 4262 | .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: { |
| 4324 | 4266 | 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 | } |
| 4374 | 4284 | ||
| ... | @@ -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 | } |
| 4395 | 4304 | ||
| 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)) or | 4308 | 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"); |
| 4402 | 4313 | ||
| 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; |
| 4407 | 4317 | ||
| 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 | ); |
| 4413 | 4323 | ||
| 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 | } |
| 4419 | 4326 | ||
| 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; |
| 4422 | 4329 | ||
| 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 | } |
| 4438 | 4345 | ||
| 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)) or | 4350 | 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 | } | ||
| 4443 | 4355 | ||
| 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).global | 4357 | (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 | ); |
| 4454 | 4366 | ||
| 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 | } |
| 4460 | 4369 | ||
| 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; |
| 865 | 865 | ||
| 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 | } |
| 1109 | 1109 | ||
| 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?? |
| 1112 | 1112 | ||
| 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 | } | ||
| 1115 | 1120 | ||
| 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(); | ||
| 1117 | 1123 | ||
| 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, but | 1134 | // TODO: This can probably be an OpSpecConstantOp Bitcast, but |
| 1124 | // that is not implemented by Mesa yet. Therefore, just generate it | 1135 | // 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, // TODO | 1149 | .anon_decl_ptr => |ad| { |
| 1134 | .opt_payload => unreachable, // TODO | 1150 | 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| { |
| 1140 | 1156 | 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); |
| 1142 | 1158 | 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.*); |
| 1146 | 1162 | 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 is | 1186 | 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. |
| 1176 | 1200 | ||
| ... | @@ -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); |
| 4458 | 4482 | ||
| 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, // TODO | 4491 | .@"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, // TODO | 4497 | .@"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 | } |
| 4477 | 4505 | ||
| 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}); |
| 4481 | 4509 |
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 | }; |
| 56 | 56 | ||
| 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 | } |
| 100 | 100 | ||
| 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 | } |
| 338 | 347 | ||
| 339 | /// Modify a single field of a `MutableValue` which represents an aggregate or slice, leaving others | 348 | /// 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 and | 382 | if (Type.fromInterned(r.ty).zigTypeTag(zcu) != .Struct and |
| 373 | is_trivial_int and | 383 | is_trivial_int and |
| 374 | Type.fromInterned(r.ty).childType(zcu) == .u8_type and | 384 | Type.fromInterned(r.ty).childType(zcu).toIntern() == .u8_type and |
| 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` repr | 415 | // 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; |
| 17 | const FormatContext = struct { | 17 | const FormatContext = struct { |
| 18 | val: Value, | 18 | val: Value, |
| 19 | mod: *Module, | 19 | mod: *Module, |
| 20 | opt_sema: ?*Sema, | ||
| 20 | }; | 21 | }; |
| 21 | 22 | ||
| 22 | pub fn format( | 23 | pub 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 function | 32 | 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's | 126 | // 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's | 145 | // 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( |
| 176 | fn printAggregate( | 177 | fn 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 | } |
| 259 | 261 | ||
| 260 | fn printPtr( | 262 | fn 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. | ||
| 292 | fn 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 | } |
| 173 | 173 | ||
| 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 { |
| 187 | 188 | ||
| 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); |
| 353 | 354 | ||
| 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 | } |
| 1967 | 1968 | ||
| 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 | } |
| 3051 | 3058 | ||
| 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 | } |
| 3303 | 3322 | ||
| 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 | |||
| 521 | test "@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 | |||
| 550 | test "@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, |
| 141 | 141 | ||
| 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 }; |
| 144 | 144 | ||
| 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 | } |
| 33 | 33 | ||
| 34 | test "type pun signed and unsigned as offset many pointer" { | 34 | test "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 | } |
| 48 | 43 | ||
| 49 | test "type pun signed and unsigned as array pointer with pointer arithemtic" { | 44 | test "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 | } |
| 63 | 53 | ||
| ... | @@ -171,10 +161,13 @@ fn doTypePunBitsTest(as_bits: *Bits) !void { | ... | @@ -171,10 +161,13 @@ fn doTypePunBitsTest(as_bits: *Bits) !void { |
| 171 | 161 | ||
| 172 | test "type pun bits" { | 162 | test "type pun bits" { |
| 173 | if (true) { | 163 | if (true) { |
| 174 | // TODO https://github.com/ziglang/zig/issues/9646 | 164 | // TODO: currently, marking one bit of `Bits` as `undefined` does |
| 165 | // mark the whole value as `undefined`, since the pointer interpretation | ||
| 166 | // logic reads it back in as a `u32`, which is partially-undef and thus | ||
| 167 | // has value `undefined`. We need an improved comptime memory representation | ||
| 168 | // to make this work. | ||
| 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 | } |
| 297 | 290 | ||
| 298 | test "offset array ptr by element size" { | 291 | test "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 | }; |
| 312 | 300 | ||
| 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); | ||
| 319 | 302 | ||
| 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 | } |
| 324 | 307 | ||
| ... | @@ -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" { |
| 364 | 347 | ||
| 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 | } |
| 401 | 384 | ||
| 402 | test "bitcast packed union to integer" { | 385 | test "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 | }; |
| 411 | 390 | ||
| 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); |
| 417 | 396 | ||
| 418 | // truncated because the upper bit is garbage memory that we don't care about | 397 | 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 | |||
| 1058 | test "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" { |
| 1731 | test "@fieldParentPtr packed union" { | 1731 | test "@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 | ||
| 1734 | 1735 | ||
| 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" { |
| 92 | 92 | ||
| 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 | }; |
| 104 | 102 | ||
| ... | @@ -610,3 +608,27 @@ test "copied optional doesn't alias source" { | ... | @@ -610,3 +608,27 @@ test "copied optional doesn't alias source" { |
| 610 | 608 | ||
| 611 | try expect(x[0] == 0.0); | 609 | try expect(x[0] == 0.0); |
| 612 | } | 610 | } |
| 611 | |||
| 612 | test "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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const assert = std.debug.assert; | ||
| 3 | const expectEqual = std.testing.expectEqual; | 4 | const expectEqual = std.testing.expectEqual; |
| 4 | 5 | ||
| 5 | test "flags in packed union" { | 6 | test "flags in packed union" { |
| ... | @@ -106,7 +107,7 @@ test "packed union in packed struct" { | ... | @@ -106,7 +107,7 @@ test "packed union in packed struct" { |
| 106 | 107 | ||
| 107 | fn testPackedUnionInPackedStruct() !void { | 108 | fn 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 | |||
| 174 | test "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 | |||
| 625 | test "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 | |||
| 649 | test "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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const expect = std.testing.expect; | 3 | const expect = std.testing.expect; |
| 4 | const assert = std.debug.assert; | ||
| 4 | const native_endian = builtin.target.cpu.arch.endian(); | 5 | const native_endian = builtin.target.cpu.arch.endian(); |
| 5 | 6 | ||
| 6 | test "reinterpret bytes as integer with nonzero offset" { | 7 | test "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 | |||
| 297 | test "@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 | |||
| 339 | test "@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 | |||
| 762 | test "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; |
| 1533 | 1533 | ||
| 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, |
| 1537 | 1537 | ||
| 1538 | fn doTest() !void { | 1538 | fn doTest() !void { |
| ... | @@ -1850,9 +1850,8 @@ test "reinterpret packed union" { | ... | @@ -1850,9 +1850,8 @@ test "reinterpret packed union" { |
| 1850 | 1850 | ||
| 1851 | { | 1851 | { |
| 1852 | // Union initialization | 1852 | // 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 | |||
| 8 | const S = struct { | ||
| 9 | ok: u32, | ||
| 10 | bad: @typeInfo(T), | ||
| 11 | }; | ||
| 12 | |||
| 13 | const T = struct { | ||
| 14 | pub usingnamespace @compileError("usingnamespace analyzed"); | ||
| 15 | }; | ||
| 16 | |||
| 17 | comptime { | ||
| 18 | const a: S = .{ .ok = 123, .bad = undefined }; | ||
| 19 | _ = a; | ||
| 20 | @compileError("should not be reached"); | ||
| 21 | } | ||
| 22 | |||
| 23 | comptime { | ||
| 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 @@ | ||
| 1 | export fn entry1() void { | ||
| 2 | const S = extern struct { x: u32 }; | ||
| 3 | _ = *align(1:2:8) S; | ||
| 4 | } | ||
| 5 | |||
| 6 | export fn entry2() void { | ||
| 7 | const S = struct { x: u32 }; | ||
| 8 | _ = *align(1:2:@sizeOf(S) * 2) S; | ||
| 9 | } | ||
| 10 | |||
| 11 | export 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 @@ | ||
| 1 | export 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 statement | 9 | // :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 @@ | ||
| 1 | const MyStruct = struct { x: bool = false }; | ||
| 2 | |||
| 3 | comptime { | ||
| 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 { |
| 6 | 6 | ||
| 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 | } |
| 11 | comptime { | 11 | comptime { |
| 12 | var opt: ?u8 = 15; | 12 | var opt: ?u8 = 15; |
| ... | @@ -28,6 +28,5 @@ comptime { | ... | @@ -28,6 +28,5 @@ comptime { |
| 28 | // backend=stage2 | 28 | // backend=stage2 |
| 29 | // target=native | 29 | // target=native |
| 30 | // | 30 | // |
| 31 | // :9:20: error: attempt to use null value | ||
| 32 | // :16:20: error: attempt to use null value | 31 | // :16:20: error: attempt to use null value |
| 33 | // :24:20: error: attempt to unwrap error: Foo | 32 | // :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=native | 11 | // 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 4 | 14 | // :3:17: note: destination has length 4 |
| 15 | // :3:17: note: source has length 16 |
test/cases/compile_errors/issue_7810-comptime_slice-len_increment_beyond_bounds.zig+1-3| ... | @@ -8,7 +8,5 @@ export fn foo_slice_len_increment_beyond_bounds() void { | ... | @@ -8,7 +8,5 @@ export fn foo_slice_len_increment_beyond_bounds() void { |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | // error | 10 | // error |
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | 11 | // |
| 14 | // :6:16: error: comptime store of index 8 out of bounds of array length 8 | 12 | // :6:16: error: dereference of '*u8' exceeds bounds of containing decl of type '[8]u8' |
test/cases/compile_errors/overflow_arithmetic_on_vector_with_undefined_elems.zig created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | comptime { | ||
| 2 | const a: @Vector(3, u8) = .{ 1, 200, undefined }; | ||
| 3 | @compileLog(@addWithOverflow(a, a)); | ||
| 4 | } | ||
| 5 | |||
| 6 | comptime { | ||
| 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 | |||
| 12 | comptime { | ||
| 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 | } |
| 31 | export fn entry7() void { | 31 | export 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 | } |
| 36 | export fn entry8() void { | 36 | export 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 | } |
| 73 | export fn entry14() void { | ||
| 74 | const E = enum { implicit, backing, type }; | ||
| 75 | _ = @sizeOf(packed struct { | ||
| 76 | x: E, | ||
| 77 | }); | ||
| 78 | } | ||
| 73 | 79 | ||
| 74 | // error | 80 | // error |
| 75 | // backend=llvm | 81 | // 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 representation | 104 | // :70:12: note: comptime-only pointer has no guaranteed in-memory representation |
| 99 | // :70:12: note: types are not available at runtime | 105 | // :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 @@ | ||
| 1 | export fn entry1() void { | ||
| 2 | const x: u32 = 123; | ||
| 3 | const ptr: [*]const u32 = @ptrCast(&x); | ||
| 4 | _ = ptr - 1; | ||
| 5 | } | ||
| 6 | |||
| 7 | export 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 | } |
| 8 | comptime { | ||
| 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 | } | ||
| 8 | 15 | ||
| 9 | // error | 16 | // error |
| 10 | // backend=stage2 | 17 | // backend=stage2 |
| 11 | // target=native | 18 | // 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=stage2 | 7 | // backend=stage2 |
| 8 | // target=native | 8 | // 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 statement | 31 | // :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]) |