mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-09 23:29:03 +00:00
Merge pull request #23263 from mlugg/comptime-field-ptr
Sema: fix pointers to comptime fields of comptime-known aggregate pointers
This commit is contained in:
commit
f4e9846bca
4 changed files with 79 additions and 33 deletions
27
src/Sema.zig
27
src/Sema.zig
|
|
@ -27997,12 +27997,17 @@ fn structFieldPtrByIndex(
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
const ip = &zcu.intern_pool;
|
const ip = &zcu.intern_pool;
|
||||||
|
|
||||||
|
const struct_type = zcu.typeToStruct(struct_ty).?;
|
||||||
|
const field_is_comptime = struct_type.fieldIsComptime(ip, field_index);
|
||||||
|
|
||||||
|
// Comptime fields are handled later
|
||||||
|
if (!field_is_comptime) {
|
||||||
if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
|
if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
|
||||||
const val = try struct_ptr_val.ptrField(field_index, pt);
|
const val = try struct_ptr_val.ptrField(field_index, pt);
|
||||||
return Air.internedToRef(val.toIntern());
|
return Air.internedToRef(val.toIntern());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const struct_type = zcu.typeToStruct(struct_ty).?;
|
|
||||||
const field_ty = struct_type.field_types.get(ip)[field_index];
|
const field_ty = struct_type.field_types.get(ip)[field_index];
|
||||||
const struct_ptr_ty = sema.typeOf(struct_ptr);
|
const struct_ptr_ty = sema.typeOf(struct_ptr);
|
||||||
const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
|
const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
|
||||||
|
|
@ -28022,6 +28027,7 @@ fn structFieldPtrByIndex(
|
||||||
try Type.fromInterned(struct_ptr_ty_info.child).abiAlignmentSema(pt);
|
try Type.fromInterned(struct_ptr_ty_info.child).abiAlignmentSema(pt);
|
||||||
|
|
||||||
if (struct_type.layout == .@"packed") {
|
if (struct_type.layout == .@"packed") {
|
||||||
|
assert(!field_is_comptime);
|
||||||
switch (struct_ty.packedStructFieldPtrInfo(struct_ptr_ty, field_index, pt)) {
|
switch (struct_ty.packedStructFieldPtrInfo(struct_ptr_ty, field_index, pt)) {
|
||||||
.bit_ptr => |packed_offset| {
|
.bit_ptr => |packed_offset| {
|
||||||
ptr_ty_data.flags.alignment = parent_align;
|
ptr_ty_data.flags.alignment = parent_align;
|
||||||
|
|
@ -28032,6 +28038,7 @@ fn structFieldPtrByIndex(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else if (struct_type.layout == .@"extern") {
|
} else if (struct_type.layout == .@"extern") {
|
||||||
|
assert(!field_is_comptime);
|
||||||
// For extern structs, field alignment might be bigger than type's
|
// For extern structs, field alignment might be bigger than type's
|
||||||
// natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the
|
// natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the
|
||||||
// second field is aligned as u32.
|
// second field is aligned as u32.
|
||||||
|
|
@ -28055,7 +28062,7 @@ fn structFieldPtrByIndex(
|
||||||
|
|
||||||
const ptr_field_ty = try pt.ptrTypeSema(ptr_ty_data);
|
const ptr_field_ty = try pt.ptrTypeSema(ptr_ty_data);
|
||||||
|
|
||||||
if (struct_type.fieldIsComptime(ip, field_index)) {
|
if (field_is_comptime) {
|
||||||
try struct_ty.resolveStructFieldInits(pt);
|
try struct_ty.resolveStructFieldInits(pt);
|
||||||
const val = try pt.intern(.{ .ptr = .{
|
const val = try pt.intern(.{ .ptr = .{
|
||||||
.ty = ptr_field_ty.toIntern(),
|
.ty = ptr_field_ty.toIntern(),
|
||||||
|
|
@ -28602,7 +28609,8 @@ fn tupleFieldPtr(
|
||||||
const pt = sema.pt;
|
const pt = sema.pt;
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
const tuple_ptr_ty = sema.typeOf(tuple_ptr);
|
const tuple_ptr_ty = sema.typeOf(tuple_ptr);
|
||||||
const tuple_ty = tuple_ptr_ty.childType(zcu);
|
const tuple_ptr_info = tuple_ptr_ty.ptrInfo(zcu);
|
||||||
|
const tuple_ty: Type = .fromInterned(tuple_ptr_info.child);
|
||||||
try tuple_ty.resolveFields(pt);
|
try tuple_ty.resolveFields(pt);
|
||||||
const field_count = tuple_ty.structFieldCount(zcu);
|
const field_count = tuple_ty.structFieldCount(zcu);
|
||||||
|
|
||||||
|
|
@ -28620,9 +28628,16 @@ fn tupleFieldPtr(
|
||||||
const ptr_field_ty = try pt.ptrTypeSema(.{
|
const ptr_field_ty = try pt.ptrTypeSema(.{
|
||||||
.child = field_ty.toIntern(),
|
.child = field_ty.toIntern(),
|
||||||
.flags = .{
|
.flags = .{
|
||||||
.is_const = !tuple_ptr_ty.ptrIsMutable(zcu),
|
.is_const = tuple_ptr_info.flags.is_const,
|
||||||
.is_volatile = tuple_ptr_ty.isVolatilePtr(zcu),
|
.is_volatile = tuple_ptr_info.flags.is_volatile,
|
||||||
.address_space = tuple_ptr_ty.ptrAddressSpace(zcu),
|
.address_space = tuple_ptr_info.flags.address_space,
|
||||||
|
.alignment = a: {
|
||||||
|
if (tuple_ptr_info.flags.alignment == .none) break :a .none;
|
||||||
|
// The tuple pointer isn't naturally aligned, so the field pointer might be underaligned.
|
||||||
|
const tuple_align = tuple_ptr_info.flags.alignment;
|
||||||
|
const field_align = try field_ty.abiAlignmentSema(pt);
|
||||||
|
break :a tuple_align.min(field_align);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -611,7 +611,7 @@ pub const Function = struct {
|
||||||
const a = try Assignment.start(f, writer, ctype);
|
const a = try Assignment.start(f, writer, ctype);
|
||||||
try f.writeCValue(writer, dst, .Other);
|
try f.writeCValue(writer, dst, .Other);
|
||||||
try a.assign(f, writer);
|
try a.assign(f, writer);
|
||||||
try f.writeCValue(writer, src, .Initializer);
|
try f.writeCValue(writer, src, .Other);
|
||||||
try a.end(f, writer);
|
try a.end(f, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2826,7 +2826,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
|
||||||
});
|
});
|
||||||
try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, .none, .complete);
|
try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, .none, .complete);
|
||||||
try w.writeAll(" = ");
|
try w.writeAll(" = ");
|
||||||
try o.dg.renderValue(w, Value.fromInterned(name_val), .Initializer);
|
try o.dg.renderValue(w, Value.fromInterned(name_val), .StaticInitializer);
|
||||||
try w.writeAll(";\n return (");
|
try w.writeAll(";\n return (");
|
||||||
try o.dg.renderType(w, name_slice_ty);
|
try o.dg.renderType(w, name_slice_ty);
|
||||||
try w.print("){{{}, {}}};\n", .{
|
try w.print("){{{}, {}}};\n", .{
|
||||||
|
|
@ -4045,7 +4045,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
|
||||||
const new_local = try f.allocLocal(inst, src_ty);
|
const new_local = try f.allocLocal(inst, src_ty);
|
||||||
try f.writeCValue(writer, new_local, .Other);
|
try f.writeCValue(writer, new_local, .Other);
|
||||||
try writer.writeAll(" = ");
|
try writer.writeAll(" = ");
|
||||||
try f.writeCValue(writer, src_val, .Initializer);
|
try f.writeCValue(writer, src_val, .Other);
|
||||||
try writer.writeAll(";\n");
|
try writer.writeAll(";\n");
|
||||||
|
|
||||||
break :blk new_local;
|
break :blk new_local;
|
||||||
|
|
@ -4516,7 +4516,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
const a = try Assignment.start(f, writer, .usize);
|
const a = try Assignment.start(f, writer, .usize);
|
||||||
try f.writeCValueMember(writer, local, .{ .identifier = "len" });
|
try f.writeCValueMember(writer, local, .{ .identifier = "len" });
|
||||||
try a.assign(f, writer);
|
try a.assign(f, writer);
|
||||||
try f.writeCValue(writer, len, .Initializer);
|
try f.writeCValue(writer, len, .Other);
|
||||||
try a.end(f, writer);
|
try a.end(f, writer);
|
||||||
}
|
}
|
||||||
return local;
|
return local;
|
||||||
|
|
@ -4934,7 +4934,7 @@ fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {
|
||||||
const cond_local = f.loop_switch_conds.get(br.block_inst).?;
|
const cond_local = f.loop_switch_conds.get(br.block_inst).?;
|
||||||
try f.writeCValue(writer, .{ .local = cond_local }, .Other);
|
try f.writeCValue(writer, .{ .local = cond_local }, .Other);
|
||||||
try writer.writeAll(" = ");
|
try writer.writeAll(" = ");
|
||||||
try f.writeCValue(writer, cond, .Initializer);
|
try f.writeCValue(writer, cond, .Other);
|
||||||
try writer.writeAll(";\n");
|
try writer.writeAll(";\n");
|
||||||
try writer.print("goto zig_switch_{d}_loop;", .{@intFromEnum(br.block_inst)});
|
try writer.print("goto zig_switch_{d}_loop;", .{@intFromEnum(br.block_inst)});
|
||||||
}
|
}
|
||||||
|
|
@ -4979,14 +4979,8 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
|
||||||
const operand_lval = if (operand == .constant) blk: {
|
const operand_lval = if (operand == .constant) blk: {
|
||||||
const operand_local = try f.allocLocal(null, operand_ty);
|
const operand_local = try f.allocLocal(null, operand_ty);
|
||||||
try f.writeCValue(writer, operand_local, .Other);
|
try f.writeCValue(writer, operand_local, .Other);
|
||||||
if (operand_ty.isAbiInt(zcu)) {
|
|
||||||
try writer.writeAll(" = ");
|
try writer.writeAll(" = ");
|
||||||
} else {
|
try f.writeCValue(writer, operand, .Other);
|
||||||
try writer.writeAll(" = (");
|
|
||||||
try f.renderType(writer, operand_ty);
|
|
||||||
try writer.writeByte(')');
|
|
||||||
}
|
|
||||||
try f.writeCValue(writer, operand, .Initializer);
|
|
||||||
try writer.writeAll(";\n");
|
try writer.writeAll(";\n");
|
||||||
break :blk operand_local;
|
break :blk operand_local;
|
||||||
} else operand;
|
} else operand;
|
||||||
|
|
@ -5698,7 +5692,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
const a = try Assignment.start(f, writer, opt_ctype);
|
const a = try Assignment.start(f, writer, opt_ctype);
|
||||||
try f.writeCValueDeref(writer, operand);
|
try f.writeCValueDeref(writer, operand);
|
||||||
try a.assign(f, writer);
|
try a.assign(f, writer);
|
||||||
try f.object.dg.renderValue(writer, Value.false, .Initializer);
|
try f.object.dg.renderValue(writer, Value.false, .Other);
|
||||||
try a.end(f, writer);
|
try a.end(f, writer);
|
||||||
return .none;
|
return .none;
|
||||||
},
|
},
|
||||||
|
|
@ -5718,7 +5712,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
const a = try Assignment.start(f, writer, opt_ctype);
|
const a = try Assignment.start(f, writer, opt_ctype);
|
||||||
try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" });
|
try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" });
|
||||||
try a.assign(f, writer);
|
try a.assign(f, writer);
|
||||||
try f.object.dg.renderValue(writer, Value.false, .Initializer);
|
try f.object.dg.renderValue(writer, Value.false, .Other);
|
||||||
try a.end(f, writer);
|
try a.end(f, writer);
|
||||||
}
|
}
|
||||||
if (f.liveness.isUnused(inst)) return .none;
|
if (f.liveness.isUnused(inst)) return .none;
|
||||||
|
|
@ -5844,7 +5838,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
try writer.writeByte(')');
|
try writer.writeByte(')');
|
||||||
|
|
||||||
switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, pt)) {
|
switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, pt)) {
|
||||||
.begin => try f.writeCValue(writer, field_ptr_val, .Initializer),
|
.begin => try f.writeCValue(writer, field_ptr_val, .Other),
|
||||||
.field => |field| {
|
.field => |field| {
|
||||||
const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);
|
const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);
|
||||||
|
|
||||||
|
|
@ -5898,7 +5892,7 @@ fn fieldPtr(
|
||||||
try writer.writeByte(')');
|
try writer.writeByte(')');
|
||||||
|
|
||||||
switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, pt)) {
|
switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, pt)) {
|
||||||
.begin => try f.writeCValue(writer, container_ptr_val, .Initializer),
|
.begin => try f.writeCValue(writer, container_ptr_val, .Other),
|
||||||
.field => |field| {
|
.field => |field| {
|
||||||
try writer.writeByte('&');
|
try writer.writeByte('&');
|
||||||
try f.writeCValueDerefMember(writer, container_ptr_val, field);
|
try f.writeCValueDerefMember(writer, container_ptr_val, field);
|
||||||
|
|
@ -6021,7 +6015,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
const operand_local = try f.allocLocal(inst, struct_ty);
|
const operand_local = try f.allocLocal(inst, struct_ty);
|
||||||
try f.writeCValue(writer, operand_local, .Other);
|
try f.writeCValue(writer, operand_local, .Other);
|
||||||
try writer.writeAll(" = ");
|
try writer.writeAll(" = ");
|
||||||
try f.writeCValue(writer, struct_byval, .Initializer);
|
try f.writeCValue(writer, struct_byval, .Other);
|
||||||
try writer.writeAll(";\n");
|
try writer.writeAll(";\n");
|
||||||
break :blk operand_local;
|
break :blk operand_local;
|
||||||
} else struct_byval;
|
} else struct_byval;
|
||||||
|
|
@ -6119,7 +6113,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
|
||||||
try writer.writeAll(" = (");
|
try writer.writeAll(" = (");
|
||||||
try f.renderType(writer, inst_ty);
|
try f.renderType(writer, inst_ty);
|
||||||
try writer.writeByte(')');
|
try writer.writeByte(')');
|
||||||
try f.writeCValue(writer, operand, .Initializer);
|
try f.writeCValue(writer, operand, .Other);
|
||||||
try writer.writeAll(";\n");
|
try writer.writeAll(";\n");
|
||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
@ -6164,7 +6158,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
const a = try Assignment.start(f, writer, operand_ctype);
|
const a = try Assignment.start(f, writer, operand_ctype);
|
||||||
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
|
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
|
||||||
try a.assign(f, writer);
|
try a.assign(f, writer);
|
||||||
try f.writeCValue(writer, operand, .Initializer);
|
try f.writeCValue(writer, operand, .Other);
|
||||||
try a.end(f, writer);
|
try a.end(f, writer);
|
||||||
}
|
}
|
||||||
return local;
|
return local;
|
||||||
|
|
@ -6365,7 +6359,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });
|
try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });
|
||||||
try a.assign(f, writer);
|
try a.assign(f, writer);
|
||||||
if (operand == .undef) {
|
if (operand == .undef) {
|
||||||
try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Initializer);
|
try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Other);
|
||||||
} else {
|
} else {
|
||||||
const ptr_ctype = try f.ctypeFromType(ptr_ty, .complete);
|
const ptr_ctype = try f.ctypeFromType(ptr_ty, .complete);
|
||||||
const ptr_child_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
|
const ptr_child_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
|
||||||
|
|
@ -6382,7 +6376,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
try writer.writeByte('&');
|
try writer.writeByte('&');
|
||||||
try f.writeCValueDeref(writer, operand);
|
try f.writeCValueDeref(writer, operand);
|
||||||
try writer.print("[{}]", .{try f.fmtIntLiteral(try pt.intValue(.usize, 0))});
|
try writer.print("[{}]", .{try f.fmtIntLiteral(try pt.intValue(.usize, 0))});
|
||||||
} else try f.writeCValue(writer, operand, .Initializer);
|
} else try f.writeCValue(writer, operand, .Other);
|
||||||
}
|
}
|
||||||
try a.end(f, writer);
|
try a.end(f, writer);
|
||||||
}
|
}
|
||||||
|
|
@ -6912,7 +6906,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
|
||||||
try writer.writeAll("for (");
|
try writer.writeAll("for (");
|
||||||
try f.writeCValue(writer, index, .Other);
|
try f.writeCValue(writer, index, .Other);
|
||||||
try writer.writeAll(" = ");
|
try writer.writeAll(" = ");
|
||||||
try f.object.dg.renderValue(writer, try pt.intValue(.usize, 0), .Initializer);
|
try f.object.dg.renderValue(writer, try pt.intValue(.usize, 0), .Other);
|
||||||
try writer.writeAll("; ");
|
try writer.writeAll("; ");
|
||||||
try f.writeCValue(writer, index, .Other);
|
try f.writeCValue(writer, index, .Other);
|
||||||
try writer.writeAll(" != ");
|
try writer.writeAll(" != ");
|
||||||
|
|
@ -7282,7 +7276,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
.float => try pt.floatValue(scalar_ty, std.math.nan(f128)),
|
.float => try pt.floatValue(scalar_ty, std.math.nan(f128)),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
}, .Initializer);
|
}, .Other);
|
||||||
try writer.writeAll(";\n");
|
try writer.writeAll(";\n");
|
||||||
|
|
||||||
const v = try Vectorize.start(f, inst, writer, operand_ty);
|
const v = try Vectorize.start(f, inst, writer, operand_ty);
|
||||||
|
|
|
||||||
|
|
@ -602,3 +602,21 @@ test "empty union in tuple" {
|
||||||
try std.testing.expectEqualStrings("0", info.@"struct".fields[0].name);
|
try std.testing.expectEqualStrings("0", info.@"struct".fields[0].name);
|
||||||
try std.testing.expect(@typeInfo(info.@"struct".fields[0].type) == .@"union");
|
try std.testing.expect(@typeInfo(info.@"struct".fields[0].type) == .@"union");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "field pointer of underaligned tuple" {
|
||||||
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||||
|
const S = struct {
|
||||||
|
fn doTheTest() !void {
|
||||||
|
const T = struct { u8, u32 };
|
||||||
|
var val: T align(2) = .{ 1, 2 };
|
||||||
|
|
||||||
|
comptime assert(@TypeOf(&val[0]) == *u8); // `u8` field pointer isn't overaligned
|
||||||
|
comptime assert(@TypeOf(&val[1]) == *align(2) u32); // `u32` field pointer is correctly underaligned
|
||||||
|
|
||||||
|
try expect(val[0] == 1);
|
||||||
|
try expect(val[1] == 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try S.doTheTest();
|
||||||
|
try comptime S.doTheTest();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
const init: u32 = 1;
|
||||||
|
fn rt() u32 {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tuple_val = .{init};
|
||||||
|
export fn tuple_field() void {
|
||||||
|
tuple_val[0] = rt();
|
||||||
|
}
|
||||||
|
|
||||||
|
var struct_val = .{ .x = init };
|
||||||
|
export fn struct_field() void {
|
||||||
|
struct_val.x = rt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
//
|
||||||
|
// :8:14: error: cannot store runtime value in compile time variable
|
||||||
|
// :13:15: error: cannot store runtime value in compile time variable
|
||||||
Loading…
Add table
Reference in a new issue