-
Notifications
You must be signed in to change notification settings - Fork 12.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
Non-exhaustive patterns error when matching reference to empty enum #78123
Comments
This is currently working as intended, but maybe we should say so in the diagnostic |
Why is this the intended behavior? |
I don't recall, but you might be able to find some of the old discussions |
I was just reading some discussion on the exhaustive_patterns issue: IIUC, the reason that |
Though unsafe code can also construct an uninhabited without using references; e.g.: use std::mem;
#[derive(Debug)]
enum Void {}
fn main() {
println!("start");
let x: Void = unsafe { mem::transmute(()) };
println!("made Void value");
println!("{:?}", x);
println!("printed Void value");
println!("end");
} Output:
Errors:
So maybe what I said in #78123 (comment) is not correct? |
I think the difference is that creating a value of type |
Indeed, transmuting to |
Nice. Indeed dereferencing a reference to unintialized memory is also UB. Instructions to fix this:
@rustbot modify labels: +E-easy +E-mentor |
On the contrary, constructing a |
Oh shoot, I understood the opposite. Then I've misunderstood what @nikomatsakis says in their never patterns blog post:
Maybe that post is old and things have changed since? Or maybe unintialized memory does not count as an invalid value? |
The rules for validity of reference are not finally decided yet, but still being discussed at rust-lang/unsafe-code-guidelines#77. To not preempt the conclusion of this discussion, the docs declare as much UB as is possible -- we can always relax UB later, but introducing more UB is a breaking change. |
Ok, I understand that if we want to have the option to relax this later, then we can't have the compiler rely on it. So we must treat fn foo(x: Option<&!>) -> u64 {
match x {
None => 42,
}
} So |
@rustbot claim |
Thanks for taking this on @GroteGnoom ! Feel free to ask me questions here or on zulip. |
Thanks for the warm welcome :) I do have questions, but I already made a preliminary commit to check if I'm going in the right direction: Is that ok, or is it better if I ask questions before committing, or just make a PR and adapt it? |
That commit looks like what we want yes :) Go ahead and make a PR, it's easier to comment on specific bits of the code |
Add note to non-exhaustive match on reference to empty Rust prints "type `&A` is non-empty" even is A is empty. This is the intended behavior, but can be confusing. This commit adds a note to non-exhaustive pattern errors if they are a reference to something uninhabited. I did not add tests to check that the note is not shown for non-references or inhabited references, because this is already done in other tests. Maybe the added test is superfluous, because `always-inhabited-union-ref` already checks for this case. This does not handle &&Void or &&&void etc. I could add those as special cases as well and ignore people who need quadruple references. Fixes rust-lang#78123
Rust only allows an empty match statement in code that will not be run, that is when matching something that is not inhabited. References to enums are always considered inhabited, because it may avoid some undefined behaviour in unsafe code. See rust-lang/rust#78123 The solution in this PR is to match the enum rather than the reference to the enum. I also added CI for wasm32-unknown-unknown to combat regression.
Rust only allows an empty match statement in code that will not be run, that is when matching something that is not inhabited. References to enums are always considered inhabited, because it may avoid some undefined behaviour in unsafe code. See rust-lang/rust#78123 The solution in this PR is to match the enum rather than the reference to the enum. I also added CI for wasm32-unknown-unknown to combat regression.
if you use references, the compiler forces you to match on NOTHING: rust-lang/rust#78123 so yeah this fixes #5 woo hoo!
For those who (like me) find this after googling "references are always considered inhabited" (the compiler's help message), the current discussion on this topic is happening in rust-lang/unsafe-code-guidelines#413. |
I've added a comment here: rust-lang/unsafe-code-guidelines#413 (comment) Which suggests that we consider making it UB to construct such a reference, so that this macro code doesn't confusingly start breaking for empty enums: impl MyGeneratedEnum {
fn get_x(&self) {
match self {
$(
Self::$variant(v) => v.get_x(),
)*
}
}
} |
match
ing a value of an empty enum is valid, howevermatch
ing a reference to a value of an empty enum producesE0004: non-exhaustive patterns
.I tried this code (playground link):
I expected to see this happen: The code should compile with no issue, and the function should never actually execute because
A
has no variants and thus cannot be instantiated.Instead, this happened:
Meta
The bug exists on 1.47.0 and 1.49.0-nightly (2020-10-18 b1496c6) running on the playground. I first found this bug on 1.46.0.
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: