Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sema: fix pointers to comptime fields of comptime-known aggregate pointers #23263

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -27923,12 +27923,17 @@ fn structFieldPtrByIndex(
const zcu = pt.zcu;
const ip = &zcu.intern_pool;

if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
const val = try struct_ptr_val.ptrField(field_index, pt);
return Air.internedToRef(val.toIntern());
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| {
const val = try struct_ptr_val.ptrField(field_index, pt);
return Air.internedToRef(val.toIntern());
}
}

const struct_type = zcu.typeToStruct(struct_ty).?;
const field_ty = struct_type.field_types.get(ip)[field_index];
const struct_ptr_ty = sema.typeOf(struct_ptr);
const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
Expand All @@ -27948,6 +27953,7 @@ fn structFieldPtrByIndex(
try Type.fromInterned(struct_ptr_ty_info.child).abiAlignmentSema(pt);

if (struct_type.layout == .@"packed") {
assert(!field_is_comptime);
switch (struct_ty.packedStructFieldPtrInfo(struct_ptr_ty, field_index, pt)) {
.bit_ptr => |packed_offset| {
ptr_ty_data.flags.alignment = parent_align;
Expand All @@ -27958,6 +27964,7 @@ fn structFieldPtrByIndex(
},
}
} else if (struct_type.layout == .@"extern") {
assert(!field_is_comptime);
// For extern structs, field alignment might be bigger than type's
// natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the
// second field is aligned as u32.
Expand All @@ -27981,7 +27988,7 @@ fn structFieldPtrByIndex(

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);
const val = try pt.intern(.{ .ptr = .{
.ty = ptr_field_ty.toIntern(),
Expand Down Expand Up @@ -28506,7 +28513,8 @@ fn tupleFieldPtr(
const pt = sema.pt;
const zcu = pt.zcu;
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);
const field_count = tuple_ty.structFieldCount(zcu);

Expand All @@ -28524,9 +28532,16 @@ fn tupleFieldPtr(
const ptr_field_ty = try pt.ptrTypeSema(.{
.child = field_ty.toIntern(),
.flags = .{
.is_const = !tuple_ptr_ty.ptrIsMutable(zcu),
.is_volatile = tuple_ptr_ty.isVolatilePtr(zcu),
.address_space = tuple_ptr_ty.ptrAddressSpace(zcu),
.is_const = tuple_ptr_info.flags.is_const,
.is_volatile = tuple_ptr_info.flags.is_volatile,
.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);
},
},
});

Expand Down
17 changes: 17 additions & 0 deletions test/behavior/tuple.zig
Original file line number Diff line number Diff line change
Expand Up @@ -603,3 +603,20 @@ test "empty union in tuple" {
try std.testing.expectEqualStrings("0", info.@"struct".fields[0].name);
try std.testing.expect(@typeInfo(info.@"struct".fields[0].type) == .@"union");
}

test "field pointer of underaligned tuple" {
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();
}
19 changes: 19 additions & 0 deletions test/cases/compile_errors/runtime_store_to_comptime_field.zig
Original file line number Diff line number Diff line change
@@ -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