| ... | @@ -12609,6 +12609,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -12609,6 +12609,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 12609 | enum_obj.* = .{ | 12609 | enum_obj.* = .{ |
| 12610 | .owner_decl = new_decl, | 12610 | .owner_decl = new_decl, |
| 12611 | .tag_ty = Type.initTag(.@"null"), | 12611 | .tag_ty = Type.initTag(.@"null"), |
| | 12612 | .tag_ty_inferred = true, |
| 12612 | .fields = .{}, | 12613 | .fields = .{}, |
| 12613 | .values = .{}, | 12614 | .values = .{}, |
| 12614 | .node_offset = src.node_offset, | 12615 | .node_offset = src.node_offset, |
| ... | @@ -17590,6 +17591,14 @@ fn beginComptimePtrMutation( | ... | @@ -17590,6 +17591,14 @@ fn beginComptimePtrMutation( |
| 17590 | src: LazySrcLoc, | 17591 | src: LazySrcLoc, |
| 17591 | ptr_val: Value, | 17592 | ptr_val: Value, |
| 17592 | ) CompileError!ComptimePtrMutationKit { | 17593 | ) CompileError!ComptimePtrMutationKit { |
| | 17594 | |
| | 17595 | // TODO: Update this to behave like `beginComptimePtrLoad` and properly check/use |
| | 17596 | // `container_ty` and `array_ty`, instead of trusting that the parent decl type |
| | 17597 | // matches the type used to derive the elem_ptr/field_ptr/etc. |
| | 17598 | // |
| | 17599 | // This is needed because the types will not match if the pointer we're mutating |
| | 17600 | // through is reinterpreting comptime memory. |
| | 17601 | |
| 17593 | switch (ptr_val.tag()) { | 17602 | switch (ptr_val.tag()) { |
| 17594 | .decl_ref_mut => { | 17603 | .decl_ref_mut => { |
| 17595 | const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data; | 17604 | const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data; |
| ... | @@ -17850,163 +17859,191 @@ fn beginComptimePtrMutation( | ... | @@ -17850,163 +17859,191 @@ fn beginComptimePtrMutation( |
| 17850 | } | 17859 | } |
| 17851 | } | 17860 | } |
| 17852 | | 17861 | |
| 17853 | const ComptimePtrLoadKit = struct { | 17862 | const TypedValueAndOffset = struct { |
| 17854 | /// The Value of the Decl that owns this memory. | 17863 | tv: TypedValue, |
| 17855 | root_val: Value, | | |
| 17856 | /// The Type of the Decl that owns this memory. | | |
| 17857 | root_ty: Type, | | |
| 17858 | /// Parent Value. | | |
| 17859 | val: Value, | | |
| 17860 | /// The Type of the parent Value. | | |
| 17861 | ty: Type, | | |
| 17862 | /// The starting byte offset of `val` from `root_val`. | 17864 | /// The starting byte offset of `val` from `root_val`. |
| 17863 | /// If the type does not have a well-defined memory layout, this is null. | 17865 | /// If the type does not have a well-defined memory layout, this is null. |
| 17864 | byte_offset: ?usize, | 17866 | byte_offset: usize, |
| 17865 | /// Whether the `root_val` could be mutated by further | 17867 | }; |
| | 17868 | |
| | 17869 | const ComptimePtrLoadKit = struct { |
| | 17870 | /// The Value and Type corresponding to the target of the provided pointer. |
| | 17871 | /// If a direct dereference is not possible, this is null. |
| | 17872 | target: ?TypedValue, |
| | 17873 | /// The largest parent Value containing `target` and having a well-defined memory layout. |
| | 17874 | /// This is used for bitcasting, if direct dereferencing failed (i.e. `target` is null). |
| | 17875 | parent: ?TypedValueAndOffset, |
| | 17876 | /// Whether the `target` could be mutated by further |
| 17866 | /// semantic analysis and a copy must be performed. | 17877 | /// semantic analysis and a copy must be performed. |
| 17867 | is_mutable: bool, | 17878 | is_mutable: bool, |
| | 17879 | /// If the root decl could not be used as `parent`, this is the type that |
| | 17880 | /// caused that by not having a well-defined layout |
| | 17881 | ty_without_well_defined_layout: ?Type, |
| 17868 | }; | 17882 | }; |
| 17869 | | 17883 | |
| 17870 | const ComptimePtrLoadError = CompileError || error{ | 17884 | const ComptimePtrLoadError = CompileError || error{ |
| 17871 | RuntimeLoad, | 17885 | RuntimeLoad, |
| 17872 | }; | 17886 | }; |
| 17873 | | 17887 | |
| | 17888 | /// If `maybe_array_ty` is provided, it will be used to directly dereference an |
| | 17889 | /// .elem_ptr of type T to a value of [N]T, if necessary. |
| 17874 | fn beginComptimePtrLoad( | 17890 | fn beginComptimePtrLoad( |
| 17875 | sema: *Sema, | 17891 | sema: *Sema, |
| 17876 | block: *Block, | 17892 | block: *Block, |
| 17877 | src: LazySrcLoc, | 17893 | src: LazySrcLoc, |
| 17878 | ptr_val: Value, | 17894 | ptr_val: Value, |
| | 17895 | maybe_array_ty: ?Type, |
| 17879 | ) ComptimePtrLoadError!ComptimePtrLoadKit { | 17896 | ) ComptimePtrLoadError!ComptimePtrLoadKit { |
| 17880 | const target = sema.mod.getTarget(); | 17897 | const target = sema.mod.getTarget(); |
| 17881 | switch (ptr_val.tag()) { | 17898 | var deref: ComptimePtrLoadKit = switch (ptr_val.tag()) { |
| 17882 | .decl_ref => { | 17899 | .decl_ref, |
| 17883 | const decl = ptr_val.castTag(.decl_ref).?.data; | 17900 | .decl_ref_mut, |
| 17884 | const decl_val = try decl.value(); | 17901 | => blk: { |
| 17885 | if (decl_val.tag() == .variable) return error.RuntimeLoad; | 17902 | const decl = switch (ptr_val.tag()) { |
| 17886 | return ComptimePtrLoadKit{ | 17903 | .decl_ref => ptr_val.castTag(.decl_ref).?.data, |
| 17887 | .root_val = decl_val, | 17904 | .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl, |
| 17888 | .root_ty = decl.ty, | 17905 | else => unreachable, |
| 17889 | .val = decl_val, | | |
| 17890 | .ty = decl.ty, | | |
| 17891 | .byte_offset = 0, | | |
| 17892 | .is_mutable = false, | | |
| 17893 | }; | 17906 | }; |
| 17894 | }, | 17907 | const is_mutable = ptr_val.tag() == .decl_ref_mut; |
| 17895 | .decl_ref_mut => { | 17908 | const decl_tv = try decl.typedValue(); |
| 17896 | const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl; | 17909 | if (decl_tv.val.tag() == .variable) return error.RuntimeLoad; |
| 17897 | const decl_val = try decl.value(); | 17910 | |
| 17898 | if (decl_val.tag() == .variable) return error.RuntimeLoad; | 17911 | const layout_defined = try sema.typeHasWellDefinedLayout(block, src, decl.ty); |
| 17899 | return ComptimePtrLoadKit{ | 17912 | break :blk ComptimePtrLoadKit{ |
| 17900 | .root_val = decl_val, | 17913 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, |
| 17901 | .root_ty = decl.ty, | 17914 | .target = decl_tv, |
| 17902 | .val = decl_val, | 17915 | .is_mutable = is_mutable, |
| 17903 | .ty = decl.ty, | 17916 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, |
| 17904 | .byte_offset = 0, | | |
| 17905 | .is_mutable = true, | | |
| 17906 | }; | 17917 | }; |
| 17907 | }, | 17918 | }, |
| 17908 | .elem_ptr => { | 17919 | |
| | 17920 | .elem_ptr => blk: { |
| 17909 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | 17921 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; |
| 17910 | const parent = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr); | 17922 | const elem_ty = elem_ptr.elem_ty; |
| 17911 | switch (parent.ty.zigTypeTag()) { | 17923 | var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null); |
| 17912 | .Array, .Vector => { | 17924 | |
| 17913 | const check_len = parent.ty.arrayLenIncludingSentinel(); | 17925 | if (elem_ptr.index != 0) { |
| 17914 | if (elem_ptr.index >= check_len) { | 17926 | if (try sema.typeHasWellDefinedLayout(block, src, elem_ty)) { |
| 17915 | // TODO have the parent include the decl so we can say "declared here" | 17927 | if (deref.parent) |*parent| { |
| 17916 | return sema.fail(block, src, "comptime load of index {d} out of bounds of array length {d}", .{ | 17928 | // Update the byte offset (in-place) |
| 17917 | elem_ptr.index, check_len, | 17929 | const elem_size = try sema.typeAbiSize(block, src, elem_ty); |
| 17918 | }); | 17930 | const offset = parent.byte_offset + elem_size * elem_ptr.index; |
| | 17931 | parent.byte_offset = try sema.usizeCast(block, src, offset); |
| 17919 | } | 17932 | } |
| 17920 | const elem_ty = parent.ty.childType(); | 17933 | } else { |
| 17921 | const byte_offset: ?usize = bo: { | 17934 | deref.parent = null; |
| 17922 | if (try sema.typeRequiresComptime(block, src, elem_ty)) { | 17935 | deref.ty_without_well_defined_layout = elem_ty; |
| 17923 | break :bo null; | 17936 | } |
| 17924 | } else { | 17937 | } |
| 17925 | if (parent.byte_offset) |off| { | 17938 | |
| 17926 | try sema.resolveTypeLayout(block, src, elem_ty); | 17939 | // If we're loading an elem_ptr that was derived from a different type |
| 17927 | const elem_size = elem_ty.abiSize(target); | 17940 | // than the true type of the underlying decl, we cannot deref directly |
| 17928 | break :bo try sema.usizeCast(block, src, off + elem_size * elem_ptr.index); | 17941 | const ty_matches = if (deref.target != null and deref.target.?.ty.isArrayLike()) x: { |
| 17929 | } else { | 17942 | const deref_elem_ty = deref.target.?.ty.childType(); |
| 17930 | break :bo null; | 17943 | break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or |
| 17931 | } | 17944 | (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; |
| 17932 | } | 17945 | } else false; |
| 17933 | }; | 17946 | if (!ty_matches) { |
| 17934 | return ComptimePtrLoadKit{ | 17947 | deref.target = null; |
| 17935 | .root_val = parent.root_val, | 17948 | break :blk deref; |
| 17936 | .root_ty = parent.root_ty, | | |
| 17937 | .val = try parent.val.elemValue(sema.arena, elem_ptr.index), | | |
| 17938 | .ty = elem_ty, | | |
| 17939 | .byte_offset = byte_offset, | | |
| 17940 | .is_mutable = parent.is_mutable, | | |
| 17941 | }; | | |
| 17942 | }, | | |
| 17943 | else => { | | |
| 17944 | if (elem_ptr.index != 0) { | | |
| 17945 | // TODO have the parent include the decl so we can say "declared here" | | |
| 17946 | return sema.fail(block, src, "out of bounds comptime load of index {d}", .{ | | |
| 17947 | elem_ptr.index, | | |
| 17948 | }); | | |
| 17949 | } | | |
| 17950 | return ComptimePtrLoadKit{ | | |
| 17951 | .root_val = parent.root_val, | | |
| 17952 | .root_ty = parent.root_ty, | | |
| 17953 | .val = parent.val, | | |
| 17954 | .ty = parent.ty, | | |
| 17955 | .byte_offset = parent.byte_offset, | | |
| 17956 | .is_mutable = parent.is_mutable, | | |
| 17957 | }; | | |
| 17958 | }, | | |
| 17959 | } | 17949 | } |
| | 17950 | |
| | 17951 | var array_tv = deref.target.?; |
| | 17952 | const check_len = array_tv.ty.arrayLenIncludingSentinel(); |
| | 17953 | if (elem_ptr.index >= check_len) { |
| | 17954 | // TODO have the deref include the decl so we can say "declared here" |
| | 17955 | return sema.fail(block, src, "comptime load of index {d} out of bounds of array length {d}", .{ |
| | 17956 | elem_ptr.index, check_len, |
| | 17957 | }); |
| | 17958 | } |
| | 17959 | |
| | 17960 | if (maybe_array_ty) |load_ty| { |
| | 17961 | // It's possible that we're loading a [N]T, in which case we'd like to slice |
| | 17962 | // the target array directly from our parent array. |
| | 17963 | if (load_ty.isArrayLike() and load_ty.childType().eql(elem_ty)) { |
| | 17964 | const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel()); |
| | 17965 | deref.target = if (elem_ptr.index + N <= check_len) TypedValue{ |
| | 17966 | .ty = try Type.array(sema.arena, N, null, elem_ty), |
| | 17967 | .val = try array_tv.val.sliceArray(sema.arena, elem_ptr.index, elem_ptr.index + N), |
| | 17968 | } else null; |
| | 17969 | break :blk deref; |
| | 17970 | } |
| | 17971 | } |
| | 17972 | |
| | 17973 | deref.target = .{ |
| | 17974 | .ty = elem_ty, |
| | 17975 | .val = try array_tv.val.elemValue(sema.arena, elem_ptr.index), |
| | 17976 | }; |
| | 17977 | break :blk deref; |
| 17960 | }, | 17978 | }, |
| 17961 | .field_ptr => { | 17979 | |
| | 17980 | .field_ptr => blk: { |
| 17962 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | 17981 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; |
| 17963 | const parent = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr); | | |
| 17964 | const field_index = @intCast(u32, field_ptr.field_index); | 17982 | const field_index = @intCast(u32, field_ptr.field_index); |
| 17965 | const byte_offset: ?usize = bo: { | 17983 | const field_ty = field_ptr.container_ty.structFieldType(field_index); |
| 17966 | if (try sema.typeRequiresComptime(block, src, parent.ty)) { | 17984 | var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty); |
| 17967 | break :bo null; | 17985 | |
| 17968 | } else { | 17986 | if (try sema.typeHasWellDefinedLayout(block, src, field_ptr.container_ty)) { |
| 17969 | if (parent.byte_offset) |off| { | 17987 | if (deref.parent) |*parent| { |
| 17970 | try sema.resolveTypeLayout(block, src, parent.ty); | 17988 | // Update the byte offset (in-place) |
| 17971 | const field_offset = parent.ty.structFieldOffset(field_index, target); | 17989 | try sema.resolveTypeLayout(block, src, field_ptr.container_ty); |
| 17972 | break :bo try sema.usizeCast(block, src, off + field_offset); | 17990 | const field_offset = field_ptr.container_ty.structFieldOffset(field_index, target); |
| 17973 | } else { | 17991 | parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); |
| 17974 | break :bo null; | | |
| 17975 | } | | |
| 17976 | } | 17992 | } |
| 17977 | }; | 17993 | } else { |
| 17978 | return ComptimePtrLoadKit{ | 17994 | deref.parent = null; |
| 17979 | .root_val = parent.root_val, | 17995 | deref.ty_without_well_defined_layout = field_ptr.container_ty; |
| 17980 | .root_ty = parent.root_ty, | 17996 | } |
| 17981 | .val = try parent.val.fieldValue(sema.arena, field_index), | 17997 | |
| 17982 | .ty = parent.ty.structFieldType(field_index), | 17998 | if (deref.target) |*tv| { |
| 17983 | .byte_offset = byte_offset, | 17999 | const coerce_in_mem_ok = |
| 17984 | .is_mutable = parent.is_mutable, | 18000 | (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or |
| 17985 | }; | 18001 | (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok; |
| 17986 | }, | 18002 | if (coerce_in_mem_ok) { |
| 17987 | .eu_payload_ptr => { | 18003 | deref.target = TypedValue{ |
| 17988 | const err_union_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; | 18004 | .ty = field_ty, |
| 17989 | const parent = try beginComptimePtrLoad(sema, block, src, err_union_ptr.container_ptr); | 18005 | .val = try tv.val.fieldValue(sema.arena, field_index), |
| 17990 | return ComptimePtrLoadKit{ | 18006 | }; |
| 17991 | .root_val = parent.root_val, | 18007 | break :blk deref; |
| 17992 | .root_ty = parent.root_ty, | 18008 | } |
| 17993 | .val = parent.val.castTag(.eu_payload).?.data, | 18009 | } |
| 17994 | .ty = parent.ty.errorUnionPayload(), | 18010 | deref.target = null; |
| 17995 | .byte_offset = null, | 18011 | break :blk deref; |
| 17996 | .is_mutable = parent.is_mutable, | | |
| 17997 | }; | | |
| 17998 | }, | 18012 | }, |
| 17999 | .opt_payload_ptr => { | 18013 | |
| 18000 | const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; | 18014 | .opt_payload_ptr, |
| 18001 | const parent = try beginComptimePtrLoad(sema, block, src, opt_ptr.container_ptr); | 18015 | .eu_payload_ptr, |
| 18002 | return ComptimePtrLoadKit{ | 18016 | => blk: { |
| 18003 | .root_val = parent.root_val, | 18017 | const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data; |
| 18004 | .root_ty = parent.root_ty, | 18018 | const payload_ty = switch (ptr_val.tag()) { |
| 18005 | .val = parent.val.castTag(.opt_payload).?.data, | 18019 | .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(), |
| 18006 | .ty = try parent.ty.optionalChildAlloc(sema.arena), | 18020 | .opt_payload_ptr => try payload_ptr.container_ty.optionalChildAlloc(sema.arena), |
| 18007 | .byte_offset = null, | 18021 | else => unreachable, |
| 18008 | .is_mutable = parent.is_mutable, | | |
| 18009 | }; | 18022 | }; |
| | 18023 | var deref = try beginComptimePtrLoad(sema, block, src, payload_ptr.container_ptr, payload_ptr.container_ty); |
| | 18024 | |
| | 18025 | // eu_payload_ptr and opt_payload_ptr never have a well-defined layout |
| | 18026 | if (deref.parent != null) { |
| | 18027 | deref.parent = null; |
| | 18028 | deref.ty_without_well_defined_layout = payload_ptr.container_ty; |
| | 18029 | } |
| | 18030 | |
| | 18031 | if (deref.target) |*tv| { |
| | 18032 | const coerce_in_mem_ok = |
| | 18033 | (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or |
| | 18034 | (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok; |
| | 18035 | if (coerce_in_mem_ok) { |
| | 18036 | const payload_val = switch (ptr_val.tag()) { |
| | 18037 | .eu_payload_ptr => tv.val.castTag(.eu_payload).?.data, |
| | 18038 | .opt_payload_ptr => tv.val.castTag(.opt_payload).?.data, |
| | 18039 | else => unreachable, |
| | 18040 | }; |
| | 18041 | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; |
| | 18042 | break :blk deref; |
| | 18043 | } |
| | 18044 | } |
| | 18045 | deref.target = null; |
| | 18046 | break :blk deref; |
| 18010 | }, | 18047 | }, |
| 18011 | | 18048 | |
| 18012 | .zero, | 18049 | .zero, |
| ... | @@ -18021,7 +18058,14 @@ fn beginComptimePtrLoad( | ... | @@ -18021,7 +18058,14 @@ fn beginComptimePtrLoad( |
| 18021 | => return error.RuntimeLoad, | 18058 | => return error.RuntimeLoad, |
| 18022 | | 18059 | |
| 18023 | else => unreachable, | 18060 | else => unreachable, |
| | 18061 | }; |
| | 18062 | |
| | 18063 | if (deref.target) |tv| { |
| | 18064 | if (deref.parent == null and tv.ty.hasWellDefinedLayout()) { |
| | 18065 | deref.parent = .{ .tv = tv, .byte_offset = 0 }; |
| | 18066 | } |
| 18024 | } | 18067 | } |
| | 18068 | return deref; |
| 18025 | } | 18069 | } |
| 18026 | | 18070 | |
| 18027 | fn bitCast( | 18071 | fn bitCast( |
| ... | @@ -21106,39 +21150,53 @@ pub fn analyzeAddrspace( | ... | @@ -21106,39 +21150,53 @@ pub fn analyzeAddrspace( |
| 21106 | /// Asserts the value is a pointer and dereferences it. | 21150 | /// Asserts the value is a pointer and dereferences it. |
| 21107 | /// Returns `null` if the pointer contents cannot be loaded at comptime. | 21151 | /// Returns `null` if the pointer contents cannot be loaded at comptime. |
| 21108 | fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { | 21152 | fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { |
| 21109 | const target = sema.mod.getTarget(); | | |
| 21110 | const load_ty = ptr_ty.childType(); | 21153 | const load_ty = ptr_ty.childType(); |
| 21111 | const parent = sema.beginComptimePtrLoad(block, src, ptr_val) catch |err| switch (err) { | 21154 | const target = sema.mod.getTarget(); |
| | 21155 | const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) { |
| 21112 | error.RuntimeLoad => return null, | 21156 | error.RuntimeLoad => return null, |
| 21113 | else => |e| return e, | 21157 | else => |e| return e, |
| 21114 | }; | 21158 | }; |
| 21115 | // We have a Value that lines up in virtual memory exactly with what we want to load. | 21159 | |
| 21116 | // If the Type is in-memory coercable to `load_ty`, it may be returned without modifications. | 21160 | if (deref.target) |tv| { |
| 21117 | const coerce_in_mem_ok = | 21161 | const coerce_in_mem_ok = |
| 21118 | (try sema.coerceInMemoryAllowed(block, load_ty, parent.ty, false, target, src, src)) == .ok or | 21162 | (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or |
| 21119 | (try sema.coerceInMemoryAllowed(block, parent.ty, load_ty, false, target, src, src)) == .ok; | 21163 | (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok; |
| 21120 | if (coerce_in_mem_ok) { | 21164 | if (coerce_in_mem_ok) { |
| 21121 | if (parent.is_mutable) { | 21165 | // We have a Value that lines up in virtual memory exactly with what we want to load, |
| 21122 | // The decl whose value we are obtaining here may be overwritten with | 21166 | // and it is in-memory coercible to load_ty. It may be returned without modifications. |
| 21123 | // a different value upon further semantic analysis, which would | 21167 | if (deref.is_mutable) { |
| 21124 | // invalidate this memory. So we must copy here. | 21168 | // The decl whose value we are obtaining here may be overwritten with |
| 21125 | return try parent.val.copy(sema.arena); | 21169 | // a different value upon further semantic analysis, which would |
| | 21170 | // invalidate this memory. So we must copy here. |
| | 21171 | return try tv.val.copy(sema.arena); |
| | 21172 | } |
| | 21173 | return tv.val; |
| 21126 | } | 21174 | } |
| 21127 | return parent.val; | | |
| 21128 | } | 21175 | } |
| 21129 | | 21176 | |
| 21130 | // The type is not in-memory coercable, so it must be bitcasted according | 21177 | // The type is not in-memory coercible or the direct dereference failed, so it must |
| 21131 | // to the pointer type we are performing the load through. | 21178 | // be bitcast according to the pointer type we are performing the load through. |
| | 21179 | if (!(try sema.typeHasWellDefinedLayout(block, src, load_ty))) |
| | 21180 | return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{load_ty}); |
| | 21181 | |
| | 21182 | const load_sz = try sema.typeAbiSize(block, src, load_ty); |
| | 21183 | |
| | 21184 | // Try the smaller bit-cast first, since that's more efficient than using the larger `parent` |
| | 21185 | if (deref.target) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty)) |
| | 21186 | return try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0); |
| 21132 | | 21187 | |
| 21133 | // TODO emit a compile error if the types are not allowed to be bitcasted | 21188 | // If that fails, try to bit-cast from the largest parent value with a well-defined layout |
| | 21189 | if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(block, src, parent.tv.ty)) |
| | 21190 | return try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset); |
| 21134 | | 21191 | |
| 21135 | if (parent.ty.abiSize(target) >= load_ty.abiSize(target)) { | 21192 | if (deref.ty_without_well_defined_layout) |bad_ty| { |
| 21136 | // The Type it is stored as in the compiler has an ABI size greater or equal to | 21193 | // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem |
| 21137 | // the ABI size of `load_ty`. We may perform the bitcast based on | 21194 | // is that some type we encountered when de-referencing does not have a well-defined layout. |
| 21138 | // `parent.val` alone (more efficient). | 21195 | return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{bad_ty}); |
| 21139 | return try sema.bitCastVal(block, src, parent.val, parent.ty, load_ty, 0); | | |
| 21140 | } else { | 21196 | } else { |
| 21141 | return try sema.bitCastVal(block, src, parent.root_val, parent.root_ty, load_ty, parent.byte_offset.?); | 21197 | // If all encountered types had well-defined layouts, the parent is the root decl and it just |
| | 21198 | // wasn't big enough for the load. |
| | 21199 | return sema.fail(block, src, "dereference of {} exceeds bounds of containing decl of type {}", .{ ptr_ty, deref.parent.?.tv.ty }); |
| 21142 | } | 21200 | } |
| 21143 | } | 21201 | } |
| 21144 | | 21202 | |