| author | |
| committer | |
| log | d0e74ffe52d0ae0d876d4e3f7ef5d32b5f5460a5 |
| tree | 001cb2b59a48e913e6036675b71f4736c55647c7 |
| parent | 77abd3a96aa8c8c1277cdbb33d88149d4674d389 |
| signature |
We've got a big one here! This commit reworks how we represent pointers
in the InternPool, and rewrites the logic for loading and storing from
them at comptime.
Firstly, the pointer representation. Previously, pointers were
represented in a highly structured manner: pointers to fields, array
elements, etc, were explicitly represented. This works well for simple
cases, but is quite difficult to handle in the cases of unusual
reinterpretations, pointer casts, offsets, etc. Therefore, pointers are
now represented in a more "flat" manner. For types without well-defined
layouts -- such as comptime-only types, automatic-layout aggregates, and
so on -- we still use this "hierarchical" structure. However, for types
with well-defined layouts, we use a byte offset associated with the
pointer. This allows the comptime pointer access logic to deal with
reinterpreted pointers far more gracefully, because the "base address"
of a pointer -- for instance a `field` -- is a single value which
pointer accesses cannot exceed since the parent has undefined layout.
This strategy is also more useful to most backends -- see the updated
logic in `codegen.zig` and `codegen/llvm.zig`. For backends which do
prefer a chain of field and elements accesses for lowering pointer
values, such as SPIR-V, there is a helpful function in `Value` which
creates a strategy to derive a pointer value using ideally only field
and element accesses. This is actually more correct than the previous
logic, since it correctly handles pointer casts which, after the dust
has settled, end up referring exactly to an aggregate field or array
element.
In terms of the pointer access code, it has been rewritten from the
ground up. The old logic had become rather a mess of special cases being
added whenever bugs were hit, and was still riddled with bugs. The new
logic was written to handle the "difficult" cases correctly, the most
notable of which is restructuring of a comptime-only array (for
instance, converting a `[3][2]comptime_int` to a `[2][3]comptime_int`.
Currently, the logic for loading and storing work somewhat differently,
but a future change will likely improve the loading logic to bring it
more in line with the store strategy. As far as I can tell, the rewrite
has fixed all bugs exposed by #19414.
As a part of this, the comptime bitcast logic has also been rewritten.
Previously, bitcasts simply worked by serializing the entire value into
an in-memory buffer, then deserializing it. This strategy has two key
weaknesses: pointers, and undefined values. Representations of these
values at comptime cannot be easily serialized/deserialized whilst
preserving data, which means many bitcasts would become runtime-known if
pointers were involved, or would turn `undefined` values into `0xAA`.
The new logic works by "flattening" the datastructure to be cast into a
sequence of bit-packed atomic values, and then "unflattening" it; using
serialization when necessary, but with special handling for `undefined`
values and for pointers which align in virtual memory. The resulting
code is definitely slower -- more on this later -- but it is correct.
The pointer access and bitcast logic required some helper functions and
types which are not generally useful elsewhere, so I opted to split them
into separate files `Sema/comptime_ptr_access.zig` and
`Sema/bitcast.zig`, with simple re-exports in `Sema.zig` for their small
public APIs.
Whilst working on this branch, I caught various unrelated bugs with
transitive Sema errors, and with the handling of `undefined` values.
These bugs have been fixed, and corresponding behavior test added.
In terms of performance, I do anticipate that this commit will regress
performance somewhat, because the new pointer access and bitcast logic
is necessarily more complex. I have not yet taken performance
measurements, but will do shortly, and post the results in this PR. If
the performance regression is severe, I will do work to to optimize the
new logic before merge.
Resolves: #19452
Resolves: #1946046 files changed, 4794 insertions(+), 2523 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+10-1| ... | @@ -271,13 +271,16 @@ pub const Ip4Address = extern struct { | ... | @@ -271,13 +271,16 @@ 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, |
| 278 | }, | 278 | }, |
| 279 | }; | 279 | }; |
| 280 | const out_ptr = mem.asBytes(&result.sa.addr); | 280 | const out_ptr = mem.asBytes(&result.sa.addr); |
| 281 | if (@inComptime()) { | ||
| 282 | @memset(out_ptr, 0); // TODO: #19634 | ||
| 283 | } | ||
| 281 | 284 | ||
| 282 | var x: u8 = 0; | 285 | var x: u8 = 0; |
| 283 | var index: u8 = 0; | 286 | var index: u8 = 0; |
| ... | @@ -389,6 +392,9 @@ pub const Ip6Address = extern struct { | ... | @@ -389,6 +392,9 @@ pub const Ip6Address = extern struct { |
| 389 | .addr = undefined, | 392 | .addr = undefined, |
| 390 | }, | 393 | }, |
| 391 | }; | 394 | }; |
| 395 | if (@inComptime()) { | ||
| 396 | @memset(std.mem.asBytes(&result.sa.addr), 0); // TODO: #19634 | ||
| 397 | } | ||
| 392 | var ip_slice: *[16]u8 = result.sa.addr[0..]; | 398 | var ip_slice: *[16]u8 = result.sa.addr[0..]; |
| 393 | 399 | ||
| 394 | var tail: [16]u8 = undefined; | 400 | var tail: [16]u8 = undefined; |
| ... | @@ -507,6 +513,9 @@ pub const Ip6Address = extern struct { | ... | @@ -507,6 +513,9 @@ pub const Ip6Address = extern struct { |
| 507 | .addr = undefined, | 513 | .addr = undefined, |
| 508 | }, | 514 | }, |
| 509 | }; | 515 | }; |
| 516 | if (@inComptime()) { | ||
| 517 | @memset(std.mem.asBytes(&result.sa.addr), 0); // TODO: #19634 | ||
| 518 | } | ||
| 510 | var ip_slice: *[16]u8 = result.sa.addr[0..]; | 519 | var ip_slice: *[16]u8 = result.sa.addr[0..]; |
| 511 | 520 | ||
| 512 | var tail: [16]u8 = undefined; | 521 | var tail: [16]u8 = undefined; |
lib/std/packed_int_array.zig+8| ... | @@ -214,6 +214,10 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim | ... | @@ -214,6 +214,10 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim |
| 214 | /// or, more likely, an array literal. | 214 | /// or, more likely, an array literal. |
| 215 | pub fn init(ints: [int_count]Int) Self { | 215 | pub fn init(ints: [int_count]Int) Self { |
| 216 | var self: Self = undefined; | 216 | var self: Self = undefined; |
| 217 | if (@inComptime()) { | ||
| 218 | // TODO: #19634 | ||
| 219 | @memset(&self.bytes, 0xAA); | ||
| 220 | } | ||
| 217 | for (ints, 0..) |int, i| self.set(i, int); | 221 | for (ints, 0..) |int, i| self.set(i, int); |
| 218 | return self; | 222 | return self; |
| 219 | } | 223 | } |
| ... | @@ -221,6 +225,10 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim | ... | @@ -221,6 +225,10 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim |
| 221 | /// Initialize all entries of a packed array to the same value. | 225 | /// Initialize all entries of a packed array to the same value. |
| 222 | pub fn initAllTo(int: Int) Self { | 226 | pub fn initAllTo(int: Int) Self { |
| 223 | var self: Self = undefined; | 227 | var self: Self = undefined; |
| 228 | if (@inComptime()) { | ||
| 229 | // TODO: #19634 | ||
| 230 | @memset(&self.bytes, 0xAA); | ||
| 231 | } | ||
| 224 | self.setAll(int); | 232 | self.setAll(int); |
| 225 | return self; | 233 | return self; |
| 226 | } | 234 | } |
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+756| ... | @@ -0,0 +1,756 @@ | ||
| 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)) { | ||
| 685 | // The value contains undef bits, so is considered entirely undef. | ||
| 686 | return zcu.undefValue(want_ty); | ||
| 687 | } | ||
| 688 | } | ||
| 689 | |||
| 690 | ptr_cast: { | ||
| 691 | if (vals.len != 1) break :ptr_cast; | ||
| 692 | const val = Value.fromInterned(vals[0]); | ||
| 693 | if (!val.typeOf(zcu).isPtrAtRuntime(zcu)) break :ptr_cast; | ||
| 694 | if (!want_ty.isPtrAtRuntime(zcu)) break :ptr_cast; | ||
| 695 | return zcu.getCoerced(val, want_ty); | ||
| 696 | } | ||
| 697 | |||
| 698 | // Reinterpret via an in-memory buffer. | ||
| 699 | |||
| 700 | var buf_bits: u64 = 0; | ||
| 701 | for (vals) |ip_val| { | ||
| 702 | const val = Value.fromInterned(ip_val); | ||
| 703 | const ty = val.typeOf(zcu); | ||
| 704 | buf_bits += ty.bitSize(zcu); | ||
| 705 | } | ||
| 706 | |||
| 707 | const buf = try pack.arena.alloc(u8, @intCast((buf_bits + 7) / 8)); | ||
| 708 | var cur_bit_off: usize = 0; | ||
| 709 | for (vals) |ip_val| { | ||
| 710 | const val = Value.fromInterned(ip_val); | ||
| 711 | const ty = val.typeOf(zcu); | ||
| 712 | try val.writeToPackedMemory(ty, zcu, buf, cur_bit_off); | ||
| 713 | cur_bit_off += @intCast(ty.bitSize(zcu)); | ||
| 714 | } | ||
| 715 | |||
| 716 | return Value.readFromPackedMemory(want_ty, zcu, buf, @intCast(bit_offset), pack.arena); | ||
| 717 | } | ||
| 718 | |||
| 719 | fn prepareBits(pack: *PackValueBits, need_bits: u64) struct { []const InternPool.Index, u64 } { | ||
| 720 | if (need_bits == 0) return .{ &.{}, 0 }; | ||
| 721 | |||
| 722 | const zcu = pack.zcu; | ||
| 723 | |||
| 724 | var bits: u64 = 0; | ||
| 725 | var len: usize = 0; | ||
| 726 | while (bits < pack.bit_offset + need_bits) { | ||
| 727 | bits += Value.fromInterned(pack.unpacked[len]).typeOf(zcu).bitSize(zcu); | ||
| 728 | len += 1; | ||
| 729 | } | ||
| 730 | |||
| 731 | const result_vals = pack.unpacked[0..len]; | ||
| 732 | const result_offset = pack.bit_offset; | ||
| 733 | |||
| 734 | const extra_bits = bits - pack.bit_offset - need_bits; | ||
| 735 | if (extra_bits == 0) { | ||
| 736 | pack.unpacked = pack.unpacked[len..]; | ||
| 737 | pack.bit_offset = 0; | ||
| 738 | } else { | ||
| 739 | pack.unpacked = pack.unpacked[len - 1 ..]; | ||
| 740 | pack.bit_offset = Value.fromInterned(pack.unpacked[0]).typeOf(zcu).bitSize(zcu) - extra_bits; | ||
| 741 | } | ||
| 742 | |||
| 743 | return .{ result_vals, result_offset }; | ||
| 744 | } | ||
| 745 | }; | ||
| 746 | |||
| 747 | const std = @import("std"); | ||
| 748 | const Allocator = std.mem.Allocator; | ||
| 749 | const assert = std.debug.assert; | ||
| 750 | |||
| 751 | const Sema = @import("../Sema.zig"); | ||
| 752 | const Zcu = @import("../Module.zig"); | ||
| 753 | const InternPool = @import("../InternPool.zig"); | ||
| 754 | const Type = @import("../type.zig").Type; | ||
| 755 | const Value = @import("../Value.zig"); | ||
| 756 | 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+714-81| ... | @@ -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 | }; |
| ... | @@ -731,7 +727,8 @@ pub fn readFromMemory( | ... | @@ -731,7 +727,8 @@ pub fn readFromMemory( |
| 731 | const int_val = try readFromMemory(Type.usize, mod, buffer, arena); | 727 | const int_val = try readFromMemory(Type.usize, mod, buffer, arena); |
| 732 | return Value.fromInterned((try mod.intern(.{ .ptr = .{ | 728 | return Value.fromInterned((try mod.intern(.{ .ptr = .{ |
| 733 | .ty = ty.toIntern(), | 729 | .ty = ty.toIntern(), |
| 734 | .addr = .{ .int = int_val.toIntern() }, | 730 | .base_addr = .int, |
| 731 | .byte_offset = int_val.toUnsignedInt(mod), | ||
| 735 | } }))); | 732 | } }))); |
| 736 | }, | 733 | }, |
| 737 | .Optional => { | 734 | .Optional => { |
| ... | @@ -869,12 +866,25 @@ pub fn readFromPackedMemory( | ... | @@ -869,12 +866,25 @@ pub fn readFromPackedMemory( |
| 869 | }, | 866 | }, |
| 870 | .Pointer => { | 867 | .Pointer => { |
| 871 | assert(!ty.isSlice(mod)); // No well defined layout. | 868 | assert(!ty.isSlice(mod)); // No well defined layout. |
| 872 | return readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena); | 869 | const int_val = try readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena); |
| 870 | return Value.fromInterned(try mod.intern(.{ .ptr = .{ | ||
| 871 | .ty = ty.toIntern(), | ||
| 872 | .base_addr = .int, | ||
| 873 | .byte_offset = int_val.toUnsignedInt(mod), | ||
| 874 | } })); | ||
| 873 | }, | 875 | }, |
| 874 | .Optional => { | 876 | .Optional => { |
| 875 | assert(ty.isPtrLikeOptional(mod)); | 877 | assert(ty.isPtrLikeOptional(mod)); |
| 876 | const child = ty.optionalChild(mod); | 878 | const child_ty = ty.optionalChild(mod); |
| 877 | return readFromPackedMemory(child, mod, buffer, bit_offset, arena); | 879 | const child_val = try readFromPackedMemory(child_ty, mod, buffer, bit_offset, arena); |
| 880 | return Value.fromInterned(try mod.intern(.{ .opt = .{ | ||
| 881 | .ty = ty.toIntern(), | ||
| 882 | .val = switch (child_val.orderAgainstZero(mod)) { | ||
| 883 | .lt => unreachable, | ||
| 884 | .eq => .none, | ||
| 885 | .gt => child_val.toIntern(), | ||
| 886 | }, | ||
| 887 | } })); | ||
| 878 | }, | 888 | }, |
| 879 | else => @panic("TODO implement readFromPackedMemory for more types"), | 889 | else => @panic("TODO implement readFromPackedMemory for more types"), |
| 880 | } | 890 | } |
| ... | @@ -983,16 +993,17 @@ pub fn intBitCountTwosComp(self: Value, mod: *Module) usize { | ... | @@ -983,16 +993,17 @@ pub fn intBitCountTwosComp(self: Value, mod: *Module) usize { |
| 983 | 993 | ||
| 984 | /// Converts an integer or a float to a float. May result in a loss of information. | 994 | /// 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. | 995 | /// Caller can find out by equality checking the result against the operand. |
| 986 | pub fn floatCast(self: Value, dest_ty: Type, mod: *Module) !Value { | 996 | pub fn floatCast(val: Value, dest_ty: Type, zcu: *Zcu) !Value { |
| 987 | const target = mod.getTarget(); | 997 | const target = zcu.getTarget(); |
| 988 | return Value.fromInterned((try mod.intern(.{ .float = .{ | 998 | if (val.isUndef(zcu)) return zcu.undefValue(dest_ty); |
| 999 | return Value.fromInterned((try zcu.intern(.{ .float = .{ | ||
| 989 | .ty = dest_ty.toIntern(), | 1000 | .ty = dest_ty.toIntern(), |
| 990 | .storage = switch (dest_ty.floatBits(target)) { | 1001 | .storage = switch (dest_ty.floatBits(target)) { |
| 991 | 16 => .{ .f16 = self.toFloat(f16, mod) }, | 1002 | 16 => .{ .f16 = val.toFloat(f16, zcu) }, |
| 992 | 32 => .{ .f32 = self.toFloat(f32, mod) }, | 1003 | 32 => .{ .f32 = val.toFloat(f32, zcu) }, |
| 993 | 64 => .{ .f64 = self.toFloat(f64, mod) }, | 1004 | 64 => .{ .f64 = val.toFloat(f64, zcu) }, |
| 994 | 80 => .{ .f80 = self.toFloat(f80, mod) }, | 1005 | 80 => .{ .f80 = val.toFloat(f80, zcu) }, |
| 995 | 128 => .{ .f128 = self.toFloat(f128, mod) }, | 1006 | 128 => .{ .f128 = val.toFloat(f128, zcu) }, |
| 996 | else => unreachable, | 1007 | else => unreachable, |
| 997 | }, | 1008 | }, |
| 998 | } }))); | 1009 | } }))); |
| ... | @@ -1021,14 +1032,9 @@ pub fn orderAgainstZeroAdvanced( | ... | @@ -1021,14 +1032,9 @@ pub fn orderAgainstZeroAdvanced( |
| 1021 | .bool_false => .eq, | 1032 | .bool_false => .eq, |
| 1022 | .bool_true => .gt, | 1033 | .bool_true => .gt, |
| 1023 | else => switch (mod.intern_pool.indexToKey(lhs.toIntern())) { | 1034 | else => switch (mod.intern_pool.indexToKey(lhs.toIntern())) { |
| 1024 | .ptr => |ptr| switch (ptr.addr) { | 1035 | .ptr => |ptr| if (ptr.byte_offset > 0) .gt else switch (ptr.base_addr) { |
| 1025 | .decl, .comptime_alloc, .comptime_field => .gt, | 1036 | .decl, .comptime_alloc, .comptime_field => .gt, |
| 1026 | .int => |int| Value.fromInterned(int).orderAgainstZeroAdvanced(mod, opt_sema), | 1037 | .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, | 1038 | else => unreachable, |
| 1033 | }, | 1039 | }, |
| 1034 | .int => |int| switch (int.storage) { | 1040 | .int => |int| switch (int.storage) { |
| ... | @@ -1158,6 +1164,7 @@ pub fn compareScalar( | ... | @@ -1158,6 +1164,7 @@ pub fn compareScalar( |
| 1158 | 1164 | ||
| 1159 | /// Asserts the value is comparable. | 1165 | /// Asserts the value is comparable. |
| 1160 | /// For vectors, returns true if comparison is true for ALL elements. | 1166 | /// For vectors, returns true if comparison is true for ALL elements. |
| 1167 | /// Returns `false` if the value or any vector element is undefined. | ||
| 1161 | /// | 1168 | /// |
| 1162 | /// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)` | 1169 | /// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)` |
| 1163 | pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, mod: *Module) bool { | 1170 | pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, mod: *Module) bool { |
| ... | @@ -1200,6 +1207,7 @@ pub fn compareAllWithZeroAdvancedExtra( | ... | @@ -1200,6 +1207,7 @@ pub fn compareAllWithZeroAdvancedExtra( |
| 1200 | } else true, | 1207 | } else true, |
| 1201 | .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, opt_sema), | 1208 | .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, opt_sema), |
| 1202 | }, | 1209 | }, |
| 1210 | .undef => return false, | ||
| 1203 | else => {}, | 1211 | else => {}, |
| 1204 | } | 1212 | } |
| 1205 | return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op); | 1213 | return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op); |
| ... | @@ -1217,14 +1225,14 @@ pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool { | ... | @@ -1217,14 +1225,14 @@ pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool { |
| 1217 | .err_name => false, | 1225 | .err_name => false, |
| 1218 | .payload => |payload| Value.fromInterned(payload).canMutateComptimeVarState(zcu), | 1226 | .payload => |payload| Value.fromInterned(payload).canMutateComptimeVarState(zcu), |
| 1219 | }, | 1227 | }, |
| 1220 | .ptr => |ptr| switch (ptr.addr) { | 1228 | .ptr => |ptr| switch (ptr.base_addr) { |
| 1221 | .decl => false, // The value of a Decl can never reference a comptime alloc. | 1229 | .decl => false, // The value of a Decl can never reference a comptime alloc. |
| 1222 | .int => false, | 1230 | .int => false, |
| 1223 | .comptime_alloc => true, // A comptime alloc is either mutable or references comptime-mutable memory. | 1231 | .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. | 1232 | .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), | 1233 | .eu_payload, .opt_payload => |base| Value.fromInterned(base).canMutateComptimeVarState(zcu), |
| 1226 | .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).canMutateComptimeVarState(zcu), | 1234 | .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).canMutateComptimeVarState(zcu), |
| 1227 | .elem, .field => |base_index| Value.fromInterned(base_index.base).canMutateComptimeVarState(zcu), | 1235 | .arr_elem, .field => |base_index| Value.fromInterned(base_index.base).canMutateComptimeVarState(zcu), |
| 1228 | }, | 1236 | }, |
| 1229 | .slice => |slice| return Value.fromInterned(slice.ptr).canMutateComptimeVarState(zcu), | 1237 | .slice => |slice| return Value.fromInterned(slice.ptr).canMutateComptimeVarState(zcu), |
| 1230 | .opt => |opt| switch (opt.val) { | 1238 | .opt => |opt| switch (opt.val) { |
| ... | @@ -1247,10 +1255,10 @@ pub fn pointerDecl(val: Value, mod: *Module) ?InternPool.DeclIndex { | ... | @@ -1247,10 +1255,10 @@ pub fn pointerDecl(val: Value, mod: *Module) ?InternPool.DeclIndex { |
| 1247 | .variable => |variable| variable.decl, | 1255 | .variable => |variable| variable.decl, |
| 1248 | .extern_func => |extern_func| extern_func.decl, | 1256 | .extern_func => |extern_func| extern_func.decl, |
| 1249 | .func => |func| func.owner_decl, | 1257 | .func => |func| func.owner_decl, |
| 1250 | .ptr => |ptr| switch (ptr.addr) { | 1258 | .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) { |
| 1251 | .decl => |decl| decl, | 1259 | .decl => |decl| decl, |
| 1252 | else => null, | 1260 | else => null, |
| 1253 | }, | 1261 | } else null, |
| 1254 | else => null, | 1262 | else => null, |
| 1255 | }; | 1263 | }; |
| 1256 | } | 1264 | } |
| ... | @@ -1386,44 +1394,6 @@ pub fn unionValue(val: Value, mod: *Module) Value { | ... | @@ -1386,44 +1394,6 @@ pub fn unionValue(val: Value, mod: *Module) Value { |
| 1386 | }; | 1394 | }; |
| 1387 | } | 1395 | } |
| 1388 | 1396 | ||
| 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 { | 1397 | pub fn isUndef(val: Value, mod: *Module) bool { |
| 1428 | return mod.intern_pool.isUndef(val.toIntern()); | 1398 | return mod.intern_pool.isUndef(val.toIntern()); |
| 1429 | } | 1399 | } |
| ... | @@ -1444,11 +1414,8 @@ pub fn isNull(val: Value, mod: *Module) bool { | ... | @@ -1444,11 +1414,8 @@ pub fn isNull(val: Value, mod: *Module) bool { |
| 1444 | .null_value => true, | 1414 | .null_value => true, |
| 1445 | else => return switch (mod.intern_pool.indexToKey(val.toIntern())) { | 1415 | else => return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1446 | .undef => unreachable, | 1416 | .undef => unreachable, |
| 1447 | .ptr => |ptr| switch (ptr.addr) { | 1417 | .ptr => |ptr| switch (ptr.base_addr) { |
| 1448 | .int => { | 1418 | .int => ptr.byte_offset == 0, |
| 1449 | var buf: BigIntSpace = undefined; | ||
| 1450 | return val.toBigInt(&buf, mod).eqlZero(); | ||
| 1451 | }, | ||
| 1452 | else => false, | 1419 | else => false, |
| 1453 | }, | 1420 | }, |
| 1454 | .opt => |opt| opt.val == .none, | 1421 | .opt => |opt| opt.val == .none, |
| ... | @@ -1725,6 +1692,13 @@ pub fn intMulWithOverflowScalar( | ... | @@ -1725,6 +1692,13 @@ pub fn intMulWithOverflowScalar( |
| 1725 | ) !OverflowArithmeticResult { | 1692 | ) !OverflowArithmeticResult { |
| 1726 | const info = ty.intInfo(mod); | 1693 | const info = ty.intInfo(mod); |
| 1727 | 1694 | ||
| 1695 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) { | ||
| 1696 | return .{ | ||
| 1697 | .overflow_bit = try mod.undefValue(Type.u1), | ||
| 1698 | .wrapped_result = try mod.undefValue(ty), | ||
| 1699 | }; | ||
| 1700 | } | ||
| 1701 | |||
| 1728 | var lhs_space: Value.BigIntSpace = undefined; | 1702 | var lhs_space: Value.BigIntSpace = undefined; |
| 1729 | var rhs_space: Value.BigIntSpace = undefined; | 1703 | var rhs_space: Value.BigIntSpace = undefined; |
| 1730 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); | 1704 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| ... | @@ -2439,12 +2413,14 @@ pub fn intTruncScalar( | ... | @@ -2439,12 +2413,14 @@ pub fn intTruncScalar( |
| 2439 | allocator: Allocator, | 2413 | allocator: Allocator, |
| 2440 | signedness: std.builtin.Signedness, | 2414 | signedness: std.builtin.Signedness, |
| 2441 | bits: u16, | 2415 | bits: u16, |
| 2442 | mod: *Module, | 2416 | zcu: *Zcu, |
| 2443 | ) !Value { | 2417 | ) !Value { |
| 2444 | if (bits == 0) return mod.intValue(ty, 0); | 2418 | if (bits == 0) return zcu.intValue(ty, 0); |
| 2419 | |||
| 2420 | if (val.isUndef(zcu)) return zcu.undefValue(ty); | ||
| 2445 | 2421 | ||
| 2446 | var val_space: Value.BigIntSpace = undefined; | 2422 | var val_space: Value.BigIntSpace = undefined; |
| 2447 | const val_bigint = val.toBigInt(&val_space, mod); | 2423 | const val_bigint = val.toBigInt(&val_space, zcu); |
| 2448 | 2424 | ||
| 2449 | const limbs = try allocator.alloc( | 2425 | const limbs = try allocator.alloc( |
| 2450 | std.math.big.Limb, | 2426 | std.math.big.Limb, |
| ... | @@ -2453,7 +2429,7 @@ pub fn intTruncScalar( | ... | @@ -2453,7 +2429,7 @@ pub fn intTruncScalar( |
| 2453 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 2429 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 2454 | 2430 | ||
| 2455 | result_bigint.truncate(val_bigint, signedness, bits); | 2431 | result_bigint.truncate(val_bigint, signedness, bits); |
| 2456 | return mod.intValue_big(ty, result_bigint.toConst()); | 2432 | return zcu.intValue_big(ty, result_bigint.toConst()); |
| 2457 | } | 2433 | } |
| 2458 | 2434 | ||
| 2459 | pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 2435 | pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| ... | @@ -3585,3 +3561,660 @@ pub fn makeBool(x: bool) Value { | ... | @@ -3585,3 +3561,660 @@ pub fn makeBool(x: bool) Value { |
| 3585 | } | 3561 | } |
| 3586 | 3562 | ||
| 3587 | pub const RuntimeIndex = InternPool.RuntimeIndex; | 3563 | pub const RuntimeIndex = InternPool.RuntimeIndex; |
| 3564 | |||
| 3565 | /// `parent_ptr` must be a single-pointer to some optional. | ||
| 3566 | /// Returns a pointer to the payload of the optional. | ||
| 3567 | /// This takes a `Sema` because it may need to perform type resolution. | ||
| 3568 | pub fn ptrOptPayload(parent_ptr: Value, sema: *Sema) !Value { | ||
| 3569 | const zcu = sema.mod; | ||
| 3570 | |||
| 3571 | const parent_ptr_ty = parent_ptr.typeOf(zcu); | ||
| 3572 | const opt_ty = parent_ptr_ty.childType(zcu); | ||
| 3573 | |||
| 3574 | assert(parent_ptr_ty.ptrSize(zcu) == .One); | ||
| 3575 | assert(opt_ty.zigTypeTag(zcu) == .Optional); | ||
| 3576 | |||
| 3577 | const result_ty = try sema.ptrType(info: { | ||
| 3578 | var new = parent_ptr_ty.ptrInfo(zcu); | ||
| 3579 | // We can correctly preserve alignment `.none`, since an optional has the same | ||
| 3580 | // natural alignment as its child type. | ||
| 3581 | new.child = opt_ty.childType(zcu).toIntern(); | ||
| 3582 | break :info new; | ||
| 3583 | }); | ||
| 3584 | |||
| 3585 | if (parent_ptr.isUndef(zcu)) return zcu.undefValue(result_ty); | ||
| 3586 | |||
| 3587 | if (opt_ty.isPtrLikeOptional(zcu)) { | ||
| 3588 | // Just reinterpret the pointer, since the layout is well-defined | ||
| 3589 | return zcu.getCoerced(parent_ptr, result_ty); | ||
| 3590 | } | ||
| 3591 | |||
| 3592 | const base_ptr = try parent_ptr.canonicalizeBasePtr(.One, opt_ty, zcu); | ||
| 3593 | return Value.fromInterned(try zcu.intern(.{ .ptr = .{ | ||
| 3594 | .ty = result_ty.toIntern(), | ||
| 3595 | .base_addr = .{ .opt_payload = base_ptr.toIntern() }, | ||
| 3596 | .byte_offset = 0, | ||
| 3597 | } })); | ||
| 3598 | } | ||
| 3599 | |||
| 3600 | /// `parent_ptr` must be a single-pointer to some error union. | ||
| 3601 | /// Returns a pointer to the payload of the error union. | ||
| 3602 | /// This takes a `Sema` because it may need to perform type resolution. | ||
| 3603 | pub fn ptrEuPayload(parent_ptr: Value, sema: *Sema) !Value { | ||
| 3604 | const zcu = sema.mod; | ||
| 3605 | |||
| 3606 | const parent_ptr_ty = parent_ptr.typeOf(zcu); | ||
| 3607 | const eu_ty = parent_ptr_ty.childType(zcu); | ||
| 3608 | |||
| 3609 | assert(parent_ptr_ty.ptrSize(zcu) == .One); | ||
| 3610 | assert(eu_ty.zigTypeTag(zcu) == .ErrorUnion); | ||
| 3611 | |||
| 3612 | const result_ty = try sema.ptrType(info: { | ||
| 3613 | var new = parent_ptr_ty.ptrInfo(zcu); | ||
| 3614 | // We can correctly preserve alignment `.none`, since an error union has a | ||
| 3615 | // natural alignment greater than or equal to that of its payload type. | ||
| 3616 | new.child = eu_ty.errorUnionPayload(zcu).toIntern(); | ||
| 3617 | break :info new; | ||
| 3618 | }); | ||
| 3619 | |||
| 3620 | if (parent_ptr.isUndef(zcu)) return zcu.undefValue(result_ty); | ||
| 3621 | |||
| 3622 | const base_ptr = try parent_ptr.canonicalizeBasePtr(.One, eu_ty, zcu); | ||
| 3623 | return Value.fromInterned(try zcu.intern(.{ .ptr = .{ | ||
| 3624 | .ty = result_ty.toIntern(), | ||
| 3625 | .base_addr = .{ .eu_payload = base_ptr.toIntern() }, | ||
| 3626 | .byte_offset = 0, | ||
| 3627 | } })); | ||
| 3628 | } | ||
| 3629 | |||
| 3630 | /// `parent_ptr` must be a single-pointer to a struct, union, or slice. | ||
| 3631 | /// Returns a pointer to the aggregate field at the specified index. | ||
| 3632 | /// For slices, uses `slice_ptr_index` and `slice_len_index`. | ||
| 3633 | /// This takes a `Sema` because it may need to perform type resolution. | ||
| 3634 | pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value { | ||
| 3635 | const zcu = sema.mod; | ||
| 3636 | |||
| 3637 | const parent_ptr_ty = parent_ptr.typeOf(zcu); | ||
| 3638 | const aggregate_ty = parent_ptr_ty.childType(zcu); | ||
| 3639 | |||
| 3640 | const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu); | ||
| 3641 | assert(parent_ptr_info.flags.size == .One); | ||
| 3642 | |||
| 3643 | // Exiting this `switch` indicates that the `field` pointer repsentation should be used. | ||
| 3644 | // `field_align` may be `.none` to represent the natural alignment of `field_ty`, but is not necessarily. | ||
| 3645 | const field_ty: Type, const field_align: InternPool.Alignment = switch (aggregate_ty.zigTypeTag(zcu)) { | ||
| 3646 | .Struct => field: { | ||
| 3647 | const field_ty = aggregate_ty.structFieldType(field_idx, zcu); | ||
| 3648 | switch (aggregate_ty.containerLayout(zcu)) { | ||
| 3649 | .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, sema) }, | ||
| 3650 | .@"extern" => { | ||
| 3651 | // Well-defined layout, so just offset the pointer appropriately. | ||
| 3652 | const byte_off = aggregate_ty.structFieldOffset(field_idx, zcu); | ||
| 3653 | const field_align = a: { | ||
| 3654 | const parent_align = if (parent_ptr_info.flags.alignment == .none) pa: { | ||
| 3655 | break :pa try sema.typeAbiAlignment(aggregate_ty); | ||
| 3656 | } else parent_ptr_info.flags.alignment; | ||
| 3657 | break :a InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(byte_off))); | ||
| 3658 | }; | ||
| 3659 | const result_ty = try sema.ptrType(info: { | ||
| 3660 | var new = parent_ptr_info; | ||
| 3661 | new.child = field_ty.toIntern(); | ||
| 3662 | new.flags.alignment = field_align; | ||
| 3663 | break :info new; | ||
| 3664 | }); | ||
| 3665 | return parent_ptr.getOffsetPtr(byte_off, result_ty, zcu); | ||
| 3666 | }, | ||
| 3667 | .@"packed" => switch (aggregate_ty.packedStructFieldPtrInfo(parent_ptr_ty, field_idx, zcu)) { | ||
| 3668 | .bit_ptr => |packed_offset| { | ||
| 3669 | const result_ty = try zcu.ptrType(info: { | ||
| 3670 | var new = parent_ptr_info; | ||
| 3671 | new.packed_offset = packed_offset; | ||
| 3672 | new.child = field_ty.toIntern(); | ||
| 3673 | if (new.flags.alignment == .none) { | ||
| 3674 | new.flags.alignment = try sema.typeAbiAlignment(aggregate_ty); | ||
| 3675 | } | ||
| 3676 | break :info new; | ||
| 3677 | }); | ||
| 3678 | return zcu.getCoerced(parent_ptr, result_ty); | ||
| 3679 | }, | ||
| 3680 | .byte_ptr => |ptr_info| { | ||
| 3681 | const result_ty = try sema.ptrType(info: { | ||
| 3682 | var new = parent_ptr_info; | ||
| 3683 | new.child = field_ty.toIntern(); | ||
| 3684 | new.packed_offset = .{ | ||
| 3685 | .host_size = 0, | ||
| 3686 | .bit_offset = 0, | ||
| 3687 | }; | ||
| 3688 | new.flags.alignment = ptr_info.alignment; | ||
| 3689 | break :info new; | ||
| 3690 | }); | ||
| 3691 | return parent_ptr.getOffsetPtr(ptr_info.offset, result_ty, zcu); | ||
| 3692 | }, | ||
| 3693 | }, | ||
| 3694 | } | ||
| 3695 | }, | ||
| 3696 | .Union => field: { | ||
| 3697 | const union_obj = zcu.typeToUnion(aggregate_ty).?; | ||
| 3698 | const field_ty = Type.fromInterned(union_obj.field_types.get(&zcu.intern_pool)[field_idx]); | ||
| 3699 | switch (aggregate_ty.containerLayout(zcu)) { | ||
| 3700 | .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, sema) }, | ||
| 3701 | .@"extern" => { | ||
| 3702 | // Point to the same address. | ||
| 3703 | const result_ty = try sema.ptrType(info: { | ||
| 3704 | var new = parent_ptr_info; | ||
| 3705 | new.child = field_ty.toIntern(); | ||
| 3706 | break :info new; | ||
| 3707 | }); | ||
| 3708 | return zcu.getCoerced(parent_ptr, result_ty); | ||
| 3709 | }, | ||
| 3710 | .@"packed" => { | ||
| 3711 | // If the field has an ABI size matching its bit size, then we can continue to use a | ||
| 3712 | // non-bit pointer if the parent pointer is also a non-bit pointer. | ||
| 3713 | if (parent_ptr_info.packed_offset.host_size == 0 and try sema.typeAbiSize(field_ty) * 8 == try field_ty.bitSizeAdvanced(zcu, sema)) { | ||
| 3714 | // We must offset the pointer on big-endian targets, since the bits of packed memory don't align nicely. | ||
| 3715 | const byte_offset = switch (zcu.getTarget().cpu.arch.endian()) { | ||
| 3716 | .little => 0, | ||
| 3717 | .big => try sema.typeAbiSize(aggregate_ty) - try sema.typeAbiSize(field_ty), | ||
| 3718 | }; | ||
| 3719 | const result_ty = try sema.ptrType(info: { | ||
| 3720 | var new = parent_ptr_info; | ||
| 3721 | new.child = field_ty.toIntern(); | ||
| 3722 | new.flags.alignment = InternPool.Alignment.fromLog2Units( | ||
| 3723 | @ctz(byte_offset | (try parent_ptr_ty.ptrAlignmentAdvanced(zcu, sema)).toByteUnits().?), | ||
| 3724 | ); | ||
| 3725 | break :info new; | ||
| 3726 | }); | ||
| 3727 | return parent_ptr.getOffsetPtr(byte_offset, result_ty, zcu); | ||
| 3728 | } else { | ||
| 3729 | // The result must be a bit-pointer if it is not already. | ||
| 3730 | const result_ty = try sema.ptrType(info: { | ||
| 3731 | var new = parent_ptr_info; | ||
| 3732 | new.child = field_ty.toIntern(); | ||
| 3733 | if (new.packed_offset.host_size == 0) { | ||
| 3734 | new.packed_offset.host_size = @intCast(((try aggregate_ty.bitSizeAdvanced(zcu, sema)) + 7) / 8); | ||
| 3735 | assert(new.packed_offset.bit_offset == 0); | ||
| 3736 | } | ||
| 3737 | break :info new; | ||
| 3738 | }); | ||
| 3739 | return zcu.getCoerced(parent_ptr, result_ty); | ||
| 3740 | } | ||
| 3741 | }, | ||
| 3742 | } | ||
| 3743 | }, | ||
| 3744 | .Pointer => field_ty: { | ||
| 3745 | assert(aggregate_ty.isSlice(zcu)); | ||
| 3746 | break :field_ty switch (field_idx) { | ||
| 3747 | Value.slice_ptr_index => .{ aggregate_ty.slicePtrFieldType(zcu), Type.usize.abiAlignment(zcu) }, | ||
| 3748 | Value.slice_len_index => .{ Type.usize, Type.usize.abiAlignment(zcu) }, | ||
| 3749 | else => unreachable, | ||
| 3750 | }; | ||
| 3751 | }, | ||
| 3752 | else => unreachable, | ||
| 3753 | }; | ||
| 3754 | |||
| 3755 | const new_align: InternPool.Alignment = if (parent_ptr_info.flags.alignment != .none) a: { | ||
| 3756 | const ty_align = try sema.typeAbiAlignment(field_ty); | ||
| 3757 | const true_field_align = if (field_align == .none) ty_align else field_align; | ||
| 3758 | const new_align = true_field_align.min(parent_ptr_info.flags.alignment); | ||
| 3759 | if (new_align == ty_align) break :a .none; | ||
| 3760 | break :a new_align; | ||
| 3761 | } else field_align; | ||
| 3762 | |||
| 3763 | const result_ty = try sema.ptrType(info: { | ||
| 3764 | var new = parent_ptr_info; | ||
| 3765 | new.child = field_ty.toIntern(); | ||
| 3766 | new.flags.alignment = new_align; | ||
| 3767 | break :info new; | ||
| 3768 | }); | ||
| 3769 | |||
| 3770 | if (parent_ptr.isUndef(zcu)) return zcu.undefValue(result_ty); | ||
| 3771 | |||
| 3772 | const base_ptr = try parent_ptr.canonicalizeBasePtr(.One, aggregate_ty, zcu); | ||
| 3773 | return Value.fromInterned(try zcu.intern(.{ .ptr = .{ | ||
| 3774 | .ty = result_ty.toIntern(), | ||
| 3775 | .base_addr = .{ .field = .{ | ||
| 3776 | .base = base_ptr.toIntern(), | ||
| 3777 | .index = field_idx, | ||
| 3778 | } }, | ||
| 3779 | .byte_offset = 0, | ||
| 3780 | } })); | ||
| 3781 | } | ||
| 3782 | |||
| 3783 | /// `orig_parent_ptr` must be either a single-pointer to an array or vector, or a many-pointer or C-pointer or slice. | ||
| 3784 | /// Returns a pointer to the element at the specified index. | ||
| 3785 | /// This takes a `Sema` because it may need to perform type resolution. | ||
| 3786 | pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, sema: *Sema) !Value { | ||
| 3787 | const zcu = sema.mod; | ||
| 3788 | |||
| 3789 | const parent_ptr = switch (orig_parent_ptr.typeOf(zcu).ptrSize(zcu)) { | ||
| 3790 | .One, .Many, .C => orig_parent_ptr, | ||
| 3791 | .Slice => orig_parent_ptr.slicePtr(zcu), | ||
| 3792 | }; | ||
| 3793 | |||
| 3794 | const parent_ptr_ty = parent_ptr.typeOf(zcu); | ||
| 3795 | const elem_ty = parent_ptr_ty.childType(zcu); | ||
| 3796 | const result_ty = try sema.elemPtrType(parent_ptr_ty, @intCast(field_idx)); | ||
| 3797 | |||
| 3798 | if (parent_ptr.isUndef(zcu)) return zcu.undefValue(result_ty); | ||
| 3799 | |||
| 3800 | if (result_ty.ptrInfo(zcu).packed_offset.host_size != 0) { | ||
| 3801 | // Since we have a bit-pointer, the pointer address should be unchanged. | ||
| 3802 | assert(elem_ty.zigTypeTag(zcu) == .Vector); | ||
| 3803 | return zcu.getCoerced(parent_ptr, result_ty); | ||
| 3804 | } | ||
| 3805 | |||
| 3806 | const PtrStrat = union(enum) { | ||
| 3807 | offset: u64, | ||
| 3808 | elem_ptr: Type, // many-ptr elem ty | ||
| 3809 | }; | ||
| 3810 | |||
| 3811 | const strat: PtrStrat = switch (parent_ptr_ty.ptrSize(zcu)) { | ||
| 3812 | .One => switch (elem_ty.zigTypeTag(zcu)) { | ||
| 3813 | .Vector => .{ .offset = field_idx * @divExact(try elem_ty.childType(zcu).bitSizeAdvanced(zcu, sema), 8) }, | ||
| 3814 | .Array => strat: { | ||
| 3815 | const arr_elem_ty = elem_ty.childType(zcu); | ||
| 3816 | if (try sema.typeRequiresComptime(arr_elem_ty)) { | ||
| 3817 | break :strat .{ .elem_ptr = arr_elem_ty }; | ||
| 3818 | } | ||
| 3819 | break :strat .{ .offset = field_idx * try sema.typeAbiSize(arr_elem_ty) }; | ||
| 3820 | }, | ||
| 3821 | else => unreachable, | ||
| 3822 | }, | ||
| 3823 | |||
| 3824 | .Many, .C => if (try sema.typeRequiresComptime(elem_ty)) | ||
| 3825 | .{ .elem_ptr = elem_ty } | ||
| 3826 | else | ||
| 3827 | .{ .offset = field_idx * try sema.typeAbiSize(elem_ty) }, | ||
| 3828 | |||
| 3829 | .Slice => unreachable, | ||
| 3830 | }; | ||
| 3831 | |||
| 3832 | switch (strat) { | ||
| 3833 | .offset => |byte_offset| { | ||
| 3834 | return parent_ptr.getOffsetPtr(byte_offset, result_ty, zcu); | ||
| 3835 | }, | ||
| 3836 | .elem_ptr => |manyptr_elem_ty| if (field_idx == 0) { | ||
| 3837 | return zcu.getCoerced(parent_ptr, result_ty); | ||
| 3838 | } else { | ||
| 3839 | const arr_base_ty, const arr_base_len = manyptr_elem_ty.arrayBase(zcu); | ||
| 3840 | const base_idx = arr_base_len * field_idx; | ||
| 3841 | const parent_info = zcu.intern_pool.indexToKey(parent_ptr.toIntern()).ptr; | ||
| 3842 | switch (parent_info.base_addr) { | ||
| 3843 | .arr_elem => |arr_elem| { | ||
| 3844 | if (Value.fromInterned(arr_elem.base).typeOf(zcu).childType(zcu).toIntern() == arr_base_ty.toIntern()) { | ||
| 3845 | // We already have a pointer to an element of an array of this type. | ||
| 3846 | // Just modify the index. | ||
| 3847 | return Value.fromInterned(try zcu.intern(.{ .ptr = ptr: { | ||
| 3848 | var new = parent_info; | ||
| 3849 | new.base_addr.arr_elem.index += base_idx; | ||
| 3850 | new.ty = result_ty.toIntern(); | ||
| 3851 | break :ptr new; | ||
| 3852 | } })); | ||
| 3853 | } | ||
| 3854 | }, | ||
| 3855 | else => {}, | ||
| 3856 | } | ||
| 3857 | const base_ptr = try parent_ptr.canonicalizeBasePtr(.Many, arr_base_ty, zcu); | ||
| 3858 | return Value.fromInterned(try zcu.intern(.{ .ptr = .{ | ||
| 3859 | .ty = result_ty.toIntern(), | ||
| 3860 | .base_addr = .{ .arr_elem = .{ | ||
| 3861 | .base = base_ptr.toIntern(), | ||
| 3862 | .index = base_idx, | ||
| 3863 | } }, | ||
| 3864 | .byte_offset = 0, | ||
| 3865 | } })); | ||
| 3866 | }, | ||
| 3867 | } | ||
| 3868 | } | ||
| 3869 | |||
| 3870 | fn canonicalizeBasePtr(base_ptr: Value, want_size: std.builtin.Type.Pointer.Size, want_child: Type, zcu: *Zcu) !Value { | ||
| 3871 | const ptr_ty = base_ptr.typeOf(zcu); | ||
| 3872 | const ptr_info = ptr_ty.ptrInfo(zcu); | ||
| 3873 | |||
| 3874 | if (ptr_info.flags.size == want_size and | ||
| 3875 | ptr_info.child == want_child.toIntern() and | ||
| 3876 | !ptr_info.flags.is_const and | ||
| 3877 | !ptr_info.flags.is_volatile and | ||
| 3878 | !ptr_info.flags.is_allowzero and | ||
| 3879 | ptr_info.sentinel == .none and | ||
| 3880 | ptr_info.flags.alignment == .none) | ||
| 3881 | { | ||
| 3882 | // Already canonical! | ||
| 3883 | return base_ptr; | ||
| 3884 | } | ||
| 3885 | |||
| 3886 | const new_ty = try zcu.ptrType(.{ | ||
| 3887 | .child = want_child.toIntern(), | ||
| 3888 | .sentinel = .none, | ||
| 3889 | .flags = .{ | ||
| 3890 | .size = want_size, | ||
| 3891 | .alignment = .none, | ||
| 3892 | .is_const = false, | ||
| 3893 | .is_volatile = false, | ||
| 3894 | .is_allowzero = false, | ||
| 3895 | .address_space = ptr_info.flags.address_space, | ||
| 3896 | }, | ||
| 3897 | }); | ||
| 3898 | return zcu.getCoerced(base_ptr, new_ty); | ||
| 3899 | } | ||
| 3900 | |||
| 3901 | pub fn getOffsetPtr(ptr_val: Value, byte_off: u64, new_ty: Type, zcu: *Zcu) !Value { | ||
| 3902 | if (ptr_val.isUndef(zcu)) return ptr_val; | ||
| 3903 | var ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr; | ||
| 3904 | ptr.ty = new_ty.toIntern(); | ||
| 3905 | ptr.byte_offset += byte_off; | ||
| 3906 | return Value.fromInterned(try zcu.intern(.{ .ptr = ptr })); | ||
| 3907 | } | ||
| 3908 | |||
| 3909 | pub const PointerDeriveStep = union(enum) { | ||
| 3910 | int: struct { | ||
| 3911 | addr: u64, | ||
| 3912 | ptr_ty: Type, | ||
| 3913 | }, | ||
| 3914 | decl_ptr: InternPool.DeclIndex, | ||
| 3915 | anon_decl_ptr: InternPool.Key.Ptr.BaseAddr.AnonDecl, | ||
| 3916 | comptime_alloc_ptr: struct { | ||
| 3917 | val: Value, | ||
| 3918 | ptr_ty: Type, | ||
| 3919 | }, | ||
| 3920 | comptime_field_ptr: Value, | ||
| 3921 | eu_payload_ptr: struct { | ||
| 3922 | parent: *PointerDeriveStep, | ||
| 3923 | /// This type will never be cast: it is provided for convenience. | ||
| 3924 | result_ptr_ty: Type, | ||
| 3925 | }, | ||
| 3926 | opt_payload_ptr: struct { | ||
| 3927 | parent: *PointerDeriveStep, | ||
| 3928 | /// This type will never be cast: it is provided for convenience. | ||
| 3929 | result_ptr_ty: Type, | ||
| 3930 | }, | ||
| 3931 | field_ptr: struct { | ||
| 3932 | parent: *PointerDeriveStep, | ||
| 3933 | field_idx: u32, | ||
| 3934 | /// This type will never be cast: it is provided for convenience. | ||
| 3935 | result_ptr_ty: Type, | ||
| 3936 | }, | ||
| 3937 | elem_ptr: struct { | ||
| 3938 | parent: *PointerDeriveStep, | ||
| 3939 | elem_idx: u64, | ||
| 3940 | /// This type will never be cast: it is provided for convenience. | ||
| 3941 | result_ptr_ty: Type, | ||
| 3942 | }, | ||
| 3943 | offset_and_cast: struct { | ||
| 3944 | parent: *PointerDeriveStep, | ||
| 3945 | byte_offset: u64, | ||
| 3946 | new_ptr_ty: Type, | ||
| 3947 | }, | ||
| 3948 | |||
| 3949 | pub fn ptrType(step: PointerDeriveStep, zcu: *Zcu) !Type { | ||
| 3950 | return switch (step) { | ||
| 3951 | .int => |int| int.ptr_ty, | ||
| 3952 | .decl_ptr => |decl| try zcu.declPtr(decl).declPtrType(zcu), | ||
| 3953 | .anon_decl_ptr => |ad| Type.fromInterned(ad.orig_ty), | ||
| 3954 | .comptime_alloc_ptr => |info| info.ptr_ty, | ||
| 3955 | .comptime_field_ptr => |val| try zcu.singleConstPtrType(val.typeOf(zcu)), | ||
| 3956 | .offset_and_cast => |oac| oac.new_ptr_ty, | ||
| 3957 | inline .eu_payload_ptr, .opt_payload_ptr, .field_ptr, .elem_ptr => |x| x.result_ptr_ty, | ||
| 3958 | }; | ||
| 3959 | } | ||
| 3960 | }; | ||
| 3961 | |||
| 3962 | pub fn pointerDerivation(ptr_val: Value, arena: Allocator, zcu: *Zcu) Allocator.Error!PointerDeriveStep { | ||
| 3963 | return ptr_val.pointerDerivationAdvanced(arena, zcu, null) catch |err| switch (err) { | ||
| 3964 | error.OutOfMemory => |e| return e, | ||
| 3965 | error.AnalysisFail, | ||
| 3966 | error.NeededSourceLocation, | ||
| 3967 | error.GenericPoison, | ||
| 3968 | error.ComptimeReturn, | ||
| 3969 | error.ComptimeBreak, | ||
| 3970 | => unreachable, | ||
| 3971 | }; | ||
| 3972 | } | ||
| 3973 | |||
| 3974 | /// Given a pointer value, get the sequence of steps to derive it, ideally by taking | ||
| 3975 | /// only field and element pointers with no casts. This can be used by codegen backends | ||
| 3976 | /// which prefer field/elem accesses when lowering constant pointer values. | ||
| 3977 | /// It is also used by the Value printing logic for pointers. | ||
| 3978 | pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, zcu: *Zcu, opt_sema: ?*Sema) !PointerDeriveStep { | ||
| 3979 | const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr; | ||
| 3980 | const base_derive: PointerDeriveStep = switch (ptr.base_addr) { | ||
| 3981 | .int => return .{ .int = .{ | ||
| 3982 | .addr = ptr.byte_offset, | ||
| 3983 | .ptr_ty = Type.fromInterned(ptr.ty), | ||
| 3984 | } }, | ||
| 3985 | .decl => |decl| .{ .decl_ptr = decl }, | ||
| 3986 | .anon_decl => |ad| base: { | ||
| 3987 | // A slight tweak: `orig_ty` here is sometimes not `const`, but it ought to be. | ||
| 3988 | // TODO: fix this in the sites interning anon decls! | ||
| 3989 | const const_ty = try zcu.ptrType(info: { | ||
| 3990 | var info = Type.fromInterned(ad.orig_ty).ptrInfo(zcu); | ||
| 3991 | info.flags.is_const = true; | ||
| 3992 | break :info info; | ||
| 3993 | }); | ||
| 3994 | break :base .{ .anon_decl_ptr = .{ | ||
| 3995 | .val = ad.val, | ||
| 3996 | .orig_ty = const_ty.toIntern(), | ||
| 3997 | } }; | ||
| 3998 | }, | ||
| 3999 | .comptime_alloc => |idx| base: { | ||
| 4000 | const alloc = opt_sema.?.getComptimeAlloc(idx); | ||
| 4001 | const val = try alloc.val.intern(zcu, opt_sema.?.arena); | ||
| 4002 | const ty = val.typeOf(zcu); | ||
| 4003 | break :base .{ .comptime_alloc_ptr = .{ | ||
| 4004 | .val = val, | ||
| 4005 | .ptr_ty = try zcu.ptrType(.{ | ||
| 4006 | .child = ty.toIntern(), | ||
| 4007 | .flags = .{ | ||
| 4008 | .alignment = alloc.alignment, | ||
| 4009 | }, | ||
| 4010 | }), | ||
| 4011 | } }; | ||
| 4012 | }, | ||
| 4013 | .comptime_field => |val| .{ .comptime_field_ptr = Value.fromInterned(val) }, | ||
| 4014 | .eu_payload => |eu_ptr| base: { | ||
| 4015 | const base_ptr = Value.fromInterned(eu_ptr); | ||
| 4016 | const base_ptr_ty = base_ptr.typeOf(zcu); | ||
| 4017 | const parent_step = try arena.create(PointerDeriveStep); | ||
| 4018 | parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(eu_ptr), arena, zcu, opt_sema); | ||
| 4019 | break :base .{ .eu_payload_ptr = .{ | ||
| 4020 | .parent = parent_step, | ||
| 4021 | .result_ptr_ty = try zcu.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).errorUnionPayload(zcu)), | ||
| 4022 | } }; | ||
| 4023 | }, | ||
| 4024 | .opt_payload => |opt_ptr| base: { | ||
| 4025 | const base_ptr = Value.fromInterned(opt_ptr); | ||
| 4026 | const base_ptr_ty = base_ptr.typeOf(zcu); | ||
| 4027 | const parent_step = try arena.create(PointerDeriveStep); | ||
| 4028 | parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(opt_ptr), arena, zcu, opt_sema); | ||
| 4029 | break :base .{ .opt_payload_ptr = .{ | ||
| 4030 | .parent = parent_step, | ||
| 4031 | .result_ptr_ty = try zcu.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).optionalChild(zcu)), | ||
| 4032 | } }; | ||
| 4033 | }, | ||
| 4034 | .field => |field| base: { | ||
| 4035 | const base_ptr = Value.fromInterned(field.base); | ||
| 4036 | const base_ptr_ty = base_ptr.typeOf(zcu); | ||
| 4037 | const agg_ty = base_ptr_ty.childType(zcu); | ||
| 4038 | const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) { | ||
| 4039 | .Struct => .{ agg_ty.structFieldType(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, opt_sema) }, | ||
| 4040 | .Union => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, opt_sema) }, | ||
| 4041 | .Pointer => .{ switch (field.index) { | ||
| 4042 | Value.slice_ptr_index => agg_ty.slicePtrFieldType(zcu), | ||
| 4043 | Value.slice_len_index => Type.usize, | ||
| 4044 | else => unreachable, | ||
| 4045 | }, Type.usize.abiAlignment(zcu) }, | ||
| 4046 | else => unreachable, | ||
| 4047 | }; | ||
| 4048 | const base_align = base_ptr_ty.ptrAlignment(zcu); | ||
| 4049 | const result_align = field_align.minStrict(base_align); | ||
| 4050 | const result_ty = try zcu.ptrType(.{ | ||
| 4051 | .child = field_ty.toIntern(), | ||
| 4052 | .flags = flags: { | ||
| 4053 | var flags = base_ptr_ty.ptrInfo(zcu).flags; | ||
| 4054 | if (result_align == field_ty.abiAlignment(zcu)) { | ||
| 4055 | flags.alignment = .none; | ||
| 4056 | } else { | ||
| 4057 | flags.alignment = result_align; | ||
| 4058 | } | ||
| 4059 | break :flags flags; | ||
| 4060 | }, | ||
| 4061 | }); | ||
| 4062 | const parent_step = try arena.create(PointerDeriveStep); | ||
| 4063 | parent_step.* = try pointerDerivationAdvanced(base_ptr, arena, zcu, opt_sema); | ||
| 4064 | break :base .{ .field_ptr = .{ | ||
| 4065 | .parent = parent_step, | ||
| 4066 | .field_idx = @intCast(field.index), | ||
| 4067 | .result_ptr_ty = result_ty, | ||
| 4068 | } }; | ||
| 4069 | }, | ||
| 4070 | .arr_elem => |arr_elem| base: { | ||
| 4071 | const parent_step = try arena.create(PointerDeriveStep); | ||
| 4072 | parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(arr_elem.base), arena, zcu, opt_sema); | ||
| 4073 | const parent_ptr_info = (try parent_step.ptrType(zcu)).ptrInfo(zcu); | ||
| 4074 | const result_ptr_ty = try zcu.ptrType(.{ | ||
| 4075 | .child = parent_ptr_info.child, | ||
| 4076 | .flags = flags: { | ||
| 4077 | var flags = parent_ptr_info.flags; | ||
| 4078 | flags.size = .One; | ||
| 4079 | break :flags flags; | ||
| 4080 | }, | ||
| 4081 | }); | ||
| 4082 | break :base .{ .elem_ptr = .{ | ||
| 4083 | .parent = parent_step, | ||
| 4084 | .elem_idx = arr_elem.index, | ||
| 4085 | .result_ptr_ty = result_ptr_ty, | ||
| 4086 | } }; | ||
| 4087 | }, | ||
| 4088 | }; | ||
| 4089 | |||
| 4090 | if (ptr.byte_offset == 0 and ptr.ty == (try base_derive.ptrType(zcu)).toIntern()) { | ||
| 4091 | return base_derive; | ||
| 4092 | } | ||
| 4093 | |||
| 4094 | const need_child = Type.fromInterned(ptr.ty).childType(zcu); | ||
| 4095 | if (need_child.comptimeOnly(zcu)) { | ||
| 4096 | // No refinement can happen - this pointer is presumably invalid. | ||
| 4097 | // Just offset it. | ||
| 4098 | const parent = try arena.create(PointerDeriveStep); | ||
| 4099 | parent.* = base_derive; | ||
| 4100 | return .{ .offset_and_cast = .{ | ||
| 4101 | .parent = parent, | ||
| 4102 | .byte_offset = ptr.byte_offset, | ||
| 4103 | .new_ptr_ty = Type.fromInterned(ptr.ty), | ||
| 4104 | } }; | ||
| 4105 | } | ||
| 4106 | const need_bytes = need_child.abiSize(zcu); | ||
| 4107 | |||
| 4108 | var cur_derive = base_derive; | ||
| 4109 | var cur_offset = ptr.byte_offset; | ||
| 4110 | |||
| 4111 | // Refine through fields and array elements as much as possible. | ||
| 4112 | |||
| 4113 | if (need_bytes > 0) while (true) { | ||
| 4114 | const cur_ty = (try cur_derive.ptrType(zcu)).childType(zcu); | ||
| 4115 | if (cur_ty.toIntern() == need_child.toIntern() and cur_offset == 0) { | ||
| 4116 | break; | ||
| 4117 | } | ||
| 4118 | switch (cur_ty.zigTypeTag(zcu)) { | ||
| 4119 | .NoReturn, | ||
| 4120 | .Type, | ||
| 4121 | .ComptimeInt, | ||
| 4122 | .ComptimeFloat, | ||
| 4123 | .Null, | ||
| 4124 | .Undefined, | ||
| 4125 | .EnumLiteral, | ||
| 4126 | .Opaque, | ||
| 4127 | .Fn, | ||
| 4128 | .ErrorUnion, | ||
| 4129 | .Int, | ||
| 4130 | .Float, | ||
| 4131 | .Bool, | ||
| 4132 | .Void, | ||
| 4133 | .Pointer, | ||
| 4134 | .ErrorSet, | ||
| 4135 | .AnyFrame, | ||
| 4136 | .Frame, | ||
| 4137 | .Enum, | ||
| 4138 | .Vector, | ||
| 4139 | .Optional, | ||
| 4140 | .Union, | ||
| 4141 | => break, | ||
| 4142 | |||
| 4143 | .Array => { | ||
| 4144 | const elem_ty = cur_ty.childType(zcu); | ||
| 4145 | const elem_size = elem_ty.abiSize(zcu); | ||
| 4146 | const start_idx = cur_offset / elem_size; | ||
| 4147 | const end_idx = (cur_offset + need_bytes + elem_size - 1) / elem_size; | ||
| 4148 | if (end_idx == start_idx + 1) { | ||
| 4149 | const parent = try arena.create(PointerDeriveStep); | ||
| 4150 | parent.* = cur_derive; | ||
| 4151 | cur_derive = .{ .elem_ptr = .{ | ||
| 4152 | .parent = parent, | ||
| 4153 | .elem_idx = start_idx, | ||
| 4154 | .result_ptr_ty = try zcu.adjustPtrTypeChild(try parent.ptrType(zcu), elem_ty), | ||
| 4155 | } }; | ||
| 4156 | cur_offset -= start_idx * elem_size; | ||
| 4157 | } else { | ||
| 4158 | // Go into the first element if needed, but don't go any deeper. | ||
| 4159 | if (start_idx > 0) { | ||
| 4160 | const parent = try arena.create(PointerDeriveStep); | ||
| 4161 | parent.* = cur_derive; | ||
| 4162 | cur_derive = .{ .elem_ptr = .{ | ||
| 4163 | .parent = parent, | ||
| 4164 | .elem_idx = start_idx, | ||
| 4165 | .result_ptr_ty = try zcu.adjustPtrTypeChild(try parent.ptrType(zcu), elem_ty), | ||
| 4166 | } }; | ||
| 4167 | cur_offset -= start_idx * elem_size; | ||
| 4168 | } | ||
| 4169 | break; | ||
| 4170 | } | ||
| 4171 | }, | ||
| 4172 | .Struct => switch (cur_ty.containerLayout(zcu)) { | ||
| 4173 | .auto, .@"packed" => break, | ||
| 4174 | .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| { | ||
| 4175 | const field_ty = cur_ty.structFieldType(field_idx, zcu); | ||
| 4176 | const start_off = cur_ty.structFieldOffset(field_idx, zcu); | ||
| 4177 | const end_off = start_off + field_ty.abiSize(zcu); | ||
| 4178 | if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) { | ||
| 4179 | const old_ptr_ty = try cur_derive.ptrType(zcu); | ||
| 4180 | const parent_align = old_ptr_ty.ptrAlignment(zcu); | ||
| 4181 | const field_align = InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(start_off))); | ||
| 4182 | const parent = try arena.create(PointerDeriveStep); | ||
| 4183 | parent.* = cur_derive; | ||
| 4184 | const new_ptr_ty = try zcu.ptrType(.{ | ||
| 4185 | .child = field_ty.toIntern(), | ||
| 4186 | .flags = flags: { | ||
| 4187 | var flags = old_ptr_ty.ptrInfo(zcu).flags; | ||
| 4188 | if (field_align == field_ty.abiAlignment(zcu)) { | ||
| 4189 | flags.alignment = .none; | ||
| 4190 | } else { | ||
| 4191 | flags.alignment = field_align; | ||
| 4192 | } | ||
| 4193 | break :flags flags; | ||
| 4194 | }, | ||
| 4195 | }); | ||
| 4196 | cur_derive = .{ .field_ptr = .{ | ||
| 4197 | .parent = parent, | ||
| 4198 | .field_idx = @intCast(field_idx), | ||
| 4199 | .result_ptr_ty = new_ptr_ty, | ||
| 4200 | } }; | ||
| 4201 | cur_offset -= start_off; | ||
| 4202 | break; | ||
| 4203 | } | ||
| 4204 | } else break, // pointer spans multiple fields | ||
| 4205 | }, | ||
| 4206 | } | ||
| 4207 | }; | ||
| 4208 | |||
| 4209 | if (cur_offset == 0 and (try cur_derive.ptrType(zcu)).toIntern() == ptr.ty) { | ||
| 4210 | return cur_derive; | ||
| 4211 | } | ||
| 4212 | |||
| 4213 | const parent = try arena.create(PointerDeriveStep); | ||
| 4214 | parent.* = cur_derive; | ||
| 4215 | return .{ .offset_and_cast = .{ | ||
| 4216 | .parent = parent, | ||
| 4217 | .byte_offset = cur_offset, | ||
| 4218 | .new_ptr_ty = Type.fromInterned(ptr.ty), | ||
| 4219 | } }; | ||
| 4220 | } |
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/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+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | export fn entry1() void { | ||
| 2 | const x: i32 = undefined; | ||
| 3 | const y: u32 = @bitCast(x); | ||
| 4 | @compileLog(y); | ||
| 5 | } | ||
| 6 | |||
| 7 | export fn entry2() void { | ||
| 8 | const x: packed struct { x: u16, y: u16 } = .{ .x = 123, .y = undefined }; | ||
| 9 | const y: u32 = @bitCast(x); | ||
| 10 | @compileLog(y); | ||
| 11 | } | ||
| 12 | |||
| 13 | // error | ||
| 14 | // | ||
| 15 | // :4:5: error: found compile log statement | ||
| 16 | // :10:5: note: also here | ||
| 17 | // | ||
| 18 | // Compile Log Output: | ||
| 19 | // @as(u32, undefined) | ||
| 20 | // @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]) |