-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Incorrect "unreachable match arm" warning #117119
Comments
Here's another variant of the false warning: fn main() {
#[derive(Copy, Clone)]
enum Void {}
let ptr = 1 as *const Void;
unsafe {
match *ptr {
_ => println!("hello from the Void"),
}
}
} |
In fact the warning is actively harmful -- by removing the arm, UB is introduced into this well-defined code! |
There was a now-deleted comment saying that the warnings appear even without the feature gate -- that seems right, the lint is actually already misfiring. But at least currently when people then try to remove the "unreachable" arm they get a build error. Cc @Nadrieril @oli-obk (pattern match lint issue) |
They don't (playground) |
There's a special case in exhaustiveness checking to allow
What could we do? Could we detect the unsafe block? Or detect pointer dereference/union field access? |
They don't
Oh... I thought this needs the exhaustive_patterns feature. That seems bad, IMO we should not accept this code without some sort of explicit "never pattern".
|
Or detect pointer dereference/union field access?
That makes most sense to me.
|
Let me check with you to be sure: in the following, the unsafe {
let x: Uninit<Void> = Uninit { uninit: () };
let y = x.value;
match y {
}
} and in here, the braces also would cause UB? unsafe {
let x: Uninit<Void> = Uninit { uninit: () };
match {x.value} {
}
} So for the purposes of exhaustivenesss/unreachability I only need to check if the match scrutinee is literally a union field access expression or a pointer dereference expression? Anything else? |
Yes.
I think braces mean we do a load from the place, create a new temporary place, and then match on that. If that's accurate then yes that would also be UB already at the
Yes.
I have some concerns around dereferencing references (not just raw pointers) as well. The reference says that references have to be recursively valid, but that's not actually the semantics I think we should end up with. But I haven't found a clear example yet so it's possible that this is fine. We should IMO start with the places where we clearly allow invalid values: raw pointers and unions. |
Even |
…take-3, r=<try> Don't warn an empty pattern unreachable if we're not sure the data is valid Exhaustiveness checking used to be naive about the possibility of a place containing invalid data. This could cause it to emit an "unreachable pattern" lint on an arm that was in fact reachable, as in rust-lang#117119. This PR fixes that. We now track whether a place that is matched on may hold invalid data. This also forced me to be extra precise about how exhaustiveness manages empty types. Note that this now errs in the opposite direction: the following arm is truly unreachable but not linted as such. I'd rather not recommend writing a `match ... {}` that has the implicit side-effect of loading the value. [Never patterns](rust-lang#118155) will solve this cleanly. ```rust match union.value { _x => unreachable!(), } ``` I recommend reviewing commit by commit. I went all-in on the test suite because this went through a lot of iterations and I kept everything. The bit I'm least confident in is `is_known_valid_scrutinee` in `check_match.rs`. Fixes rust-lang#117119.
The following code generates a warning:
This warning is wrong: running the code in Miri shows that this arm is reachable and there is no UB.
The text was updated successfully, but these errors were encountered: