Commit 2f92d1a026

Andrew Kelley <andrew@ziglang.org>
2022-03-15 05:11:49
stage2: fixups for topolarity-comptime-memory-reinterp branch
* don't store `has_well_defined_layout` in memory. * remove struct `hasWellDefinedLayout` logic. it's just `layout != .Auto`. This means we only need one implementation, in Type. * fix some of the cases being wrong in `hasWellDefinedLayout`, such as optional pointers. * move `tag_ty_inferred` field into a position that makes it more obvious how the struct layout will be done. Also we don't have a compiler that intelligently moves fields around so this layout is better. * Sema: don't `resolveTypeLayout` in `zirCoerceResultPtr` unless necessary. * Rename `ComptimePtrLoadKit` `target` field to `pointee` to avoid confusion with `target`.
1 parent 50a1ca2
Changed files (8)
src/codegen/llvm.zig
@@ -2829,7 +2829,10 @@ pub const DeclGen = struct {
                             // (void) payload is the same.
                             break :blk parent_llvm_ptr;
                         }
-                        const llvm_pl_index = if (layout.tag_size == 0) 0 else @boolToInt(layout.tag_align >= layout.payload_align);
+                        const llvm_pl_index = if (layout.tag_size == 0)
+                            0
+                        else
+                            @boolToInt(layout.tag_align >= layout.payload_align);
                         const indices: [2]*const llvm.Value = .{
                             llvm_u32.constInt(0, .False),
                             llvm_u32.constInt(llvm_pl_index, .False),
src/Module.zig
@@ -885,7 +885,6 @@ pub const Struct = struct {
     /// one possible value.
     known_non_opv: bool,
     requires_comptime: PropertyBoolean = .unknown,
-    has_well_defined_layout: PropertyBoolean = .unknown,
 
     pub const Fields = std.StringArrayHashMapUnmanaged(Field);
 
@@ -1080,8 +1079,6 @@ pub const EnumFull = struct {
     /// An integer type which is used for the numerical value of the enum.
     /// Whether zig chooses this type or the user specifies it, it is stored here.
     tag_ty: Type,
-    /// true if zig inferred this tag type, false if user specified it
-    tag_ty_inferred: bool,
     /// Set of field names in declaration order.
     fields: NameMap,
     /// Maps integer tag value to field index.
@@ -1092,6 +1089,8 @@ pub const EnumFull = struct {
     namespace: Namespace,
     /// Offset from `owner_decl`, points to the enum decl AST node.
     node_offset: i32,
+    /// true if zig inferred this tag type, false if user specified it
+    tag_ty_inferred: bool,
 
     pub const NameMap = std.StringArrayHashMapUnmanaged(void);
     pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false);
@@ -1136,7 +1135,6 @@ pub const Union = struct {
         fully_resolved,
     },
     requires_comptime: PropertyBoolean = .unknown,
-    has_well_defined_layout: PropertyBoolean = .unknown,
 
     pub const Field = struct {
         /// undefined until `status` is `have_field_types` or `have_layout`.
src/Sema.zig
@@ -1579,8 +1579,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
     const target = sema.mod.getTarget();
     const addr_space = target_util.defaultAddressSpace(target, .local);
 
-    try sema.resolveTypeLayout(block, src, pointee_ty);
-
     if (Air.refToIndex(ptr)) |ptr_inst| {
         if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
             const air_datas = sema.air_instructions.items(.data);
@@ -1617,6 +1615,9 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
                         try pointee_ty.copy(anon_decl.arena()),
                         Value.undef,
                     );
+                    if (iac.data.alignment != 0) {
+                        try sema.resolveTypeLayout(block, src, pointee_ty);
+                    }
                     const ptr_ty = try Type.ptr(sema.arena, target, .{
                         .pointee_type = pointee_ty,
                         .@"align" = iac.data.alignment,
@@ -1886,7 +1887,7 @@ fn zirEnumDecl(
 
     enum_obj.* = .{
         .owner_decl = new_decl,
-        .tag_ty = Type.initTag(.@"null"),
+        .tag_ty = Type.@"null",
         .tag_ty_inferred = true,
         .fields = .{},
         .values = .{},
@@ -17867,13 +17868,13 @@ const TypedValueAndOffset = struct {
 };
 
 const ComptimePtrLoadKit = struct {
-    /// The Value and Type corresponding to the target of the provided pointer.
+    /// The Value and Type corresponding to the pointee of the provided pointer.
     /// If a direct dereference is not possible, this is null.
-    target: ?TypedValue,
-    /// The largest parent Value containing `target` and having a well-defined memory layout.
-    /// This is used for bitcasting, if direct dereferencing failed (i.e. `target` is null).
+    pointee: ?TypedValue,
+    /// The largest parent Value containing `pointee` and having a well-defined memory layout.
+    /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null).
     parent: ?TypedValueAndOffset,
-    /// Whether the `target` could be mutated by further
+    /// Whether the `pointee` could be mutated by further
     /// semantic analysis and a copy must be performed.
     is_mutable: bool,
     /// If the root decl could not be used as `parent`, this is the type that
@@ -17885,7 +17886,7 @@ const ComptimePtrLoadError = CompileError || error{
     RuntimeLoad,
 };
 
-/// If `maybe_array_ty` is provided, it will be used to directly dereference an 
+/// If `maybe_array_ty` is provided, it will be used to directly dereference an
 /// .elem_ptr of type T to a value of [N]T, if necessary.
 fn beginComptimePtrLoad(
     sema: *Sema,
@@ -17908,10 +17909,10 @@ fn beginComptimePtrLoad(
             const decl_tv = try decl.typedValue();
             if (decl_tv.val.tag() == .variable) return error.RuntimeLoad;
 
-            const layout_defined = try sema.typeHasWellDefinedLayout(block, src, decl.ty);
+            const layout_defined = decl.ty.hasWellDefinedLayout();
             break :blk ComptimePtrLoadKit{
                 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
-                .target = decl_tv,
+                .pointee = decl_tv,
                 .is_mutable = is_mutable,
                 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
             };
@@ -17923,7 +17924,7 @@ fn beginComptimePtrLoad(
             var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null);
 
             if (elem_ptr.index != 0) {
-                if (try sema.typeHasWellDefinedLayout(block, src, elem_ty)) {
+                if (elem_ty.hasWellDefinedLayout()) {
                     if (deref.parent) |*parent| {
                         // Update the byte offset (in-place)
                         const elem_size = try sema.typeAbiSize(block, src, elem_ty);
@@ -17938,17 +17939,17 @@ fn beginComptimePtrLoad(
 
             // If we're loading an elem_ptr that was derived from a different type
             // than the true type of the underlying decl, we cannot deref directly
-            const ty_matches = if (deref.target != null and deref.target.?.ty.isArrayLike()) x: {
-                const deref_elem_ty = deref.target.?.ty.childType();
+            const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayLike()) x: {
+                const deref_elem_ty = deref.pointee.?.ty.childType();
                 break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or
                     (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok;
             } else false;
             if (!ty_matches) {
-                deref.target = null;
+                deref.pointee = null;
                 break :blk deref;
             }
 
-            var array_tv = deref.target.?;
+            var array_tv = deref.pointee.?;
             const check_len = array_tv.ty.arrayLenIncludingSentinel();
             if (elem_ptr.index >= check_len) {
                 // TODO have the deref include the decl so we can say "declared here"
@@ -17959,10 +17960,10 @@ fn beginComptimePtrLoad(
 
             if (maybe_array_ty) |load_ty| {
                 // It's possible that we're loading a [N]T, in which case we'd like to slice
-                // the target array directly from our parent array.
+                // the pointee array directly from our parent array.
                 if (load_ty.isArrayLike() and load_ty.childType().eql(elem_ty)) {
                     const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel());
-                    deref.target = if (elem_ptr.index + N <= check_len) TypedValue{
+                    deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{
                         .ty = try Type.array(sema.arena, N, null, elem_ty),
                         .val = try array_tv.val.sliceArray(sema.arena, elem_ptr.index, elem_ptr.index + N),
                     } else null;
@@ -17970,7 +17971,7 @@ fn beginComptimePtrLoad(
                 }
             }
 
-            deref.target = .{
+            deref.pointee = .{
                 .ty = elem_ty,
                 .val = try array_tv.val.elemValue(sema.arena, elem_ptr.index),
             };
@@ -17983,7 +17984,7 @@ fn beginComptimePtrLoad(
             const field_ty = field_ptr.container_ty.structFieldType(field_index);
             var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);
 
-            if (try sema.typeHasWellDefinedLayout(block, src, field_ptr.container_ty)) {
+            if (field_ptr.container_ty.hasWellDefinedLayout()) {
                 if (deref.parent) |*parent| {
                     // Update the byte offset (in-place)
                     try sema.resolveTypeLayout(block, src, field_ptr.container_ty);
@@ -17995,19 +17996,19 @@ fn beginComptimePtrLoad(
                 deref.ty_without_well_defined_layout = field_ptr.container_ty;
             }
 
-            if (deref.target) |*tv| {
+            if (deref.pointee) |*tv| {
                 const coerce_in_mem_ok =
                     (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
                     (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
                 if (coerce_in_mem_ok) {
-                    deref.target = TypedValue{
+                    deref.pointee = TypedValue{
                         .ty = field_ty,
                         .val = try tv.val.fieldValue(sema.arena, field_index),
                     };
                     break :blk deref;
                 }
             }
-            deref.target = null;
+            deref.pointee = null;
             break :blk deref;
         },
 
@@ -18028,7 +18029,7 @@ fn beginComptimePtrLoad(
                 deref.ty_without_well_defined_layout = payload_ptr.container_ty;
             }
 
-            if (deref.target) |*tv| {
+            if (deref.pointee) |*tv| {
                 const coerce_in_mem_ok =
                     (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
                     (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok;
@@ -18042,7 +18043,7 @@ fn beginComptimePtrLoad(
                     break :blk deref;
                 }
             }
-            deref.target = null;
+            deref.pointee = null;
             break :blk deref;
         },
 
@@ -18060,7 +18061,7 @@ fn beginComptimePtrLoad(
         else => unreachable,
     };
 
-    if (deref.target) |tv| {
+    if (deref.pointee) |tv| {
         if (deref.parent == null and tv.ty.hasWellDefinedLayout()) {
             deref.parent = .{ .tv = tv, .byte_offset = 0 };
         }
@@ -21157,7 +21158,7 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
         else => |e| return e,
     };
 
-    if (deref.target) |tv| {
+    if (deref.pointee) |tv| {
         const coerce_in_mem_ok =
             (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or
             (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok;
@@ -21176,13 +21177,13 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
 
     // The type is not in-memory coercible or the direct dereference failed, so it must
     // be bitcast according to the pointer type we are performing the load through.
-    if (!(try sema.typeHasWellDefinedLayout(block, src, load_ty)))
+    if (!load_ty.hasWellDefinedLayout())
         return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{load_ty});
 
     const load_sz = try sema.typeAbiSize(block, src, load_ty);
 
     // Try the smaller bit-cast first, since that's more efficient than using the larger `parent`
-    if (deref.target) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty))
+    if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty))
         return try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0);
 
     // If that fails, try to bit-cast from the largest parent value with a well-defined layout
@@ -21271,182 +21272,6 @@ fn typePtrOrOptionalPtrTy(
     }
 }
 
-fn typeHasWellDefinedLayout(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
-    return switch (ty.tag()) {
-        .u1,
-        .u8,
-        .i8,
-        .u16,
-        .i16,
-        .u32,
-        .i32,
-        .u64,
-        .i64,
-        .u128,
-        .i128,
-        .usize,
-        .isize,
-        .c_short,
-        .c_ushort,
-        .c_int,
-        .c_uint,
-        .c_long,
-        .c_ulong,
-        .c_longlong,
-        .c_ulonglong,
-        .c_longdouble,
-        .f16,
-        .f32,
-        .f64,
-        .f80,
-        .f128,
-        .bool,
-        .void,
-        .manyptr_u8,
-        .manyptr_const_u8,
-        .manyptr_const_u8_sentinel_0,
-        .anyerror_void_error_union,
-        .empty_struct_literal,
-        .empty_struct,
-        .array_u8,
-        .array_u8_sentinel_0,
-        .int_signed,
-        .int_unsigned,
-        .pointer,
-        .single_const_pointer,
-        .single_mut_pointer,
-        .many_const_pointer,
-        .many_mut_pointer,
-        .c_const_pointer,
-        .c_mut_pointer,
-        .single_const_pointer_to_comptime_int,
-        .enum_numbered,
-        => true,
-
-        .anyopaque,
-        .anyerror,
-        .noreturn,
-        .@"null",
-        .@"anyframe",
-        .@"undefined",
-        .atomic_order,
-        .atomic_rmw_op,
-        .calling_convention,
-        .address_space,
-        .float_mode,
-        .reduce_op,
-        .call_options,
-        .prefetch_options,
-        .export_options,
-        .extern_options,
-        .error_set,
-        .error_set_single,
-        .error_set_inferred,
-        .error_set_merged,
-        .@"opaque",
-        .generic_poison,
-        .type,
-        .comptime_int,
-        .comptime_float,
-        .enum_literal,
-        .type_info,
-        // These are function bodies, not function pointers.
-        .fn_noreturn_no_args,
-        .fn_void_no_args,
-        .fn_naked_noreturn_no_args,
-        .fn_ccc_void_no_args,
-        .function,
-        .const_slice_u8,
-        .const_slice_u8_sentinel_0,
-        .const_slice,
-        .mut_slice,
-        .enum_simple,
-        .error_union,
-        .anyframe_T,
-        .tuple,
-        .anon_struct,
-        => false,
-
-        .enum_full,
-        .enum_nonexhaustive,
-        => !ty.cast(Type.Payload.EnumFull).?.data.tag_ty_inferred,
-
-        .var_args_param => unreachable,
-        .inferred_alloc_mut => unreachable,
-        .inferred_alloc_const => unreachable,
-        .bound_fn => unreachable,
-
-        .array,
-        .array_sentinel,
-        .vector,
-        => sema.typeHasWellDefinedLayout(block, src, ty.childType()),
-
-        .optional,
-        .optional_single_mut_pointer,
-        .optional_single_const_pointer,
-        => blk: {
-            var buf: Type.Payload.ElemType = undefined;
-            break :blk sema.typeHasWellDefinedLayout(block, src, ty.optionalChild(&buf));
-        },
-
-        .@"struct" => {
-            const struct_obj = ty.castTag(.@"struct").?.data;
-            if (struct_obj.layout == .Auto) {
-                struct_obj.has_well_defined_layout = .no;
-                return false;
-            }
-            switch (struct_obj.has_well_defined_layout) {
-                .no => return false,
-                .yes, .wip => return true,
-                .unknown => {
-                    if (struct_obj.status == .field_types_wip)
-                        return true;
-
-                    try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
-
-                    struct_obj.has_well_defined_layout = .wip;
-                    for (struct_obj.fields.values()) |field| {
-                        if (!(try sema.typeHasWellDefinedLayout(block, src, field.ty))) {
-                            struct_obj.has_well_defined_layout = .no;
-                            return false;
-                        }
-                    }
-                    struct_obj.has_well_defined_layout = .yes;
-                    return true;
-                },
-            }
-        },
-
-        .@"union", .union_tagged => {
-            const union_obj = ty.cast(Type.Payload.Union).?.data;
-            if (union_obj.layout == .Auto) {
-                union_obj.has_well_defined_layout = .no;
-                return false;
-            }
-            switch (union_obj.has_well_defined_layout) {
-                .no => return false,
-                .yes, .wip => return true,
-                .unknown => {
-                    if (union_obj.status == .field_types_wip)
-                        return true;
-
-                    try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
-
-                    union_obj.has_well_defined_layout = .wip;
-                    for (union_obj.fields.values()) |field| {
-                        if (!(try sema.typeHasWellDefinedLayout(block, src, field.ty))) {
-                            union_obj.has_well_defined_layout = .no;
-                            return false;
-                        }
-                    }
-                    union_obj.has_well_defined_layout = .yes;
-                    return true;
-                },
-            }
-        },
-    };
-}
-
 /// `generic_poison` will return false.
 /// This function returns false negatives when structs and unions are having their
 /// field types resolved.
src/type.zig
@@ -2210,9 +2210,6 @@ pub const Type = extern union {
             .manyptr_u8,
             .manyptr_const_u8,
             .manyptr_const_u8_sentinel_0,
-            .anyerror_void_error_union,
-            .empty_struct_literal,
-            .empty_struct,
             .array_u8,
             .array_u8_sentinel_0,
             .int_signed,
@@ -2226,6 +2223,9 @@ pub const Type = extern union {
             .c_mut_pointer,
             .single_const_pointer_to_comptime_int,
             .enum_numbered,
+            .vector,
+            .optional_single_mut_pointer,
+            .optional_single_const_pointer,
             => true,
 
             .anyopaque,
@@ -2267,9 +2267,12 @@ pub const Type = extern union {
             .mut_slice,
             .enum_simple,
             .error_union,
+            .anyerror_void_error_union,
             .anyframe_T,
             .tuple,
             .anon_struct,
+            .empty_struct_literal,
+            .empty_struct,
             => false,
 
             .enum_full,
@@ -2283,36 +2286,12 @@ pub const Type = extern union {
 
             .array,
             .array_sentinel,
-            .vector,
             => ty.childType().hasWellDefinedLayout(),
 
-            .optional,
-            .optional_single_mut_pointer,
-            .optional_single_const_pointer,
-            => {
-                var buf: Type.Payload.ElemType = undefined;
-                return ty.optionalChild(&buf).hasWellDefinedLayout();
-            },
-
-            .@"struct" => {
-                const struct_obj = ty.castTag(.@"struct").?.data;
-                if (struct_obj.layout == .Auto) return false;
-                switch (struct_obj.has_well_defined_layout) {
-                    .wip, .unknown => unreachable, // This function asserts types already resolved.
-                    .no => return false,
-                    .yes => return true,
-                }
-            },
-
-            .@"union", .union_tagged => {
-                const union_obj = ty.cast(Type.Payload.Union).?.data;
-                if (union_obj.layout == .Auto) return false;
-                switch (union_obj.has_well_defined_layout) {
-                    .wip, .unknown => unreachable, // This function asserts types already resolved.
-                    .no => return false,
-                    .yes => return true,
-                }
-            },
+            .optional => ty.isPtrLikeOptional(),
+            .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto,
+            .@"union" => ty.castTag(.@"union").?.data.layout != .Auto,
+            .union_tagged => false,
         };
     }
 
@@ -3299,13 +3278,12 @@ pub const Type = extern union {
             => return true,
 
             .optional => {
-                var buf: Payload.ElemType = undefined;
-                const child_type = self.optionalChild(&buf);
+                const child_ty = self.castTag(.optional).?.data;
                 // optionals of zero sized types behave like bools, not pointers
-                if (!child_type.hasRuntimeBits()) return false;
-                if (child_type.zigTypeTag() != .Pointer) return false;
+                if (!child_ty.hasRuntimeBits()) return false;
+                if (child_ty.zigTypeTag() != .Pointer) return false;
 
-                const info = child_type.ptrInfo().data;
+                const info = child_ty.ptrInfo().data;
                 switch (info.size) {
                     .Slice, .C => return false,
                     .Many, .One => return !info.@"allowzero",
@@ -5496,6 +5474,7 @@ pub const Type = extern union {
     pub const @"type" = initTag(.type);
     pub const @"anyerror" = initTag(.anyerror);
     pub const @"anyopaque" = initTag(.anyopaque);
+    pub const @"null" = initTag(.@"null");
 
     pub fn ptr(arena: Allocator, target: Target, data: Payload.Pointer.Data) !Type {
         var d = data;
src/value.zig
@@ -2417,7 +2417,7 @@ pub const Value = extern union {
         return switch (val.tag()) {
             .empty_array_sentinel => if (start == 0 and end == 1) val else Value.initTag(.empty_array),
             .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]),
-            .array => Tag.array.create(arena, val.castTag(.array).?.data[start..end]),
+            .aggregate => Tag.aggregate.create(arena, val.castTag(.aggregate).?.data[start..end]),
             .slice => sliceArray(val.castTag(.slice).?.data.ptr, arena, start, end),
 
             .decl_ref => sliceArray(val.castTag(.decl_ref).?.data.val, arena, start, end),
@@ -2466,7 +2466,7 @@ pub const Value = extern union {
     pub fn elemPtr(val: Value, ty: Type, arena: Allocator, index: usize) Allocator.Error!Value {
         const elem_ty = ty.elemType2();
         const ptr_val = switch (val.tag()) {
-            .slice => val.slicePtr(),
+            .slice => val.castTag(.slice).?.data.ptr,
             else => val,
         };
 
test/behavior/bugs/11139.zig
@@ -3,9 +3,9 @@ const builtin = @import("builtin");
 const expect = std.testing.expect;
 
 test "store array of array of structs at comptime" {
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     try expect(storeArrayOfArrayOfStructs() == 15);
     comptime try expect(storeArrayOfArrayOfStructs() == 15);
test/behavior/cast.zig
@@ -871,7 +871,7 @@ test "peer cast [N:x]T to [N]T" {
 }
 
 test "peer cast *[N:x]T to *[N]T" {
-    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
@@ -887,9 +887,9 @@ test "peer cast *[N:x]T to *[N]T" {
 }
 
 test "peer cast [*:x]T to [*]T" {
-    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
 
     const S = struct {
         fn doTheTest() !void {
test/behavior/ptrcast.zig
@@ -23,9 +23,9 @@ fn testReinterpretBytesAsInteger() !void {
 
 test "reinterpret an array over multiple elements, with no well-defined layout" {
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
 
     try testReinterpretWithOffsetAndNoWellDefinedLayout();
     comptime try testReinterpretWithOffsetAndNoWellDefinedLayout();
@@ -40,9 +40,9 @@ fn testReinterpretWithOffsetAndNoWellDefinedLayout() !void {
 }
 
 test "reinterpret bytes inside auto-layout struct as integer with nonzero offset" {
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
 
     try testReinterpretStructWrappedBytesAsInteger();
     comptime try testReinterpretStructWrappedBytesAsInteger();
@@ -59,9 +59,9 @@ fn testReinterpretStructWrappedBytesAsInteger() !void {
 }
 
 test "reinterpret bytes of an array into an extern struct" {
-    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
 
     try testReinterpretBytesAsExternStruct();
     comptime try testReinterpretBytesAsExternStruct();
@@ -83,8 +83,8 @@ fn testReinterpretBytesAsExternStruct() !void {
 
 test "reinterpret bytes of an extern struct into another" {
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
 
     try testReinterpretExternStructAsExternStruct();
     comptime try testReinterpretExternStructAsExternStruct();
@@ -109,11 +109,11 @@ fn testReinterpretExternStructAsExternStruct() !void {
 
 test "lower reinterpreted comptime field ptr" {
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
 
     // Test lowering a field ptr
     comptime var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 };