From 92d65a92e210ebc209e7c8ed0536ad1fbb1661a6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 8 Feb 2024 00:09:31 +0100 Subject: [PATCH 1/2] Add tests --- ...atterns.opt1.SimplifyCfg-initial.after.mir | 54 +++++++++++++ .../mir-opt/building/match/never_patterns.rs | 17 +++++ .../ui/rfcs/rfc-0000-never_patterns/check.rs | 1 + .../rfcs/rfc-0000-never_patterns/check.stderr | 12 +-- .../check_place_is_initialized.rs | 12 +++ .../ui/rfcs/rfc-0000-never_patterns/typeck.rs | 12 +++ .../rfc-0000-never_patterns/use-bindings.rs | 34 +++++++++ .../use-bindings.stderr | 75 +++++++++++++++++++ 8 files changed, 211 insertions(+), 6 deletions(-) create mode 100644 tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir create mode 100644 tests/mir-opt/building/match/never_patterns.rs create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.stderr diff --git a/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir new file mode 100644 index 0000000000000..47598a3f48a3a --- /dev/null +++ b/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir @@ -0,0 +1,54 @@ +// MIR for `opt1` after SimplifyCfg-initial + +fn opt1(_1: &Result) -> &u32 { + debug res => _1; + let mut _0: &u32; + let mut _2: isize; + let _3: &u32; + let mut _4: !; + let mut _5: (); + scope 1 { + debug x => _3; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + falseEdge -> [real: bb4, imaginary: bb3]; + } + + bb3: { + StorageLive(_4); + goto -> bb5; + } + + bb4: { + StorageLive(_3); + _3 = &(((*_1) as Ok).0: u32); + _0 = &(*_3); + StorageDead(_3); + return; + } + + bb5: { + falseUnwind -> [real: bb6, unwind: bb7]; + } + + bb6: { + _5 = const (); + goto -> bb5; + } + + bb7 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/match/never_patterns.rs b/tests/mir-opt/building/match/never_patterns.rs new file mode 100644 index 0000000000000..b6047aabe0163 --- /dev/null +++ b/tests/mir-opt/building/match/never_patterns.rs @@ -0,0 +1,17 @@ +// skip-filecheck +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +// EMIT_MIR never_patterns.opt1.SimplifyCfg-initial.after.mir +fn opt1(res: &Result) -> &u32 { + match res { + Ok(x) => x, + Err(!), + } +} + +fn main() { + opt1(&Ok(0)); +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check.rs b/tests/ui/rfcs/rfc-0000-never_patterns/check.rs index 0831477e74900..dc13dd05fa6a2 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/check.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/check.rs @@ -1,3 +1,4 @@ +// Check that never patterns can't have bodies or guards. #![feature(never_patterns)] #![allow(incomplete_features)] diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr index 25f7343a8a801..fbf7aa02ac2b9 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr @@ -1,5 +1,5 @@ error: a never pattern is always unreachable - --> $DIR/check.rs:14:20 + --> $DIR/check.rs:15:20 | LL | Some(!) => {} | ^^ @@ -8,13 +8,13 @@ LL | Some(!) => {} | help: remove this expression error: a guard on a never pattern will never be run - --> $DIR/check.rs:19:20 + --> $DIR/check.rs:20:20 | LL | Some(!) if true, | ^^^^ help: remove this guard error: a never pattern is always unreachable - --> $DIR/check.rs:24:28 + --> $DIR/check.rs:25:28 | LL | Some(!) if true => {} | ^^ @@ -23,7 +23,7 @@ LL | Some(!) if true => {} | help: remove this expression error: a never pattern is always unreachable - --> $DIR/check.rs:29:27 + --> $DIR/check.rs:30:27 | LL | Some(never!()) => {} | ^^ @@ -32,7 +32,7 @@ LL | Some(never!()) => {} | help: remove this expression error[E0004]: non-exhaustive patterns: `Some(!)` not covered - --> $DIR/check.rs:18:11 + --> $DIR/check.rs:19:11 | LL | match None:: { | ^^^^^^^^^^^^ pattern `Some(!)` not covered @@ -50,7 +50,7 @@ LL + Some(!) | error[E0004]: non-exhaustive patterns: `Some(!)` not covered - --> $DIR/check.rs:23:11 + --> $DIR/check.rs:24:11 | LL | match None:: { | ^^^^^^^^^^^^ pattern `Some(!)` not covered diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs b/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs new file mode 100644 index 0000000000000..c3d21a4b363cf --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs @@ -0,0 +1,12 @@ +//@ check-pass +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +fn main() {} + +fn anything() -> T { + let x: Void; + match x { ! } +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs index e8bfa9245f597..8300f953dc162 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs @@ -123,3 +123,15 @@ fn never_pattern_typeck_pass(void: Void) { Some(!), } } + +struct Unsized { + void: Void, + slice: [u8], +} + +#[cfg(pass)] +fn not_sized(x: &Unsized) { + match *x { + !, + } +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs b/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs new file mode 100644 index 0000000000000..7e38d45d5953f --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs @@ -0,0 +1,34 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] + +#[derive(Copy, Clone)] +enum Void {} + +fn main() { + let res_void: Result = Ok(true); + + let (Ok(x) | Err(!)) = res_void; + println!("{x}"); + //~^ ERROR: used binding `x` is possibly-uninitialized + let (Ok(x) | Err(!)) = &res_void; + println!("{x}"); + //~^ ERROR: used binding `x` is possibly-uninitialized + let (Err(!) | Ok(x)) = res_void; + println!("{x}"); + //~^ ERROR: used binding `x` is possibly-uninitialized + + match res_void { + Ok(x) | Err(!) => println!("{x}"), + //~^ ERROR: used binding `x` is possibly-uninitialized + } + match res_void { + Err(!) | Ok(x) => println!("{x}"), + //~^ ERROR: used binding `x` is possibly-uninitialized + } + + let res_res_void: Result, Void> = Ok(Ok(true)); + match res_res_void { + Ok(Ok(x) | Err(!)) | Err(!) => println!("{x}"), + //~^ ERROR: used binding `x` is possibly-uninitialized + } +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.stderr new file mode 100644 index 0000000000000..ca8277c76632c --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.stderr @@ -0,0 +1,75 @@ +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/use-bindings.rs:11:15 + | +LL | let (Ok(x) | Err(!)) = res_void; + | - + | | + | binding initialized here in some conditions + | binding declared here but left uninitialized +LL | println!("{x}"); + | ^^^ `x` used here but it is possibly-uninitialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/use-bindings.rs:14:15 + | +LL | let (Ok(x) | Err(!)) = &res_void; + | - + | | + | binding initialized here in some conditions + | binding declared here but left uninitialized +LL | println!("{x}"); + | ^^^ `x` used here but it is possibly-uninitialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/use-bindings.rs:17:15 + | +LL | let (Err(!) | Ok(x)) = res_void; + | - + | | + | binding initialized here in some conditions + | binding declared here but left uninitialized +LL | println!("{x}"); + | ^^^ `x` used here but it is possibly-uninitialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/use-bindings.rs:21:37 + | +LL | Ok(x) | Err(!) => println!("{x}"), + | - ^^^ `x` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions + | binding declared here but left uninitialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/use-bindings.rs:25:37 + | +LL | Err(!) | Ok(x) => println!("{x}"), + | - ^^^ `x` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions + | binding declared here but left uninitialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/use-bindings.rs:31:50 + | +LL | Ok(Ok(x) | Err(!)) | Err(!) => println!("{x}"), + | - ^^^ `x` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions + | binding declared here but left uninitialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0381`. From 57e8aebb6c035c0279677c041fbb589466ce9146 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Feb 2024 04:07:50 +0100 Subject: [PATCH 2/2] Lower never patterns to Unreachable in mir --- compiler/rustc_ast_lowering/src/expr.rs | 4 +- compiler/rustc_middle/src/thir.rs | 17 +++++ .../rustc_mir_build/src/build/matches/mod.rs | 40 ++++++++++ .../rustc_mir_build/src/build/matches/test.rs | 21 ++++++ .../rustc_mir_build/src/build/matches/util.rs | 5 +- tests/crashes/120421.rs | 12 --- ...atterns.opt1.SimplifyCfg-initial.after.mir | 17 +---- ...atterns.opt2.SimplifyCfg-initial.after.mir | 35 +++++++++ ...atterns.opt3.SimplifyCfg-initial.after.mir | 35 +++++++++ .../mir-opt/building/match/never_patterns.rs | 31 +++++++- .../check_place_is_initialized.rs | 2 +- .../check_place_is_initialized.stderr | 16 ++++ .../rfc-0000-never_patterns/use-bindings.rs | 7 +- .../use-bindings.stderr | 75 ------------------- 14 files changed, 203 insertions(+), 114 deletions(-) delete mode 100644 tests/crashes/120421.rs create mode 100644 tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir create mode 100644 tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.stderr delete mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.stderr diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 5cc05d7336eed..443b596b9177f 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -581,8 +581,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().emit_err(NeverPatternWithGuard { span: g.span }); } - // We add a fake `loop {}` arm body so that it typecks to `!`. - // FIXME(never_patterns): Desugar into a call to `unreachable_unchecked`. + // We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never + // patterns ensures this loop is not reachable. let block = self.arena.alloc(hir::Block { stmts: &[], expr: None, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index a7d8ead567738..c68b7a6c9eb39 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -682,6 +682,23 @@ impl<'tcx> Pat<'tcx> { true }) } + + /// Whether this a never pattern. + pub fn is_never_pattern(&self) -> bool { + let mut is_never_pattern = false; + self.walk(|pat| match &pat.kind { + PatKind::Never => { + is_never_pattern = true; + false + } + PatKind::Or { pats } => { + is_never_pattern = pats.iter().all(|p| p.is_never_pattern()); + false + } + _ => true, + }); + is_never_pattern + } } impl<'tcx> IntoDiagArg for Pat<'tcx> { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index bce1526775963..30ebe7d547ea6 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1016,6 +1016,9 @@ struct PatternExtraData<'tcx> { /// Types that must be asserted. ascriptions: Vec>, + + /// Whether this corresponds to a never pattern. + is_never: bool, } impl<'tcx> PatternExtraData<'tcx> { @@ -1041,12 +1044,14 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { pattern: &'pat Pat<'tcx>, cx: &mut Builder<'_, 'tcx>, ) -> Self { + let is_never = pattern.is_never_pattern(); let mut flat_pat = FlatPat { match_pairs: vec![MatchPair::new(place, pattern, cx)], extra_data: PatternExtraData { span: pattern.span, bindings: Vec::new(), ascriptions: Vec::new(), + is_never, }, }; cx.simplify_match_pairs(&mut flat_pat.match_pairs, &mut flat_pat.extra_data); @@ -1062,6 +1067,8 @@ struct Candidate<'pat, 'tcx> { match_pairs: Vec>, /// ...and if this is non-empty, one of these subcandidates also has to match... + // Invariant: at the end of the algorithm, this must never contain a `is_never` candidate + // because that would break binding consistency. subcandidates: Vec>, /// ...and the guard must be evaluated if there is one. @@ -1172,6 +1179,7 @@ enum TestCase<'pat, 'tcx> { Range(&'pat PatRange<'tcx>), Slice { len: usize, variable_length: bool }, Deref { temp: Place<'tcx>, mutability: Mutability }, + Never, Or { pats: Box<[FlatPat<'pat, 'tcx>]> }, } @@ -1238,6 +1246,9 @@ enum TestKind<'tcx> { temp: Place<'tcx>, mutability: Mutability, }, + + /// Assert unreachability of never patterns. + Never, } /// A test to perform to determine which [`Candidate`] matches a value. @@ -1662,6 +1673,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.goto(or_block, source_info, any_matches); } candidate.pre_binding_block = Some(any_matches); + } else { + // Never subcandidates may have a set of bindings inconsistent with their siblings, + // which would break later code. So we filter them out. Note that we can't filter out + // top-level candidates this way. + candidate.subcandidates.retain_mut(|candidate| { + if candidate.extra_data.is_never { + candidate.visit_leaves(|subcandidate| { + let block = subcandidate.pre_binding_block.unwrap(); + // That block is already unreachable but needs a terminator to make the MIR well-formed. + let source_info = self.source_info(subcandidate.extra_data.span); + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + }); + false + } else { + true + } + }); + if candidate.subcandidates.is_empty() { + // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`. + candidate.pre_binding_block = Some(self.cfg.start_new_block()); + } } } @@ -2008,6 +2040,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = fresh_block; } + if candidate.extra_data.is_never { + // This arm has a dummy body, we don't need to generate code for it. `block` is already + // unreachable (except via false edge). + let source_info = self.source_info(candidate.extra_data.span); + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + return self.cfg.start_new_block(); + } + self.ascribe_types( block, parent_data diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 5dd478aa4224a..7f65697fa4b2b 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -44,6 +44,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability }, + TestCase::Never => TestKind::Never, + TestCase::Or { .. } => bug!("or-patterns should have already been handled"), TestCase::Irrefutable { .. } => span_bug!( @@ -262,6 +264,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target = target_block(TestBranch::Success); self.call_deref(block, target, place, mutability, ty, temp, test.span); } + + TestKind::Never => { + // Check that the place is initialized. + // FIXME(never_patterns): Also assert validity of the data at `place`. + self.cfg.push_fake_read( + block, + source_info, + FakeReadCause::ForMatchedPlace(None), + place, + ); + // A never pattern is only allowed on an uninhabited type, so validity of the data + // implies unreachability. + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + } } } @@ -710,6 +726,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(TestBranch::Success) } + (TestKind::Never, _) => { + fully_matched = true; + Some(TestBranch::Success) + } + ( TestKind::Switch { .. } | TestKind::SwitchInt { .. } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 2f9390c22a89d..02bea6f8e9eb2 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -124,7 +124,8 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; let mut subpairs = Vec::new(); let test_case = match pattern.kind { - PatKind::Never | PatKind::Wild | PatKind::Error(_) => default_irrefutable(), + PatKind::Wild | PatKind::Error(_) => default_irrefutable(), + PatKind::Or { ref pats } => TestCase::Or { pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), }, @@ -260,6 +261,8 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); TestCase::Deref { temp, mutability } } + + PatKind::Never => TestCase::Never, }; MatchPair { place, test_case, subpairs, pattern } diff --git a/tests/crashes/120421.rs b/tests/crashes/120421.rs deleted file mode 100644 index b6059f3ace4fd..0000000000000 --- a/tests/crashes/120421.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #120421 -//@ compile-flags: -Zlint-mir - -#![feature(never_patterns)] - -enum Void {} - -fn main() { - let res_void: Result = Ok(true); - - for (Ok(mut _x) | Err(!)) in [res_void] {} -} diff --git a/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir index 47598a3f48a3a..78356a90743a6 100644 --- a/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir @@ -27,8 +27,8 @@ fn opt1(_1: &Result) -> &u32 { } bb3: { - StorageLive(_4); - goto -> bb5; + FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void)); + unreachable; } bb4: { @@ -38,17 +38,4 @@ fn opt1(_1: &Result) -> &u32 { StorageDead(_3); return; } - - bb5: { - falseUnwind -> [real: bb6, unwind: bb7]; - } - - bb6: { - _5 = const (); - goto -> bb5; - } - - bb7 (cleanup): { - resume; - } } diff --git a/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir new file mode 100644 index 0000000000000..979fbb2860dcb --- /dev/null +++ b/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir @@ -0,0 +1,35 @@ +// MIR for `opt2` after SimplifyCfg-initial + +fn opt2(_1: &Result) -> &u32 { + debug res => _1; + let mut _0: &u32; + let mut _2: isize; + let _3: &u32; + scope 1 { + debug x => _3; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + StorageLive(_3); + _3 = &(((*_1) as Ok).0: u32); + _0 = &(*_3); + StorageDead(_3); + return; + } + + bb3: { + FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void)); + unreachable; + } +} diff --git a/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir new file mode 100644 index 0000000000000..93ebe600b3ff7 --- /dev/null +++ b/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir @@ -0,0 +1,35 @@ +// MIR for `opt3` after SimplifyCfg-initial + +fn opt3(_1: &Result) -> &u32 { + debug res => _1; + let mut _0: &u32; + let mut _2: isize; + let _3: &u32; + scope 1 { + debug x => _3; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void)); + unreachable; + } + + bb3: { + StorageLive(_3); + _3 = &(((*_1) as Ok).0: u32); + _0 = &(*_3); + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/building/match/never_patterns.rs b/tests/mir-opt/building/match/never_patterns.rs index b6047aabe0163..8b52440da4c3d 100644 --- a/tests/mir-opt/building/match/never_patterns.rs +++ b/tests/mir-opt/building/match/never_patterns.rs @@ -1,4 +1,3 @@ -// skip-filecheck #![feature(never_patterns)] #![allow(incomplete_features)] @@ -6,12 +5,40 @@ enum Void {} // EMIT_MIR never_patterns.opt1.SimplifyCfg-initial.after.mir fn opt1(res: &Result) -> &u32 { + // CHECK-LABEL: fn opt1( + // CHECK: bb0: { + // CHECK-NOT: {{bb.*}}: { + // CHECK: return; match res { Ok(x) => x, Err(!), } } +// EMIT_MIR never_patterns.opt2.SimplifyCfg-initial.after.mir +fn opt2(res: &Result) -> &u32 { + // CHECK-LABEL: fn opt2( + // CHECK: bb0: { + // CHECK-NOT: {{bb.*}}: { + // CHECK: return; + match res { + Ok(x) | Err(!) => x, + } +} + +// EMIT_MIR never_patterns.opt3.SimplifyCfg-initial.after.mir +fn opt3(res: &Result) -> &u32 { + // CHECK-LABEL: fn opt3( + // CHECK: bb0: { + // CHECK-NOT: {{bb.*}}: { + // CHECK: return; + match res { + Err(!) | Ok(x) => x, + } +} + fn main() { - opt1(&Ok(0)); + assert_eq!(opt1(&Ok(0)), &0); + assert_eq!(opt2(&Ok(0)), &0); + assert_eq!(opt3(&Ok(0)), &0); } diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs b/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs index c3d21a4b363cf..f8f9d7a9aa6ce 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs @@ -1,4 +1,3 @@ -//@ check-pass #![feature(never_patterns)] #![allow(incomplete_features)] @@ -9,4 +8,5 @@ fn main() {} fn anything() -> T { let x: Void; match x { ! } + //~^ ERROR used binding `x` isn't initialized } diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.stderr new file mode 100644 index 0000000000000..1a6c412708579 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/check_place_is_initialized.rs:10:15 + | +LL | let x: Void; + | - binding declared here but left uninitialized +LL | match x { ! } + | ^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: Void = /* value */; + | +++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs b/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs index 7e38d45d5953f..33da6f02ce269 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs @@ -1,3 +1,4 @@ +//@ check-pass #![feature(never_patterns)] #![allow(incomplete_features)] @@ -9,26 +10,20 @@ fn main() { let (Ok(x) | Err(!)) = res_void; println!("{x}"); - //~^ ERROR: used binding `x` is possibly-uninitialized let (Ok(x) | Err(!)) = &res_void; println!("{x}"); - //~^ ERROR: used binding `x` is possibly-uninitialized let (Err(!) | Ok(x)) = res_void; println!("{x}"); - //~^ ERROR: used binding `x` is possibly-uninitialized match res_void { Ok(x) | Err(!) => println!("{x}"), - //~^ ERROR: used binding `x` is possibly-uninitialized } match res_void { Err(!) | Ok(x) => println!("{x}"), - //~^ ERROR: used binding `x` is possibly-uninitialized } let res_res_void: Result, Void> = Ok(Ok(true)); match res_res_void { Ok(Ok(x) | Err(!)) | Err(!) => println!("{x}"), - //~^ ERROR: used binding `x` is possibly-uninitialized } } diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.stderr deleted file mode 100644 index ca8277c76632c..0000000000000 --- a/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.stderr +++ /dev/null @@ -1,75 +0,0 @@ -error[E0381]: used binding `x` is possibly-uninitialized - --> $DIR/use-bindings.rs:11:15 - | -LL | let (Ok(x) | Err(!)) = res_void; - | - - | | - | binding initialized here in some conditions - | binding declared here but left uninitialized -LL | println!("{x}"); - | ^^^ `x` used here but it is possibly-uninitialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0381]: used binding `x` is possibly-uninitialized - --> $DIR/use-bindings.rs:14:15 - | -LL | let (Ok(x) | Err(!)) = &res_void; - | - - | | - | binding initialized here in some conditions - | binding declared here but left uninitialized -LL | println!("{x}"); - | ^^^ `x` used here but it is possibly-uninitialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0381]: used binding `x` is possibly-uninitialized - --> $DIR/use-bindings.rs:17:15 - | -LL | let (Err(!) | Ok(x)) = res_void; - | - - | | - | binding initialized here in some conditions - | binding declared here but left uninitialized -LL | println!("{x}"); - | ^^^ `x` used here but it is possibly-uninitialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0381]: used binding `x` is possibly-uninitialized - --> $DIR/use-bindings.rs:21:37 - | -LL | Ok(x) | Err(!) => println!("{x}"), - | - ^^^ `x` used here but it is possibly-uninitialized - | | - | binding initialized here in some conditions - | binding declared here but left uninitialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0381]: used binding `x` is possibly-uninitialized - --> $DIR/use-bindings.rs:25:37 - | -LL | Err(!) | Ok(x) => println!("{x}"), - | - ^^^ `x` used here but it is possibly-uninitialized - | | - | binding initialized here in some conditions - | binding declared here but left uninitialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0381]: used binding `x` is possibly-uninitialized - --> $DIR/use-bindings.rs:31:50 - | -LL | Ok(Ok(x) | Err(!)) | Err(!) => println!("{x}"), - | - ^^^ `x` used here but it is possibly-uninitialized - | | - | binding initialized here in some conditions - | binding declared here but left uninitialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0381`.