diff --git a/src/Sema.zig b/src/Sema.zig index 136abcc8981345f3066aee9bd1c471dc217452b8..65ccf0e089a25ab84fd7626345ea06d9e8bfed62 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -18777,6 +18777,18 @@ fn structInitAnon( break :rs runtime_index; }; + // A field can't be `comptime` if it references a `comptime var` but the aggregate can still be comptime-known. + // Replace these fields with `.none` only for generating the type. + const values_no_comptime = if (!any_values) values else blk: { + const new_values = try sema.arena.alloc(InternPool.Index, types.len); + for (values, new_values) |val, *new_val| { + if (val != .none and Value.fromInterned(val).canMutateComptimeVarState(zcu)) { + new_val.* = .none; + } else new_val.* = val; + } + break :blk new_values; + }; + // We treat anonymous struct types as reified types, because there are similarities: they have // no captures, and instead use a form of structural equivalence which we can easy represent by // hashing the field names/types/values. They also perform layout resolution immediately. These @@ -18785,7 +18797,7 @@ fn structInitAnon( const type_hash: u64 = hash: { var hasher = std.hash.Wyhash.init(0); hasher.update(std.mem.sliceAsBytes(types)); - hasher.update(std.mem.sliceAsBytes(values)); + hasher.update(std.mem.sliceAsBytes(values_no_comptime)); hasher.update(std.mem.sliceAsBytes(names)); break :hash hasher.final(); }; @@ -18809,9 +18821,9 @@ fn structInitAnon( @memcpy(wip.field_names.get(ip), names); @memcpy(wip.field_types.get(ip), types); if (any_values) { - @memcpy(wip.field_values.get(ip), values); + @memcpy(wip.field_values.get(ip), values_no_comptime); @memset(wip.field_is_comptime_bits.getAll(ip), 0); - for (values, 0..) |val, field_index| { + for (values_no_comptime, 0..) |val, field_index| { if (val == .none) continue; const bit_bag_index = field_index / 32; const mask = @as(u32, 1) << @intCast(field_index % 32); @@ -18839,6 +18851,15 @@ fn structInitAnon( return sema.addConstantMaybeRef(struct_val, is_ref); }; + for (values, 0..) |field_val, i| { + if (field_val == .none) continue; // runtime-known + const field_src = block.src(.{ .init_elem = .{ + .init_node_offset = src.offset.node_offset.x, + .elem_index = @intCast(i), + } }); + try sema.validateRuntimeValue(block, field_src, .fromIntern(field_val)); + } + if (is_ref) { const target = zcu.getTarget(); const alloc_ty = try pt.ptrType(.{ diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index ad0c11d7051088e50af5eaf144fa7c62ad2168d3..ee4c0df4ba0b74acdda2653c75ccce4878492572 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -2326,3 +2326,12 @@ test "pointer to runtime field of struct containing struct containing comptime-o ptr = &foo.number; try expect(ptr.* == 123); } + +test "struct field referencing comptime var isn't comptime" { + comptime var v: u8 = 0; + const s = .{ .v = &v }; + // field isn't comptime but struct is still comptime-known + comptime assert(!@typeInfo(@TypeOf(s)).@"struct".field_attrs[0].@"comptime"); + v = 1; + comptime assert(s.v.* == 1); +} diff --git a/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig b/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig index 603ce497326d547334cf5a99af0ff4fbb1e2c04d..897c298e6181ff75fd866370674e0ea769f7ae2c 100644 --- a/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig +++ b/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig @@ -71,6 +71,12 @@ export fn bax() void { @memmove(&rt, &x); } +export fn qoo(i: u8) void { + comptime var x: u32 = 123; + const y = .{ .p = &x, .i = i }; + _ = y; +} + // error // // :5:19: error: runtime value contains reference to comptime var @@ -103,3 +109,6 @@ export fn bax() void { // :71:19: error: runtime value contains reference to comptime var // :71:19: note: comptime var pointers are not available at runtime // :67:14: note: 'runtime_value' points to comptime var declared here +// :76:19: error: runtime value contains reference to comptime var +// :76:19: note: comptime var pointers are not available at runtime +// :75:14: note: 'runtime_value' points to comptime var declared here