-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Special-case switching on error union capture #18173
Conversation
0f08626
to
0436b3b
Compare
Not sure what the errors in the CI are - I can reproduce the segfault in bootstrap locally, but don't know what would be causing it. Perhaps there is some incompatibility with the x86_64 backend. Edit: The segfault referenced above has been fixed, but there is a new/different segfault happening in the CI that I cannot reproduce. |
ad85f90
to
815b4d4
Compare
815b4d4
to
905abb9
Compare
905abb9
to
599ca96
Compare
Looks like stage2 is broken, probably due to the C backend emitting broken code in readFromPackedMemory and utf8ToUtf16Le. Since this is Linux Release, I'd guess that readFromPackedMemory is broken. I do see 3 ways forward, since I suspect you checked that the miscompilation is not detectable within standard debugging tools (valgrind, memsanitizer etc):
Please let me know what you think. |
Aren't the quoted warnings from The failure in this case seems to be after those:
|
Buffer overreads or overwrites are undefined behavior and, if conforming to the c standard, compilers are free to optimize based on the absence of such things and miscompile your programs. |
599ca96
to
3d26d8c
Compare
This change only emits the unwrap_errunion_err instruction if the error capture is actually used in a branch.
3d26d8c
to
67d7d7b
Compare
I think you were probably right - I started investigating and it looked like a bug when Now that I've rebased to include those changes, hopefully the CI will pass on all the x86_64-linux targets. |
// The non-error and error cases are only peers if the error case is just a switch expression; | ||
// the pattern `if (x) {...} else |err| blk: { switch (err) {...} }` does not consider the | ||
// non-error and error case to be peers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like how this turns a limitation of the compiler into a feature of the language.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just trying to be clear about what the behaviour is so as to not cause confusion, but I can see that this may the source of future problems if peer type resolution changes for these cases. Should I remove the sentence, or add a note saying something along the lines of 'this is the current behaviour and may change'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's good enough for now. I need to go over the langref anyway; it's collected quite a few different contributors' conflicting ideas about what a langref should be and it needs to be reworked by one person with a vision.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @dweiller - nice work. The amount of additions and copy-pasted code makes me a bit uneasy, but you made up for it with robust test coverage.
I have a couple review comments but they are insignificant and so I will proceed with the merge regardless. Feel free to ignore them, they can be cleaned up later along with a future enhancement or bug fix.
pub const Bits = packed struct(u32) { | ||
/// If true, one or more prongs have multiple items. | ||
has_multi_cases: bool, | ||
/// If true, there is an else prong. This is mutually exclusive with `has_under`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this comment looks like it was copy pasted and no longer applies since there is no has_under
field.
sema.inst_map.putAssumeCapacity(err_capture_inst, spa.operand); | ||
} | ||
defer if (extra.data.bits.any_uses_err_capture) assert(sema.inst_map.remove(err_capture_inst)); | ||
_ = try sema.analyzeSwitchRuntimeBlock( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks like this return value is never used by any caller.
// The non-error and error cases are only peers if the error case is just a switch expression; | ||
// the pattern `if (x) {...} else |err| blk: { switch (err) {...} }` does not consider the | ||
// non-error and error case to be peers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's good enough for now. I need to go over the langref anyway; it's collected quite a few different contributors' conflicting ideas about what a langref should be and it needs to be reworked by one person with a vision.
I wouldn't be surprise if there is a way to unify the new logic more with the regular switch logic to reduce the amount of duplication. However, there are a number of subtle differences that made it tricky to do without requiring interleaving a bunch of |
Closes #11957 and as well as the related issues #16770 and #11812.
There are a few things left to do before merging:
if (x) { ... } else |err| switch (err) { ... }
pattern-Donly-ast-check
build flag?)AstGen.zig
andSema.zig
)if
andcatch
patterns in langref (contrast with using a block around theswitch
)