-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Proposal: disallow direct assignment to x.?
#17508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Just wanted to note that there is a possible use case. The silent failure / UB is certainly wrong, all illegal behavior should be checked in safe build modes, see #2301 . On a related note, writing to
IMO this is ultimately the same edge case, and should be declared illegal behavior and safety-checked as well, to the effect that writing to |
doing this is checked in safe modes as I mentioned at the top of the post. by "silently causes incorrect code" I meant that it seems innocent if you're unaware of the effect it has which, imo, makes your code incorrect. |
I would like to point out that code generated with unreachable is a bit different. In principle, x.? = 1; should be equivalent to if (x == null) unreachable;
x.? = 1; However, LLVM isn't smart enough to pick up on this (and I doubt Zig self-hosted backend would be smart enough for this either). For instance, this Zig code fn f(target: *?u64) void {
if (target.* == null) unreachable;
target.* = 1;
}
fn f2(target: *?u64) void {
target.*.? = 1
} compiles to this assembly on amd64 example.f:
vmovups xmm0, xmmword ptr [rip + .L__unnamed_1]
vmovups xmmword ptr [rdi], xmm0
ret
example.f2:
mov qword ptr [rdi], 1
ret See https://godbolt.org/z/TEcosqjsx
|
that's a fair observation but seeing how very rare this use seems to be, I'm guessing optimization is not the reason for it. as for the optimizers being smart enough, the self hosted might not be able to do that yet but it can be specifically curated to zig and it's patterns, this could be one such case. |
One way to still have good codegen here is to take address with fn f3(target: *?u64) void {
(&target.*.?).* = 1;
} This produces same exact code as direct assignment with LLVM and is convoluted enough for no beginner to arrive at by mistake. |
currently zig allows the following code to compile
not only is this dangerous as it causes panics in safe modes and UB in unsafe modes, but it's just plain wrong, a user should simply do
x = 10
instead. for newcomers to zig this code may be a logical conclusion to come to, it seemingly synergizes well with the syntax of pointers@InKryption pointed out to me that
x.?
as an lvalue semantically is useful and should still be allowed, e.g.&x.?
. if we changed the semantic meaning ofx.?
this would cause the unwrapped value to be a temporary and therefore yield a constant pointer.this pattern is also extremely uncommon. using sourcegraph i counted only 11 occurrences in total, 3 of which were simply a duplicated behavior test from within zig itself across zig, zig-bootstrap, and zig-spec. see:
zig/test/behavior/optional.zig
Lines 225 to 232 in 027aabf
i see no reason for this syntax to be allowed as it silently causes incorrect code and is almost never used
The text was updated successfully, but these errors were encountered: