authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-15 00:43:26-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-15 00:43:26-04:00
log9eceba248511849ff77a90876424f9930bf7f9f9
treed6691a25a828b44cb4c17365fb8549d339046810
parenta2a5d3c2885cacf16d55d7943d10a81a5dc31b8a
parent2f92d1a0264b6827cb67a55726c4c9a082337508
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11128 from topolarity/comptime-memory-reinterp

stage2: Track parent type for `.elem_ptr`, `.field_ptr`, and `.*_payload_ptr`

9 files changed, 670 insertions(+), 326 deletions(-)

src/Module.zig+5-3
......@@ -852,7 +852,7 @@ pub const ErrorSet = struct {
852852 }
853853};
854854
855pub const RequiresComptime = enum { no, yes, unknown, wip };
855pub const PropertyBoolean = enum { no, yes, unknown, wip };
856856
857857/// Represents the data that a struct declaration provides.
858858pub const Struct = struct {
......@@ -884,7 +884,7 @@ pub const Struct = struct {
884884 /// If false, resolving the fields is necessary to determine whether the type has only
885885 /// one possible value.
886886 known_non_opv: bool,
887 requires_comptime: RequiresComptime = .unknown,
887 requires_comptime: PropertyBoolean = .unknown,
888888
889889 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
890890
......@@ -1089,6 +1089,8 @@ pub const EnumFull = struct {
10891089 namespace: Namespace,
10901090 /// Offset from `owner_decl`, points to the enum decl AST node.
10911091 node_offset: i32,
1092 /// true if zig inferred this tag type, false if user specified it
1093 tag_ty_inferred: bool,
10921094
10931095 pub const NameMap = std.StringArrayHashMapUnmanaged(void);
10941096 pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false);
......@@ -1132,7 +1134,7 @@ pub const Union = struct {
11321134 // which `have_layout` does not ensure.
11331135 fully_resolved,
11341136 },
1135 requires_comptime: RequiresComptime = .unknown,
1137 requires_comptime: PropertyBoolean = .unknown,
11361138
11371139 pub const Field = struct {
11381140 /// undefined until `status` is `have_field_types` or `have_layout`.
src/Sema.zig+261-175
......@@ -1615,6 +1615,9 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
16151615 try pointee_ty.copy(anon_decl.arena()),
16161616 Value.undef,
16171617 );
1618 if (iac.data.alignment != 0) {
1619 try sema.resolveTypeLayout(block, src, pointee_ty);
1620 }
16181621 const ptr_ty = try Type.ptr(sema.arena, target, .{
16191622 .pointee_type = pointee_ty,
16201623 .@"align" = iac.data.alignment,
......@@ -1884,7 +1887,8 @@ fn zirEnumDecl(
18841887
18851888 enum_obj.* = .{
18861889 .owner_decl = new_decl,
1887 .tag_ty = Type.initTag(.@"null"),
1890 .tag_ty = Type.@"null",
1891 .tag_ty_inferred = true,
18881892 .fields = .{},
18891893 .values = .{},
18901894 .node_offset = src.node_offset,
......@@ -1907,6 +1911,7 @@ fn zirEnumDecl(
19071911 // TODO better source location
19081912 const ty = try sema.resolveType(block, src, tag_type_ref);
19091913 enum_obj.tag_ty = try ty.copy(new_decl_arena_allocator);
1914 enum_obj.tag_ty_inferred = false;
19101915 }
19111916 try new_decl.finalizeNewArena(&new_decl_arena);
19121917 return sema.analyzeDeclVal(block, src, new_decl);
......@@ -1956,16 +1961,16 @@ fn zirEnumDecl(
19561961
19571962 try wip_captures.finalize();
19581963
1959 const tag_ty = blk: {
1960 if (tag_type_ref != .none) {
1961 // TODO better source location
1962 const ty = try sema.resolveType(block, src, tag_type_ref);
1963 break :blk try ty.copy(new_decl_arena_allocator);
1964 }
1964 if (tag_type_ref != .none) {
1965 // TODO better source location
1966 const ty = try sema.resolveType(block, src, tag_type_ref);
1967 enum_obj.tag_ty = try ty.copy(new_decl_arena_allocator);
1968 enum_obj.tag_ty_inferred = false;
1969 } else {
19651970 const bits = std.math.log2_int_ceil(usize, fields_len);
1966 break :blk try Type.Tag.int_unsigned.create(new_decl_arena_allocator, bits);
1967 };
1968 enum_obj.tag_ty = tag_ty;
1971 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(new_decl_arena_allocator, bits);
1972 enum_obj.tag_ty_inferred = true;
1973 }
19691974 }
19701975
19711976 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
......@@ -2417,13 +2422,13 @@ fn zirAllocExtended(
24172422 try sema.validateVarType(block, ty_src, var_ty, false);
24182423 }
24192424 const target = sema.mod.getTarget();
2425 try sema.requireRuntimeBlock(block, src);
2426 try sema.resolveTypeLayout(block, src, var_ty);
24202427 const ptr_type = try Type.ptr(sema.arena, target, .{
24212428 .pointee_type = var_ty,
24222429 .@"align" = alignment,
24232430 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
24242431 });
2425 try sema.requireRuntimeBlock(block, src);
2426 try sema.resolveTypeLayout(block, src, var_ty);
24272432 return block.addTy(.alloc, ptr_type);
24282433 }
24292434
......@@ -5568,7 +5573,10 @@ fn analyzeOptionalPayloadPtr(
55685573 }
55695574 return sema.addConstant(
55705575 child_pointer,
5571 try Value.Tag.opt_payload_ptr.create(sema.arena, ptr_val),
5576 try Value.Tag.opt_payload_ptr.create(sema.arena, .{
5577 .container_ptr = ptr_val,
5578 .container_ty = optional_ptr_ty.childType(),
5579 }),
55725580 );
55735581 }
55745582 if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| {
......@@ -5578,7 +5586,10 @@ fn analyzeOptionalPayloadPtr(
55785586 // The same Value represents the pointer to the optional and the payload.
55795587 return sema.addConstant(
55805588 child_pointer,
5581 try Value.Tag.opt_payload_ptr.create(sema.arena, ptr_val),
5589 try Value.Tag.opt_payload_ptr.create(sema.arena, .{
5590 .container_ptr = ptr_val,
5591 .container_ty = optional_ptr_ty.childType(),
5592 }),
55825593 );
55835594 }
55845595 }
......@@ -5733,7 +5744,10 @@ fn analyzeErrUnionPayloadPtr(
57335744 }
57345745 return sema.addConstant(
57355746 operand_pointer_ty,
5736 try Value.Tag.eu_payload_ptr.create(sema.arena, ptr_val),
5747 try Value.Tag.eu_payload_ptr.create(sema.arena, .{
5748 .container_ptr = ptr_val,
5749 .container_ty = operand_ty.elemType(),
5750 }),
57375751 );
57385752 }
57395753 if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| {
......@@ -5743,7 +5757,10 @@ fn analyzeErrUnionPayloadPtr(
57435757
57445758 return sema.addConstant(
57455759 operand_pointer_ty,
5746 try Value.Tag.eu_payload_ptr.create(sema.arena, ptr_val),
5760 try Value.Tag.eu_payload_ptr.create(sema.arena, .{
5761 .container_ptr = ptr_val,
5762 .container_ty = operand_ty.elemType(),
5763 }),
57475764 );
57485765 }
57495766 }
......@@ -6652,6 +6669,7 @@ fn zirSwitchCapture(
66526669 field_ty_ptr,
66536670 try Value.Tag.field_ptr.create(sema.arena, .{
66546671 .container_ptr = op_ptr_val,
6672 .container_ty = operand_ty,
66556673 .field_index = field_index,
66566674 }),
66576675 );
......@@ -9638,7 +9656,7 @@ fn analyzePtrArithmetic(
96389656 if (air_tag == .ptr_sub) {
96399657 return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{});
96409658 }
9641 const new_ptr_val = try ptr_val.elemPtr(sema.arena, offset_int);
9659 const new_ptr_val = try ptr_val.elemPtr(ptr_ty, sema.arena, offset_int);
96429660 return sema.addConstant(new_ptr_ty, new_ptr_val);
96439661 } else break :rs offset_src;
96449662 } else break :rs ptr_src;
......@@ -12592,6 +12610,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1259212610 enum_obj.* = .{
1259312611 .owner_decl = new_decl,
1259412612 .tag_ty = Type.initTag(.@"null"),
12613 .tag_ty_inferred = true,
1259512614 .fields = .{},
1259612615 .values = .{},
1259712616 .node_offset = src.node_offset,
......@@ -15903,6 +15922,7 @@ fn finishFieldCallBind(
1590315922 ptr_field_ty,
1590415923 try Value.Tag.field_ptr.create(arena, .{
1590515924 .container_ptr = struct_ptr_val,
15925 .container_ty = ptr_ty.childType(),
1590615926 .field_index = field_index,
1590715927 }),
1590815928 );
......@@ -16065,6 +16085,7 @@ fn structFieldPtrByIndex(
1606516085 ptr_field_ty,
1606616086 try Value.Tag.field_ptr.create(sema.arena, .{
1606716087 .container_ptr = struct_ptr_val,
16088 .container_ty = struct_ptr_ty.childType(),
1606816089 .field_index = field_index,
1606916090 }),
1607016091 );
......@@ -16241,6 +16262,7 @@ fn unionFieldPtr(
1624116262 ptr_field_ty,
1624216263 try Value.Tag.field_ptr.create(arena, .{
1624316264 .container_ptr = union_ptr_val,
16265 .container_ty = union_ty,
1624416266 .field_index = field_index,
1624516267 }),
1624616268 );
......@@ -16333,7 +16355,7 @@ fn elemPtr(
1633316355 const runtime_src = if (maybe_slice_val) |slice_val| rs: {
1633416356 const index_val = maybe_index_val orelse break :rs elem_index_src;
1633516357 const index = @intCast(usize, index_val.toUnsignedInt());
16336 const elem_ptr = try slice_val.elemPtr(sema.arena, index);
16358 const elem_ptr = try slice_val.elemPtr(array_ty, sema.arena, index);
1633716359 return sema.addConstant(result_ty, elem_ptr);
1633816360 } else array_ptr_src;
1633916361
......@@ -16348,7 +16370,7 @@ fn elemPtr(
1634816370 const ptr_val = maybe_ptr_val orelse break :rs array_ptr_src;
1634916371 const index_val = maybe_index_val orelse break :rs elem_index_src;
1635016372 const index = @intCast(usize, index_val.toUnsignedInt());
16351 const elem_ptr = try ptr_val.elemPtr(sema.arena, index);
16373 const elem_ptr = try ptr_val.elemPtr(array_ty, sema.arena, index);
1635216374 return sema.addConstant(result_ty, elem_ptr);
1635316375 };
1635416376
......@@ -16473,6 +16495,7 @@ fn tupleFieldPtr(
1647316495 ptr_field_ty,
1647416496 try Value.Tag.field_ptr.create(sema.arena, .{
1647516497 .container_ptr = tuple_ptr_val,
16498 .container_ty = tuple_ty,
1647616499 .field_index = field_index,
1647716500 }),
1647816501 );
......@@ -16563,7 +16586,7 @@ fn elemPtrArray(
1656316586 const index_u64 = index_val.toUnsignedInt();
1656416587 // @intCast here because it would have been impossible to construct a value that
1656516588 // required a larger index.
16566 const elem_ptr = try array_ptr_val.elemPtr(sema.arena, @intCast(usize, index_u64));
16589 const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, @intCast(usize, index_u64));
1656716590 return sema.addConstant(result_ty, elem_ptr);
1656816591 }
1656916592 }
......@@ -17569,6 +17592,14 @@ fn beginComptimePtrMutation(
1756917592 src: LazySrcLoc,
1757017593 ptr_val: Value,
1757117594) CompileError!ComptimePtrMutationKit {
17595
17596 // TODO: Update this to behave like `beginComptimePtrLoad` and properly check/use
17597 // `container_ty` and `array_ty`, instead of trusting that the parent decl type
17598 // matches the type used to derive the elem_ptr/field_ptr/etc.
17599 //
17600 // This is needed because the types will not match if the pointer we're mutating
17601 // through is reinterpreting comptime memory.
17602
1757217603 switch (ptr_val.tag()) {
1757317604 .decl_ref_mut => {
1757417605 const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data;
......@@ -17757,8 +17788,8 @@ fn beginComptimePtrMutation(
1775717788 }
1775817789 },
1775917790 .eu_payload_ptr => {
17760 const eu_ptr_val = ptr_val.castTag(.eu_payload_ptr).?.data;
17761 var parent = try beginComptimePtrMutation(sema, block, src, eu_ptr_val);
17791 const eu_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
17792 var parent = try beginComptimePtrMutation(sema, block, src, eu_ptr.container_ptr);
1776217793 const payload_ty = parent.ty.errorUnionPayload();
1776317794 switch (parent.val.tag()) {
1776417795 else => {
......@@ -17790,8 +17821,8 @@ fn beginComptimePtrMutation(
1779017821 }
1779117822 },
1779217823 .opt_payload_ptr => {
17793 const opt_ptr_val = ptr_val.castTag(.opt_payload_ptr).?.data;
17794 var parent = try beginComptimePtrMutation(sema, block, src, opt_ptr_val);
17824 const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
17825 var parent = try beginComptimePtrMutation(sema, block, src, opt_ptr.container_ptr);
1779517826 const payload_ty = try parent.ty.optionalChildAlloc(sema.arena);
1779617827 switch (parent.val.tag()) {
1779717828 .undef, .null_value => {
......@@ -17829,163 +17860,191 @@ fn beginComptimePtrMutation(
1782917860 }
1783017861}
1783117862
17832const ComptimePtrLoadKit = struct {
17833 /// The Value of the Decl that owns this memory.
17834 root_val: Value,
17835 /// The Type of the Decl that owns this memory.
17836 root_ty: Type,
17837 /// Parent Value.
17838 val: Value,
17839 /// The Type of the parent Value.
17840 ty: Type,
17863const TypedValueAndOffset = struct {
17864 tv: TypedValue,
1784117865 /// The starting byte offset of `val` from `root_val`.
1784217866 /// If the type does not have a well-defined memory layout, this is null.
17843 byte_offset: ?usize,
17844 /// Whether the `root_val` could be mutated by further
17867 byte_offset: usize,
17868};
17869
17870const ComptimePtrLoadKit = struct {
17871 /// The Value and Type corresponding to the pointee of the provided pointer.
17872 /// If a direct dereference is not possible, this is null.
17873 pointee: ?TypedValue,
17874 /// The largest parent Value containing `pointee` and having a well-defined memory layout.
17875 /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null).
17876 parent: ?TypedValueAndOffset,
17877 /// Whether the `pointee` could be mutated by further
1784517878 /// semantic analysis and a copy must be performed.
1784617879 is_mutable: bool,
17880 /// If the root decl could not be used as `parent`, this is the type that
17881 /// caused that by not having a well-defined layout
17882 ty_without_well_defined_layout: ?Type,
1784717883};
1784817884
1784917885const ComptimePtrLoadError = CompileError || error{
1785017886 RuntimeLoad,
1785117887};
1785217888
17889/// If `maybe_array_ty` is provided, it will be used to directly dereference an
17890/// .elem_ptr of type T to a value of [N]T, if necessary.
1785317891fn beginComptimePtrLoad(
1785417892 sema: *Sema,
1785517893 block: *Block,
1785617894 src: LazySrcLoc,
1785717895 ptr_val: Value,
17896 maybe_array_ty: ?Type,
1785817897) ComptimePtrLoadError!ComptimePtrLoadKit {
1785917898 const target = sema.mod.getTarget();
17860 switch (ptr_val.tag()) {
17861 .decl_ref => {
17862 const decl = ptr_val.castTag(.decl_ref).?.data;
17863 const decl_val = try decl.value();
17864 if (decl_val.tag() == .variable) return error.RuntimeLoad;
17865 return ComptimePtrLoadKit{
17866 .root_val = decl_val,
17867 .root_ty = decl.ty,
17868 .val = decl_val,
17869 .ty = decl.ty,
17870 .byte_offset = 0,
17871 .is_mutable = false,
17899 var deref: ComptimePtrLoadKit = switch (ptr_val.tag()) {
17900 .decl_ref,
17901 .decl_ref_mut,
17902 => blk: {
17903 const decl = switch (ptr_val.tag()) {
17904 .decl_ref => ptr_val.castTag(.decl_ref).?.data,
17905 .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl,
17906 else => unreachable,
1787217907 };
17873 },
17874 .decl_ref_mut => {
17875 const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl;
17876 const decl_val = try decl.value();
17877 if (decl_val.tag() == .variable) return error.RuntimeLoad;
17878 return ComptimePtrLoadKit{
17879 .root_val = decl_val,
17880 .root_ty = decl.ty,
17881 .val = decl_val,
17882 .ty = decl.ty,
17883 .byte_offset = 0,
17884 .is_mutable = true,
17908 const is_mutable = ptr_val.tag() == .decl_ref_mut;
17909 const decl_tv = try decl.typedValue();
17910 if (decl_tv.val.tag() == .variable) return error.RuntimeLoad;
17911
17912 const layout_defined = decl.ty.hasWellDefinedLayout();
17913 break :blk ComptimePtrLoadKit{
17914 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
17915 .pointee = decl_tv,
17916 .is_mutable = is_mutable,
17917 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
1788517918 };
1788617919 },
17887 .elem_ptr => {
17920
17921 .elem_ptr => blk: {
1788817922 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
17889 const parent = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr);
17890 switch (parent.ty.zigTypeTag()) {
17891 .Array, .Vector => {
17892 const check_len = parent.ty.arrayLenIncludingSentinel();
17893 if (elem_ptr.index >= check_len) {
17894 // TODO have the parent include the decl so we can say "declared here"
17895 return sema.fail(block, src, "comptime load of index {d} out of bounds of array length {d}", .{
17896 elem_ptr.index, check_len,
17897 });
17898 }
17899 const elem_ty = parent.ty.childType();
17900 const byte_offset: ?usize = bo: {
17901 if (try sema.typeRequiresComptime(block, src, elem_ty)) {
17902 break :bo null;
17903 } else {
17904 if (parent.byte_offset) |off| {
17905 try sema.resolveTypeLayout(block, src, elem_ty);
17906 const elem_size = elem_ty.abiSize(target);
17907 break :bo try sema.usizeCast(block, src, off + elem_size * elem_ptr.index);
17908 } else {
17909 break :bo null;
17910 }
17911 }
17912 };
17913 return ComptimePtrLoadKit{
17914 .root_val = parent.root_val,
17915 .root_ty = parent.root_ty,
17916 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),
17917 .ty = elem_ty,
17918 .byte_offset = byte_offset,
17919 .is_mutable = parent.is_mutable,
17920 };
17921 },
17922 else => {
17923 if (elem_ptr.index != 0) {
17924 // TODO have the parent include the decl so we can say "declared here"
17925 return sema.fail(block, src, "out of bounds comptime load of index {d}", .{
17926 elem_ptr.index,
17927 });
17923 const elem_ty = elem_ptr.elem_ty;
17924 var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null);
17925
17926 if (elem_ptr.index != 0) {
17927 if (elem_ty.hasWellDefinedLayout()) {
17928 if (deref.parent) |*parent| {
17929 // Update the byte offset (in-place)
17930 const elem_size = try sema.typeAbiSize(block, src, elem_ty);
17931 const offset = parent.byte_offset + elem_size * elem_ptr.index;
17932 parent.byte_offset = try sema.usizeCast(block, src, offset);
1792817933 }
17929 return ComptimePtrLoadKit{
17930 .root_val = parent.root_val,
17931 .root_ty = parent.root_ty,
17932 .val = parent.val,
17933 .ty = parent.ty,
17934 .byte_offset = parent.byte_offset,
17935 .is_mutable = parent.is_mutable,
17936 };
17937 },
17934 } else {
17935 deref.parent = null;
17936 deref.ty_without_well_defined_layout = elem_ty;
17937 }
17938 }
17939
17940 // If we're loading an elem_ptr that was derived from a different type
17941 // than the true type of the underlying decl, we cannot deref directly
17942 const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayLike()) x: {
17943 const deref_elem_ty = deref.pointee.?.ty.childType();
17944 break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or
17945 (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok;
17946 } else false;
17947 if (!ty_matches) {
17948 deref.pointee = null;
17949 break :blk deref;
1793817950 }
17951
17952 var array_tv = deref.pointee.?;
17953 const check_len = array_tv.ty.arrayLenIncludingSentinel();
17954 if (elem_ptr.index >= check_len) {
17955 // TODO have the deref include the decl so we can say "declared here"
17956 return sema.fail(block, src, "comptime load of index {d} out of bounds of array length {d}", .{
17957 elem_ptr.index, check_len,
17958 });
17959 }
17960
17961 if (maybe_array_ty) |load_ty| {
17962 // It's possible that we're loading a [N]T, in which case we'd like to slice
17963 // the pointee array directly from our parent array.
17964 if (load_ty.isArrayLike() and load_ty.childType().eql(elem_ty)) {
17965 const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel());
17966 deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{
17967 .ty = try Type.array(sema.arena, N, null, elem_ty),
17968 .val = try array_tv.val.sliceArray(sema.arena, elem_ptr.index, elem_ptr.index + N),
17969 } else null;
17970 break :blk deref;
17971 }
17972 }
17973
17974 deref.pointee = .{
17975 .ty = elem_ty,
17976 .val = try array_tv.val.elemValue(sema.arena, elem_ptr.index),
17977 };
17978 break :blk deref;
1793917979 },
17940 .field_ptr => {
17980
17981 .field_ptr => blk: {
1794117982 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
17942 const parent = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr);
1794317983 const field_index = @intCast(u32, field_ptr.field_index);
17944 const byte_offset: ?usize = bo: {
17945 if (try sema.typeRequiresComptime(block, src, parent.ty)) {
17946 break :bo null;
17947 } else {
17948 if (parent.byte_offset) |off| {
17949 try sema.resolveTypeLayout(block, src, parent.ty);
17950 const field_offset = parent.ty.structFieldOffset(field_index, target);
17951 break :bo try sema.usizeCast(block, src, off + field_offset);
17952 } else {
17953 break :bo null;
17954 }
17984 const field_ty = field_ptr.container_ty.structFieldType(field_index);
17985 var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);
17986
17987 if (field_ptr.container_ty.hasWellDefinedLayout()) {
17988 if (deref.parent) |*parent| {
17989 // Update the byte offset (in-place)
17990 try sema.resolveTypeLayout(block, src, field_ptr.container_ty);
17991 const field_offset = field_ptr.container_ty.structFieldOffset(field_index, target);
17992 parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset);
1795517993 }
17956 };
17957 return ComptimePtrLoadKit{
17958 .root_val = parent.root_val,
17959 .root_ty = parent.root_ty,
17960 .val = try parent.val.fieldValue(sema.arena, field_index),
17961 .ty = parent.ty.structFieldType(field_index),
17962 .byte_offset = byte_offset,
17963 .is_mutable = parent.is_mutable,
17964 };
17965 },
17966 .eu_payload_ptr => {
17967 const err_union_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
17968 const parent = try beginComptimePtrLoad(sema, block, src, err_union_ptr);
17969 return ComptimePtrLoadKit{
17970 .root_val = parent.root_val,
17971 .root_ty = parent.root_ty,
17972 .val = parent.val.castTag(.eu_payload).?.data,
17973 .ty = parent.ty.errorUnionPayload(),
17974 .byte_offset = null,
17975 .is_mutable = parent.is_mutable,
17976 };
17994 } else {
17995 deref.parent = null;
17996 deref.ty_without_well_defined_layout = field_ptr.container_ty;
17997 }
17998
17999 if (deref.pointee) |*tv| {
18000 const coerce_in_mem_ok =
18001 (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
18002 (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
18003 if (coerce_in_mem_ok) {
18004 deref.pointee = TypedValue{
18005 .ty = field_ty,
18006 .val = try tv.val.fieldValue(sema.arena, field_index),
18007 };
18008 break :blk deref;
18009 }
18010 }
18011 deref.pointee = null;
18012 break :blk deref;
1797718013 },
17978 .opt_payload_ptr => {
17979 const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
17980 const parent = try beginComptimePtrLoad(sema, block, src, opt_ptr);
17981 return ComptimePtrLoadKit{
17982 .root_val = parent.root_val,
17983 .root_ty = parent.root_ty,
17984 .val = parent.val.castTag(.opt_payload).?.data,
17985 .ty = try parent.ty.optionalChildAlloc(sema.arena),
17986 .byte_offset = null,
17987 .is_mutable = parent.is_mutable,
18014
18015 .opt_payload_ptr,
18016 .eu_payload_ptr,
18017 => blk: {
18018 const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data;
18019 const payload_ty = switch (ptr_val.tag()) {
18020 .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(),
18021 .opt_payload_ptr => try payload_ptr.container_ty.optionalChildAlloc(sema.arena),
18022 else => unreachable,
1798818023 };
18024 var deref = try beginComptimePtrLoad(sema, block, src, payload_ptr.container_ptr, payload_ptr.container_ty);
18025
18026 // eu_payload_ptr and opt_payload_ptr never have a well-defined layout
18027 if (deref.parent != null) {
18028 deref.parent = null;
18029 deref.ty_without_well_defined_layout = payload_ptr.container_ty;
18030 }
18031
18032 if (deref.pointee) |*tv| {
18033 const coerce_in_mem_ok =
18034 (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
18035 (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok;
18036 if (coerce_in_mem_ok) {
18037 const payload_val = switch (ptr_val.tag()) {
18038 .eu_payload_ptr => tv.val.castTag(.eu_payload).?.data,
18039 .opt_payload_ptr => tv.val.castTag(.opt_payload).?.data,
18040 else => unreachable,
18041 };
18042 tv.* = TypedValue{ .ty = payload_ty, .val = payload_val };
18043 break :blk deref;
18044 }
18045 }
18046 deref.pointee = null;
18047 break :blk deref;
1798918048 },
1799018049
1799118050 .zero,
......@@ -18000,7 +18059,14 @@ fn beginComptimePtrLoad(
1800018059 => return error.RuntimeLoad,
1800118060
1800218061 else => unreachable,
18062 };
18063
18064 if (deref.pointee) |tv| {
18065 if (deref.parent == null and tv.ty.hasWellDefinedLayout()) {
18066 deref.parent = .{ .tv = tv, .byte_offset = 0 };
18067 }
1800318068 }
18069 return deref;
1800418070}
1800518071
1800618072fn bitCast(
......@@ -21085,39 +21151,53 @@ pub fn analyzeAddrspace(
2108521151/// Asserts the value is a pointer and dereferences it.
2108621152/// Returns `null` if the pointer contents cannot be loaded at comptime.
2108721153fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value {
21088 const target = sema.mod.getTarget();
2108921154 const load_ty = ptr_ty.childType();
21090 const parent = sema.beginComptimePtrLoad(block, src, ptr_val) catch |err| switch (err) {
21155 const target = sema.mod.getTarget();
21156 const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) {
2109121157 error.RuntimeLoad => return null,
2109221158 else => |e| return e,
2109321159 };
21094 // We have a Value that lines up in virtual memory exactly with what we want to load.
21095 // If the Type is in-memory coercable to `load_ty`, it may be returned without modifications.
21096 const coerce_in_mem_ok =
21097 (try sema.coerceInMemoryAllowed(block, load_ty, parent.ty, false, target, src, src)) == .ok or
21098 (try sema.coerceInMemoryAllowed(block, parent.ty, load_ty, false, target, src, src)) == .ok;
21099 if (coerce_in_mem_ok) {
21100 if (parent.is_mutable) {
21101 // The decl whose value we are obtaining here may be overwritten with
21102 // a different value upon further semantic analysis, which would
21103 // invalidate this memory. So we must copy here.
21104 return try parent.val.copy(sema.arena);
21160
21161 if (deref.pointee) |tv| {
21162 const coerce_in_mem_ok =
21163 (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or
21164 (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok;
21165 if (coerce_in_mem_ok) {
21166 // We have a Value that lines up in virtual memory exactly with what we want to load,
21167 // and it is in-memory coercible to load_ty. It may be returned without modifications.
21168 if (deref.is_mutable) {
21169 // The decl whose value we are obtaining here may be overwritten with
21170 // a different value upon further semantic analysis, which would
21171 // invalidate this memory. So we must copy here.
21172 return try tv.val.copy(sema.arena);
21173 }
21174 return tv.val;
2110521175 }
21106 return parent.val;
2110721176 }
2110821177
21109 // The type is not in-memory coercable, so it must be bitcasted according
21110 // to the pointer type we are performing the load through.
21178 // The type is not in-memory coercible or the direct dereference failed, so it must
21179 // be bitcast according to the pointer type we are performing the load through.
21180 if (!load_ty.hasWellDefinedLayout())
21181 return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{load_ty});
21182
21183 const load_sz = try sema.typeAbiSize(block, src, load_ty);
2111121184
21112 // TODO emit a compile error if the types are not allowed to be bitcasted
21185 // Try the smaller bit-cast first, since that's more efficient than using the larger `parent`
21186 if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty))
21187 return try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0);
2111321188
21114 if (parent.ty.abiSize(target) >= load_ty.abiSize(target)) {
21115 // The Type it is stored as in the compiler has an ABI size greater or equal to
21116 // the ABI size of `load_ty`. We may perform the bitcast based on
21117 // `parent.val` alone (more efficient).
21118 return try sema.bitCastVal(block, src, parent.val, parent.ty, load_ty, 0);
21189 // If that fails, try to bit-cast from the largest parent value with a well-defined layout
21190 if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(block, src, parent.tv.ty))
21191 return try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset);
21192
21193 if (deref.ty_without_well_defined_layout) |bad_ty| {
21194 // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem
21195 // is that some type we encountered when de-referencing does not have a well-defined layout.
21196 return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{bad_ty});
2111921197 } else {
21120 return try sema.bitCastVal(block, src, parent.root_val, parent.root_ty, load_ty, parent.byte_offset.?);
21198 // If all encountered types had well-defined layouts, the parent is the root decl and it just
21199 // wasn't big enough for the load.
21200 return sema.fail(block, src, "dereference of {} exceeds bounds of containing decl of type {}", .{ ptr_ty, deref.parent.?.tv.ty });
2112121201 }
2112221202}
2112321203
......@@ -21395,6 +21475,12 @@ pub fn typeHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type)
2139521475 return true;
2139621476}
2139721477
21478fn typeAbiSize(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u64 {
21479 try sema.resolveTypeLayout(block, src, ty);
21480 const target = sema.mod.getTarget();
21481 return ty.abiSize(target);
21482}
21483
2139821484fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32 {
2139921485 try sema.resolveTypeLayout(block, src, ty);
2140021486 const target = sema.mod.getTarget();
src/codegen/llvm.zig+64-99
......@@ -1518,26 +1518,8 @@ pub const DeclGen = struct {
15181518 const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False);
15191519 return llvm_int.constIntToPtr(try dg.llvmType(tv.ty));
15201520 },
1521 .field_ptr, .opt_payload_ptr, .eu_payload_ptr => {
1522 const parent = try dg.lowerParentPtr(tv.val, tv.ty);
1523 return parent.llvm_ptr.constBitCast(try dg.llvmType(tv.ty));
1524 },
1525 .elem_ptr => {
1526 const elem_ptr = tv.val.castTag(.elem_ptr).?.data;
1527 const parent = try dg.lowerParentPtr(elem_ptr.array_ptr, tv.ty);
1528 const llvm_usize = try dg.llvmType(Type.usize);
1529 if (parent.llvm_ptr.typeOf().getElementType().getTypeKind() == .Array) {
1530 const indices: [2]*const llvm.Value = .{
1531 llvm_usize.constInt(0, .False),
1532 llvm_usize.constInt(elem_ptr.index, .False),
1533 };
1534 return parent.llvm_ptr.constInBoundsGEP(&indices, indices.len);
1535 } else {
1536 const indices: [1]*const llvm.Value = .{
1537 llvm_usize.constInt(elem_ptr.index, .False),
1538 };
1539 return parent.llvm_ptr.constInBoundsGEP(&indices, indices.len);
1540 }
1521 .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => {
1522 return dg.lowerParentPtr(tv.val, tv.ty.childType());
15411523 },
15421524 .null_value, .zero => {
15431525 const llvm_type = try dg.llvmType(tv.ty);
......@@ -2786,7 +2768,7 @@ pub const DeclGen = struct {
27862768 llvm_ptr: *const llvm.Value,
27872769 };
27882770
2789 fn lowerParentPtrDecl(dg: *DeclGen, ptr_val: Value, decl: *Module.Decl) Error!ParentPtr {
2771 fn lowerParentPtrDecl(dg: *DeclGen, ptr_val: Value, decl: *Module.Decl, ptr_child_ty: Type) Error!*const llvm.Value {
27902772 decl.markAlive();
27912773 var ptr_ty_payload: Type.Payload.ElemType = .{
27922774 .base = .{ .tag = .single_mut_pointer },
......@@ -2794,123 +2776,107 @@ pub const DeclGen = struct {
27942776 };
27952777 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
27962778 const llvm_ptr = try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl);
2797 return ParentPtr{
2798 .llvm_ptr = llvm_ptr,
2799 .ty = decl.ty,
2800 };
2779
2780 if (ptr_child_ty.eql(decl.ty)) {
2781 return llvm_ptr;
2782 } else {
2783 return llvm_ptr.constBitCast((try dg.llvmType(ptr_child_ty)).pointerType(0));
2784 }
28012785 }
28022786
2803 fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, base_ty: Type) Error!ParentPtr {
2804 switch (ptr_val.tag()) {
2787 fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, ptr_child_ty: Type) Error!*const llvm.Value {
2788 var bitcast_needed: bool = undefined;
2789 const llvm_ptr = switch (ptr_val.tag()) {
28052790 .decl_ref_mut => {
28062791 const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl;
2807 return dg.lowerParentPtrDecl(ptr_val, decl);
2792 return dg.lowerParentPtrDecl(ptr_val, decl, ptr_child_ty);
28082793 },
28092794 .decl_ref => {
28102795 const decl = ptr_val.castTag(.decl_ref).?.data;
2811 return dg.lowerParentPtrDecl(ptr_val, decl);
2796 return dg.lowerParentPtrDecl(ptr_val, decl, ptr_child_ty);
28122797 },
28132798 .variable => {
28142799 const decl = ptr_val.castTag(.variable).?.data.owner_decl;
2815 return dg.lowerParentPtrDecl(ptr_val, decl);
2800 return dg.lowerParentPtrDecl(ptr_val, decl, ptr_child_ty);
28162801 },
28172802 .int_i64 => {
28182803 const int = ptr_val.castTag(.int_i64).?.data;
28192804 const llvm_usize = try dg.llvmType(Type.usize);
28202805 const llvm_int = llvm_usize.constInt(@bitCast(u64, int), .False);
2821 return ParentPtr{
2822 .llvm_ptr = llvm_int.constIntToPtr(try dg.llvmType(base_ty)),
2823 .ty = base_ty,
2824 };
2806 return llvm_int.constIntToPtr((try dg.llvmType(ptr_child_ty)).pointerType(0));
28252807 },
28262808 .int_u64 => {
28272809 const int = ptr_val.castTag(.int_u64).?.data;
28282810 const llvm_usize = try dg.llvmType(Type.usize);
28292811 const llvm_int = llvm_usize.constInt(int, .False);
2830 return ParentPtr{
2831 .llvm_ptr = llvm_int.constIntToPtr(try dg.llvmType(base_ty)),
2832 .ty = base_ty,
2833 };
2812 return llvm_int.constIntToPtr((try dg.llvmType(ptr_child_ty)).pointerType(0));
28342813 },
2835 .field_ptr => {
2814 .field_ptr => blk: {
28362815 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
2837 const parent = try dg.lowerParentPtr(field_ptr.container_ptr, base_ty);
2816 const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.container_ptr, field_ptr.container_ty);
2817 const parent_ty = field_ptr.container_ty;
2818
28382819 const field_index = @intCast(u32, field_ptr.field_index);
28392820 const llvm_u32 = dg.context.intType(32);
28402821 const target = dg.module.getTarget();
2841 switch (parent.ty.zigTypeTag()) {
2822 switch (parent_ty.zigTypeTag()) {
28422823 .Union => {
2843 const fields = parent.ty.unionFields();
2844 const layout = parent.ty.unionGetLayout(target);
2845 const field_ty = fields.values()[field_index].ty;
2824 bitcast_needed = true;
2825
2826 const layout = parent_ty.unionGetLayout(target);
28462827 if (layout.payload_size == 0) {
28472828 // In this case a pointer to the union and a pointer to any
28482829 // (void) payload is the same.
2849 return ParentPtr{
2850 .llvm_ptr = parent.llvm_ptr,
2851 .ty = field_ty,
2852 };
2853 }
2854 if (layout.tag_size == 0) {
2855 const indices: [2]*const llvm.Value = .{
2856 llvm_u32.constInt(0, .False),
2857 llvm_u32.constInt(0, .False),
2858 };
2859 return ParentPtr{
2860 .llvm_ptr = parent.llvm_ptr.constInBoundsGEP(&indices, indices.len),
2861 .ty = field_ty,
2862 };
2830 break :blk parent_llvm_ptr;
28632831 }
2864 const llvm_pl_index = @boolToInt(layout.tag_align >= layout.payload_align);
2832 const llvm_pl_index = if (layout.tag_size == 0)
2833 0
2834 else
2835 @boolToInt(layout.tag_align >= layout.payload_align);
28652836 const indices: [2]*const llvm.Value = .{
28662837 llvm_u32.constInt(0, .False),
28672838 llvm_u32.constInt(llvm_pl_index, .False),
28682839 };
2869 return ParentPtr{
2870 .llvm_ptr = parent.llvm_ptr.constInBoundsGEP(&indices, indices.len),
2871 .ty = field_ty,
2872 };
2840 break :blk parent_llvm_ptr.constInBoundsGEP(&indices, indices.len);
28732841 },
28742842 .Struct => {
2843 const field_ty = parent_ty.structFieldType(field_index);
2844 bitcast_needed = !field_ty.eql(ptr_child_ty);
2845
28752846 var ty_buf: Type.Payload.Pointer = undefined;
2876 const llvm_field_index = llvmFieldIndex(parent.ty, field_index, target, &ty_buf).?;
2847 const llvm_field_index = llvmFieldIndex(parent_ty, field_index, target, &ty_buf).?;
28772848 const indices: [2]*const llvm.Value = .{
28782849 llvm_u32.constInt(0, .False),
28792850 llvm_u32.constInt(llvm_field_index, .False),
28802851 };
2881 return ParentPtr{
2882 .llvm_ptr = parent.llvm_ptr.constInBoundsGEP(&indices, indices.len),
2883 .ty = parent.ty.structFieldType(field_index),
2884 };
2852 break :blk parent_llvm_ptr.constInBoundsGEP(&indices, indices.len);
28852853 },
28862854 else => unreachable,
28872855 }
28882856 },
2889 .elem_ptr => {
2857 .elem_ptr => blk: {
28902858 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
2891 const parent = try dg.lowerParentPtr(elem_ptr.array_ptr, base_ty);
2859 const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr, elem_ptr.elem_ty);
2860 bitcast_needed = !elem_ptr.elem_ty.eql(ptr_child_ty);
2861
28922862 const llvm_usize = try dg.llvmType(Type.usize);
2893 const indices: [2]*const llvm.Value = .{
2894 llvm_usize.constInt(0, .False),
2863 const indices: [1]*const llvm.Value = .{
28952864 llvm_usize.constInt(elem_ptr.index, .False),
28962865 };
2897 return ParentPtr{
2898 .llvm_ptr = parent.llvm_ptr.constInBoundsGEP(&indices, indices.len),
2899 .ty = parent.ty.childType(),
2900 };
2866 break :blk parent_llvm_ptr.constInBoundsGEP(&indices, indices.len);
29012867 },
2902 .opt_payload_ptr => {
2868 .opt_payload_ptr => blk: {
29032869 const opt_payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
2904 const parent = try dg.lowerParentPtr(opt_payload_ptr, base_ty);
2870 const parent_llvm_ptr = try dg.lowerParentPtr(opt_payload_ptr.container_ptr, opt_payload_ptr.container_ty);
29052871 var buf: Type.Payload.ElemType = undefined;
2906 const payload_ty = parent.ty.optionalChild(&buf);
2907 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or parent.ty.isPtrLikeOptional()) {
2872
2873 const payload_ty = opt_payload_ptr.container_ty.optionalChild(&buf);
2874 bitcast_needed = !payload_ty.eql(ptr_child_ty);
2875
2876 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or payload_ty.isPtrLikeOptional()) {
29082877 // In this case, we represent pointer to optional the same as pointer
29092878 // to the payload.
2910 return ParentPtr{
2911 .llvm_ptr = parent.llvm_ptr,
2912 .ty = payload_ty,
2913 };
2879 break :blk parent_llvm_ptr;
29142880 }
29152881
29162882 const llvm_u32 = dg.context.intType(32);
......@@ -2918,22 +2884,19 @@ pub const DeclGen = struct {
29182884 llvm_u32.constInt(0, .False),
29192885 llvm_u32.constInt(0, .False),
29202886 };
2921 return ParentPtr{
2922 .llvm_ptr = parent.llvm_ptr.constInBoundsGEP(&indices, indices.len),
2923 .ty = payload_ty,
2924 };
2887 break :blk parent_llvm_ptr.constInBoundsGEP(&indices, indices.len);
29252888 },
2926 .eu_payload_ptr => {
2889 .eu_payload_ptr => blk: {
29272890 const eu_payload_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
2928 const parent = try dg.lowerParentPtr(eu_payload_ptr, base_ty);
2929 const payload_ty = parent.ty.errorUnionPayload();
2891 const parent_llvm_ptr = try dg.lowerParentPtr(eu_payload_ptr.container_ptr, eu_payload_ptr.container_ty);
2892
2893 const payload_ty = eu_payload_ptr.container_ty.errorUnionPayload();
2894 bitcast_needed = !payload_ty.eql(ptr_child_ty);
2895
29302896 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
29312897 // In this case, we represent pointer to error union the same as pointer
29322898 // to the payload.
2933 return ParentPtr{
2934 .llvm_ptr = parent.llvm_ptr,
2935 .ty = payload_ty,
2936 };
2899 break :blk parent_llvm_ptr;
29372900 }
29382901
29392902 const llvm_u32 = dg.context.intType(32);
......@@ -2941,12 +2904,14 @@ pub const DeclGen = struct {
29412904 llvm_u32.constInt(0, .False),
29422905 llvm_u32.constInt(1, .False),
29432906 };
2944 return ParentPtr{
2945 .llvm_ptr = parent.llvm_ptr.constInBoundsGEP(&indices, indices.len),
2946 .ty = payload_ty,
2947 };
2907 break :blk parent_llvm_ptr.constInBoundsGEP(&indices, indices.len);
29482908 },
29492909 else => unreachable,
2910 };
2911 if (bitcast_needed) {
2912 return llvm_ptr.constBitCast((try dg.llvmType(ptr_child_ty)).pointerType(0));
2913 } else {
2914 return llvm_ptr;
29502915 }
29512916 }
29522917
src/type.zig+137-7
......@@ -2173,6 +2173,128 @@ pub const Type = extern union {
21732173 };
21742174 }
21752175
2176 /// true if and only if the type has a well-defined memory layout
2177 /// readFrom/writeToMemory are supported only for types with a well-
2178 /// defined memory layout
2179 pub fn hasWellDefinedLayout(ty: Type) bool {
2180 return switch (ty.tag()) {
2181 .u1,
2182 .u8,
2183 .i8,
2184 .u16,
2185 .i16,
2186 .u32,
2187 .i32,
2188 .u64,
2189 .i64,
2190 .u128,
2191 .i128,
2192 .usize,
2193 .isize,
2194 .c_short,
2195 .c_ushort,
2196 .c_int,
2197 .c_uint,
2198 .c_long,
2199 .c_ulong,
2200 .c_longlong,
2201 .c_ulonglong,
2202 .c_longdouble,
2203 .f16,
2204 .f32,
2205 .f64,
2206 .f80,
2207 .f128,
2208 .bool,
2209 .void,
2210 .manyptr_u8,
2211 .manyptr_const_u8,
2212 .manyptr_const_u8_sentinel_0,
2213 .array_u8,
2214 .array_u8_sentinel_0,
2215 .int_signed,
2216 .int_unsigned,
2217 .pointer,
2218 .single_const_pointer,
2219 .single_mut_pointer,
2220 .many_const_pointer,
2221 .many_mut_pointer,
2222 .c_const_pointer,
2223 .c_mut_pointer,
2224 .single_const_pointer_to_comptime_int,
2225 .enum_numbered,
2226 .vector,
2227 .optional_single_mut_pointer,
2228 .optional_single_const_pointer,
2229 => true,
2230
2231 .anyopaque,
2232 .anyerror,
2233 .noreturn,
2234 .@"null",
2235 .@"anyframe",
2236 .@"undefined",
2237 .atomic_order,
2238 .atomic_rmw_op,
2239 .calling_convention,
2240 .address_space,
2241 .float_mode,
2242 .reduce_op,
2243 .call_options,
2244 .prefetch_options,
2245 .export_options,
2246 .extern_options,
2247 .error_set,
2248 .error_set_single,
2249 .error_set_inferred,
2250 .error_set_merged,
2251 .@"opaque",
2252 .generic_poison,
2253 .type,
2254 .comptime_int,
2255 .comptime_float,
2256 .enum_literal,
2257 .type_info,
2258 // These are function bodies, not function pointers.
2259 .fn_noreturn_no_args,
2260 .fn_void_no_args,
2261 .fn_naked_noreturn_no_args,
2262 .fn_ccc_void_no_args,
2263 .function,
2264 .const_slice_u8,
2265 .const_slice_u8_sentinel_0,
2266 .const_slice,
2267 .mut_slice,
2268 .enum_simple,
2269 .error_union,
2270 .anyerror_void_error_union,
2271 .anyframe_T,
2272 .tuple,
2273 .anon_struct,
2274 .empty_struct_literal,
2275 .empty_struct,
2276 => false,
2277
2278 .enum_full,
2279 .enum_nonexhaustive,
2280 => !ty.cast(Payload.EnumFull).?.data.tag_ty_inferred,
2281
2282 .var_args_param => unreachable,
2283 .inferred_alloc_mut => unreachable,
2284 .inferred_alloc_const => unreachable,
2285 .bound_fn => unreachable,
2286
2287 .array,
2288 .array_sentinel,
2289 => ty.childType().hasWellDefinedLayout(),
2290
2291 .optional => ty.isPtrLikeOptional(),
2292 .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto,
2293 .@"union" => ty.castTag(.@"union").?.data.layout != .Auto,
2294 .union_tagged => false,
2295 };
2296 }
2297
21762298 pub fn hasRuntimeBits(ty: Type) bool {
21772299 return hasRuntimeBitsAdvanced(ty, false);
21782300 }
......@@ -3156,13 +3278,12 @@ pub const Type = extern union {
31563278 => return true,
31573279
31583280 .optional => {
3159 var buf: Payload.ElemType = undefined;
3160 const child_type = self.optionalChild(&buf);
3281 const child_ty = self.castTag(.optional).?.data;
31613282 // optionals of zero sized types behave like bools, not pointers
3162 if (!child_type.hasRuntimeBits()) return false;
3163 if (child_type.zigTypeTag() != .Pointer) return false;
3283 if (!child_ty.hasRuntimeBits()) return false;
3284 if (child_ty.zigTypeTag() != .Pointer) return false;
31643285
3165 const info = child_type.ptrInfo().data;
3286 const info = child_ty.ptrInfo().data;
31663287 switch (info.size) {
31673288 .Slice, .C => return false,
31683289 .Many, .One => return !info.@"allowzero",
......@@ -3263,6 +3384,7 @@ pub const Type = extern union {
32633384 /// For ?[*]T, returns T.
32643385 /// For *T, returns T.
32653386 /// For [*]T, returns T.
3387 /// For [N]T, returns T.
32663388 /// For []T, returns T.
32673389 pub fn elemType2(ty: Type) Type {
32683390 return switch (ty.tag()) {
......@@ -4256,6 +4378,13 @@ pub const Type = extern union {
42564378 };
42574379 }
42584380
4381 pub fn isArrayLike(ty: Type) bool {
4382 return switch (ty.zigTypeTag()) {
4383 .Array, .Vector => true,
4384 else => false,
4385 };
4386 }
4387
42594388 pub fn isIndexable(ty: Type) bool {
42604389 return switch (ty.zigTypeTag()) {
42614390 .Array, .Vector => true,
......@@ -4642,7 +4771,7 @@ pub const Type = extern union {
46424771 return field_offset.offset;
46434772 }
46444773
4645 return std.mem.alignForwardGeneric(u64, it.offset, it.big_align);
4774 return std.mem.alignForwardGeneric(u64, it.offset, @maximum(it.big_align, 1));
46464775 },
46474776
46484777 .tuple, .anon_struct => {
......@@ -4665,7 +4794,7 @@ pub const Type = extern union {
46654794 if (i == index) return offset;
46664795 offset += field_ty.abiSize(target);
46674796 }
4668 offset = std.mem.alignForwardGeneric(u64, offset, big_align);
4797 offset = std.mem.alignForwardGeneric(u64, offset, @maximum(big_align, 1));
46694798 return offset;
46704799 },
46714800
......@@ -5345,6 +5474,7 @@ pub const Type = extern union {
53455474 pub const @"type" = initTag(.type);
53465475 pub const @"anyerror" = initTag(.anyerror);
53475476 pub const @"anyopaque" = initTag(.anyopaque);
5477 pub const @"null" = initTag(.@"null");
53485478
53495479 pub fn ptr(arena: Allocator, target: Target, data: Payload.Pointer.Data) !Type {
53505480 var d = data;
src/value.zig+82-39
......@@ -268,12 +268,14 @@ pub const Value = extern union {
268268
269269 .repeated,
270270 .eu_payload,
271 .eu_payload_ptr,
272271 .opt_payload,
273 .opt_payload_ptr,
274272 .empty_array_sentinel,
275273 => Payload.SubValue,
276274
275 .eu_payload_ptr,
276 .opt_payload_ptr,
277 => Payload.PayloadPtr,
278
277279 .bytes,
278280 .enum_literal,
279281 => Payload.Bytes,
......@@ -479,6 +481,20 @@ pub const Value = extern union {
479481 .variable => return self.copyPayloadShallow(arena, Payload.Variable),
480482 .decl_ref => return self.copyPayloadShallow(arena, Payload.Decl),
481483 .decl_ref_mut => return self.copyPayloadShallow(arena, Payload.DeclRefMut),
484 .eu_payload_ptr,
485 .opt_payload_ptr,
486 => {
487 const payload = self.cast(Payload.PayloadPtr).?;
488 const new_payload = try arena.create(Payload.PayloadPtr);
489 new_payload.* = .{
490 .base = payload.base,
491 .data = .{
492 .container_ptr = try payload.data.container_ptr.copy(arena),
493 .container_ty = try payload.data.container_ty.copy(arena),
494 },
495 };
496 return Value{ .ptr_otherwise = &new_payload.base };
497 },
482498 .elem_ptr => {
483499 const payload = self.castTag(.elem_ptr).?;
484500 const new_payload = try arena.create(Payload.ElemPtr);
......@@ -486,6 +502,7 @@ pub const Value = extern union {
486502 .base = payload.base,
487503 .data = .{
488504 .array_ptr = try payload.data.array_ptr.copy(arena),
505 .elem_ty = try payload.data.elem_ty.copy(arena),
489506 .index = payload.data.index,
490507 },
491508 };
......@@ -498,6 +515,7 @@ pub const Value = extern union {
498515 .base = payload.base,
499516 .data = .{
500517 .container_ptr = try payload.data.container_ptr.copy(arena),
518 .container_ty = try payload.data.container_ty.copy(arena),
501519 .field_index = payload.data.field_index,
502520 },
503521 };
......@@ -506,9 +524,7 @@ pub const Value = extern union {
506524 .bytes => return self.copyPayloadShallow(arena, Payload.Bytes),
507525 .repeated,
508526 .eu_payload,
509 .eu_payload_ptr,
510527 .opt_payload,
511 .opt_payload_ptr,
512528 .empty_array_sentinel,
513529 => {
514530 const payload = self.cast(Payload.SubValue).?;
......@@ -740,11 +756,11 @@ pub const Value = extern union {
740756 .inferred_alloc_comptime => return out_stream.writeAll("(inferred comptime allocation value)"),
741757 .eu_payload_ptr => {
742758 try out_stream.writeAll("(eu_payload_ptr)");
743 val = val.castTag(.eu_payload_ptr).?.data;
759 val = val.castTag(.eu_payload_ptr).?.data.container_ptr;
744760 },
745761 .opt_payload_ptr => {
746762 try out_stream.writeAll("(opt_payload_ptr)");
747 val = val.castTag(.opt_payload_ptr).?.data;
763 val = val.castTag(.opt_payload_ptr).?.data.container_ptr;
748764 },
749765 .bound_fn => {
750766 const bound_func = val.castTag(.bound_fn).?.data;
......@@ -2162,8 +2178,8 @@ pub const Value = extern union {
21622178 .decl_ref_mut => true,
21632179 .elem_ptr => isComptimeMutablePtr(val.castTag(.elem_ptr).?.data.array_ptr),
21642180 .field_ptr => isComptimeMutablePtr(val.castTag(.field_ptr).?.data.container_ptr),
2165 .eu_payload_ptr => isComptimeMutablePtr(val.castTag(.eu_payload_ptr).?.data),
2166 .opt_payload_ptr => isComptimeMutablePtr(val.castTag(.opt_payload_ptr).?.data),
2181 .eu_payload_ptr => isComptimeMutablePtr(val.castTag(.eu_payload_ptr).?.data.container_ptr),
2182 .opt_payload_ptr => isComptimeMutablePtr(val.castTag(.opt_payload_ptr).?.data.container_ptr),
21672183
21682184 else => false,
21692185 };
......@@ -2174,9 +2190,9 @@ pub const Value = extern union {
21742190 switch (val.tag()) {
21752191 .repeated => return val.castTag(.repeated).?.data.canMutateComptimeVarState(),
21762192 .eu_payload => return val.castTag(.eu_payload).?.data.canMutateComptimeVarState(),
2177 .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.canMutateComptimeVarState(),
2193 .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(),
21782194 .opt_payload => return val.castTag(.opt_payload).?.data.canMutateComptimeVarState(),
2179 .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.canMutateComptimeVarState(),
2195 .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(),
21802196 .aggregate => {
21812197 const fields = val.castTag(.aggregate).?.data;
21822198 for (fields) |field| {
......@@ -2239,12 +2255,12 @@ pub const Value = extern union {
22392255 .eu_payload_ptr => {
22402256 const err_union_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
22412257 std.hash.autoHash(hasher, Value.Tag.eu_payload_ptr);
2242 hashPtr(err_union_ptr, hasher);
2258 hashPtr(err_union_ptr.container_ptr, hasher);
22432259 },
22442260 .opt_payload_ptr => {
22452261 const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
22462262 std.hash.autoHash(hasher, Value.Tag.opt_payload_ptr);
2247 hashPtr(opt_ptr, hasher);
2263 hashPtr(opt_ptr.container_ptr, hasher);
22482264 },
22492265
22502266 .zero,
......@@ -2272,12 +2288,14 @@ pub const Value = extern union {
22722288
22732289 .repeated,
22742290 .eu_payload,
2275 .eu_payload_ptr,
22762291 .opt_payload,
2277 .opt_payload_ptr,
22782292 .empty_array_sentinel,
22792293 => return markReferencedDeclsAlive(val.cast(Payload.SubValue).?.data),
22802294
2295 .eu_payload_ptr,
2296 .opt_payload_ptr,
2297 => return markReferencedDeclsAlive(val.cast(Payload.PayloadPtr).?.data.container_ptr),
2298
22812299 .slice => {
22822300 const slice = val.cast(Payload.Slice).?.data;
22832301 markReferencedDeclsAlive(slice.ptr);
......@@ -2394,6 +2412,29 @@ pub const Value = extern union {
23942412 }
23952413 }
23962414
2415 // Asserts that the provided start/end are in-bounds.
2416 pub fn sliceArray(val: Value, arena: Allocator, start: usize, end: usize) error{OutOfMemory}!Value {
2417 return switch (val.tag()) {
2418 .empty_array_sentinel => if (start == 0 and end == 1) val else Value.initTag(.empty_array),
2419 .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]),
2420 .aggregate => Tag.aggregate.create(arena, val.castTag(.aggregate).?.data[start..end]),
2421 .slice => sliceArray(val.castTag(.slice).?.data.ptr, arena, start, end),
2422
2423 .decl_ref => sliceArray(val.castTag(.decl_ref).?.data.val, arena, start, end),
2424 .decl_ref_mut => sliceArray(val.castTag(.decl_ref_mut).?.data.decl.val, arena, start, end),
2425 .elem_ptr => blk: {
2426 const elem_ptr = val.castTag(.elem_ptr).?.data;
2427 break :blk sliceArray(elem_ptr.array_ptr, arena, start + elem_ptr.index, end + elem_ptr.index);
2428 },
2429
2430 .repeated,
2431 .the_only_possible_value,
2432 => val,
2433
2434 else => unreachable,
2435 };
2436 }
2437
23972438 pub fn fieldValue(val: Value, allocator: Allocator, index: usize) error{OutOfMemory}!Value {
23982439 _ = allocator;
23992440 switch (val.tag()) {
......@@ -2422,36 +2463,28 @@ pub const Value = extern union {
24222463 }
24232464
24242465 /// Returns a pointer to the element value at the index.
2425 pub fn elemPtr(val: Value, arena: Allocator, index: usize) Allocator.Error!Value {
2426 switch (val.tag()) {
2427 .elem_ptr => {
2428 const elem_ptr = val.castTag(.elem_ptr).?.data;
2466 pub fn elemPtr(val: Value, ty: Type, arena: Allocator, index: usize) Allocator.Error!Value {
2467 const elem_ty = ty.elemType2();
2468 const ptr_val = switch (val.tag()) {
2469 .slice => val.castTag(.slice).?.data.ptr,
2470 else => val,
2471 };
2472
2473 if (ptr_val.tag() == .elem_ptr) {
2474 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
2475 if (elem_ptr.elem_ty.eql(elem_ty)) {
24292476 return Tag.elem_ptr.create(arena, .{
24302477 .array_ptr = elem_ptr.array_ptr,
2478 .elem_ty = elem_ptr.elem_ty,
24312479 .index = elem_ptr.index + index,
24322480 });
2433 },
2434 .slice => {
2435 const ptr_val = val.castTag(.slice).?.data.ptr;
2436 switch (ptr_val.tag()) {
2437 .elem_ptr => {
2438 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
2439 return Tag.elem_ptr.create(arena, .{
2440 .array_ptr = elem_ptr.array_ptr,
2441 .index = elem_ptr.index + index,
2442 });
2443 },
2444 else => return Tag.elem_ptr.create(arena, .{
2445 .array_ptr = ptr_val,
2446 .index = index,
2447 }),
2448 }
2449 },
2450 else => return Tag.elem_ptr.create(arena, .{
2451 .array_ptr = val,
2452 .index = index,
2453 }),
2481 }
24542482 }
2483 return Tag.elem_ptr.create(arena, .{
2484 .array_ptr = ptr_val,
2485 .elem_ty = elem_ty,
2486 .index = index,
2487 });
24552488 }
24562489
24572490 pub fn isUndef(self: Value) bool {
......@@ -4144,12 +4177,21 @@ pub const Value = extern union {
41444177 };
41454178 };
41464179
4180 pub const PayloadPtr = struct {
4181 base: Payload,
4182 data: struct {
4183 container_ptr: Value,
4184 container_ty: Type,
4185 },
4186 };
4187
41474188 pub const ElemPtr = struct {
41484189 pub const base_tag = Tag.elem_ptr;
41494190
41504191 base: Payload = Payload{ .tag = base_tag },
41514192 data: struct {
41524193 array_ptr: Value,
4194 elem_ty: Type,
41534195 index: usize,
41544196 },
41554197 };
......@@ -4160,6 +4202,7 @@ pub const Value = extern union {
41604202 base: Payload = Payload{ .tag = base_tag },
41614203 data: struct {
41624204 container_ptr: Value,
4205 container_ty: Type,
41634206 field_index: usize,
41644207 },
41654208 };
test/behavior.zig+1
......@@ -62,6 +62,7 @@ test {
6262 _ = @import("behavior/bugs/11100.zig");
6363 _ = @import("behavior/bugs/10970.zig");
6464 _ = @import("behavior/bugs/11046.zig");
65 _ = @import("behavior/bugs/11139.zig");
6566 _ = @import("behavior/bugs/11165.zig");
6667 _ = @import("behavior/call.zig");
6768 _ = @import("behavior/cast.zig");
test/behavior/bugs/11139.zig created+25
......@@ -0,0 +1,25 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4
5test "store array of array of structs at comptime" {
6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9
10 try expect(storeArrayOfArrayOfStructs() == 15);
11 comptime try expect(storeArrayOfArrayOfStructs() == 15);
12}
13
14fn storeArrayOfArrayOfStructs() u8 {
15 const S = struct {
16 x: u8,
17 };
18
19 var cases = [_][1]S{
20 [_]S{
21 S{ .x = 15 },
22 },
23 };
24 return cases[0][0].x;
25}
test/behavior/cast.zig+4-2
......@@ -871,7 +871,7 @@ test "peer cast [N:x]T to [N]T" {
871871}
872872
873873test "peer cast *[N:x]T to *[N]T" {
874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
875875 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
876876 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
877877
......@@ -887,7 +887,9 @@ test "peer cast *[N:x]T to *[N]T" {
887887}
888888
889889test "peer cast [*:x]T to [*]T" {
890 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
890 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
891 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
892 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
891893
892894 const S = struct {
893895 fn doTheTest() !void {
test/behavior/ptrcast.zig+91-1
......@@ -21,8 +21,47 @@ fn testReinterpretBytesAsInteger() !void {
2121 try expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected);
2222}
2323
24test "reinterpret an array over multiple elements, with no well-defined layout" {
25 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
29
30 try testReinterpretWithOffsetAndNoWellDefinedLayout();
31 comptime try testReinterpretWithOffsetAndNoWellDefinedLayout();
32}
33
34fn testReinterpretWithOffsetAndNoWellDefinedLayout() !void {
35 const bytes: ?[5]?u8 = [5]?u8{ 0x12, 0x34, 0x56, 0x78, 0x9a };
36 const ptr = &bytes.?[1];
37 const copy: [4]?u8 = @ptrCast(*const [4]?u8, ptr).*;
38 _ = copy;
39 //try expect(@ptrCast(*align(1)?u8, bytes[1..5]).* == );
40}
41
42test "reinterpret bytes inside auto-layout struct as integer with nonzero offset" {
43 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
46
47 try testReinterpretStructWrappedBytesAsInteger();
48 comptime try testReinterpretStructWrappedBytesAsInteger();
49}
50
51fn testReinterpretStructWrappedBytesAsInteger() !void {
52 const S = struct { bytes: [5:0]u8 };
53 const obj = S{ .bytes = "\x12\x34\x56\x78\xab".* };
54 const expected = switch (native_endian) {
55 .Little => 0xab785634,
56 .Big => 0x345678ab,
57 };
58 try expect(@ptrCast(*align(1) const u32, obj.bytes[1..5]).* == expected);
59}
60
2461test "reinterpret bytes of an array into an extern struct" {
25 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
62 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
64 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2665
2766 try testReinterpretBytesAsExternStruct();
2867 comptime try testReinterpretBytesAsExternStruct();
......@@ -42,6 +81,57 @@ fn testReinterpretBytesAsExternStruct() !void {
4281 try expect(val == 5);
4382}
4483
84test "reinterpret bytes of an extern struct into another" {
85 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
86 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
88
89 try testReinterpretExternStructAsExternStruct();
90 comptime try testReinterpretExternStructAsExternStruct();
91}
92
93fn testReinterpretExternStructAsExternStruct() !void {
94 const S1 = extern struct {
95 a: u8,
96 b: u16,
97 c: u8,
98 };
99 comptime var bytes align(2) = S1{ .a = 0, .b = 0, .c = 5 };
100
101 const S2 = extern struct {
102 a: u32 align(2),
103 c: u8,
104 };
105 var ptr = @ptrCast(*const S2, &bytes);
106 var val = ptr.c;
107 try expect(val == 5);
108}
109
110test "lower reinterpreted comptime field ptr" {
111 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
112 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
116 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
117
118 // Test lowering a field ptr
119 comptime var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 };
120 const S = extern struct {
121 a: u32 align(2),
122 c: u8,
123 };
124 comptime var ptr = @ptrCast(*const S, &bytes);
125 var val = &ptr.c;
126 try expect(val.* == 5);
127
128 // Test lowering an elem ptr
129 comptime var src_value = S{ .a = 15, .c = 5 };
130 comptime var ptr2 = @ptrCast(*[@sizeOf(S)]u8, &src_value);
131 var val2 = &ptr2[4];
132 try expect(val2.* == 5);
133}
134
45135test "reinterpret struct field at comptime" {
46136 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
47137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO