-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Design flaw: Swapping struct fields yields unexpected value #12064
Comments
Note this still happens even if the swapping is moved to a function:
I suspect the function is getting inlined though; changing the swap function to store it in a temporary variable before returning fixes it:
Which makes sense since even if it's inlined, the assignment now happens in a separate statement. |
I believe your explanation is on point, this is yet another manifestation of #3696 (which is a bit hard to find for how commonly it crops up imo). The current semantics are to split struct assignments up into individual field writes(, always ordered as written in source code I believe?). IMO this is a big footgun and language semantics should be changed, however, this is not currently being worked on. |
Thanks for the reference. In my opinion optimizations which rely on (non)aliasing assumptions shouldn't be enabled by default, except maybe for |
this is intentional behavior due to a quirk in Zig's Result Location Semantics. the rules behind it allow for many great things, but this one pattern of in-line reassignment now becomes problematic. its a topic of open research to fix before 1.0 but thats how it works at the moment.
this is correct, so in your original example both |
Thanks, "Result Location Semantics" was the search term that I didn't know to search for (since #2809 hasn't gotten any love). Since it's functioning as intended (for now at least) I'll close this ticket. |
Hope you don't mind I'm going to reopen this issue because it concisely demonstrates a design flaw with result location semantics and I'm not ready to accept status quo as permanent due to aliasing issues like this. |
I just tried out and figured out it was working, so I copy-pasted that snippet into my local editor and got the error. Guess what was the difference between my version and this issue’s? x = .{ … }
x = X{ … } It works if the struct literal is present, but doesn’t if it tries to infer with
I don’t reproduce with this anymore. |
The current implementation allows different optimizations to alter the program behavior. |
At the time this ticket was opened, there was no documentation in the language reference about how RLS works. If you look at the 0.10.1 langref, you can see there's a "Result Location Semantics" heading but it just says "TODO". The current language reference clearly explains that typed initializer expressions do not receive a result location: https://ziglang.org/documentation/master/#Result-Locations To be clear, there is no bug here; the compiler is working as documented and (currently) intended. This ticket remains open only as an example of a case where RLS causes aliasing that could be confusing for new users. |
What about enforcing noalias debug safety checks across both sides of destructured assignments? (as described in #1108) This would make the problematic code fail to compile instead of giving surprising results. Then the programmer could explicitly copy whatever data is needed to eliminate the aliasing. This would make the required temporary's space cost readily apparent when reading the code. |
Zig Version
0.10.0-dev.2880+6f0807f50
Steps to Reproduce
Expected Behavior
Conceptually, I expect everything on the right side of an assignment to be evaluated before the left side is modified.
So
x.a
should be 234 andx.b
should be 47, and the test should pass.Actual Behavior
Both
x.a
andx.b
ends up being equal to 234, and the test fails:It would appear that the compiler has transformed the swap into the equivalent of:
The documentation doesn't say much about order of evaluation guarantees as far as I can tell, so maybe this is just undefined behavior in zig, but if that's the case, it seems like a pretty big footgun.
The text was updated successfully, but these errors were encountered: