From b5c1ab9944b15ace6f118b5c23ca6d36f11ceda3 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 1 Jan 2018 16:28:28 +0000 Subject: [PATCH 01/16] Unreachable never arguments --- src/librustc_mir/build/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 23c5499bb6396..b99d570a2ea51 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -658,6 +658,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let body = self.hir.mirror(ast_body); + for (t, _) in arguments.iter() { + match t.sty { + ty::TyNever => { + let source_info = self.source_info(body.span); + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + let end_block = self.cfg.start_new_block(); + return end_block.unit(); + }, + _ => {} + } + } self.into(&Place::Local(RETURN_PLACE), block, body) } From e37f4247cab094d16c63865d543d8a426c52d411 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 8 Jan 2018 23:36:45 +0000 Subject: [PATCH 02/16] Unreachable match arms --- src/librustc_mir/build/matches/mod.rs | 4 ++++ src/librustc_mir/build/mod.rs | 22 +++++++++--------- src/librustc_mir/hair/pattern/mod.rs | 32 +++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 229e33dcd7862..ece00436714e0 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -54,6 +54,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let dummy_temp = self.temp(dummy_ty, dummy_source_info.span); self.cfg.push_assign(block, dummy_source_info, &dummy_temp, dummy_access); + let arms: Vec> = arms.into_iter().filter(|arm| + !arm.patterns.iter().any(|pat| pat.is_unreachable()) + ).collect(); + let mut arm_blocks = ArmBlocks { blocks: arms.iter() .map(|_| self.cfg.start_new_block()) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index b99d570a2ea51..e22fe7ebd75e9 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -623,6 +623,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let mut scope = None; + let mut unreachable_arguments = false; // Bind the argument patterns for (index, &(ty, pattern)) in arguments.iter().enumerate() { // Function arguments always get the first Local indices after the return place @@ -632,6 +633,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(pattern) = pattern { let pattern = self.hir.pattern_from_hir(pattern); + if pattern.is_unreachable() { + unreachable_arguments = true; + break; + } + match *pattern.kind { // Don't introduce extra copies for simple bindings PatternKind::Binding { mutability, var, mode: BindingMode::ByValue, .. } => { @@ -649,7 +655,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop(pattern.as_ref().map_or(ast_body.span, |pat| pat.span), argument_scope, &place, ty); - } // Enter the argument pattern bindings visibility scope, if it exists. @@ -658,16 +663,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let body = self.hir.mirror(ast_body); - for (t, _) in arguments.iter() { - match t.sty { - ty::TyNever => { - let source_info = self.source_info(body.span); - self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); - let end_block = self.cfg.start_new_block(); - return end_block.unit(); - }, - _ => {} - } + if unreachable_arguments { + let source_info = self.source_info(body.span); + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + let end_block = self.cfg.start_new_block(); + return end_block.unit(); } self.into(&Place::Local(RETURN_PLACE), block, body) } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index eb87d5b044b45..e2d035bad781b 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -65,6 +65,7 @@ pub struct Pattern<'tcx> { #[derive(Clone, Debug)] pub enum PatternKind<'tcx> { + /// Wildcard `_` Wild, /// x, ref x, x @ P, etc @@ -306,6 +307,37 @@ impl<'a, 'tcx> Pattern<'tcx> { debug!("Pattern::from_hir({:?}) = {:?}", pat, result); result } + + pub fn is_unreachable(&self) -> bool { + if self.ty.sty == ty::TyNever { + return true; + } + match *self.kind { + PatternKind::Binding { ty, ref subpattern, .. } => { + if ty.sty == ty::TyNever { + return true; + } + if let &Some(ref subpattern) = subpattern { + subpattern.is_unreachable() + } else { false } + }, + PatternKind::Variant { ref subpatterns, .. } | + PatternKind::Leaf { ref subpatterns } => { + subpatterns.iter().any(|field_pattern| + field_pattern.pattern.is_unreachable()) + }, + PatternKind::Deref { ref subpattern } => { + subpattern.is_unreachable() + }, + PatternKind::Slice { ref prefix, ref slice, ref suffix } | + PatternKind::Array { ref prefix, ref slice, ref suffix } => { + prefix.iter().any(|pat| pat.is_unreachable()) || + slice.iter().any(|pat| pat.is_unreachable()) || + suffix.iter().any(|pat| pat.is_unreachable()) + }, + _ => false + } + } } impl<'a, 'tcx> PatternContext<'a, 'tcx> { From ad2b47885c810de83ec65a7e14b78fa4a45e9018 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 9 Jan 2018 00:57:56 +0000 Subject: [PATCH 03/16] Add test --- src/test/run-pass/never-type-args.rs | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/run-pass/never-type-args.rs diff --git a/src/test/run-pass/never-type-args.rs b/src/test/run-pass/never-type-args.rs new file mode 100644 index 0000000000000..edc58ff1b9832 --- /dev/null +++ b/src/test/run-pass/never-type-args.rs @@ -0,0 +1,30 @@ +#![feature(never_type)] +#![allow(dead_code)] +#![allow(path_statements)] +#![allow(unreachable_patterns)] + +fn never_direct(x: !) { + x; +} + +fn never_ref_pat(ref x: !) { + *x; +} + +fn never_ref(x: &!) { + let &y = x; + y; +} + +fn never_slice(x: &[!]) { + x[0]; +} + +fn never_match(x: Result<(), !>) { + match x { + Ok(_) => {}, + Err(_) => {}, + } +} + +pub fn main() { } From c5f7ab3ce47223b969d0381a819e59190ff4dd6a Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 9 Jan 2018 00:58:15 +0000 Subject: [PATCH 04/16] Add more general checks for never-type arguments --- src/librustc_mir/hair/pattern/mod.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index e2d035bad781b..0624649a4cf2d 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -308,13 +308,27 @@ impl<'a, 'tcx> Pattern<'tcx> { result } + // Returns true if the pattern cannot bind, as it would require a value of type `!` to have + // been constructed. This check is conservative. pub fn is_unreachable(&self) -> bool { - if self.ty.sty == ty::TyNever { + // Returns true if the construction of the type `ty` would require a value of type `!` + // to have been constructed. This check is conservative. + fn requires_never_value<'tcx>(ty: &Ty<'tcx>) -> bool { + match ty.sty { + ty::TyNever => true, + ty::TyRawPtr(ty_and_mut) | + ty::TyRef(_, ty_and_mut) => requires_never_value(&ty_and_mut.ty), + ty::TyTuple(comps, _) => comps.iter().any(requires_never_value), + _ => false + } + } + + if requires_never_value(&self.ty) { return true; } match *self.kind { PatternKind::Binding { ty, ref subpattern, .. } => { - if ty.sty == ty::TyNever { + if requires_never_value(&ty) { return true; } if let &Some(ref subpattern) = subpattern { From 50d533b11894c174939f825f796527825e13dde6 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 9 Jan 2018 01:57:46 +0000 Subject: [PATCH 05/16] Prevent never-type rvalues --- src/librustc_mir/build/expr/into.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 28dc329e4fe7c..ff8cbcc41b8cd 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -27,8 +27,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { expr: Expr<'tcx>) -> BlockAnd<()> { - debug!("into_expr(destination={:?}, block={:?}, expr={:?})", - destination, block, expr); + debug!("into_expr(destination={:?}, block={:?}, expr_kind={:?}, expr={:?})", + destination, block, expr.kind, expr); // since we frequently have to reference `self` from within a // closure, where `self` would be shadowed, it's easier to @@ -317,9 +317,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { _ => true, }); + let ty = expr.ty; let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); - this.cfg.push_assign(block, source_info, destination, rvalue); - block.unit() + + if ty.sty == ty::TyNever { + // It's impossible to have an rvalue of type `!`, so if we encounter one, + // we can terminate the block as unreachable immediately. + this.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + let end_block = this.cfg.start_new_block(); + end_block.unit() + } else { + this.cfg.push_assign(block, source_info, destination, rvalue); + block.unit() + } } } } From 4a37e05b9cb5672017fcbf9f6de544aeb513c8fb Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 9 Jan 2018 12:06:35 +0000 Subject: [PATCH 06/16] Generate unreachable for rvalues earlier --- src/librustc/ty/mod.rs | 12 ++++++++++++ src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/hair/pattern/mod.rs | 16 ++-------------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 09b11a36352e1..a71e67e21b552 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -529,6 +529,18 @@ impl<'tcx> TyS<'tcx> { _ => true, } } + + // Returns true if the construction of `self` would require a value of type `!` + // to have been constructed. This check is conservative. + pub fn requires_never_value(&self) -> bool { + match self.sty { + ty::TyNever => true, + ty::TyRawPtr(ty_and_mut) | + ty::TyRef(_, ty_and_mut) => ty_and_mut.ty.requires_never_value(), + ty::TyTuple(comps, _) => comps.iter().any(|ty| ty.requires_never_value()), + _ => false + } + } } impl<'a, 'gcx> HashStable> for ty::TyS<'gcx> { diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index ff8cbcc41b8cd..2c5ffdb9bc741 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -320,7 +320,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let ty = expr.ty; let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); - if ty.sty == ty::TyNever { + if ty.requires_never_value() { // It's impossible to have an rvalue of type `!`, so if we encounter one, // we can terminate the block as unreachable immediately. this.cfg.terminate(block, source_info, TerminatorKind::Unreachable); diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 0624649a4cf2d..25e24d9cb41d7 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -311,24 +311,12 @@ impl<'a, 'tcx> Pattern<'tcx> { // Returns true if the pattern cannot bind, as it would require a value of type `!` to have // been constructed. This check is conservative. pub fn is_unreachable(&self) -> bool { - // Returns true if the construction of the type `ty` would require a value of type `!` - // to have been constructed. This check is conservative. - fn requires_never_value<'tcx>(ty: &Ty<'tcx>) -> bool { - match ty.sty { - ty::TyNever => true, - ty::TyRawPtr(ty_and_mut) | - ty::TyRef(_, ty_and_mut) => requires_never_value(&ty_and_mut.ty), - ty::TyTuple(comps, _) => comps.iter().any(requires_never_value), - _ => false - } - } - - if requires_never_value(&self.ty) { + if self.ty.requires_never_value() { return true; } match *self.kind { PatternKind::Binding { ty, ref subpattern, .. } => { - if requires_never_value(&ty) { + if ty.requires_never_value() { return true; } if let &Some(ref subpattern) = subpattern { From 3db42b7d6ed1df6c7aceceb77c470f173287cc04 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 9 Jan 2018 12:12:31 +0000 Subject: [PATCH 07/16] Add copyright to test --- src/test/run-pass/never-type-args.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/run-pass/never-type-args.rs b/src/test/run-pass/never-type-args.rs index edc58ff1b9832..33885a5f6dee6 100644 --- a/src/test/run-pass/never-type-args.rs +++ b/src/test/run-pass/never-type-args.rs @@ -1,3 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + #![feature(never_type)] #![allow(dead_code)] #![allow(path_statements)] From 27d4d5e2c70b0da35b21906933ee86ecde551858 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 9 Jan 2018 13:10:08 +0000 Subject: [PATCH 08/16] Remove tabs that sneaked in --- src/test/run-pass/never-type-args.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/run-pass/never-type-args.rs b/src/test/run-pass/never-type-args.rs index 33885a5f6dee6..58f16cf75cf22 100644 --- a/src/test/run-pass/never-type-args.rs +++ b/src/test/run-pass/never-type-args.rs @@ -27,14 +27,14 @@ fn never_ref(x: &!) { } fn never_slice(x: &[!]) { - x[0]; + x[0]; } fn never_match(x: Result<(), !>) { - match x { - Ok(_) => {}, - Err(_) => {}, - } + match x { + Ok(_) => {}, + Err(_) => {}, + } } pub fn main() { } From a656814eb519155d66924e42c3998f3a222ca905 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 9 Jan 2018 16:38:59 +0000 Subject: [PATCH 09/16] Add mir-opt test --- src/test/mir-opt/never_type_unreachable.rs | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/test/mir-opt/never_type_unreachable.rs diff --git a/src/test/mir-opt/never_type_unreachable.rs b/src/test/mir-opt/never_type_unreachable.rs new file mode 100644 index 0000000000000..792905779b131 --- /dev/null +++ b/src/test/mir-opt/never_type_unreachable.rs @@ -0,0 +1,83 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(never_type)] +#![allow(dead_code)] +#![allow(path_statements)] +#![allow(unreachable_patterns)] + +fn never_direct(x: !) { + x; +} + +fn never_ref_pat(ref x: !) { + *x; +} + +fn never_ref(x: &!) { + let &y = x; + y; +} + +fn never_slice(x: &[!]) { + x[0]; +} + +fn never_match(x: Result<(), !>) { + match x { + Ok(_) => {}, + Err(_) => {}, + } +} + +pub fn main() { } + +// END RUST SOURCE + +// START rustc.never_direct.SimplifyCfg-initial.after.mir +// bb0: { +// unreachable; +// } +// END rustc.never_direct.SimplifyCfg-initial.after.mir + +// START rustc.never_ref_pat.SimplifyCfg-initial.after.mir +// bb0: { +// unreachable; +// } +// END rustc.never_ref_pat.SimplifyCfg-initial.after.mir + +// START rustc.never_ref.SimplifyCfg-initial.after.mir +// bb0: { +// unreachable; +// } +// END rustc.never_ref.SimplifyCfg-initial.after.mir + +// START rustc.never_slice.SimplifyCfg-initial.after.mir +// bb1: { +// ... +// unreachable; +// } +// END rustc.never_slice.SimplifyCfg-initial.after.mir + +// START rustc.never_match.SimplifyCfg-initial.after.mir +// fn never_match(_1: std::result::Result<(), !>) -> () { +// ... +// bb0: { +// ... +// } +// bb1: { +// unreachable; +// } +// bb2: { +// _0 = (); +// return; +// } +// } +// END rustc.never_match.SimplifyCfg-initial.after.mir From 63c7a3eaf4cc9d3a39872e2774fe4d69506821e3 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 11 Jan 2018 22:01:37 +0000 Subject: [PATCH 10/16] Reuse conservative_is_uninhabited --- src/librustc/ty/mod.rs | 12 ------------ src/librustc/ty/sty.rs | 10 ++++++++++ src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/hair/pattern/check_match.rs | 11 +---------- src/librustc_mir/hair/pattern/mod.rs | 4 ++-- src/test/mir-opt/never_type_unreachable.rs | 1 + 7 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a71e67e21b552..09b11a36352e1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -529,18 +529,6 @@ impl<'tcx> TyS<'tcx> { _ => true, } } - - // Returns true if the construction of `self` would require a value of type `!` - // to have been constructed. This check is conservative. - pub fn requires_never_value(&self) -> bool { - match self.sty { - ty::TyNever => true, - ty::TyRawPtr(ty_and_mut) | - ty::TyRef(_, ty_and_mut) => ty_and_mut.ty.requires_never_value(), - ty::TyTuple(comps, _) => comps.iter().any(|ty| ty.requires_never_value()), - _ => false - } - } } impl<'a, 'gcx> HashStable> for ty::TyS<'gcx> { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index ae053d7f4f58d..7b98acbd5a807 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1282,6 +1282,16 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + pub fn conservative_is_uninhabited(&self) -> bool { + // "rustc-1.0-style" uncontentious uninhabitableness check + match self.sty { + ty::TyNever => true, + ty::TyAdt(def, _) => def.variants.is_empty(), + ty::TyTuple(tys, _) => tys.iter().any(|ty| ty.conservative_is_uninhabited()), + _ => false + } + } + pub fn is_primitive(&self) -> bool { match self.sty { TyBool | TyChar | TyInt(_) | TyUint(_) | TyFloat(_) => true, diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 2c5ffdb9bc741..c4f8fca741151 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -320,7 +320,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let ty = expr.ty; let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); - if ty.requires_never_value() { + if ty.conservative_is_uninhabited() { // It's impossible to have an rvalue of type `!`, so if we encounter one, // we can terminate the block as unreachable immediately. this.cfg.terminate(block, source_info, TerminatorKind::Unreachable); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index ece00436714e0..9bb305c6d5ab2 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.push_assign(block, dummy_source_info, &dummy_temp, dummy_access); let arms: Vec> = arms.into_iter().filter(|arm| - !arm.patterns.iter().any(|pat| pat.is_unreachable()) + arm.patterns.iter().any(|pat| !pat.is_unreachable()) ).collect(); let mut arm_blocks = ArmBlocks { diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index d924baaf00521..055561008a124 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -225,7 +225,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns { self.tcx.is_ty_uninhabited_from(module, pat_ty) } else { - self.conservative_is_uninhabited(pat_ty) + pat_ty.conservative_is_uninhabited() }; if !scrutinee_is_uninhabited { // We know the type is inhabited, so this must be wrong @@ -253,15 +253,6 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { }) } - fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool { - // "rustc-1.0-style" uncontentious uninhabitableness check - match scrutinee_ty.sty { - ty::TyNever => true, - ty::TyAdt(def, _) => def.variants.is_empty(), - _ => false - } - } - fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) { let module = self.tcx.hir.get_module_parent(pat.id); MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| { diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 25e24d9cb41d7..24eafc2b62538 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -311,12 +311,12 @@ impl<'a, 'tcx> Pattern<'tcx> { // Returns true if the pattern cannot bind, as it would require a value of type `!` to have // been constructed. This check is conservative. pub fn is_unreachable(&self) -> bool { - if self.ty.requires_never_value() { + if self.ty.conservative_is_uninhabited() { return true; } match *self.kind { PatternKind::Binding { ty, ref subpattern, .. } => { - if ty.requires_never_value() { + if ty.conservative_is_uninhabited() { return true; } if let &Some(ref subpattern) = subpattern { diff --git a/src/test/mir-opt/never_type_unreachable.rs b/src/test/mir-opt/never_type_unreachable.rs index 792905779b131..9457961ede45d 100644 --- a/src/test/mir-opt/never_type_unreachable.rs +++ b/src/test/mir-opt/never_type_unreachable.rs @@ -55,6 +55,7 @@ pub fn main() { } // START rustc.never_ref.SimplifyCfg-initial.after.mir // bb0: { +// ... // unreachable; // } // END rustc.never_ref.SimplifyCfg-initial.after.mir From e22be282c07c39d4b04b06035e18e4653fd3af21 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 12 Jan 2018 12:47:35 +0000 Subject: [PATCH 11/16] Remove test statements that are now optimised away --- src/test/compile-fail/uninhabited-matches-feature-gated.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/test/compile-fail/uninhabited-matches-feature-gated.rs b/src/test/compile-fail/uninhabited-matches-feature-gated.rs index 0c3ea53a903ae..e4e7f5390b2ba 100644 --- a/src/test/compile-fail/uninhabited-matches-feature-gated.rs +++ b/src/test/compile-fail/uninhabited-matches-feature-gated.rs @@ -21,9 +21,6 @@ fn main() { let x: &Void = unsafe { std::mem::uninitialized() }; let _ = match x {}; //~ ERROR non-exhaustive - let x: (Void,) = unsafe { std::mem::uninitialized() }; - let _ = match x {}; //~ ERROR non-exhaustive - let x: [Void; 1] = unsafe { std::mem::uninitialized() }; let _ = match x {}; //~ ERROR non-exhaustive @@ -32,9 +29,6 @@ fn main() { &[] => (), }; - let x: Void = unsafe { std::mem::uninitialized() }; - let _ = match x {}; // okay - let x: Result = Ok(23); let _ = match x { //~ ERROR non-exhaustive Ok(x) => x, From b82ee5702e6e7ae6dea8f7b65edf53414e378de9 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 12 Jan 2018 19:37:17 +0000 Subject: [PATCH 12/16] Improve arm filtering Unmatchable arm patterns are now also filtered, even if the arm itself is reachable. --- src/librustc_mir/build/matches/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 9bb305c6d5ab2..55487745460bc 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -54,9 +54,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let dummy_temp = self.temp(dummy_ty, dummy_source_info.span); self.cfg.push_assign(block, dummy_source_info, &dummy_temp, dummy_access); - let arms: Vec> = arms.into_iter().filter(|arm| - arm.patterns.iter().any(|pat| !pat.is_unreachable()) - ).collect(); + let arms: Vec> = arms.into_iter().filter_map(|mut arm| { + arm.patterns = + arm.patterns.iter().filter(|pat| !pat.is_unreachable()).cloned().collect(); + if !arm.patterns.is_empty() { Some(arm) } else { None } + }).collect(); let mut arm_blocks = ArmBlocks { blocks: arms.iter() From 4578a16728e551e8f295d0e0ed26191a1f81028a Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 12 Jan 2018 22:01:13 +0000 Subject: [PATCH 13/16] Add test for disjunctive patterns --- src/test/mir-opt/never_type_unreachable.rs | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/test/mir-opt/never_type_unreachable.rs b/src/test/mir-opt/never_type_unreachable.rs index 9457961ede45d..e9f31ad989c20 100644 --- a/src/test/mir-opt/never_type_unreachable.rs +++ b/src/test/mir-opt/never_type_unreachable.rs @@ -37,6 +37,13 @@ fn never_match(x: Result<(), !>) { } } +fn never_match_disj_patterns() { + let x: Option = None; + match x { + Some(_) | None => {} + } +} + pub fn main() { } // END RUST SOURCE @@ -82,3 +89,20 @@ pub fn main() { } // } // } // END rustc.never_match.SimplifyCfg-initial.after.mir + +// START rustc.never_match_disj_patterns.SimplifyCfg-initial.after.mir +// fn never_match_disj_patterns() -> () { +// ... +// bb0: { +// ... +// } +// bb1: { +// unreachable; +// } +// bb2: { +// _0 = (); +// StorageDead(_1); +// return; +// } +// } +// END rustc.never_match_disj_patterns.SimplifyCfg-initial.after.mir From 1a799c0d5374901948c1bc7b784a61fc6020955d Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 16 Mar 2018 14:53:24 +0000 Subject: [PATCH 14/16] Removed redundant test The equivalent test now exists as `never-type-rvalues.rs`. --- src/test/run-pass/never-type-args.rs | 40 ---------------------------- 1 file changed, 40 deletions(-) delete mode 100644 src/test/run-pass/never-type-args.rs diff --git a/src/test/run-pass/never-type-args.rs b/src/test/run-pass/never-type-args.rs deleted file mode 100644 index 58f16cf75cf22..0000000000000 --- a/src/test/run-pass/never-type-args.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(never_type)] -#![allow(dead_code)] -#![allow(path_statements)] -#![allow(unreachable_patterns)] - -fn never_direct(x: !) { - x; -} - -fn never_ref_pat(ref x: !) { - *x; -} - -fn never_ref(x: &!) { - let &y = x; - y; -} - -fn never_slice(x: &[!]) { - x[0]; -} - -fn never_match(x: Result<(), !>) { - match x { - Ok(_) => {}, - Err(_) => {}, - } -} - -pub fn main() { } From c17319cfc3beb71969283ef9b3192ed10c358c2c Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 16 Mar 2018 16:25:18 +0000 Subject: [PATCH 15/16] Fix TyTuple after never type stabilisation --- src/librustc/ty/sty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7b98acbd5a807..5ce7f3cc5e3b0 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1287,7 +1287,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { match self.sty { ty::TyNever => true, ty::TyAdt(def, _) => def.variants.is_empty(), - ty::TyTuple(tys, _) => tys.iter().any(|ty| ty.conservative_is_uninhabited()), + ty::TyTuple(tys) => tys.iter().any(|ty| ty.conservative_is_uninhabited()), _ => false } } From 741c8ab2ad7ccb2dd3618fba06bae95311a000c8 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 16 Mar 2018 18:44:27 +0000 Subject: [PATCH 16/16] Update mir-opt test --- src/test/mir-opt/never_type_unreachable.rs | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/test/mir-opt/never_type_unreachable.rs b/src/test/mir-opt/never_type_unreachable.rs index e9f31ad989c20..eec5db9ca9b4c 100644 --- a/src/test/mir-opt/never_type_unreachable.rs +++ b/src/test/mir-opt/never_type_unreachable.rs @@ -81,12 +81,18 @@ pub fn main() { } // ... // } // bb1: { -// unreachable; -// } -// bb2: { // _0 = (); // return; // } +// bb2: { +// ... +// } +// bb3: { +// unreachable; +// } +// bb4: { +// unreachable; +// } // } // END rustc.never_match.SimplifyCfg-initial.after.mir @@ -97,12 +103,18 @@ pub fn main() { } // ... // } // bb1: { -// unreachable; -// } -// bb2: { // _0 = (); // StorageDead(_1); // return; // } +// bb2: { +// ... +// } +// bb3: { +// unreachable; +// } +// bb4: { +// unreachable; +// } // } // END rustc.never_match_disj_patterns.SimplifyCfg-initial.after.mir