Skip to content

Commit f4e9846

Browse files
authored
Merge pull request ziglang#23263 from mlugg/comptime-field-ptr
Sema: fix pointers to comptime fields of comptime-known aggregate pointers
2 parents f83fe27 + 81277b5 commit f4e9846

File tree

4 files changed

+79
-33
lines changed

4 files changed

+79
-33
lines changed

src/Sema.zig

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27997,12 +27997,17 @@ fn structFieldPtrByIndex(
2799727997
const zcu = pt.zcu;
2799827998
const ip = &zcu.intern_pool;
2799927999

28000-
if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
28001-
const val = try struct_ptr_val.ptrField(field_index, pt);
28002-
return Air.internedToRef(val.toIntern());
28000+
const struct_type = zcu.typeToStruct(struct_ty).?;
28001+
const field_is_comptime = struct_type.fieldIsComptime(ip, field_index);
28002+
28003+
// Comptime fields are handled later
28004+
if (!field_is_comptime) {
28005+
if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
28006+
const val = try struct_ptr_val.ptrField(field_index, pt);
28007+
return Air.internedToRef(val.toIntern());
28008+
}
2800328009
}
2800428010

28005-
const struct_type = zcu.typeToStruct(struct_ty).?;
2800628011
const field_ty = struct_type.field_types.get(ip)[field_index];
2800728012
const struct_ptr_ty = sema.typeOf(struct_ptr);
2800828013
const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
@@ -28022,6 +28027,7 @@ fn structFieldPtrByIndex(
2802228027
try Type.fromInterned(struct_ptr_ty_info.child).abiAlignmentSema(pt);
2802328028

2802428029
if (struct_type.layout == .@"packed") {
28030+
assert(!field_is_comptime);
2802528031
switch (struct_ty.packedStructFieldPtrInfo(struct_ptr_ty, field_index, pt)) {
2802628032
.bit_ptr => |packed_offset| {
2802728033
ptr_ty_data.flags.alignment = parent_align;
@@ -28032,6 +28038,7 @@ fn structFieldPtrByIndex(
2803228038
},
2803328039
}
2803428040
} else if (struct_type.layout == .@"extern") {
28041+
assert(!field_is_comptime);
2803528042
// For extern structs, field alignment might be bigger than type's
2803628043
// natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the
2803728044
// second field is aligned as u32.
@@ -28055,7 +28062,7 @@ fn structFieldPtrByIndex(
2805528062

2805628063
const ptr_field_ty = try pt.ptrTypeSema(ptr_ty_data);
2805728064

28058-
if (struct_type.fieldIsComptime(ip, field_index)) {
28065+
if (field_is_comptime) {
2805928066
try struct_ty.resolveStructFieldInits(pt);
2806028067
const val = try pt.intern(.{ .ptr = .{
2806128068
.ty = ptr_field_ty.toIntern(),
@@ -28602,7 +28609,8 @@ fn tupleFieldPtr(
2860228609
const pt = sema.pt;
2860328610
const zcu = pt.zcu;
2860428611
const tuple_ptr_ty = sema.typeOf(tuple_ptr);
28605-
const tuple_ty = tuple_ptr_ty.childType(zcu);
28612+
const tuple_ptr_info = tuple_ptr_ty.ptrInfo(zcu);
28613+
const tuple_ty: Type = .fromInterned(tuple_ptr_info.child);
2860628614
try tuple_ty.resolveFields(pt);
2860728615
const field_count = tuple_ty.structFieldCount(zcu);
2860828616

@@ -28620,9 +28628,16 @@ fn tupleFieldPtr(
2862028628
const ptr_field_ty = try pt.ptrTypeSema(.{
2862128629
.child = field_ty.toIntern(),
2862228630
.flags = .{
28623-
.is_const = !tuple_ptr_ty.ptrIsMutable(zcu),
28624-
.is_volatile = tuple_ptr_ty.isVolatilePtr(zcu),
28625-
.address_space = tuple_ptr_ty.ptrAddressSpace(zcu),
28631+
.is_const = tuple_ptr_info.flags.is_const,
28632+
.is_volatile = tuple_ptr_info.flags.is_volatile,
28633+
.address_space = tuple_ptr_info.flags.address_space,
28634+
.alignment = a: {
28635+
if (tuple_ptr_info.flags.alignment == .none) break :a .none;
28636+
// The tuple pointer isn't naturally aligned, so the field pointer might be underaligned.
28637+
const tuple_align = tuple_ptr_info.flags.alignment;
28638+
const field_align = try field_ty.abiAlignmentSema(pt);
28639+
break :a tuple_align.min(field_align);
28640+
},
2862628641
},
2862728642
});
2862828643

src/codegen/c.zig

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ pub const Function = struct {
611611
const a = try Assignment.start(f, writer, ctype);
612612
try f.writeCValue(writer, dst, .Other);
613613
try a.assign(f, writer);
614-
try f.writeCValue(writer, src, .Initializer);
614+
try f.writeCValue(writer, src, .Other);
615615
try a.end(f, writer);
616616
}
617617

@@ -2826,7 +2826,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
28262826
});
28272827
try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, .none, .complete);
28282828
try w.writeAll(" = ");
2829-
try o.dg.renderValue(w, Value.fromInterned(name_val), .Initializer);
2829+
try o.dg.renderValue(w, Value.fromInterned(name_val), .StaticInitializer);
28302830
try w.writeAll(";\n return (");
28312831
try o.dg.renderType(w, name_slice_ty);
28322832
try w.print("){{{}, {}}};\n", .{
@@ -4045,7 +4045,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
40454045
const new_local = try f.allocLocal(inst, src_ty);
40464046
try f.writeCValue(writer, new_local, .Other);
40474047
try writer.writeAll(" = ");
4048-
try f.writeCValue(writer, src_val, .Initializer);
4048+
try f.writeCValue(writer, src_val, .Other);
40494049
try writer.writeAll(";\n");
40504050
40514051
break :blk new_local;
@@ -4516,7 +4516,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
45164516
const a = try Assignment.start(f, writer, .usize);
45174517
try f.writeCValueMember(writer, local, .{ .identifier = "len" });
45184518
try a.assign(f, writer);
4519-
try f.writeCValue(writer, len, .Initializer);
4519+
try f.writeCValue(writer, len, .Other);
45204520
try a.end(f, writer);
45214521
}
45224522
return local;
@@ -4934,7 +4934,7 @@ fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {
49344934
const cond_local = f.loop_switch_conds.get(br.block_inst).?;
49354935
try f.writeCValue(writer, .{ .local = cond_local }, .Other);
49364936
try writer.writeAll(" = ");
4937-
try f.writeCValue(writer, cond, .Initializer);
4937+
try f.writeCValue(writer, cond, .Other);
49384938
try writer.writeAll(";\n");
49394939
try writer.print("goto zig_switch_{d}_loop;", .{@intFromEnum(br.block_inst)});
49404940
}
@@ -4979,14 +4979,8 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
49794979
const operand_lval = if (operand == .constant) blk: {
49804980
const operand_local = try f.allocLocal(null, operand_ty);
49814981
try f.writeCValue(writer, operand_local, .Other);
4982-
if (operand_ty.isAbiInt(zcu)) {
4983-
try writer.writeAll(" = ");
4984-
} else {
4985-
try writer.writeAll(" = (");
4986-
try f.renderType(writer, operand_ty);
4987-
try writer.writeByte(')');
4988-
}
4989-
try f.writeCValue(writer, operand, .Initializer);
4982+
try writer.writeAll(" = ");
4983+
try f.writeCValue(writer, operand, .Other);
49904984
try writer.writeAll(";\n");
49914985
break :blk operand_local;
49924986
} else operand;
@@ -5698,7 +5692,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
56985692
const a = try Assignment.start(f, writer, opt_ctype);
56995693
try f.writeCValueDeref(writer, operand);
57005694
try a.assign(f, writer);
5701-
try f.object.dg.renderValue(writer, Value.false, .Initializer);
5695+
try f.object.dg.renderValue(writer, Value.false, .Other);
57025696
try a.end(f, writer);
57035697
return .none;
57045698
},
@@ -5718,7 +5712,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
57185712
const a = try Assignment.start(f, writer, opt_ctype);
57195713
try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" });
57205714
try a.assign(f, writer);
5721-
try f.object.dg.renderValue(writer, Value.false, .Initializer);
5715+
try f.object.dg.renderValue(writer, Value.false, .Other);
57225716
try a.end(f, writer);
57235717
}
57245718
if (f.liveness.isUnused(inst)) return .none;
@@ -5844,7 +5838,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
58445838
try writer.writeByte(')');
58455839

58465840
switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, pt)) {
5847-
.begin => try f.writeCValue(writer, field_ptr_val, .Initializer),
5841+
.begin => try f.writeCValue(writer, field_ptr_val, .Other),
58485842
.field => |field| {
58495843
const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);
58505844

@@ -5898,7 +5892,7 @@ fn fieldPtr(
58985892
try writer.writeByte(')');
58995893

59005894
switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, pt)) {
5901-
.begin => try f.writeCValue(writer, container_ptr_val, .Initializer),
5895+
.begin => try f.writeCValue(writer, container_ptr_val, .Other),
59025896
.field => |field| {
59035897
try writer.writeByte('&');
59045898
try f.writeCValueDerefMember(writer, container_ptr_val, field);
@@ -6021,7 +6015,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
60216015
const operand_local = try f.allocLocal(inst, struct_ty);
60226016
try f.writeCValue(writer, operand_local, .Other);
60236017
try writer.writeAll(" = ");
6024-
try f.writeCValue(writer, struct_byval, .Initializer);
6018+
try f.writeCValue(writer, struct_byval, .Other);
60256019
try writer.writeAll(";\n");
60266020
break :blk operand_local;
60276021
} else struct_byval;
@@ -6119,7 +6113,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
61196113
try writer.writeAll(" = (");
61206114
try f.renderType(writer, inst_ty);
61216115
try writer.writeByte(')');
6122-
try f.writeCValue(writer, operand, .Initializer);
6116+
try f.writeCValue(writer, operand, .Other);
61236117
try writer.writeAll(";\n");
61246118
return local;
61256119
}
@@ -6164,7 +6158,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
61646158
const a = try Assignment.start(f, writer, operand_ctype);
61656159
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
61666160
try a.assign(f, writer);
6167-
try f.writeCValue(writer, operand, .Initializer);
6161+
try f.writeCValue(writer, operand, .Other);
61686162
try a.end(f, writer);
61696163
}
61706164
return local;
@@ -6365,7 +6359,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
63656359
try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });
63666360
try a.assign(f, writer);
63676361
if (operand == .undef) {
6368-
try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Initializer);
6362+
try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Other);
63696363
} else {
63706364
const ptr_ctype = try f.ctypeFromType(ptr_ty, .complete);
63716365
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 {
63826376
try writer.writeByte('&');
63836377
try f.writeCValueDeref(writer, operand);
63846378
try writer.print("[{}]", .{try f.fmtIntLiteral(try pt.intValue(.usize, 0))});
6385-
} else try f.writeCValue(writer, operand, .Initializer);
6379+
} else try f.writeCValue(writer, operand, .Other);
63866380
}
63876381
try a.end(f, writer);
63886382
}
@@ -6912,7 +6906,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
69126906
try writer.writeAll("for (");
69136907
try f.writeCValue(writer, index, .Other);
69146908
try writer.writeAll(" = ");
6915-
try f.object.dg.renderValue(writer, try pt.intValue(.usize, 0), .Initializer);
6909+
try f.object.dg.renderValue(writer, try pt.intValue(.usize, 0), .Other);
69166910
try writer.writeAll("; ");
69176911
try f.writeCValue(writer, index, .Other);
69186912
try writer.writeAll(" != ");
@@ -7282,7 +7276,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
72827276
.float => try pt.floatValue(scalar_ty, std.math.nan(f128)),
72837277
else => unreachable,
72847278
},
7285-
}, .Initializer);
7279+
}, .Other);
72867280
try writer.writeAll(";\n");
72877281

