Commit b0bcd4add2

Veikka Tuominen <git@vexu.eu>
2022-08-22 09:17:58
Sema: allow optional pointers in packed structs
Closes #12572
1 parent 74c7782
Changed files (3)
src
test
src/codegen/llvm.zig
@@ -3417,7 +3417,10 @@ pub const DeclGen = struct {
                         });
                         const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
                         const small_int_ty = dg.context.intType(ty_bit_size);
-                        const small_int_val = non_int_val.constBitCast(small_int_ty);
+                        const small_int_val = if (field.ty.isPtrAtRuntime())
+                            non_int_val.constPtrToInt(small_int_ty)
+                        else
+                            non_int_val.constBitCast(small_int_ty);
                         const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
                         // If the field is as large as the entire packed struct, this
                         // zext would go from, e.g. i16 to i16. This is legal with
@@ -5343,7 +5346,7 @@ pub const FuncGen = struct {
                             const same_size_int = self.context.intType(elem_bits);
                             const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
                             return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
-                        } else if (field_ty.zigTypeTag() == .Pointer) {
+                        } else if (field_ty.isPtrAtRuntime()) {
                             const elem_bits = @intCast(c_uint, field_ty.bitSize(target));
                             const same_size_int = self.context.intType(elem_bits);
                             const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
@@ -8408,7 +8411,7 @@ pub const FuncGen = struct {
                         const non_int_val = try self.resolveInst(elem);
                         const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
                         const small_int_ty = self.dg.context.intType(ty_bit_size);
-                        const small_int_val = if (field.ty.zigTypeTag() == .Pointer)
+                        const small_int_val = if (field.ty.isPtrAtRuntime())
                             self.builder.buildPtrToInt(non_int_val, small_int_ty, "")
                         else
                             self.builder.buildBitCast(non_int_val, small_int_ty, "");
src/Sema.zig
@@ -20565,8 +20565,8 @@ fn validatePackedType(ty: Type) bool {
         .AnyFrame,
         .Fn,
         .Array,
-        .Optional,
         => return false,
+        .Optional => return ty.isPtrLikeOptional(),
         .Void,
         .Bool,
         .Float,
test/behavior/packed-struct.zig
@@ -434,3 +434,15 @@ test "@ptrToInt on a packed struct field" {
     };
     try expect(@ptrToInt(&S.p0.z) - @ptrToInt(&S.p0.x) == 2);
 }
+
+test "optional pointer in packed struct" {
+    if (builtin.zig_backend == .stage2_x86_64) 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_wasm) return error.SkipZigTest;
+
+    const T = packed struct { ptr: ?*const u8 };
+    var n: u8 = 0;
+    const x = T{ .ptr = &n };
+    try expect(x.ptr.? == &n);
+}