diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index a72ae6a423..f27957d3f5 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/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, }; diff --git a/src/codegen.zig b/src/codegen.zig index f5340458a5..e7f927a2d6 100644 --- a/src/codegen.zig +++ b/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, diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 4a09c09cc9..b25e05e118 100644 --- a/src/codegen/c.zig +++ b/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 => { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 300a24280a..7038606611 100644 --- a/src/codegen/llvm.zig +++ b/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, } }, diff --git a/test/behavior.zig b/test/behavior.zig index 6a6844a840..468ecd034c 100644 --- a/test/behavior.zig +++ b/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"); diff --git a/test/behavior/bugs/13068.zig b/test/behavior/bugs/13068.zig new file mode 100644 index 0000000000..bfc05452a4 --- /dev/null +++ b/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; +} diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index 5aeb6a3414..25527ed742 100644 --- a/test/behavior/slice.zig +++ b/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); +}