72887282
const v = try Vectorize.start(f, inst, writer, operand_ty);

test/behavior/tuple.zig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,3 +602,21 @@ test "empty union in tuple" {
602602
try std.testing.expectEqualStrings("0", info.@"struct".fields[0].name);
603603
try std.testing.expect(@typeInfo(info.@"struct".fields[0].type) == .@"union");
604604
}
605+
606+
test "field pointer of underaligned tuple" {
607+
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
608+
const S = struct {
609+
fn doTheTest() !void {
610+
const T = struct { u8, u32 };
611+
var val: T align(2) = .{ 1, 2 };
612+
613+
comptime assert(@TypeOf(&val[0]) == *u8); // `u8` field pointer isn't overaligned
614+
comptime assert(@TypeOf(&val[1]) == *align(2) u32); // `u32` field pointer is correctly underaligned
615+
616+
try expect(val[0] == 1);
617+
try expect(val[1] == 2);
618+
}
619+
};
620+
try S.doTheTest();
621+
try comptime S.doTheTest();
622+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const init: u32 = 1;
2+
fn rt() u32 {
3+
return 3;
4+
}
5+
6+
var tuple_val = .{init};
7+
export fn tuple_field() void {
8+
tuple_val[0] = rt();
9+
}
10+
11+
var struct_val = .{ .x = init };
12+
export fn struct_field() void {
13+
struct_val.x = rt();
14+
}
15+
16+
// error
17+
//
18+
// :8:14: error: cannot store runtime value in compile time variable
19+
// :13:15: error: cannot store runtime value in compile time variable

0 commit comments

Comments
 (0)