codegen: add support for lowering .field_ptr on a slice

Closes #13068
This commit is contained in:
jacobly0 2022-10-12 05:40:59 -04:00 committed by GitHub
parent b47e54ed3f
commit 562ac8be48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 83 additions and 18 deletions

View File

@ -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,
};

View File

@ -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,

View File

@ -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 => {

View File

@ -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,
}
},

View File

@ -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");

View File

@ -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;
}

View File

@ -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);
}