Commit 562ac8be48

jacobly0 <jacobly0@users.noreply.github.com>
2022-10-12 11:40:59
codegen: add support for lowering .field_ptr on a slice
Closes #13068
1 parent b47e54e
Changed files (7)
src/arch/wasm/CodeGen.zig
@@ -2289,6 +2289,14 @@ fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WV
                     const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align));
                     break :blk offset;
                 },
+                .Pointer => switch (parent_ty.ptrSize()) {
+                    .Slice => switch (field_ptr.field_index) {
+                        0 => 0,
+                        1 => self.ptrSize(),
+                        else => unreachable,
+                    },
+                    else => unreachable,
+                },
                 else => unreachable,
             };
 
src/codegen/c.zig
@@ -485,14 +485,24 @@ pub const DeclGen = struct {
                 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
                 const container_ty = field_ptr.container_ty;
                 const index = field_ptr.field_index;
-                const field_name = switch (container_ty.zigTypeTag()) {
-                    .Struct => container_ty.structFields().keys()[index],
-                    .Union => container_ty.unionFields().keys()[index],
-                    else => unreachable,
-                };
-                const field_ty = switch (container_ty.zigTypeTag()) {
-                    .Struct => container_ty.structFields().values()[index].ty,
-                    .Union => container_ty.unionFields().values()[index].ty,
+                const FieldInfo = struct { name: []const u8, ty: Type };
+                const field_info: FieldInfo = switch (container_ty.zigTypeTag()) {
+                    .Struct => .{
+                        .name = container_ty.structFields().keys()[index],
+                        .ty = container_ty.structFields().values()[index].ty,
+                    },
+                    .Union => .{
+                        .name = container_ty.unionFields().keys()[index],
+                        .ty = container_ty.unionFields().values()[index].ty,
+                    },
+                    .Pointer => switch (container_ty.ptrSize()) {
+                        .Slice => switch (index) {
+                            0 => FieldInfo{ .name = "ptr", .ty = container_ty.childType() },
+                            1 => FieldInfo{ .name = "len", .ty = Type.usize },
+                            else => unreachable,
+                        },
+                        else => unreachable,
+                    },
                     else => unreachable,
                 };
                 var container_ptr_ty_pl: Type.Payload.ElemType = .{
@@ -501,16 +511,16 @@ pub const DeclGen = struct {
                 };
                 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
 
-                if (field_ty.hasRuntimeBitsIgnoreComptime()) {
+                if (field_info.ty.hasRuntimeBitsIgnoreComptime()) {
                     try writer.writeAll("&(");
                     try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
                     if (field_ptr.container_ty.tag() == .union_tagged or field_ptr.container_ty.tag() == .union_safety_tagged) {
-                        try writer.print(")->payload.{ }", .{fmtIdent(field_name)});
+                        try writer.print(")->payload.{ }", .{fmtIdent(field_info.name)});
                     } else {
-                        try writer.print(")->{ }", .{fmtIdent(field_name)});
+                        try writer.print(")->{ }", .{fmtIdent(field_info.name)});
                     }
                 } else {
-                    try dg.renderParentPtr(writer, field_ptr.container_ptr, field_ty);
+                    try dg.renderParentPtr(writer, field_ptr.container_ptr, field_info.ty);
                 }
             },
             .elem_ptr => {
src/codegen/llvm.zig
@@ -3938,6 +3938,15 @@ pub const DeclGen = struct {
                         const parent_llvm_ty = try dg.lowerType(parent_ty);
                         break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
                     },
+                    .Pointer => {
+                        assert(parent_ty.isSlice());
+                        const indices: [2]*llvm.Value = .{
+                            llvm_u32.constInt(0, .False),
+                            llvm_u32.constInt(field_index, .False),
+                        };
+                        const parent_llvm_ty = try dg.lowerType(parent_ty);
+                        break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
+                    },
                     else => unreachable,
                 }
             },
src/codegen.zig
@@ -363,11 +363,21 @@ pub fn generateSymbol(
                         const mod = bin_file.options.module.?;
                         const decl = mod.declPtr(decl_index);
                         const addend = blk: {
-                            switch (decl.ty.tag()) {
-                                .@"struct" => {
+                            switch (decl.ty.zigTypeTag()) {
+                                .Struct => {
                                     const addend = decl.ty.structFieldOffset(field_ptr.field_index, target);
                                     break :blk @intCast(u32, addend);
                                 },
+                                .Pointer => {
+                                    assert(decl.ty.isSlice());
+                                    var buf: Type.SlicePtrFieldTypeBuffer = undefined;
+                                    const addend = switch (field_ptr.field_index) {
+                                        0 => 0,
+                                        1 => decl.ty.slicePtrFieldType(&buf).abiSize(target),
+                                        else => unreachable,
+                                    };
+                                    break :blk @intCast(u32, addend);
+                                },
                                 else => return Result{
                                     .fail = try ErrorMsg.create(
                                         bin_file.allocator,
test/behavior/bugs/13068.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+pub const allocator = std.heap.page_allocator;
+var list = std.ArrayList(u32).init(allocator);
+
+test {
+    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_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
+    list.items.len = 0;
+}
test/behavior/slice.zig
@@ -2,6 +2,7 @@ const builtin = @import("builtin");
 const std = @import("std");
 const expect = std.testing.expect;
 const expectEqualSlices = std.testing.expectEqualSlices;
+const expectEqualStrings = std.testing.expectEqualStrings;
 const expectEqual = std.testing.expectEqual;
 const mem = std.mem;
 
@@ -686,8 +687,6 @@ test "slice len modification at comptime" {
 }
 
 test "slice field ptr const" {
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
-
     const const_slice: []const u8 = "string";
 
     const const_ptr_const_slice = &const_slice;
@@ -700,8 +699,6 @@ test "slice field ptr const" {
 }
 
 test "slice field ptr var" {
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
-
     var var_slice: []const u8 = "string";
 
     var var_ptr_var_slice = &var_slice;
@@ -712,3 +709,18 @@ test "slice field ptr var" {
     try expectEqual(*[]const u8, @TypeOf(&const_ptr_var_slice.*));
     try expectEqual(*[*]const u8, @TypeOf(&const_ptr_var_slice.ptr));
 }
+
+test "global slice field access" {
+    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_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
+    const S = struct {
+        var slice: []const u8 = undefined;
+    };
+    S.slice = "string";
+    S.slice.ptr += 1;
+    S.slice.len -= 2;
+    try expectEqualStrings("trin", S.slice);
+}
test/behavior.zig
@@ -100,6 +100,7 @@ test {
     _ = @import("behavior/bugs/12928.zig");
     _ = @import("behavior/bugs/12945.zig");
     _ = @import("behavior/bugs/12984.zig");
+    _ = @import("behavior/bugs/13068.zig");
     _ = @import("behavior/bugs/13128.zig");
     _ = @import("behavior/byteswap.zig");
     _ = @import("behavior/byval_arg_var.zig");