diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2024-12-06 08:15:46 +0000 |
|---|---|---|
| committer | mlugg <mlugg@mlugg.co.uk> | 2024-12-08 10:53:50 +0000 |
| commit | 03f5b967f0d0dcdcb850061613cdb0793e2d8be2 (patch) | |
| tree | b24253b9f2c865e5564e1503f3533c170df1bd58 /test | |
| parent | e62aac3ec4b21da20d7c57d937e508f2929138d0 (diff) | |
| download | zig-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.zig | 51 |
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); +} |
