authorgravatar for 51252236+xdBronch@users.noreply.github.comxdBronch <51252236+xdBronch@users.noreply.github.com> 2025-10-04 00:12:26-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-10-07 11:58:12+01:00
log2810e4b173507b6d94a7108462b5c9bdcc0b6e0b
tree66382e34648d33165947438acec82aa03f7633a0
parent6893e7feeed8b528d0a03d3491f4254bbcf5c7ce

detect references to `comptime var` in default values and sentinels


4 files changed, 123 insertions(+), 3 deletions(-)

src/Sema.zig+31-2
......@@ -8050,6 +8050,10 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
80508050 const tracy = trace(@src());
80518051 defer tracy.end();
80528052
8053 const pt = sema.pt;
8054 const zcu = pt.zcu;
8055 const ip = &zcu.intern_pool;
8056
80538057 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
80548058 const extra = sema.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data;
80558059 const len_src = block.src(.{ .node_offset_array_type_len = inst_data.src_node });
......@@ -8061,7 +8065,11 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
80618065 const uncasted_sentinel = try sema.resolveInst(extra.sentinel);
80628066 const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src);
80638067 const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel, .{ .simple = .array_sentinel });
8064 const array_ty = try sema.pt.arrayType(.{
8068 if (sentinel_val.canMutateComptimeVarState(zcu)) {
8069 const sentinel_name = try ip.getOrPutString(sema.gpa, pt.tid, "sentinel", .no_embedded_nulls);
8070 return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", sentinel_val);
8071 }
8072 const array_ty = try pt.arrayType(.{
80658073 .len = len,
80668074 .sentinel = sentinel_val.toIntern(),
80678075 .child = elem_type.toIntern(),
......@@ -19021,6 +19029,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1902119029
1902219030 const pt = sema.pt;
1902319031 const zcu = pt.zcu;
19032 const ip = &zcu.intern_pool;
19033
1902419034 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].ptr_type;
1902519035 const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index);
1902619036 const elem_ty_src = block.src(.{ .node_offset_ptr_elem = extra.data.src_node });
......@@ -19055,6 +19065,10 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1905519065 const coerced = try sema.coerce(block, elem_ty, try sema.resolveInst(ref), sentinel_src);
1905619066 const val = try sema.resolveConstDefinedValue(block, sentinel_src, coerced, .{ .simple = .pointer_sentinel });
1905719067 try checkSentinelType(sema, block, sentinel_src, elem_ty);
19068 if (val.canMutateComptimeVarState(zcu)) {
19069 const sentinel_name = try ip.getOrPutString(sema.gpa, pt.tid, "sentinel", .no_embedded_nulls);
19070 return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", val);
19071 }
1905819072 break :blk val.toIntern();
1905919073 } else .none;
1906019074
......@@ -20580,6 +20594,10 @@ fn zirReify(
2058020594 const ptr_ty = try pt.singleMutPtrType(elem_ty);
2058120595 const sent_val = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?;
2058220596 try sema.checkSentinelType(block, src, elem_ty);
20597 if (sent_val.canMutateComptimeVarState(zcu)) {
20598 const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls);
20599 return sema.failWithContainsReferenceToComptimeVar(block, src, sentinel_name, "sentinel", sent_val);
20600 }
2058320601 break :s sent_val.toIntern();
2058420602 }
2058520603 break :s .none;
......@@ -20645,7 +20663,12 @@ fn zirReify(
2064520663 const sentinel = if (sentinel_val.optionalValue(zcu)) |p| blk: {
2064620664 const ptr_ty = try pt.singleMutPtrType(child_ty);
2064720665 try sema.checkSentinelType(block, src, child_ty);
20648 break :blk (try sema.pointerDeref(block, src, p, ptr_ty)).?;
20666 const sentinel = (try sema.pointerDeref(block, src, p, ptr_ty)).?;
20667 if (sentinel.canMutateComptimeVarState(zcu)) {
20668 const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls);
20669 return sema.failWithContainsReferenceToComptimeVar(block, src, sentinel_name, "sentinel", sentinel);
20670 }
20671 break :blk sentinel;
2064920672 } else null;
2065020673
2065120674 const ty = try pt.arrayType(.{
......@@ -21387,6 +21410,9 @@ fn reifyTuple(
2138721410 src,
2138821411 .{ .simple = .tuple_field_default_value },
2138921412 );
21413 if (val.canMutateComptimeVarState(zcu)) {
21414 return sema.failWithContainsReferenceToComptimeVar(block, src, field_name, "field default value", val);
21415 }
2139021416 // Resolve the value so that lazy values do not create distinct types.
2139121417 break :d (try sema.resolveLazyValue(val)).toIntern();
2139221418 } else .none;
......@@ -21500,6 +21526,9 @@ fn reifyStruct(
2150021526 src,
2150121527 .{ .simple = .struct_field_default_value },
2150221528 );
21529 if (val.canMutateComptimeVarState(zcu)) {
21530 return sema.failWithContainsReferenceToComptimeVar(block, src, field_name, "field default value", val);
21531 }
2150321532 // Resolve the value so that lazy values do not create distinct types.
2150421533 break :d (try sema.resolveLazyValue(val)).toIntern();
2150521534 } else .none;
src/Zcu.zig+1-1
......@@ -2023,7 +2023,7 @@ pub const SrcLoc = struct {
20232023 },
20242024 .tuple_field_type, .tuple_field_init => |field_info| {
20252025 const tree = try src_loc.file_scope.getTree(zcu);
2026 const node = src_loc.base_node;
2026 const node = field_info.tuple_decl_node_offset.toAbsolute(src_loc.base_node);
20272027 var buf: [2]Ast.Node.Index = undefined;
20282028 const container_decl = tree.fullContainerDecl(&buf, node) orelse
20292029 return tree.nodeToSpan(node);
test/cases/default_value_references_comptime_var.zig created+50
......@@ -0,0 +1,50 @@
1export fn foo() void {
2 comptime var a: u8 = 0;
3 _ = struct { comptime *u8 = &a };
4}
5export fn bar() void {
6 comptime var a: u8 = 0;
7 _ = @Type(.{ .@"struct" = .{
8 .layout = .auto,
9 .fields = &.{.{
10 .name = "0",
11 .type = *u8,
12 .default_value_ptr = @ptrCast(&&a),
13 .is_comptime = true,
14 .alignment = @alignOf(*u8),
15 }},
16 .decls = &.{},
17 .is_tuple = true,
18 } });
19}
20
21export fn baz() void {
22 comptime var a: u8 = 0;
23 _ = struct { foo: *u8 = &a };
24}
25export fn qux() void {
26 comptime var a: u8 = 0;
27 _ = @Type(.{ .@"struct" = .{
28 .layout = .auto,
29 .fields = &.{.{
30 .name = "foo",
31 .type = *u8,
32 .default_value_ptr = @ptrCast(&&a),
33 .is_comptime = false,
34 .alignment = @alignOf(*u8),
35 }},
36 .decls = &.{},
37 .is_tuple = false,
38 } });
39}
40
41// error
42//
43// :3:33: error: field default value contains reference to comptime var
44// :2:14: note: '0' points to comptime var declared here
45// :7:9: error: field default value contains reference to comptime var
46// :6:14: note: '0' points to comptime var declared here
47// :23:9: error: captured value contains reference to comptime var
48// :22:14: note: 'a' points to comptime var declared here
49// :27:9: error: field default value contains reference to comptime var
50// :26:14: note: 'foo' points to comptime var declared here
test/cases/sentinel_references_comptime_var.zig created+41
......@@ -0,0 +1,41 @@
1export fn foo() void {
2 comptime var a: u8 = 0;
3 _ = [0:&a]*u8;
4}
5export fn bar() void {
6 comptime var a: u8 = 0;
7 _ = @Type(.{ .array = .{
8 .child = *u8,
9 .len = 0,
10 .sentinel_ptr = @ptrCast(&&a),
11 } });
12}
13
14export fn baz() void {
15 comptime var a: u8 = 0;
16 _ = [:&a]*u8;
17}
18export fn qux() void {
19 comptime var a: u8 = 0;
20 _ = @Type(.{ .pointer = .{
21 .size = .many,
22 .is_const = false,
23 .is_volatile = false,
24 .alignment = @alignOf(u8),
25 .address_space = .generic,
26 .child = *u8,
27 .is_allowzero = false,
28 .sentinel_ptr = @ptrCast(&&a),
29 } });
30}
31
32// error
33//
34// :3:12: error: sentinel contains reference to comptime var
35// :2:14: note: 'sentinel' points to comptime var declared here
36// :7:9: error: sentinel contains reference to comptime var
37// :6:14: note: 'sentinel_ptr' points to comptime var declared here
38// :16:11: error: sentinel contains reference to comptime var
39// :15:14: note: 'sentinel' points to comptime var declared here
40// :20:9: error: sentinel contains reference to comptime var
41// :19:14: note: 'sentinel_ptr' points to comptime var declared here