| ... | @@ -19212,9 +19212,9 @@ fn elemValArray( | ... | @@ -19212,9 +19212,9 @@ fn elemValArray( |
| 19212 | elem_index: Air.Inst.Ref, | 19212 | elem_index: Air.Inst.Ref, |
| 19213 | ) CompileError!Air.Inst.Ref { | 19213 | ) CompileError!Air.Inst.Ref { |
| 19214 | const array_ty = sema.typeOf(array); | 19214 | const array_ty = sema.typeOf(array); |
| 19215 | const array_sent = array_ty.sentinel() != null; | 19215 | const array_sent = array_ty.sentinel(); |
| 19216 | const array_len = array_ty.arrayLen(); | 19216 | const array_len = array_ty.arrayLen(); |
| 19217 | const array_len_s = array_len + @boolToInt(array_sent); | 19217 | const array_len_s = array_len + @boolToInt(array_sent != null); |
| 19218 | const elem_ty = array_ty.childType(); | 19218 | const elem_ty = array_ty.childType(); |
| 19219 | | 19219 | |
| 19220 | if (array_len_s == 0) { | 19220 | if (array_len_s == 0) { |
| ... | @@ -19228,8 +19228,13 @@ fn elemValArray( | ... | @@ -19228,8 +19228,13 @@ fn elemValArray( |
| 19228 | | 19228 | |
| 19229 | if (maybe_index_val) |index_val| { | 19229 | if (maybe_index_val) |index_val| { |
| 19230 | const index = @intCast(usize, index_val.toUnsignedInt(target)); | 19230 | const index = @intCast(usize, index_val.toUnsignedInt(target)); |
| | 19231 | if (array_sent) |s| { |
| | 19232 | if (index == array_len) { |
| | 19233 | return sema.addConstant(elem_ty, s); |
| | 19234 | } |
| | 19235 | } |
| 19231 | if (index >= array_len_s) { | 19236 | if (index >= array_len_s) { |
| 19232 | const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; | 19237 | const sentinel_label: []const u8 = if (array_sent != null) " +1 (sentinel)" else ""; |
| 19233 | return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); | 19238 | return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); |
| 19234 | } | 19239 | } |
| 19235 | } | 19240 | } |
| ... | @@ -19269,7 +19274,7 @@ fn elemValArray( | ... | @@ -19269,7 +19274,7 @@ fn elemValArray( |
| 19269 | // Runtime check is only needed if unable to comptime check | 19274 | // Runtime check is only needed if unable to comptime check |
| 19270 | if (maybe_index_val == null) { | 19275 | if (maybe_index_val == null) { |
| 19271 | const len_inst = try sema.addIntUnsigned(Type.usize, array_len); | 19276 | const len_inst = try sema.addIntUnsigned(Type.usize, array_len); |
| 19272 | const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; | 19277 | const cmp_op: Air.Inst.Tag = if (array_sent != null) .cmp_lte else .cmp_lt; |
| 19273 | try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op); | 19278 | try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op); |
| 19274 | } | 19279 | } |
| 19275 | } | 19280 | } |
| ... | @@ -20521,27 +20526,67 @@ fn storePtrVal( | ... | @@ -20521,27 +20526,67 @@ fn storePtrVal( |
| 20521 | operand_val: Value, | 20526 | operand_val: Value, |
| 20522 | operand_ty: Type, | 20527 | operand_ty: Type, |
| 20523 | ) !void { | 20528 | ) !void { |
| 20524 | var mut_kit = try beginComptimePtrMutation(sema, block, src, ptr_val); | 20529 | var mut_kit = try beginComptimePtrMutation(sema, block, src, ptr_val, operand_ty); |
| 20525 | try sema.checkComptimeVarStore(block, src, mut_kit.decl_ref_mut); | 20530 | try sema.checkComptimeVarStore(block, src, mut_kit.decl_ref_mut); |
| 20526 | | 20531 | |
| 20527 | const bitcasted_val = try sema.bitCastVal(block, src, operand_val, operand_ty, mut_kit.ty, 0); | 20532 | switch (mut_kit.pointee) { |
| | 20533 | .direct => |val_ptr| { |
| | 20534 | if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) { |
| | 20535 | if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) { |
| | 20536 | // TODO add note showing where default value is provided |
| | 20537 | return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); |
| | 20538 | } |
| | 20539 | return; |
| | 20540 | } |
| | 20541 | const arena = mut_kit.beginArena(sema.mod); |
| | 20542 | defer mut_kit.finishArena(sema.mod); |
| 20528 | | 20543 | |
| 20529 | if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) { | 20544 | val_ptr.* = try operand_val.copy(arena); |
| 20530 | if (!mut_kit.val.eql(bitcasted_val, mut_kit.ty, sema.mod)) { | 20545 | }, |
| 20531 | return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); | 20546 | .reinterpret => |reinterpret| { |
| 20532 | } | 20547 | const target = sema.mod.getTarget(); |
| 20533 | return; | 20548 | const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(target)); |
| 20534 | } | 20549 | const buffer = try sema.gpa.alloc(u8, abi_size); |
| | 20550 | defer sema.gpa.free(buffer); |
| | 20551 | reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer); |
| | 20552 | operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]); |
| 20535 | | 20553 | |
| 20536 | const arena = mut_kit.beginArena(sema.mod); | 20554 | const arena = mut_kit.beginArena(sema.mod); |
| 20537 | defer mut_kit.finishArena(sema.mod); | 20555 | defer mut_kit.finishArena(sema.mod); |
| 20538 | | 20556 | |
| 20539 | mut_kit.val.* = try bitcasted_val.copy(arena); | 20557 | reinterpret.val_ptr.* = try Value.readFromMemory(mut_kit.ty, sema.mod, buffer, arena); |
| | 20558 | }, |
| | 20559 | .bad_decl_ty, .bad_ptr_ty => { |
| | 20560 | // TODO show the decl declaration site in a note and explain whether the decl |
| | 20561 | // or the pointer is the problematic type |
| | 20562 | return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(sema.mod)}); |
| | 20563 | }, |
| | 20564 | } |
| 20540 | } | 20565 | } |
| 20541 | | 20566 | |
| 20542 | const ComptimePtrMutationKit = struct { | 20567 | const ComptimePtrMutationKit = struct { |
| 20543 | decl_ref_mut: Value.Payload.DeclRefMut.Data, | 20568 | decl_ref_mut: Value.Payload.DeclRefMut.Data, |
| 20544 | val: *Value, | 20569 | pointee: union(enum) { |
| | 20570 | /// The pointer type matches the actual comptime Value so a direct |
| | 20571 | /// modification is possible. |
| | 20572 | direct: *Value, |
| | 20573 | /// The largest parent Value containing pointee and having a well-defined memory layout. |
| | 20574 | /// This is used for bitcasting, if direct dereferencing failed. |
| | 20575 | reinterpret: struct { |
| | 20576 | val_ptr: *Value, |
| | 20577 | byte_offset: usize, |
| | 20578 | }, |
| | 20579 | /// If the root decl could not be used as parent, this means `ty` is the type that |
| | 20580 | /// caused that by not having a well-defined layout. |
| | 20581 | /// This one means the Decl that owns the value trying to be modified does not |
| | 20582 | /// have a well defined memory layout. |
| | 20583 | bad_decl_ty, |
| | 20584 | /// If the root decl could not be used as parent, this means `ty` is the type that |
| | 20585 | /// caused that by not having a well-defined layout. |
| | 20586 | /// This one means the pointer type that is being stored through does not |
| | 20587 | /// have a well defined memory layout. |
| | 20588 | bad_ptr_ty, |
| | 20589 | }, |
| 20545 | ty: Type, | 20590 | ty: Type, |
| 20546 | decl_arena: std.heap.ArenaAllocator = undefined, | 20591 | decl_arena: std.heap.ArenaAllocator = undefined, |
| 20547 | | 20592 | |
| ... | @@ -20563,354 +20608,469 @@ fn beginComptimePtrMutation( | ... | @@ -20563,354 +20608,469 @@ fn beginComptimePtrMutation( |
| 20563 | block: *Block, | 20608 | block: *Block, |
| 20564 | src: LazySrcLoc, | 20609 | src: LazySrcLoc, |
| 20565 | ptr_val: Value, | 20610 | ptr_val: Value, |
| | 20611 | ptr_elem_ty: Type, |
| 20566 | ) CompileError!ComptimePtrMutationKit { | 20612 | ) CompileError!ComptimePtrMutationKit { |
| 20567 | | 20613 | const target = sema.mod.getTarget(); |
| 20568 | // TODO: Update this to behave like `beginComptimePtrLoad` and properly check/use | | |
| 20569 | // `container_ty` and `array_ty`, instead of trusting that the parent decl type | | |
| 20570 | // matches the type used to derive the elem_ptr/field_ptr/etc. | | |
| 20571 | // | | |
| 20572 | // This is needed because the types will not match if the pointer we're mutating | | |
| 20573 | // through is reinterpreting comptime memory. | | |
| 20574 | | | |
| 20575 | switch (ptr_val.tag()) { | 20614 | switch (ptr_val.tag()) { |
| 20576 | .decl_ref_mut => { | 20615 | .decl_ref_mut => { |
| 20577 | const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data; | 20616 | const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data; |
| 20578 | const decl = sema.mod.declPtr(decl_ref_mut.decl_index); | 20617 | const decl = sema.mod.declPtr(decl_ref_mut.decl_index); |
| 20579 | return ComptimePtrMutationKit{ | 20618 | return beginComptimePtrMutationInner(sema, block, src, decl.ty, &decl.val, ptr_elem_ty, decl_ref_mut); |
| 20580 | .decl_ref_mut = decl_ref_mut, | | |
| 20581 | .val = &decl.val, | | |
| 20582 | .ty = decl.ty, | | |
| 20583 | }; | | |
| 20584 | }, | 20619 | }, |
| 20585 | .comptime_field_ptr => { | 20620 | .comptime_field_ptr => { |
| 20586 | const payload = ptr_val.castTag(.comptime_field_ptr).?.data; | 20621 | const payload = ptr_val.castTag(.comptime_field_ptr).?.data; |
| 20587 | const duped = try sema.arena.create(Value); | 20622 | const duped = try sema.arena.create(Value); |
| 20588 | duped.* = payload.field_val; | 20623 | duped.* = payload.field_val; |
| 20589 | return ComptimePtrMutationKit{ | 20624 | return beginComptimePtrMutationInner(sema, block, src, payload.field_ty, duped, ptr_elem_ty, .{ |
| 20590 | .decl_ref_mut = .{ | 20625 | .decl_index = @intToEnum(Module.Decl.Index, 0), |
| 20591 | .decl_index = @intToEnum(Module.Decl.Index, 0), | 20626 | .runtime_index = .comptime_field_ptr, |
| 20592 | .runtime_index = .comptime_field_ptr, | 20627 | }); |
| 20593 | }, | | |
| 20594 | .val = duped, | | |
| 20595 | .ty = payload.field_ty, | | |
| 20596 | }; | | |
| 20597 | }, | 20628 | }, |
| 20598 | .elem_ptr => { | 20629 | .elem_ptr => { |
| 20599 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | 20630 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; |
| 20600 | var parent = try beginComptimePtrMutation(sema, block, src, elem_ptr.array_ptr); | 20631 | var parent = try beginComptimePtrMutation(sema, block, src, elem_ptr.array_ptr, elem_ptr.elem_ty); |
| 20601 | switch (parent.ty.zigTypeTag()) { | 20632 | switch (parent.pointee) { |
| 20602 | .Array, .Vector => { | 20633 | .direct => |val_ptr| switch (parent.ty.zigTypeTag()) { |
| 20603 | const check_len = parent.ty.arrayLenIncludingSentinel(); | 20634 | .Array, .Vector => { |
| 20604 | if (elem_ptr.index >= check_len) { | 20635 | const check_len = parent.ty.arrayLenIncludingSentinel(); |
| 20605 | // TODO have the parent include the decl so we can say "declared here" | 20636 | if (elem_ptr.index >= check_len) { |
| 20606 | return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{ | 20637 | // TODO have the parent include the decl so we can say "declared here" |
| 20607 | elem_ptr.index, check_len, | 20638 | return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{ |
| 20608 | }); | 20639 | elem_ptr.index, check_len, |
| 20609 | } | 20640 | }); |
| 20610 | const elem_ty = parent.ty.childType(); | 20641 | } |
| 20611 | switch (parent.val.tag()) { | 20642 | const elem_ty = parent.ty.childType(); |
| 20612 | .undef => { | 20643 | switch (val_ptr.tag()) { |
| 20613 | // An array has been initialized to undefined at comptime and now we | 20644 | .undef => { |
| 20614 | // are for the first time setting an element. We must change the representation | 20645 | // An array has been initialized to undefined at comptime and now we |
| 20615 | // of the array from `undef` to `array`. | 20646 | // are for the first time setting an element. We must change the representation |
| 20616 | const arena = parent.beginArena(sema.mod); | 20647 | // of the array from `undef` to `array`. |
| 20617 | defer parent.finishArena(sema.mod); | 20648 | const arena = parent.beginArena(sema.mod); |
| 20618 | | 20649 | defer parent.finishArena(sema.mod); |
| 20619 | const array_len_including_sentinel = | 20650 | |
| 20620 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); | 20651 | const array_len_including_sentinel = |
| 20621 | const elems = try arena.alloc(Value, array_len_including_sentinel); | 20652 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); |
| 20622 | mem.set(Value, elems, Value.undef); | 20653 | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 20623 | | 20654 | mem.set(Value, elems, Value.undef); |
| 20624 | parent.val.* = try Value.Tag.aggregate.create(arena, elems); | 20655 | |
| 20625 | | 20656 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 20626 | return ComptimePtrMutationKit{ | 20657 | |
| 20627 | .decl_ref_mut = parent.decl_ref_mut, | 20658 | return beginComptimePtrMutationInner( |
| 20628 | .val = &elems[elem_ptr.index], | 20659 | sema, |
| 20629 | .ty = elem_ty, | 20660 | block, |
| 20630 | }; | 20661 | src, |
| 20631 | }, | 20662 | elem_ty, |
| 20632 | .bytes => { | 20663 | &elems[elem_ptr.index], |
| 20633 | // An array is memory-optimized to store a slice of bytes, but we are about | 20664 | ptr_elem_ty, |
| 20634 | // to modify an individual field and the representation has to change. | 20665 | parent.decl_ref_mut, |
| 20635 | // If we wanted to avoid this, there would need to be special detection | 20666 | ); |
| 20636 | // elsewhere to identify when writing a value to an array element that is stored | 20667 | }, |
| 20637 | // using the `bytes` tag, and handle it without making a call to this function. | 20668 | .bytes => { |
| 20638 | const arena = parent.beginArena(sema.mod); | 20669 | // An array is memory-optimized to store a slice of bytes, but we are about |
| 20639 | defer parent.finishArena(sema.mod); | 20670 | // to modify an individual field and the representation has to change. |
| 20640 | | 20671 | // If we wanted to avoid this, there would need to be special detection |
| 20641 | const bytes = parent.val.castTag(.bytes).?.data; | 20672 | // elsewhere to identify when writing a value to an array element that is stored |
| 20642 | const dest_len = parent.ty.arrayLenIncludingSentinel(); | 20673 | // using the `bytes` tag, and handle it without making a call to this function. |
| 20643 | // bytes.len may be one greater than dest_len because of the case when | 20674 | const arena = parent.beginArena(sema.mod); |
| 20644 | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. | 20675 | defer parent.finishArena(sema.mod); |
| 20645 | assert(bytes.len >= dest_len); | 20676 | |
| 20646 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); | 20677 | const bytes = val_ptr.castTag(.bytes).?.data; |
| 20647 | for (elems) |*elem, i| { | 20678 | const dest_len = parent.ty.arrayLenIncludingSentinel(); |
| 20648 | elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); | 20679 | // bytes.len may be one greater than dest_len because of the case when |
| 20649 | } | 20680 | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. |
| 20650 | | 20681 | assert(bytes.len >= dest_len); |
| 20651 | parent.val.* = try Value.Tag.aggregate.create(arena, elems); | 20682 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); |
| 20652 | | 20683 | for (elems) |*elem, i| { |
| 20653 | return ComptimePtrMutationKit{ | 20684 | elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); |
| 20654 | .decl_ref_mut = parent.decl_ref_mut, | 20685 | } |
| 20655 | .val = &elems[elem_ptr.index], | | |
| 20656 | .ty = elem_ty, | | |
| 20657 | }; | | |
| 20658 | }, | | |
| 20659 | .str_lit => { | | |
| 20660 | // An array is memory-optimized to store a slice of bytes, but we are about | | |
| 20661 | // to modify an individual field and the representation has to change. | | |
| 20662 | // If we wanted to avoid this, there would need to be special detection | | |
| 20663 | // elsewhere to identify when writing a value to an array element that is stored | | |
| 20664 | // using the `str_lit` tag, and handle it without making a call to this function. | | |
| 20665 | const arena = parent.beginArena(sema.mod); | | |
| 20666 | defer parent.finishArena(sema.mod); | | |
| 20667 | | | |
| 20668 | const str_lit = parent.val.castTag(.str_lit).?.data; | | |
| 20669 | const dest_len = parent.ty.arrayLenIncludingSentinel(); | | |
| 20670 | const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | | |
| 20671 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); | | |
| 20672 | for (bytes) |byte, i| { | | |
| 20673 | elems[i] = try Value.Tag.int_u64.create(arena, byte); | | |
| 20674 | } | | |
| 20675 | if (parent.ty.sentinel()) |sent_val| { | | |
| 20676 | assert(elems.len == bytes.len + 1); | | |
| 20677 | elems[bytes.len] = sent_val; | | |
| 20678 | } | | |
| 20679 | | | |
| 20680 | parent.val.* = try Value.Tag.aggregate.create(arena, elems); | | |
| 20681 | | | |
| 20682 | return ComptimePtrMutationKit{ | | |
| 20683 | .decl_ref_mut = parent.decl_ref_mut, | | |
| 20684 | .val = &elems[elem_ptr.index], | | |
| 20685 | .ty = elem_ty, | | |
| 20686 | }; | | |
| 20687 | }, | | |
| 20688 | .repeated => { | | |
| 20689 | // An array is memory-optimized to store only a single element value, and | | |
| 20690 | // that value is understood to be the same for the entire length of the array. | | |
| 20691 | // However, now we want to modify an individual field and so the | | |
| 20692 | // representation has to change. If we wanted to avoid this, there would | | |
| 20693 | // need to be special detection elsewhere to identify when writing a value to an | | |
| 20694 | // array element that is stored using the `repeated` tag, and handle it | | |
| 20695 | // without making a call to this function. | | |
| 20696 | const arena = parent.beginArena(sema.mod); | | |
| 20697 | defer parent.finishArena(sema.mod); | | |
| 20698 | | 20686 | |
| 20699 | const repeated_val = try parent.val.castTag(.repeated).?.data.copy(arena); | 20687 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 20700 | const array_len_including_sentinel = | | |
| 20701 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); | | |
| 20702 | const elems = try arena.alloc(Value, array_len_including_sentinel); | | |
| 20703 | mem.set(Value, elems, repeated_val); | | |
| 20704 | | 20688 | |
| 20705 | parent.val.* = try Value.Tag.aggregate.create(arena, elems); | 20689 | return beginComptimePtrMutationInner( |
| | 20690 | sema, |
| | 20691 | block, |
| | 20692 | src, |
| | 20693 | elem_ty, |
| | 20694 | &elems[elem_ptr.index], |
| | 20695 | ptr_elem_ty, |
| | 20696 | parent.decl_ref_mut, |
| | 20697 | ); |
| | 20698 | }, |
| | 20699 | .str_lit => { |
| | 20700 | // An array is memory-optimized to store a slice of bytes, but we are about |
| | 20701 | // to modify an individual field and the representation has to change. |
| | 20702 | // If we wanted to avoid this, there would need to be special detection |
| | 20703 | // elsewhere to identify when writing a value to an array element that is stored |
| | 20704 | // using the `str_lit` tag, and handle it without making a call to this function. |
| | 20705 | const arena = parent.beginArena(sema.mod); |
| | 20706 | defer parent.finishArena(sema.mod); |
| | 20707 | |
| | 20708 | const str_lit = val_ptr.castTag(.str_lit).?.data; |
| | 20709 | const dest_len = parent.ty.arrayLenIncludingSentinel(); |
| | 20710 | const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; |
| | 20711 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); |
| | 20712 | for (bytes) |byte, i| { |
| | 20713 | elems[i] = try Value.Tag.int_u64.create(arena, byte); |
| | 20714 | } |
| | 20715 | if (parent.ty.sentinel()) |sent_val| { |
| | 20716 | assert(elems.len == bytes.len + 1); |
| | 20717 | elems[bytes.len] = sent_val; |
| | 20718 | } |
| 20706 | | 20719 | |
| 20707 | return ComptimePtrMutationKit{ | 20720 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 20708 | .decl_ref_mut = parent.decl_ref_mut, | | |
| 20709 | .val = &elems[elem_ptr.index], | | |
| 20710 | .ty = elem_ty, | | |
| 20711 | }; | | |
| 20712 | }, | | |
| 20713 | | 20721 | |
| 20714 | .aggregate => return ComptimePtrMutationKit{ | 20722 | return beginComptimePtrMutationInner( |
| 20715 | .decl_ref_mut = parent.decl_ref_mut, | 20723 | sema, |
| 20716 | .val = &parent.val.castTag(.aggregate).?.data[elem_ptr.index], | 20724 | block, |
| 20717 | .ty = elem_ty, | 20725 | src, |
| 20718 | }, | 20726 | elem_ty, |
| | 20727 | &elems[elem_ptr.index], |
| | 20728 | ptr_elem_ty, |
| | 20729 | parent.decl_ref_mut, |
| | 20730 | ); |
| | 20731 | }, |
| | 20732 | .repeated => { |
| | 20733 | // An array is memory-optimized to store only a single element value, and |
| | 20734 | // that value is understood to be the same for the entire length of the array. |
| | 20735 | // However, now we want to modify an individual field and so the |
| | 20736 | // representation has to change. If we wanted to avoid this, there would |
| | 20737 | // need to be special detection elsewhere to identify when writing a value to an |
| | 20738 | // array element that is stored using the `repeated` tag, and handle it |
| | 20739 | // without making a call to this function. |
| | 20740 | const arena = parent.beginArena(sema.mod); |
| | 20741 | defer parent.finishArena(sema.mod); |
| | 20742 | |
| | 20743 | const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena); |
| | 20744 | const array_len_including_sentinel = |
| | 20745 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); |
| | 20746 | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| | 20747 | mem.set(Value, elems, repeated_val); |
| | 20748 | |
| | 20749 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| | 20750 | |
| | 20751 | return beginComptimePtrMutationInner( |
| | 20752 | sema, |
| | 20753 | block, |
| | 20754 | src, |
| | 20755 | elem_ty, |
| | 20756 | &elems[elem_ptr.index], |
| | 20757 | ptr_elem_ty, |
| | 20758 | parent.decl_ref_mut, |
| | 20759 | ); |
| | 20760 | }, |
| 20719 | | 20761 | |
| 20720 | .the_only_possible_value => { | 20762 | .aggregate => return beginComptimePtrMutationInner( |
| 20721 | const duped = try sema.arena.create(Value); | 20763 | sema, |
| 20722 | duped.* = Value.initTag(.the_only_possible_value); | 20764 | block, |
| 20723 | return ComptimePtrMutationKit{ | 20765 | src, |
| 20724 | .decl_ref_mut = parent.decl_ref_mut, | 20766 | elem_ty, |
| 20725 | .val = duped, | 20767 | &val_ptr.castTag(.aggregate).?.data[elem_ptr.index], |
| 20726 | .ty = elem_ty, | 20768 | ptr_elem_ty, |
| 20727 | }; | 20769 | parent.decl_ref_mut, |
| 20728 | }, | 20770 | ), |
| | 20771 | |
| | 20772 | .the_only_possible_value => { |
| | 20773 | const duped = try sema.arena.create(Value); |
| | 20774 | duped.* = Value.initTag(.the_only_possible_value); |
| | 20775 | return beginComptimePtrMutationInner( |
| | 20776 | sema, |
| | 20777 | block, |
| | 20778 | src, |
| | 20779 | elem_ty, |
| | 20780 | duped, |
| | 20781 | ptr_elem_ty, |
| | 20782 | parent.decl_ref_mut, |
| | 20783 | ); |
| | 20784 | }, |
| 20729 | | 20785 | |
| 20730 | else => unreachable, | 20786 | else => unreachable, |
| 20731 | } | 20787 | } |
| | 20788 | }, |
| | 20789 | else => { |
| | 20790 | if (elem_ptr.index != 0) { |
| | 20791 | // TODO include a "declared here" note for the decl |
| | 20792 | return sema.fail(block, src, "out of bounds comptime store of index {d}", .{ |
| | 20793 | elem_ptr.index, |
| | 20794 | }); |
| | 20795 | } |
| | 20796 | return beginComptimePtrMutationInner( |
| | 20797 | sema, |
| | 20798 | block, |
| | 20799 | src, |
| | 20800 | parent.ty, |
| | 20801 | val_ptr, |
| | 20802 | ptr_elem_ty, |
| | 20803 | parent.decl_ref_mut, |
| | 20804 | ); |
| | 20805 | }, |
| 20732 | }, | 20806 | }, |
| 20733 | else => { | 20807 | .reinterpret => |reinterpret| { |
| 20734 | if (elem_ptr.index != 0) { | 20808 | if (!elem_ptr.elem_ty.hasWellDefinedLayout()) { |
| 20735 | // TODO include a "declared here" note for the decl | 20809 | // Even though the parent value type has well-defined memory layout, our |
| 20736 | return sema.fail(block, src, "out of bounds comptime store of index {d}", .{ | 20810 | // pointer type does not. |
| 20737 | elem_ptr.index, | 20811 | return ComptimePtrMutationKit{ |
| 20738 | }); | 20812 | .decl_ref_mut = parent.decl_ref_mut, |
| | 20813 | .pointee = .bad_ptr_ty, |
| | 20814 | .ty = elem_ptr.elem_ty, |
| | 20815 | }; |
| 20739 | } | 20816 | } |
| | 20817 | |
| | 20818 | const elem_abi_size_u64 = try sema.typeAbiSize(block, src, elem_ptr.elem_ty); |
| | 20819 | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); |
| 20740 | return ComptimePtrMutationKit{ | 20820 | return ComptimePtrMutationKit{ |
| 20741 | .decl_ref_mut = parent.decl_ref_mut, | 20821 | .decl_ref_mut = parent.decl_ref_mut, |
| 20742 | .val = parent.val, | 20822 | .pointee = .{ .reinterpret = .{ |
| | 20823 | .val_ptr = reinterpret.val_ptr, |
| | 20824 | .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index, |
| | 20825 | } }, |
| 20743 | .ty = parent.ty, | 20826 | .ty = parent.ty, |
| 20744 | }; | 20827 | }; |
| 20745 | }, | 20828 | }, |
| | 20829 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 20746 | } | 20830 | } |
| 20747 | }, | 20831 | }, |
| 20748 | .field_ptr => { | 20832 | .field_ptr => { |
| 20749 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | 20833 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; |
| 20750 | var parent = try beginComptimePtrMutation(sema, block, src, field_ptr.container_ptr); | | |
| 20751 | const field_index = @intCast(u32, field_ptr.field_index); | 20834 | const field_index = @intCast(u32, field_ptr.field_index); |
| 20752 | switch (parent.val.tag()) { | | |
| 20753 | .undef => { | | |
| 20754 | // A struct or union has been initialized to undefined at comptime and now we | | |
| 20755 | // are for the first time setting a field. We must change the representation | | |
| 20756 | // of the struct/union from `undef` to `struct`/`union`. | | |
| 20757 | const arena = parent.beginArena(sema.mod); | | |
| 20758 | defer parent.finishArena(sema.mod); | | |
| 20759 | | 20835 | |
| 20760 | switch (parent.ty.zigTypeTag()) { | 20836 | var parent = try beginComptimePtrMutation(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty); |
| 20761 | .Struct => { | 20837 | switch (parent.pointee) { |
| 20762 | const fields = try arena.alloc(Value, parent.ty.structFieldCount()); | 20838 | .direct => |val_ptr| switch (val_ptr.tag()) { |
| 20763 | mem.set(Value, fields, Value.undef); | 20839 | .undef => { |
| | 20840 | // A struct or union has been initialized to undefined at comptime and now we |
| | 20841 | // are for the first time setting a field. We must change the representation |
| | 20842 | // of the struct/union from `undef` to `struct`/`union`. |
| | 20843 | const arena = parent.beginArena(sema.mod); |
| | 20844 | defer parent.finishArena(sema.mod); |
| | 20845 | |
| | 20846 | switch (parent.ty.zigTypeTag()) { |
| | 20847 | .Struct => { |
| | 20848 | const fields = try arena.alloc(Value, parent.ty.structFieldCount()); |
| | 20849 | mem.set(Value, fields, Value.undef); |
| | 20850 | |
| | 20851 | val_ptr.* = try Value.Tag.aggregate.create(arena, fields); |
| | 20852 | |
| | 20853 | return beginComptimePtrMutationInner( |
| | 20854 | sema, |
| | 20855 | block, |
| | 20856 | src, |
| | 20857 | parent.ty.structFieldType(field_index), |
| | 20858 | &fields[field_index], |
| | 20859 | ptr_elem_ty, |
| | 20860 | parent.decl_ref_mut, |
| | 20861 | ); |
| | 20862 | }, |
| | 20863 | .Union => { |
| | 20864 | const payload = try arena.create(Value.Payload.Union); |
| | 20865 | payload.* = .{ .data = .{ |
| | 20866 | .tag = try Value.Tag.enum_field_index.create(arena, field_index), |
| | 20867 | .val = Value.undef, |
| | 20868 | } }; |
| 20764 | | 20869 | |
| 20765 | parent.val.* = try Value.Tag.aggregate.create(arena, fields); | 20870 | val_ptr.* = Value.initPayload(&payload.base); |
| 20766 | | 20871 | |
| 20767 | return ComptimePtrMutationKit{ | 20872 | return beginComptimePtrMutationInner( |
| 20768 | .decl_ref_mut = parent.decl_ref_mut, | 20873 | sema, |
| 20769 | .val = &fields[field_index], | 20874 | block, |
| 20770 | .ty = parent.ty.structFieldType(field_index), | 20875 | src, |
| 20771 | }; | 20876 | parent.ty.structFieldType(field_index), |
| 20772 | }, | 20877 | &payload.data.val, |
| 20773 | .Union => { | 20878 | ptr_elem_ty, |
| 20774 | const payload = try arena.create(Value.Payload.Union); | 20879 | parent.decl_ref_mut, |
| 20775 | payload.* = .{ .data = .{ | 20880 | ); |
| 20776 | .tag = try Value.Tag.enum_field_index.create(arena, field_index), | 20881 | }, |
| 20777 | .val = Value.undef, | 20882 | .Pointer => { |
| 20778 | } }; | 20883 | assert(parent.ty.isSlice()); |
| | 20884 | val_ptr.* = try Value.Tag.slice.create(arena, .{ |
| | 20885 | .ptr = Value.undef, |
| | 20886 | .len = Value.undef, |
| | 20887 | }); |
| | 20888 | |
| | 20889 | switch (field_index) { |
| | 20890 | Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( |
| | 20891 | sema, |
| | 20892 | block, |
| | 20893 | src, |
| | 20894 | parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), |
| | 20895 | &val_ptr.castTag(.slice).?.data.ptr, |
| | 20896 | ptr_elem_ty, |
| | 20897 | parent.decl_ref_mut, |
| | 20898 | ), |
| | 20899 | Value.Payload.Slice.len_index => return beginComptimePtrMutationInner( |
| | 20900 | sema, |
| | 20901 | block, |
| | 20902 | src, |
| | 20903 | Type.usize, |
| | 20904 | &val_ptr.castTag(.slice).?.data.len, |
| | 20905 | ptr_elem_ty, |
| | 20906 | parent.decl_ref_mut, |
| | 20907 | ), |
| | 20908 | |
| | 20909 | else => unreachable, |
| | 20910 | } |
| | 20911 | }, |
| | 20912 | else => unreachable, |
| | 20913 | } |
| | 20914 | }, |
| | 20915 | .aggregate => return beginComptimePtrMutationInner( |
| | 20916 | sema, |
| | 20917 | block, |
| | 20918 | src, |
| | 20919 | parent.ty.structFieldType(field_index), |
| | 20920 | &val_ptr.castTag(.aggregate).?.data[field_index], |
| | 20921 | ptr_elem_ty, |
| | 20922 | parent.decl_ref_mut, |
| | 20923 | ), |
| 20779 | | 20924 | |
| 20780 | parent.val.* = Value.initPayload(&payload.base); | 20925 | .@"union" => { |
| | 20926 | // We need to set the active field of the union. |
| | 20927 | const arena = parent.beginArena(sema.mod); |
| | 20928 | defer parent.finishArena(sema.mod); |
| 20781 | | 20929 | |
| 20782 | return ComptimePtrMutationKit{ | 20930 | const payload = &val_ptr.castTag(.@"union").?.data; |
| 20783 | .decl_ref_mut = parent.decl_ref_mut, | 20931 | payload.tag = try Value.Tag.enum_field_index.create(arena, field_index); |
| 20784 | .val = &payload.data.val, | | |
| 20785 | .ty = parent.ty.structFieldType(field_index), | | |
| 20786 | }; | | |
| 20787 | }, | | |
| 20788 | .Pointer => { | | |
| 20789 | assert(parent.ty.isSlice()); | | |
| 20790 | parent.val.* = try Value.Tag.slice.create(arena, .{ | | |
| 20791 | .ptr = Value.undef, | | |
| 20792 | .len = Value.undef, | | |
| 20793 | }); | | |
| 20794 | | 20932 | |
| 20795 | switch (field_index) { | 20933 | return beginComptimePtrMutationInner( |
| 20796 | Value.Payload.Slice.ptr_index => return ComptimePtrMutationKit{ | 20934 | sema, |
| 20797 | .decl_ref_mut = parent.decl_ref_mut, | 20935 | block, |
| 20798 | .val = &parent.val.castTag(.slice).?.data.ptr, | 20936 | src, |
| 20799 | .ty = parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | 20937 | parent.ty.structFieldType(field_index), |
| 20800 | }, | 20938 | &payload.val, |
| 20801 | Value.Payload.Slice.len_index => return ComptimePtrMutationKit{ | 20939 | ptr_elem_ty, |
| 20802 | .decl_ref_mut = parent.decl_ref_mut, | 20940 | parent.decl_ref_mut, |
| 20803 | .val = &parent.val.castTag(.slice).?.data.len, | 20941 | ); |
| 20804 | .ty = Type.usize, | 20942 | }, |
| 20805 | }, | 20943 | .slice => switch (field_index) { |
| 20806 | else => unreachable, | 20944 | Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( |
| 20807 | } | 20945 | sema, |
| 20808 | }, | 20946 | block, |
| 20809 | else => unreachable, | 20947 | src, |
| 20810 | } | 20948 | parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), |
| 20811 | }, | 20949 | &val_ptr.castTag(.slice).?.data.ptr, |
| 20812 | .aggregate => return ComptimePtrMutationKit{ | 20950 | ptr_elem_ty, |
| 20813 | .decl_ref_mut = parent.decl_ref_mut, | 20951 | parent.decl_ref_mut, |
| 20814 | .val = &parent.val.castTag(.aggregate).?.data[field_index], | 20952 | ), |
| 20815 | .ty = parent.ty.structFieldType(field_index), | 20953 | |
| 20816 | }, | 20954 | Value.Payload.Slice.len_index => return beginComptimePtrMutationInner( |
| 20817 | .@"union" => { | 20955 | sema, |
| 20818 | // We need to set the active field of the union. | 20956 | block, |
| 20819 | const arena = parent.beginArena(sema.mod); | 20957 | src, |
| 20820 | defer parent.finishArena(sema.mod); | 20958 | Type.usize, |
| | 20959 | &val_ptr.castTag(.slice).?.data.len, |
| | 20960 | ptr_elem_ty, |
| | 20961 | parent.decl_ref_mut, |
| | 20962 | ), |
| 20821 | | 20963 | |
| 20822 | const payload = &parent.val.castTag(.@"union").?.data; | 20964 | else => unreachable, |
| 20823 | payload.tag = try Value.Tag.enum_field_index.create(arena, field_index); | 20965 | }, |
| 20824 | | 20966 | |
| | 20967 | else => unreachable, |
| | 20968 | }, |
| | 20969 | .reinterpret => |reinterpret| { |
| | 20970 | const field_offset_u64 = field_ptr.container_ty.structFieldOffset(field_index, target); |
| | 20971 | const field_offset = try sema.usizeCast(block, src, field_offset_u64); |
| 20825 | return ComptimePtrMutationKit{ | 20972 | return ComptimePtrMutationKit{ |
| 20826 | .decl_ref_mut = parent.decl_ref_mut, | 20973 | .decl_ref_mut = parent.decl_ref_mut, |
| 20827 | .val = &payload.val, | 20974 | .pointee = .{ .reinterpret = .{ |
| 20828 | .ty = parent.ty.structFieldType(field_index), | 20975 | .val_ptr = reinterpret.val_ptr, |
| | 20976 | .byte_offset = reinterpret.byte_offset + field_offset, |
| | 20977 | } }, |
| | 20978 | .ty = parent.ty, |
| 20829 | }; | 20979 | }; |
| 20830 | }, | 20980 | }, |
| 20831 | .slice => switch (field_index) { | 20981 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 20832 | Value.Payload.Slice.ptr_index => return ComptimePtrMutationKit{ | | |
| 20833 | .decl_ref_mut = parent.decl_ref_mut, | | |
| 20834 | .val = &parent.val.castTag(.slice).?.data.ptr, | | |
| 20835 | .ty = parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | | |
| 20836 | }, | | |
| 20837 | Value.Payload.Slice.len_index => return ComptimePtrMutationKit{ | | |
| 20838 | .decl_ref_mut = parent.decl_ref_mut, | | |
| 20839 | .val = &parent.val.castTag(.slice).?.data.len, | | |
| 20840 | .ty = Type.usize, | | |
| 20841 | }, | | |
| 20842 | else => unreachable, | | |
| 20843 | }, | | |
| 20844 | | | |
| 20845 | else => unreachable, | | |
| 20846 | } | 20982 | } |
| 20847 | }, | 20983 | }, |
| 20848 | .eu_payload_ptr => { | 20984 | .eu_payload_ptr => { |
| 20849 | const eu_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; | 20985 | const eu_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; |
| 20850 | var parent = try beginComptimePtrMutation(sema, block, src, eu_ptr.container_ptr); | 20986 | var parent = try beginComptimePtrMutation(sema, block, src, eu_ptr.container_ptr, eu_ptr.container_ty); |
| 20851 | const payload_ty = parent.ty.errorUnionPayload(); | 20987 | switch (parent.pointee) { |
| 20852 | switch (parent.val.tag()) { | 20988 | .direct => |val_ptr| { |
| 20853 | else => { | 20989 | const payload_ty = parent.ty.errorUnionPayload(); |
| 20854 | // An error union has been initialized to undefined at comptime and now we | 20990 | switch (val_ptr.tag()) { |
| 20855 | // are for the first time setting the payload. We must change the | 20991 | else => { |
| 20856 | // representation of the error union from `undef` to `opt_payload`. | 20992 | // An error union has been initialized to undefined at comptime and now we |
| 20857 | const arena = parent.beginArena(sema.mod); | 20993 | // are for the first time setting the payload. We must change the |
| 20858 | defer parent.finishArena(sema.mod); | 20994 | // representation of the error union from `undef` to `opt_payload`. |
| 20859 | | 20995 | const arena = parent.beginArena(sema.mod); |
| 20860 | const payload = try arena.create(Value.Payload.SubValue); | 20996 | defer parent.finishArena(sema.mod); |
| 20861 | payload.* = .{ | 20997 | |
| 20862 | .base = .{ .tag = .eu_payload }, | 20998 | const payload = try arena.create(Value.Payload.SubValue); |
| 20863 | .data = Value.undef, | 20999 | payload.* = .{ |
| 20864 | }; | 21000 | .base = .{ .tag = .eu_payload }, |
| | 21001 | .data = Value.undef, |
| | 21002 | }; |
| 20865 | | 21003 | |
| 20866 | parent.val.* = Value.initPayload(&payload.base); | 21004 | val_ptr.* = Value.initPayload(&payload.base); |
| 20867 | | 21005 | |
| 20868 | return ComptimePtrMutationKit{ | 21006 | return ComptimePtrMutationKit{ |
| 20869 | .decl_ref_mut = parent.decl_ref_mut, | 21007 | .decl_ref_mut = parent.decl_ref_mut, |
| 20870 | .val = &payload.data, | 21008 | .pointee = .{ .direct = &payload.data }, |
| 20871 | .ty = payload_ty, | 21009 | .ty = payload_ty, |
| 20872 | }; | 21010 | }; |
| | 21011 | }, |
| | 21012 | .eu_payload => return ComptimePtrMutationKit{ |
| | 21013 | .decl_ref_mut = parent.decl_ref_mut, |
| | 21014 | .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, |
| | 21015 | .ty = payload_ty, |
| | 21016 | }, |
| | 21017 | } |
| 20873 | }, | 21018 | }, |
| 20874 | .eu_payload => return ComptimePtrMutationKit{ | 21019 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| | 21020 | // Even though the parent value type has well-defined memory layout, our |
| | 21021 | // pointer type does not. |
| | 21022 | .reinterpret => return ComptimePtrMutationKit{ |
| 20875 | .decl_ref_mut = parent.decl_ref_mut, | 21023 | .decl_ref_mut = parent.decl_ref_mut, |
| 20876 | .val = &parent.val.castTag(.eu_payload).?.data, | 21024 | .pointee = .bad_ptr_ty, |
| 20877 | .ty = payload_ty, | 21025 | .ty = eu_ptr.container_ty, |
| 20878 | }, | 21026 | }, |
| 20879 | } | 21027 | } |
| 20880 | }, | 21028 | }, |
| 20881 | .opt_payload_ptr => { | 21029 | .opt_payload_ptr => { |
| 20882 | const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; | 21030 | const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; |
| 20883 | var parent = try beginComptimePtrMutation(sema, block, src, opt_ptr.container_ptr); | 21031 | var parent = try beginComptimePtrMutation(sema, block, src, opt_ptr.container_ptr, opt_ptr.container_ty); |
| 20884 | const payload_ty = try parent.ty.optionalChildAlloc(sema.arena); | 21032 | switch (parent.pointee) { |
| 20885 | switch (parent.val.tag()) { | 21033 | .direct => |val_ptr| { |
| 20886 | .undef, .null_value => { | 21034 | const payload_ty = try parent.ty.optionalChildAlloc(sema.arena); |
| 20887 | // An optional has been initialized to undefined at comptime and now we | 21035 | switch (val_ptr.tag()) { |
| 20888 | // are for the first time setting the payload. We must change the | 21036 | .undef, .null_value => { |
| 20889 | // representation of the optional from `undef` to `opt_payload`. | 21037 | // An optional has been initialized to undefined at comptime and now we |
| 20890 | const arena = parent.beginArena(sema.mod); | 21038 | // are for the first time setting the payload. We must change the |
| 20891 | defer parent.finishArena(sema.mod); | 21039 | // representation of the optional from `undef` to `opt_payload`. |
| 20892 | | 21040 | const arena = parent.beginArena(sema.mod); |
| 20893 | const payload = try arena.create(Value.Payload.SubValue); | 21041 | defer parent.finishArena(sema.mod); |
| 20894 | payload.* = .{ | | |
| 20895 | .base = .{ .tag = .opt_payload }, | | |
| 20896 | .data = Value.undef, | | |
| 20897 | }; | | |
| 20898 | | 21042 | |
| 20899 | parent.val.* = Value.initPayload(&payload.base); | 21043 | const payload = try arena.create(Value.Payload.SubValue); |
| | 21044 | payload.* = .{ |
| | 21045 | .base = .{ .tag = .opt_payload }, |
| | 21046 | .data = Value.undef, |
| | 21047 | }; |
| 20900 | | 21048 | |
| 20901 | return ComptimePtrMutationKit{ | 21049 | val_ptr.* = Value.initPayload(&payload.base); |
| 20902 | .decl_ref_mut = parent.decl_ref_mut, | 21050 | |
| 20903 | .val = &payload.data, | 21051 | return ComptimePtrMutationKit{ |
| 20904 | .ty = payload_ty, | 21052 | .decl_ref_mut = parent.decl_ref_mut, |
| 20905 | }; | 21053 | .pointee = .{ .direct = &payload.data }, |
| | 21054 | .ty = payload_ty, |
| | 21055 | }; |
| | 21056 | }, |
| | 21057 | .opt_payload => return ComptimePtrMutationKit{ |
| | 21058 | .decl_ref_mut = parent.decl_ref_mut, |
| | 21059 | .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, |
| | 21060 | .ty = payload_ty, |
| | 21061 | }, |
| | 21062 | |
| | 21063 | else => unreachable, |
| | 21064 | } |
| 20906 | }, | 21065 | }, |
| 20907 | .opt_payload => return ComptimePtrMutationKit{ | 21066 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| | 21067 | // Even though the parent value type has well-defined memory layout, our |
| | 21068 | // pointer type does not. |
| | 21069 | .reinterpret => return ComptimePtrMutationKit{ |
| 20908 | .decl_ref_mut = parent.decl_ref_mut, | 21070 | .decl_ref_mut = parent.decl_ref_mut, |
| 20909 | .val = &parent.val.castTag(.opt_payload).?.data, | 21071 | .pointee = .bad_ptr_ty, |
| 20910 | .ty = payload_ty, | 21072 | .ty = opt_ptr.container_ty, |
| 20911 | }, | 21073 | }, |
| 20912 | | | |
| 20913 | else => unreachable, | | |
| 20914 | } | 21074 | } |
| 20915 | }, | 21075 | }, |
| 20916 | .decl_ref => unreachable, // isComptimeMutablePtr() has been checked already | 21076 | .decl_ref => unreachable, // isComptimeMutablePtr() has been checked already |
| ... | @@ -20918,10 +21078,63 @@ fn beginComptimePtrMutation( | ... | @@ -20918,10 +21078,63 @@ fn beginComptimePtrMutation( |
| 20918 | } | 21078 | } |
| 20919 | } | 21079 | } |
| 20920 | | 21080 | |
| | 21081 | fn beginComptimePtrMutationInner( |
| | 21082 | sema: *Sema, |
| | 21083 | block: *Block, |
| | 21084 | src: LazySrcLoc, |
| | 21085 | decl_ty: Type, |
| | 21086 | decl_val: *Value, |
| | 21087 | ptr_elem_ty: Type, |
| | 21088 | decl_ref_mut: Value.Payload.DeclRefMut.Data, |
| | 21089 | ) CompileError!ComptimePtrMutationKit { |
| | 21090 | const target = sema.mod.getTarget(); |
| | 21091 | const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok; |
| | 21092 | if (coerce_ok) { |
| | 21093 | return ComptimePtrMutationKit{ |
| | 21094 | .decl_ref_mut = decl_ref_mut, |
| | 21095 | .pointee = .{ .direct = decl_val }, |
| | 21096 | .ty = decl_ty, |
| | 21097 | }; |
| | 21098 | } |
| | 21099 | |
| | 21100 | // Handle the case that the decl is an array and we're actually trying to point to an element. |
| | 21101 | if (decl_ty.isArrayOrVector()) { |
| | 21102 | const decl_elem_ty = decl_ty.childType(); |
| | 21103 | if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) { |
| | 21104 | return ComptimePtrMutationKit{ |
| | 21105 | .decl_ref_mut = decl_ref_mut, |
| | 21106 | .pointee = .{ .direct = decl_val }, |
| | 21107 | .ty = decl_ty, |
| | 21108 | }; |
| | 21109 | } |
| | 21110 | } |
| | 21111 | |
| | 21112 | if (!decl_ty.hasWellDefinedLayout()) { |
| | 21113 | return ComptimePtrMutationKit{ |
| | 21114 | .decl_ref_mut = decl_ref_mut, |
| | 21115 | .pointee = .{ .bad_decl_ty = {} }, |
| | 21116 | .ty = decl_ty, |
| | 21117 | }; |
| | 21118 | } |
| | 21119 | if (!ptr_elem_ty.hasWellDefinedLayout()) { |
| | 21120 | return ComptimePtrMutationKit{ |
| | 21121 | .decl_ref_mut = decl_ref_mut, |
| | 21122 | .pointee = .{ .bad_ptr_ty = {} }, |
| | 21123 | .ty = ptr_elem_ty, |
| | 21124 | }; |
| | 21125 | } |
| | 21126 | return ComptimePtrMutationKit{ |
| | 21127 | .decl_ref_mut = decl_ref_mut, |
| | 21128 | .pointee = .{ .reinterpret = .{ |
| | 21129 | .val_ptr = decl_val, |
| | 21130 | .byte_offset = 0, |
| | 21131 | } }, |
| | 21132 | .ty = decl_ty, |
| | 21133 | }; |
| | 21134 | } |
| | 21135 | |
| 20921 | const TypedValueAndOffset = struct { | 21136 | const TypedValueAndOffset = struct { |
| 20922 | tv: TypedValue, | 21137 | tv: TypedValue, |
| 20923 | /// The starting byte offset of `val` from `root_val`. | | |
| 20924 | /// If the type does not have a well-defined memory layout, this is null. | | |
| 20925 | byte_offset: usize, | 21138 | byte_offset: usize, |
| 20926 | }; | 21139 | }; |
| 20927 | | 21140 | |
| ... | @@ -21197,7 +21410,7 @@ fn bitCast( | ... | @@ -21197,7 +21410,7 @@ fn bitCast( |
| 21197 | return block.addBitCast(dest_ty, inst); | 21410 | return block.addBitCast(dest_ty, inst); |
| 21198 | } | 21411 | } |
| 21199 | | 21412 | |
| 21200 | pub fn bitCastVal( | 21413 | fn bitCastVal( |
| 21201 | sema: *Sema, | 21414 | sema: *Sema, |
| 21202 | block: *Block, | 21415 | block: *Block, |
| 21203 | src: LazySrcLoc, | 21416 | src: LazySrcLoc, |