aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2024-12-06 08:15:46 +0000
committermlugg <mlugg@mlugg.co.uk>2024-12-08 10:53:50 +0000
commit03f5b967f0d0dcdcb850061613cdb0793e2d8be2 (patch)
treeb24253b9f2c865e5564e1503f3533c170df1bd58 /test
parente62aac3ec4b21da20d7c57d937e508f2929138d0 (diff)
downloadzig-03f5b967f0d0dcdcb850061613cdb0793e2d8be2.tar.gz
zig-03f5b967f0d0dcdcb850061613cdb0793e2d8be2.zip
AstGen: correctly deduplicate `ref` of `param` and `alloc_inferred`
Both of these instructions were previously under a special case in `rvalue` which resulted in every reference to such an instruction adding a new `ref` instruction. This had the effect that, for instance, `&a != &a` for parameters. Deduplicating these `ref` instructions was problematic for different reasons. For `alloc_inferred`, the problem was that it's not valid to `ref` the alloc until the allocation has been resolved (`resolve_inferred_alloc`), but `AstGen.appendBodyWithFixups` would place the `ref` directly after the `alloc_inferred`. This is solved by bringing `resolve_inferred_alloc` in line with `make_ptr_const` by having it *return* the final pointer, rather than modifying `sema.inst_map` of the original `alloc_inferred`. That way, the `ref` refers to the `resolve_inferred_alloc` instruction, so is placed immediately after it, avoiding this issue. For `param`, the problem is a bit trickier: `param` instructions live in a body which must contain only `param` instructions, then a `func{,_inferred,_fancy}`, then a `break_inline`. Moreover, `param` instructions may be referenced not only by the function body, but also by other parameters, the return type expression, etc. Each of these bodies requires separate `ref` instructions. This is solved by pulling entries out of `ref_table` after evaluating each component of the function declaration, and appending the refs later on when actually putting the bodies together. This gives way to another issue: if you write `fn f(x: T) @TypeOf(x.foo())`, then since `x.foo()` takes a reference to `x`, this `ref` instruction is now in a comptime context (outside of the `@TypeOf` ZIR body), so emits a compile error. This is solved by loosening the rules around `ref` instructions; because they are not side-effecting, it is okay to allow `ref` of runtime values at comptime, resulting in a runtime-known value in a comptime scope. We already apply this mechanism in some cases; for instance, it's why `runtime_array.len` works in a `comptime` context. In future, we will want to give similar treatment to many operations in Sema: in general, it's fine to apply runtime operations at comptime provided they don't have side effects! Resolves: #22140
Diffstat (limited to 'test')
-rw-r--r--test/behavior/fn.zig51
1 files changed, 51 insertions, 0 deletions
diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig
index 41e9f11f0b..0ad7bda9bd 100644
--- a/test/behavior/fn.zig
+++ b/test/behavior/fn.zig
@@ -617,3 +617,54 @@ test "inline function with comptime-known comptime-only return type called at ru
try expectEqual(111, a);
try expectEqual(f32, T);
}
+
+test "address of function parameter is consistent" {
+ const S = struct {
+ fn paramAddrMatch(x: u8) bool {
+ return &x == &x;
+ }
+ };
+ try expect(S.paramAddrMatch(0));
+ comptime assert(S.paramAddrMatch(0));
+}
+
+test "address of function parameter is consistent in other parameter type" {
+ const S = struct {
+ fn paramAddrMatch(comptime x: u8, y: if (&x != &x) unreachable else u8) void {
+ _ = y;
+ }
+ };
+ S.paramAddrMatch(1, 2);
+}
+
+test "address of function parameter is consistent in function align" {
+ switch (builtin.target.cpu.arch) {
+ .wasm32, .wasm64 => return, // function alignment not supported
+ else => {},
+ }
+ const S = struct {
+ fn paramAddrMatch(comptime x: u8) align(if (&x != &x) unreachable else 1) void {}
+ };
+ S.paramAddrMatch(1);
+}
+
+test "address of function parameter is consistent in function callconv" {
+ const S = struct {
+ fn paramAddrMatch(comptime x: u8) callconv(if (&x != &x) unreachable else .auto) void {}
+ };
+ S.paramAddrMatch(1);
+}
+
+test "address of function parameter is consistent in function return type" {
+ const S = struct {
+ fn paramAddrMatch(comptime x: u8) if (&x != &x) unreachable else void {}
+ };
+ S.paramAddrMatch(1);
+}
+
+test "address of function parameter is consistent in function addrspace" {
+ const S = struct {
+ fn paramAddrMatch(comptime x: u8) addrspace(if (&x != &x) unreachable else .generic) void {}
+ };
+ S.paramAddrMatch(1);
+}