From a092ca0400acb42bee6dbcab95356324e1d4722f Mon Sep 17 00:00:00 2001 From: xdBronch <51252236+xdBronch@users.noreply.github.com> Date: Sat, 4 Oct 2025 00:12:26 -0400 Subject: [PATCH] detect references to `comptime var` in default values and sentinels --- src/Sema.zig | 33 +++++++++++- src/Zcu.zig | 2 +- .../default_value_references_comptime_var.zig | 50 +++++++++++++++++++ .../sentinel_references_comptime_var.zig | 41 +++++++++++++++ 4 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 test/cases/default_value_references_comptime_var.zig create mode 100644 test/cases/sentinel_references_comptime_var.zig diff --git a/src/Sema.zig b/src/Sema.zig index e167ff03949e..640185b749de 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8050,6 +8050,10 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil const tracy = trace(@src()); defer tracy.end(); + const pt = sema.pt; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = sema.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data; 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 const uncasted_sentinel = try sema.resolveInst(extra.sentinel); const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src); const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel, .{ .simple = .array_sentinel }); - const array_ty = try sema.pt.arrayType(.{ + if (sentinel_val.canMutateComptimeVarState(zcu)) { + const sentinel_name = try ip.getOrPutString(sema.gpa, pt.tid, "sentinel", .no_embedded_nulls); + return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", sentinel_val); + } + const array_ty = try pt.arrayType(.{ .len = len, .sentinel = sentinel_val.toIntern(), .child = elem_type.toIntern(), @@ -19021,6 +19029,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const pt = sema.pt; const zcu = pt.zcu; + const ip = &zcu.intern_pool; + const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].ptr_type; const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index); 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 const coerced = try sema.coerce(block, elem_ty, try sema.resolveInst(ref), sentinel_src); const val = try sema.resolveConstDefinedValue(block, sentinel_src, coerced, .{ .simple = .pointer_sentinel }); try checkSentinelType(sema, block, sentinel_src, elem_ty); + if (val.canMutateComptimeVarState(zcu)) { + const sentinel_name = try ip.getOrPutString(sema.gpa, pt.tid, "sentinel", .no_embedded_nulls); + return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", val); + } break :blk val.toIntern(); } else .none; @@ -20580,6 +20594,10 @@ fn zirReify( const ptr_ty = try pt.singleMutPtrType(elem_ty); const sent_val = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?; try sema.checkSentinelType(block, src, elem_ty); + if (sent_val.canMutateComptimeVarState(zcu)) { + const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls); + return sema.failWithContainsReferenceToComptimeVar(block, src, sentinel_name, "sentinel", sent_val); + } break :s sent_val.toIntern(); } break :s .none; @@ -20645,7 +20663,12 @@ fn zirReify( const sentinel = if (sentinel_val.optionalValue(zcu)) |p| blk: { const ptr_ty = try pt.singleMutPtrType(child_ty); try sema.checkSentinelType(block, src, child_ty); - break :blk (try sema.pointerDeref(block, src, p, ptr_ty)).?; + const sentinel = (try sema.pointerDeref(block, src, p, ptr_ty)).?; + if (sentinel.canMutateComptimeVarState(zcu)) { + const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls); + return sema.failWithContainsReferenceToComptimeVar(block, src, sentinel_name, "sentinel", sentinel); + } + break :blk sentinel; } else null; const ty = try pt.arrayType(.{ @@ -21387,6 +21410,9 @@ fn reifyTuple( src, .{ .simple = .tuple_field_default_value }, ); + if (val.canMutateComptimeVarState(zcu)) { + return sema.failWithContainsReferenceToComptimeVar(block, src, field_name, "field default value", val); + } // Resolve the value so that lazy values do not create distinct types. break :d (try sema.resolveLazyValue(val)).toIntern(); } else .none; @@ -21500,6 +21526,9 @@ fn reifyStruct( src, .{ .simple = .struct_field_default_value }, ); + if (val.canMutateComptimeVarState(zcu)) { + return sema.failWithContainsReferenceToComptimeVar(block, src, field_name, "field default value", val); + } // Resolve the value so that lazy values do not create distinct types. break :d (try sema.resolveLazyValue(val)).toIntern(); } else .none; diff --git a/src/Zcu.zig b/src/Zcu.zig index ea08d7cf2cc8..8579eb39060a 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -2023,7 +2023,7 @@ pub const SrcLoc = struct { }, .tuple_field_type, .tuple_field_init => |field_info| { const tree = try src_loc.file_scope.getTree(zcu); - const node = src_loc.base_node; + const node = field_info.tuple_decl_node_offset.toAbsolute(src_loc.base_node); var buf: [2]Ast.Node.Index = undefined; const container_decl = tree.fullContainerDecl(&buf, node) orelse return tree.nodeToSpan(node); diff --git a/test/cases/default_value_references_comptime_var.zig b/test/cases/default_value_references_comptime_var.zig new file mode 100644 index 000000000000..e808f99738ba --- /dev/null +++ b/test/cases/default_value_references_comptime_var.zig @@ -0,0 +1,50 @@ +export fn foo() void { + comptime var a: u8 = 0; + _ = struct { comptime *u8 = &a }; +} +export fn bar() void { + comptime var a: u8 = 0; + _ = @Type(.{ .@"struct" = .{ + .layout = .auto, + .fields = &.{.{ + .name = "0", + .type = *u8, + .default_value_ptr = @ptrCast(&&a), + .is_comptime = true, + .alignment = @alignOf(*u8), + }}, + .decls = &.{}, + .is_tuple = true, + } }); +} + +export fn baz() void { + comptime var a: u8 = 0; + _ = struct { foo: *u8 = &a }; +} +export fn qux() void { + comptime var a: u8 = 0; + _ = @Type(.{ .@"struct" = .{ + .layout = .auto, + .fields = &.{.{ + .name = "foo", + .type = *u8, + .default_value_ptr = @ptrCast(&&a), + .is_comptime = false, + .alignment = @alignOf(*u8), + }}, + .decls = &.{}, + .is_tuple = false, + } }); +} + +// error +// +// :3:33: error: field default value contains reference to comptime var +// :2:14: note: '0' points to comptime var declared here +// :7:9: error: field default value contains reference to comptime var +// :6:14: note: '0' points to comptime var declared here +// :23:9: error: captured value contains reference to comptime var +// :22:14: note: 'a' points to comptime var declared here +// :27:9: error: field default value contains reference to comptime var +// :26:14: note: 'foo' points to comptime var declared here diff --git a/test/cases/sentinel_references_comptime_var.zig b/test/cases/sentinel_references_comptime_var.zig new file mode 100644 index 000000000000..74841385af15 --- /dev/null +++ b/test/cases/sentinel_references_comptime_var.zig @@ -0,0 +1,41 @@ +export fn foo() void { + comptime var a: u8 = 0; + _ = [0:&a]*u8; +} +export fn bar() void { + comptime var a: u8 = 0; + _ = @Type(.{ .array = .{ + .child = *u8, + .len = 0, + .sentinel_ptr = @ptrCast(&&a), + } }); +} + +export fn baz() void { + comptime var a: u8 = 0; + _ = [:&a]*u8; +} +export fn qux() void { + comptime var a: u8 = 0; + _ = @Type(.{ .pointer = .{ + .size = .many, + .is_const = false, + .is_volatile = false, + .alignment = @alignOf(u8), + .address_space = .generic, + .child = *u8, + .is_allowzero = false, + .sentinel_ptr = @ptrCast(&&a), + } }); +} + +// error +// +// :3:12: error: sentinel contains reference to comptime var +// :2:14: note: 'sentinel' points to comptime var declared here +// :7:9: error: sentinel contains reference to comptime var +// :6:14: note: 'sentinel_ptr' points to comptime var declared here +// :16:11: error: sentinel contains reference to comptime var +// :15:14: note: 'sentinel' points to comptime var declared here +// :20:9: error: sentinel contains reference to comptime var +// :19:14: note: 'sentinel_ptr' points to comptime var declared here