Skip to content

Commit 0f68d26

Browse files
committed
Value: expand canMutateComptimeVarState
Closes #17761
1 parent 107071a commit 0f68d26

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

src/value.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,8 @@ pub const Value = struct {
15501550
},
15511551
.ptr => |ptr| switch (ptr.addr) {
15521552
.eu_payload, .opt_payload => |base| Value.fromInterned(base).canMutateComptimeVarState(mod),
1553+
.anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).canMutateComptimeVarState(mod),
1554+
.elem, .field => |base_index| Value.fromInterned(base_index.base).canMutateComptimeVarState(mod),
15531555
else => false,
15541556
},
15551557
.opt => |opt| switch (opt.val) {

test/behavior/comptime_memory.zig

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,3 +459,77 @@ test "write empty array to end" {
459459
array[5..5].* = [_]u8{};
460460
try testing.expectEqualStrings("hello", &array);
461461
}
462+
463+
fn doublePtrTest() !void {
464+
var a: u32 = 0;
465+
const ptr = &a;
466+
const double_ptr = &ptr;
467+
setDoublePtr(double_ptr, 1);
468+
setDoublePtr(double_ptr, 2);
469+
setDoublePtr(double_ptr, 1);
470+
try std.testing.expect(a == 1);
471+
}
472+
fn setDoublePtr(ptr: *const *const u32, value: u32) void {
473+
setPtr(ptr.*, value);
474+
}
475+
fn setPtr(ptr: *const u32, value: u32) void {
476+
const mut_ptr: *u32 = @constCast(ptr);
477+
mut_ptr.* = value;
478+
}
479+
test "double pointer can mutate comptime state" {
480+
try comptime doublePtrTest();
481+
}
482+
483+
fn GenericIntApplier(
484+
comptime Context: type,
485+
comptime applyFn: fn (context: Context, arg: u32) void,
486+
) type {
487+
return struct {
488+
context: Context,
489+
490+
const Self = @This();
491+
492+
inline fn any(self: *const Self) IntApplier {
493+
return .{
494+
.context = @ptrCast(&self.context),
495+
.applyFn = typeErasedApplyFn,
496+
};
497+
}
498+
499+
fn typeErasedApplyFn(context: *const anyopaque, arg: u32) void {
500+
const ptr: *const Context = @alignCast(@ptrCast(context));
501+
applyFn(ptr.*, arg);
502+
}
503+
};
504+
}
505+
const IntApplier = struct {
506+
context: *const anyopaque,
507+
applyFn: *const fn (context: *const anyopaque, arg: u32) void,
508+
509+
fn apply(ia: IntApplier, arg: u32) void {
510+
ia.applyFn(ia.context, arg);
511+
}
512+
};
513+
const Accumulator = struct {
514+
value: u32,
515+
516+
const Applier = GenericIntApplier(*u32, add);
517+
518+
fn applier(a: *Accumulator) Applier {
519+
return .{ .context = &a.value };
520+
}
521+
522+
fn add(context: *u32, arg: u32) void {
523+
context.* += arg;
524+
}
525+
};
526+
fn fieldPtrTest() u32 {
527+
var a: Accumulator = .{ .value = 0 };
528+
const applier = a.applier();
529+
applier.any().apply(1);
530+
applier.any().apply(1);
531+
return a.value;
532+
}
533+
test "pointer in aggregate field can mutate comptime state" {
534+
try comptime std.testing.expect(fieldPtrTest() == 2);
535+
}

0 commit comments

Comments
 (0)