From 809a253ed990d65c6000b5582cc0082f905d7ec7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 8 Feb 2024 00:09:31 +0100 Subject: [PATCH 1/6] Add tests --- ...s.opt1.UninhabitedEnumBranching.before.mir | 40 +++++++++++++++++++ tests/mir-opt/match/never_patterns.rs | 17 ++++++++ 2 files changed, 57 insertions(+) create mode 100644 tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir create mode 100644 tests/mir-opt/match/never_patterns.rs diff --git a/tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir b/tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir new file mode 100644 index 0000000000000..5568fc3561c38 --- /dev/null +++ b/tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir @@ -0,0 +1,40 @@ +// MIR for `opt1` before UninhabitedEnumBranching + +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: { + _2 = discriminant((*_1)); + switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; + } + + bb1: { + nop; + goto -> bb4; + } + + bb2: { + unreachable; + } + + bb3: { + StorageLive(_3); + _3 = &(((*_1) as Ok).0: u32); + _0 = &(*_3); + StorageDead(_3); + return; + } + + bb4: { + nop; + goto -> bb4; + } +} diff --git a/tests/mir-opt/match/never_patterns.rs b/tests/mir-opt/match/never_patterns.rs new file mode 100644 index 0000000000000..dfc41a28e9755 --- /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.UninhabitedEnumBranching.before.mir +fn opt1(res: &Result) -> &u32 { + match res { + Ok(x) => x, + Err(!), + } +} + +fn main() { + opt1(&Ok(0)); +} From c0c83c156ea96505ea4091a445f444c2c2a211a3 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 31 Jan 2024 22:30:26 +0100 Subject: [PATCH 2/6] Add `ExprKind::Unreachable` --- compiler/rustc_ast/src/util/parser.rs | 2 + compiler/rustc_hir/src/hir.rs | 11 +++++- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 11 +++++- compiler/rustc_hir_typeck/src/expr.rs | 4 ++ .../rustc_hir_typeck/src/expr_use_visitor.rs | 1 + .../src/mem_categorization.rs | 1 + compiler/rustc_middle/src/thir.rs | 3 ++ compiler/rustc_middle/src/thir/visit.rs | 1 + .../src/build/expr/as_place.rs | 1 + .../src/build/expr/as_rvalue.rs | 1 + .../src/build/expr/category.rs | 1 + .../rustc_mir_build/src/build/expr/into.rs | 5 +++ .../rustc_mir_build/src/check_unsafety.rs | 1 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 1 + .../src/thir/pattern/check_match.rs | 2 +- compiler/rustc_mir_build/src/thir/print.rs | 3 ++ compiler/rustc_passes/src/hir_stats.rs | 38 +++++++++++++++++-- compiler/rustc_passes/src/liveness.rs | 3 ++ compiler/rustc_passes/src/naked_functions.rs | 1 + compiler/rustc_ty_utils/src/consts.rs | 6 ++- 21 files changed, 90 insertions(+), 9 deletions(-) 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_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..e94651f73ca06 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*/"); @@ -1883,10 +1886,10 @@ impl<'a> State<'a> { self.print_expr(g); self.space(); } - self.word_space("=>"); match arm.body.kind { hir::ExprKind::Block(blk, opt_label) => { + self.word_space("=>"); if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); @@ -1900,7 +1903,13 @@ impl<'a> State<'a> { self.word(","); } } + hir::ExprKind::Unreachable => { + // Empty body following a never pattern. + self.end(); // close the ibox for the pattern + self.word(","); + } _ => { + 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 { .. } From 95d881dd346bf68d304cc1555e47f20bbd39a3b3 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 8 Feb 2024 00:23:08 +0100 Subject: [PATCH 3/6] Desugar never pattern arm to `ExprKind::Unreachable` --- compiler/rustc_ast_lowering/src/expr.rs | 12 +----------- ...tterns.opt1.UninhabitedEnumBranching.before.mir | 8 +------- .../diverge-causes-unreachable-code.rs | 2 +- .../diverge-causes-unreachable-code.stderr | 14 ++++++-------- 4 files changed, 9 insertions(+), 27 deletions(-) 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/tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir b/tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir index 5568fc3561c38..3407181b7effa 100644 --- a/tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir +++ b/tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir @@ -6,7 +6,6 @@ fn opt1(_1: &Result) -> &u32 { let mut _2: isize; let _3: &u32; let mut _4: !; - let mut _5: (); scope 1 { debug x => _3; } @@ -18,7 +17,7 @@ fn opt1(_1: &Result) -> &u32 { bb1: { nop; - goto -> bb4; + unreachable; } bb2: { @@ -32,9 +31,4 @@ fn opt1(_1: &Result) -> &u32 { StorageDead(_3); return; } - - bb4: { - nop; - goto -> bb4; - } } 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 From 97ad3cb34e2ea7d0a0d12b80ccba6e9deb85a26d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 8 Feb 2024 00:59:01 +0100 Subject: [PATCH 4/6] Fix pretty-printing --- .../rustc_ast_pretty/src/pprust/state/expr.rs | 6 ++++-- compiler/rustc_hir_pretty/src/lib.rs | 7 ++++--- tests/pretty/never_patterns-ast.rs | 9 +++++++++ tests/pretty/never_patterns-hir.pp | 16 ++++++++++++++++ tests/pretty/never_patterns-hir.rs | 15 +++++++++++++++ 5 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 tests/pretty/never_patterns-ast.rs create mode 100644 tests/pretty/never_patterns-hir.pp create mode 100644 tests/pretty/never_patterns-hir.rs 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_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e94651f73ca06..140e8811d74cd 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1880,15 +1880,15 @@ 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(); } 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); @@ -1905,10 +1905,11 @@ impl<'a> State<'a> { } hir::ExprKind::Unreachable => { // Empty body following a never pattern. - self.end(); // close the ibox for the 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); 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)); +} From 371785726cd87a1dd35a9326039070b122cbb893 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 8 Feb 2024 01:29:14 +0100 Subject: [PATCH 5/6] Fix clippy build --- src/tools/clippy/clippy_lints/src/loops/never_loop.rs | 1 + .../clippy_lints/src/matches/significant_drop_in_scrutinee.rs | 3 ++- src/tools/clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/eager_or_lazy.rs | 1 + src/tools/clippy/clippy_utils/src/hir_utils.rs | 4 +++- src/tools/clippy/clippy_utils/src/sugg.rs | 1 + src/tools/clippy/clippy_utils/src/visitors.rs | 1 + 7 files changed, 10 insertions(+), 2 deletions(-) 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(()) From 065ccb6ea097dc31fdd7244dcd2b91404b94d19c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 8 Feb 2024 02:57:38 +0100 Subject: [PATCH 6/6] Test built MIR without optimizations --- ...ir => never_patterns.opt1.built.after.mir} | 27 ++++++++++++++++--- tests/mir-opt/match/never_patterns.rs | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) rename tests/mir-opt/match/{never_patterns.opt1.UninhabitedEnumBranching.before.mir => never_patterns.opt1.built.after.mir} (53%) diff --git a/tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir b/tests/mir-opt/match/never_patterns.opt1.built.after.mir similarity index 53% rename from tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir rename to tests/mir-opt/match/never_patterns.opt1.built.after.mir index 3407181b7effa..3013f6a0bbf74 100644 --- a/tests/mir-opt/match/never_patterns.opt1.UninhabitedEnumBranching.before.mir +++ b/tests/mir-opt/match/never_patterns.opt1.built.after.mir @@ -1,4 +1,4 @@ -// MIR for `opt1` before UninhabitedEnumBranching +// MIR for `opt1` after built fn opt1(_1: &Result) -> &u32 { debug res => _1; @@ -11,24 +11,43 @@ fn opt1(_1: &Result) -> &u32 { } bb0: { + PlaceMention(_1); _2 = discriminant((*_1)); - switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; + switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb3]; } bb1: { - nop; - unreachable; + 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 index dfc41a28e9755..f7c54105dcb31 100644 --- a/tests/mir-opt/match/never_patterns.rs +++ b/tests/mir-opt/match/never_patterns.rs @@ -4,7 +4,7 @@ enum Void {} -// EMIT_MIR never_patterns.opt1.UninhabitedEnumBranching.before.mir +// EMIT_MIR never_patterns.opt1.built.after.mir fn opt1(res: &Result) -> &u32 { match res { Ok(x) => x,