Commit fa59153896

kcbanner <kcbanner@gmail.com>
2025-03-09 20:44:26
Value: ensure that extern structs have their layout resolved in ptrField
1 parent 90084f4
Changed files (2)
src
test
behavior
src/Value.zig
@@ -3013,6 +3013,7 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
                 .auto => break :field .{ field_ty, try aggregate_ty.fieldAlignmentSema(field_idx, pt) },
                 .@"extern" => {
                     // Well-defined layout, so just offset the pointer appropriately.
+                    try aggregate_ty.resolveLayout(pt);
                     const byte_off = aggregate_ty.structFieldOffset(field_idx, zcu);
                     const field_align = a: {
                         const parent_align = if (parent_ptr_info.flags.alignment == .none) pa: {
test/behavior/globals.zig
@@ -171,3 +171,31 @@ test "global var can be indirectly self-referential" {
     try std.testing.expect(S.bar.other == &S.foo);
     try std.testing.expect(S.bar.other.other == &S.bar);
 }
+
+pub const Callbacks = extern struct {
+    key_callback: *const fn (key: i32) callconv(.c) i32,
+};
+
+var callbacks: Callbacks = undefined;
+var callbacks_loaded: bool = false;
+
+test "function pointer field call on global extern struct, conditional on global" {
+    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
+    if (callbacks_loaded) {
+        try std.testing.expectEqual(42, callbacks.key_callback(42));
+    }
+}
+
+test "function pointer field call on global extern struct" {
+    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
+    const S = struct {
+        fn keyCallback(key: i32) callconv(.c) i32 {
+            return key;
+        }
+    };
+
+    callbacks = Callbacks{ .key_callback = S.keyCallback };
+    try std.testing.expectEqual(42, callbacks.key_callback(42));
+}