diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 13768c1201791..066f652fa8924 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -287,6 +287,7 @@ pub enum ExprPrecedence { Struct, Gen, Await, + Unreachable, Err, } @@ -353,6 +354,7 @@ impl ExprPrecedence { | ExprPrecedence::TryBlock | ExprPrecedence::Gen | ExprPrecedence::Struct + | ExprPrecedence::Unreachable | ExprPrecedence::Err => PREC_PAREN, } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c4798887637f8..31be6b69d0d25 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -570,19 +570,9 @@ 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`. - let block = self.arena.alloc(hir::Block { - stmts: &[], - expr: None, - hir_id: self.next_id(), - rules: hir::BlockCheckMode::DefaultBlock, - span, - targeted_by_break: false, - }); self.arena.alloc(hir::Expr { hir_id: self.next_id(), - kind: hir::ExprKind::Loop(block, None, hir::LoopSource::Loop, span), + kind: hir::ExprKind::Unreachable, span, }) }; diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index ff154a009ed05..b2fa8dcb9cad2 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -919,14 +919,14 @@ impl<'a> State<'a> { self.maybe_print_comment(arm.pat.span.lo()); self.print_outer_attributes(&arm.attrs); self.print_pat(&arm.pat); - self.space(); if let Some(e) = &arm.guard { + self.space(); self.word_space("if"); self.print_expr(e, FixupContext::default()); - self.space(); } if let Some(body) = &arm.body { + self.space(); self.word_space("=>"); match &body.kind { @@ -951,7 +951,9 @@ impl<'a> State<'a> { } } } else { + // Empty body following a never pattern. self.word(","); + self.end(); // Close the ibox for the pattern. } self.end(); // Close enclosing cbox. } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ff50086ff8f98..66d6f007d3423 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1604,6 +1604,7 @@ impl Expr<'_> { ExprKind::Struct(..) => ExprPrecedence::Struct, ExprKind::Repeat(..) => ExprPrecedence::Repeat, ExprKind::Yield(..) => ExprPrecedence::Yield, + ExprKind::Unreachable => ExprPrecedence::Unreachable, ExprKind::Err(_) => ExprPrecedence::Err, } } @@ -1671,6 +1672,7 @@ impl Expr<'_> { | ExprKind::Yield(..) | ExprKind::Cast(..) | ExprKind::DropTemps(..) + | ExprKind::Unreachable | ExprKind::Err(_) => false, } } @@ -1706,7 +1708,10 @@ impl Expr<'_> { pub fn can_have_side_effects(&self) -> bool { match self.peel_drop_temps().kind { - ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) => false, + ExprKind::Path(_) + | ExprKind::Lit(_) + | ExprKind::OffsetOf(..) + | ExprKind::Unreachable => false, ExprKind::Type(base, _) | ExprKind::Unary(_, base) | ExprKind::Field(base, _) @@ -1931,6 +1936,10 @@ pub enum ExprKind<'hir> { /// A suspension point for coroutines (i.e., `yield `). Yield(&'hir Expr<'hir>, YieldSource), + /// The absent body of a match arm without a body, encountered in the presence of never + /// patterns. Statically known to be unreachable. + Unreachable, + /// A placeholder for an expression that wasn't syntactically well formed in some way. Err(rustc_span::ErrorGuaranteed), } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 27c834d848fc4..9792eedf8437e 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -804,7 +804,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::Yield(ref subexpression, _) => { visitor.visit_expr(subexpression); } - ExprKind::Lit(_) | ExprKind::Err(_) => {} + ExprKind::Lit(_) | ExprKind::Unreachable | ExprKind::Err(_) => {} } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9d0c5cb0f32b0..140e8811d74cd 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1519,6 +1519,9 @@ impl<'a> State<'a> { self.word_space("yield"); self.print_expr_maybe_paren(expr, parser::PREC_JUMP); } + hir::ExprKind::Unreachable => { + self.word("unreachable!()"); + } hir::ExprKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); @@ -1877,16 +1880,16 @@ impl<'a> State<'a> { self.ibox(0); self.print_outer_attributes(self.attrs(arm.hir_id)); self.print_pat(arm.pat); - self.space(); if let Some(ref g) = arm.guard { + self.space(); self.word_space("if"); self.print_expr(g); - self.space(); } - self.word_space("=>"); match arm.body.kind { hir::ExprKind::Block(blk, opt_label) => { + self.space(); + self.word_space("=>"); if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); @@ -1900,7 +1903,14 @@ impl<'a> State<'a> { self.word(","); } } + hir::ExprKind::Unreachable => { + // Empty body following a never pattern. + self.word(","); + self.end(); // close the ibox for the pattern + } _ => { + self.space(); + self.word_space("=>"); self.end(); // close the ibox for the pattern self.print_expr(arm.body); self.word(","); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 54664f38b19b6..321c183fec892 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -328,6 +328,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Match(discrim, arms, match_src) => { self.check_match(expr, discrim, arms, expected, match_src) } + ExprKind::Unreachable => { + self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); + self.tcx.types.never + } ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected), ExprKind::Block(body, _) => self.check_block_with_expected(body, expected), ExprKind::Call(callee, args) => self.check_call(expr, callee, args, expected), diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 3ecf6c5e428be..4529a0a4f94af 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -298,6 +298,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } hir::ExprKind::Continue(..) + | hir::ExprKind::Unreachable | hir::ExprKind::Lit(..) | hir::ExprKind::ConstBlock(..) | hir::ExprKind::OffsetOf(..) diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 1ce0240f7b830..3f820e130d3b6 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -352,6 +352,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | hir::ExprKind::AssignOp(..) | hir::ExprKind::Closure { .. } | hir::ExprKind::Ret(..) + | hir::ExprKind::Unreachable | hir::ExprKind::Become(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 0fed4ccc62a83..3293100254557 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -496,6 +496,9 @@ pub enum ExprKind<'tcx> { Yield { value: ExprId, }, + /// The absent body of a match arm without a body, encountered in the presence of never + /// patterns. Statically known to be unreachable. + Unreachable, } /// Represents the association of a field identifier and an expression. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 4847a7bea91d7..7ffe4dd382b1f 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -168,6 +168,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( OffsetOf { container: _, fields: _ } => {} ThreadLocalRef(_) => {} Yield { value } => visitor.visit_expr(&visitor.thir()[value]), + Unreachable => {} } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index f12e25db6fcd5..faa56c30f1b8c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -541,6 +541,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } + | ExprKind::Unreachable { .. } | ExprKind::Become { .. } | ExprKind::Literal { .. } | ExprKind::NamedConst { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c77f4a06d0569..1246cbf9ed0af 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -534,6 +534,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } + | ExprKind::Unreachable { .. } | ExprKind::Become { .. } | ExprKind::InlineAsm { .. } | ExprKind::PlaceTypeAscription { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs index e07ba6b6e9383..554da3c30e230 100644 --- a/compiler/rustc_mir_build/src/build/expr/category.rs +++ b/compiler/rustc_mir_build/src/build/expr/category.rs @@ -83,6 +83,7 @@ impl Category { | ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } + | ExprKind::Unreachable { .. } | ExprKind::Become { .. } => // FIXME(#27840) these probably want their own // category, like "nonterminating" diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 2978491d646e8..4a9df01267ebb 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -554,6 +554,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { resume.unit() } + ExprKind::Unreachable => { + this.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + this.cfg.start_new_block().unit() + } + // these are the cases that are more naturally handled by some other mode ExprKind::Unary { .. } | ExprKind::Binary { .. } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 8688c58906331..7a55278ddf089 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -366,6 +366,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | ExprKind::Return { .. } | ExprKind::Become { .. } | ExprKind::Yield { .. } + | ExprKind::Unreachable { .. } | ExprKind::Loop { .. } | ExprKind::Let { .. } | ExprKind::Match { .. } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 35adcc33480ca..7a8188a02ad9a 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -786,6 +786,7 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) }, hir::ExprKind::Yield(v, _) => ExprKind::Yield { value: self.mirror_expr(v) }, + hir::ExprKind::Unreachable => ExprKind::Unreachable, hir::ExprKind::Err(_) => unreachable!("cannot lower a `hir::ExprKind::Err` to THIR"), }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 1156e8be13e74..e32eb664d6ad4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -331,7 +331,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { } // These diverge. - Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true, + Become { .. } | Break { .. } | Continue { .. } | Return { .. } | Unreachable => true, // These are statements that evaluate to `()`. Assign { .. } | AssignOp { .. } | InlineAsm { .. } | Let { .. } => true, diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 267ea3aa3e12c..f43f931c6efb0 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -538,6 +538,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_expr(*value, depth_lvl + 2); print_indented!(self, "}", depth_lvl); } + Unreachable => { + print_indented!(self, "Unreachable", depth_lvl); + } } } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index e94d8c4c932f9..10fa9f8eb088f 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -319,10 +319,40 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { record_variants!( (self, e, e.kind, Id::Node(e.hir_id), hir, Expr, ExprKind), [ - ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, - DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, - Path, AddrOf, Break, Continue, Ret, Become, InlineAsm, OffsetOf, Struct, Repeat, - Yield, Err + ConstBlock, + Array, + Call, + MethodCall, + Tup, + Binary, + Unary, + Lit, + Cast, + Type, + DropTemps, + Let, + If, + Loop, + Match, + Closure, + Block, + Assign, + AssignOp, + Field, + Index, + Path, + AddrOf, + Break, + Continue, + Ret, + Become, + InlineAsm, + OffsetOf, + Struct, + Repeat, + Yield, + Unreachable, + Err ] ); hir_visit::walk_expr(self, e) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index f7c382bcd7a40..56a4cf94f55e0 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -440,6 +440,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::InlineAsm(..) | hir::ExprKind::OffsetOf(..) | hir::ExprKind::Type(..) + | hir::ExprKind::Unreachable | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {} @@ -1103,6 +1104,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::Lit(..) | hir::ExprKind::ConstBlock(..) + | hir::ExprKind::Unreachable | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::LangItem(..)) @@ -1396,6 +1398,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) | hir::ExprKind::Type(..) + | hir::ExprKind::Unreachable | hir::ExprKind::Err(_) => {} } } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 0455d6d4acba3..d87711f0a138f 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -207,6 +207,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { | ExprKind::Become(..) | ExprKind::Struct(..) | ExprKind::Repeat(..) + | ExprKind::Unreachable | ExprKind::Yield(..) => { self.items.push((ItemKind::NonAsm, span)); } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 2a2e53a81ed81..7be994fcda726 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -248,7 +248,10 @@ fn recurse_build<'tcx>( error(GenericConstantTooComplexSub::ClosureAndReturnNotSupported(node.span))? } // let expressions imply control flow - ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } => { + ExprKind::Match { .. } + | ExprKind::If { .. } + | ExprKind::Let { .. } + | ExprKind::Unreachable => { error(GenericConstantTooComplexSub::ControlFlowNotSupported(node.span))? } ExprKind::InlineAsm { .. } => { @@ -341,6 +344,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { | thir::ExprKind::Break { .. } | thir::ExprKind::Continue { .. } | thir::ExprKind::Return { .. } + | thir::ExprKind::Unreachable { .. } | thir::ExprKind::Become { .. } | thir::ExprKind::Array { .. } | thir::ExprKind::Tuple { .. } diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 62bc663191f60..e1f399d84db72 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -256,6 +256,7 @@ fn never_loop_expr<'tcx>( NeverLoopResult::Normal }, })), + ExprKind::Unreachable => NeverLoopResult::Diverging, ExprKind::OffsetOf(_, _) | ExprKind::Yield(_, _) | ExprKind::Closure { .. } diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index ee0fdb35313d5..63bc7f699c92d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -348,7 +348,8 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { ExprKind::Loop(_, _, _, _) | ExprKind::Path(_) | ExprKind::Struct(_, _, _) | - ExprKind::Type(_, _) => { + ExprKind::Type(_, _) | + ExprKind::Unreachable => { return; } } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 288df0fd663f0..b20c05dbcd77a 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -609,6 +609,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }, } }, + ExprKind::Unreachable => kind!("Unreachable"), ExprKind::Err(_) => kind!("Err(_)"), ExprKind::DropTemps(expr) => { bind!(self, expr); diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 6c40029a9de70..c889fb9c844c2 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -298,6 +298,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS | ExprKind::Let(..) | ExprKind::If(..) | ExprKind::Match(..) + | ExprKind::Unreachable | ExprKind::Closure { .. } | ExprKind::Field(..) | ExprKind::AddrOf(..) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 4fa93ad23c369..c1c1a25898c7a 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -348,6 +348,7 @@ impl HirEqInterExpr<'_, '_, '_> { }, (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup), (&ExprKind::Type(le, lt), &ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt), + (&ExprKind::Unreachable, &ExprKind::Unreachable) => true, (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re), (&ExprKind::Yield(le, _), &ExprKind::Yield(re, _)) => return self.eq_expr(le, re), ( @@ -381,6 +382,7 @@ impl HirEqInterExpr<'_, '_, '_> { | &ExprKind::Tup(..) | &ExprKind::Type(..) | &ExprKind::Unary(..) + | &ExprKind::Unreachable | &ExprKind::Yield(..) // --- Special cases that do not have a positive branch. @@ -915,7 +917,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { std::mem::discriminant(&lop).hash(&mut self.s); self.hash_expr(le); }, - ExprKind::Err(_) => {}, + ExprKind::Unreachable | ExprKind::Err(_) => {}, } } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index c86362c427ce2..e6c53c370f347 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -147,6 +147,7 @@ impl<'a> Sugg<'a> { | hir::ExprKind::Path(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::Ret(..) + | hir::ExprKind::Unreachable | hir::ExprKind::Become(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Tup(..) diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index ebc38e531fe6e..937183448e02c 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -692,6 +692,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( | ExprKind::Continue(_) | ExprKind::InlineAsm(_) | ExprKind::OffsetOf(..) + | ExprKind::Unreachable | ExprKind::Err(_) => (), } ControlFlow::Continue(()) diff --git a/tests/mir-opt/match/never_patterns.opt1.built.after.mir b/tests/mir-opt/match/never_patterns.opt1.built.after.mir new file mode 100644 index 0000000000000..3013f6a0bbf74 --- /dev/null +++ b/tests/mir-opt/match/never_patterns.opt1.built.after.mir @@ -0,0 +1,53 @@ +// MIR for `opt1` after built + +fn opt1(_1: &Result) -> &u32 { + debug res => _1; + let mut _0: &u32; + let mut _2: isize; + let _3: &u32; + let mut _4: !; + scope 1 { + debug x => _3; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb3]; + } + + bb1: { + falseEdge -> [real: bb4, imaginary: bb2]; + } + + bb2: { + StorageLive(_4); + unreachable; + } + + bb3: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb4: { + StorageLive(_3); + _3 = &(((*_1) as Ok).0: u32); + _0 = &(*_3); + StorageDead(_3); + goto -> bb7; + } + + bb5: { + unreachable; + } + + bb6: { + StorageDead(_4); + goto -> bb7; + } + + bb7: { + return; + } +} diff --git a/tests/mir-opt/match/never_patterns.rs b/tests/mir-opt/match/never_patterns.rs new file mode 100644 index 0000000000000..f7c54105dcb31 --- /dev/null +++ b/tests/mir-opt/match/never_patterns.rs @@ -0,0 +1,17 @@ +// skip-filecheck +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +// EMIT_MIR never_patterns.opt1.built.after.mir +fn opt1(res: &Result) -> &u32 { + match res { + Ok(x) => x, + Err(!), + } +} + +fn main() { + opt1(&Ok(0)); +} diff --git a/tests/pretty/never_patterns-ast.rs b/tests/pretty/never_patterns-ast.rs new file mode 100644 index 0000000000000..89e816430eaff --- /dev/null +++ b/tests/pretty/never_patterns-ast.rs @@ -0,0 +1,9 @@ +// pp-exact +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +fn foo(res: &Result) -> &u32 { match res { Ok(x) => x, Err(!), } } + +fn main() { foo(&Ok(0)); } diff --git a/tests/pretty/never_patterns-hir.pp b/tests/pretty/never_patterns-hir.pp new file mode 100644 index 0000000000000..59022aee4cb77 --- /dev/null +++ b/tests/pretty/never_patterns-hir.pp @@ -0,0 +1,16 @@ +// pretty-compare-only +// pretty-mode:hir +// pp-exact:never_patterns-hir.pp +#![feature(never_patterns)] +#![allow(incomplete_features)] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; + +enum Void { } + +fn foo<'_>(res: &'_ Result) + -> &'_ u32 { match res { Ok(x) => x, Err(!), } } + +fn main() { foo(&Ok(0)); } diff --git a/tests/pretty/never_patterns-hir.rs b/tests/pretty/never_patterns-hir.rs new file mode 100644 index 0000000000000..98993e216a741 --- /dev/null +++ b/tests/pretty/never_patterns-hir.rs @@ -0,0 +1,15 @@ +// pretty-compare-only +// pretty-mode:hir +// pp-exact:never_patterns-hir.pp +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +fn foo(res: &Result) -> &u32 { + match res { Ok(x) => x, Err(!), } +} + +fn main() { + foo(&Ok(0)); +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs index f7e4007b920d9..fa5648197f14e 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs @@ -30,7 +30,7 @@ fn never_match() -> u32 { let ptr: *const Void = std::ptr::null(); unsafe { match *ptr { ! }; + //~^ ERROR unreachable expression } println!(); - //~^ ERROR unreachable statement } diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr index c33a5855d5068..bdbf50d6e80ba 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr @@ -34,16 +34,14 @@ LL | println!(); | = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error: unreachable statement - --> $DIR/diverge-causes-unreachable-code.rs:34:5 +error: unreachable expression + --> $DIR/diverge-causes-unreachable-code.rs:32:22 | LL | match *ptr { ! }; - | ---------------- any code following this `match` expression is unreachable, as all arms diverge -LL | } -LL | println!(); - | ^^^^^^^^^^ unreachable statement - | - = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^ + | | + | unreachable expression + | any code following this expression is unreachable error: aborting due to 4 previous errors