diff --git a/compiler/rustc_hir_typeck/src/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs index b2c929f715234..e778846da4bad 100644 --- a/compiler/rustc_hir_typeck/src/diverges.rs +++ b/compiler/rustc_hir_typeck/src/diverges.rs @@ -1,3 +1,4 @@ +use rustc_hir::HirId; use rustc_span::Span; use std::{cmp, ops}; @@ -72,5 +73,6 @@ impl Diverges { pub enum DivergeReason { AllArmsDiverge, NeverPattern, + UninhabitedExpr(HirId), Other, } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 029697fa52972..54a82f67a26d0 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -244,17 +244,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // diverging expression (e.g. it arose from desugaring of `try { return }`), // we skip issuing a warning because it is autogenerated code. ExprKind::Call(..) if expr.span.is_desugaring(DesugaringKind::TryBlock) => {} - ExprKind::Call(callee, _) => self.warn_if_unreachable(expr.hir_id, callee.span, "call"), + ExprKind::Call(callee, _) => { + let emit_warning = if let ExprKind::Path(ref qpath) = callee.kind { + // Do not emit a warning for a call to a constructor. + let res = self.typeck_results.borrow().qpath_res(qpath, callee.hir_id); + !matches!(res, Res::Def(DefKind::Ctor(..), _)) + } else { + true + }; + if emit_warning { + self.warn_if_unreachable(expr.hir_id, callee.span, "call") + } + } ExprKind::MethodCall(segment, ..) => { self.warn_if_unreachable(expr.hir_id, segment.ident.span, "call") } + // allow field access when the struct and the field are both uninhabited + ExprKind::Field(..) + if matches!( + self.diverges.get(), + Diverges::Always(DivergeReason::UninhabitedExpr(_), _) + ) && self.ty_is_uninhabited(ty) => {} _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"), } - // Any expression that produces a value of type `!` must have diverged - if ty.is_never() { - self.diverges - .set(self.diverges.get() | Diverges::Always(DivergeReason::Other, expr.span)); + if !self.diverges.get().is_always() { + if ty.is_never() { + // Any expression that produces a value of type `!` must have diverged. + self.diverges.set(Diverges::Always(DivergeReason::Other, expr.span)); + } else if expr_may_be_uninhabited(expr) && self.ty_is_uninhabited(ty) { + // This expression produces a value of uninhabited type. + // This means it has diverged somehow. + self.diverges + .set(Diverges::Always(DivergeReason::UninhabitedExpr(expr.hir_id), expr.span)); + } } // Record the type, which applies it effects. @@ -271,6 +294,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + fn ty_is_uninhabited(&self, ty: Ty<'tcx>) -> bool { + let ty = self.resolve_vars_if_possible(ty); + // Freshen the type as `is_inhabited_from` may call a query on `ty`. + let ty = self.freshen(ty); + !ty.is_inhabited_from(self.tcx, self.parent_module, self.param_env) + } + #[instrument(skip(self, expr), level = "debug")] fn check_expr_kind( &self, @@ -3451,3 +3481,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.types.usize } } + +fn expr_may_be_uninhabited(expr: &hir::Expr<'_>) -> bool { + match expr.kind { + ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Cast(..) + | ExprKind::Unary(hir::UnOp::Deref, _) + | ExprKind::Field(..) + | ExprKind::Path(..) + | ExprKind::Struct(..) => true, + ExprKind::ConstBlock(..) + | ExprKind::Array(..) + | ExprKind::Tup(..) + | ExprKind::Binary(..) + | ExprKind::Unary(hir::UnOp::Neg | hir::UnOp::Not, _) + | ExprKind::Lit(..) + | ExprKind::Type(..) + | ExprKind::DropTemps(..) + | ExprKind::OffsetOf(..) + | ExprKind::Let(..) + | ExprKind::If(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::Closure(..) + | ExprKind::Block(..) + | ExprKind::Assign(..) + | ExprKind::AssignOp(..) + | ExprKind::Index(..) + | ExprKind::AddrOf(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::Become(..) + | ExprKind::InlineAsm(..) + | ExprKind::Repeat(..) + | ExprKind::Yield(..) + | ExprKind::Err(_) => false, + } +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index bf12864ec7f1c..a2dc63c4cab6b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -41,6 +41,7 @@ use rustc_trait_selection::traits::{ self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt, }; +use std::borrow::Cow; use std::collections::hash_map::Entry; use std::slice; @@ -63,16 +64,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.diverges.set(Diverges::WarnedAlways); + if matches!(reason, DivergeReason::UninhabitedExpr(_)) { + if let Some(impl_of) = self.tcx.impl_of_method(self.body_id.to_def_id()) { + if self.tcx.has_attr(impl_of, sym::automatically_derived) { + // Built-in derives are generated before typeck, + // so they may contain unreachable code if there are uninhabited types + return; + } + } + } + debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); let msg = format!("unreachable {kind}"); self.tcx().node_span_lint(lint::builtin::UNREACHABLE_CODE, id, span, msg.clone(), |lint| { - let label = match reason { + let label: Cow<'_, _> = match reason { DivergeReason::AllArmsDiverge => { "any code following this `match` expression is unreachable, as all arms diverge" + .into() + } + DivergeReason::NeverPattern => { + "any code following a never pattern is unreachable".into() } - DivergeReason::NeverPattern => "any code following a never pattern is unreachable", - DivergeReason::Other => "any code following this expression is unreachable", + DivergeReason::UninhabitedExpr(hir_id) => format!( + "this expression has type `{}`, which is uninhabited", + self.typeck_results.borrow().node_type(hir_id) + ) + .into(), + DivergeReason::Other => "any code following this expression is unreachable".into(), }; lint.span_label(span, msg).span_label(orig_span, label); }) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 05e7c5b2b4188..706f90e8aeeeb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -49,6 +49,8 @@ pub struct FnCtxt<'a, 'tcx> { /// eventually). pub(super) param_env: ty::ParamEnv<'tcx>, + pub(super) parent_module: DefId, + /// If `Some`, this stores coercion information for returned /// expressions. If `None`, this is in a context where return is /// inappropriate, such as a const expression. @@ -127,6 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { FnCtxt { body_id, param_env, + parent_module: root_ctxt.tcx.parent_module_from_def_id(body_id).to_def_id(), ret_coercion: None, ret_coercion_span: Cell::new(None), coroutine_types: None, diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index c571ac507248d..95188105ce3ef 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -90,27 +90,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod), // `t` may be a projection, for which `inhabited_predicate` returns a `GenericType`. As // we have a param_env available, we can do better. - Self::GenericType(t) => { - let normalized_pred = tcx - .try_normalize_erasing_regions(param_env, t) - .map_or(self, |t| t.inhabited_predicate(tcx)); - match normalized_pred { - // We don't have more information than we started with, so consider inhabited. - Self::GenericType(_) => Ok(true), - pred => { - // A type which is cyclic when monomorphized can happen here since the - // layout error would only trigger later. See e.g. `tests/ui/sized/recursive-type-2.rs`. - if eval_stack.contains(&t) { - return Ok(true); // Recover; this will error later. - } - eval_stack.push(t); - let ret = - pred.apply_inner(tcx, param_env, eval_stack, in_module, reveal_opaque); - eval_stack.pop(); - ret - } - } - } + Self::GenericType(_) => Ok(true), Self::OpaqueType(key) => match reveal_opaque(key) { // Unknown opaque is assumed inhabited. None => Ok(true), diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 125084f47505e..83fc5dec723c9 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -94,7 +94,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; use rustc_index::IndexVec; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; +use rustc_middle::ty::{self, RootVariableMinCaptureList, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{BytePos, Span}; @@ -118,8 +118,8 @@ rustc_index::newtype_index! { #[derive(Copy, Clone, PartialEq, Debug)] enum LiveNodeKind { UpvarNode(Span), - ExprNode(Span, HirId), - VarDefNode(Span, HirId), + ExprNode(Span), + VarDefNode(Span), ClosureNode, ExitNode, ErrNode, @@ -129,8 +129,8 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String { let sm = tcx.sess.source_map(); match lnk { UpvarNode(s) => format!("Upvar node [{}]", sm.span_to_diagnostic_string(s)), - ExprNode(s, _) => format!("Expr node [{}]", sm.span_to_diagnostic_string(s)), - VarDefNode(s, _) => format!("Var def node [{}]", sm.span_to_diagnostic_string(s)), + ExprNode(s) => format!("Expr node [{}]", sm.span_to_diagnostic_string(s)), + VarDefNode(s) => format!("Var def node [{}]", sm.span_to_diagnostic_string(s)), ClosureNode => "Closure node".to_owned(), ExitNode => "Exit node".to_owned(), ErrNode => "Error node".to_owned(), @@ -331,7 +331,7 @@ impl<'tcx> IrMaps<'tcx> { let shorthand_field_ids = self.collect_shorthand_field_ids(pat); pat.each_binding(|_, hir_id, _, ident| { - self.add_live_node_for_node(hir_id, VarDefNode(ident.span, hir_id)); + self.add_live_node_for_node(hir_id, VarDefNode(ident.span)); self.add_variable(Local(LocalInfo { id: hir_id, name: ident.name, @@ -345,7 +345,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) { self.add_from_pat(local.pat); if local.els.is_some() { - self.add_live_node_for_node(local.hir_id, ExprNode(local.span, local.hir_id)); + self.add_live_node_for_node(local.hir_id, ExprNode(local.span)); } intravisit::walk_local(self, local); } @@ -377,13 +377,13 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => { debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res); if let Res::Local(_var_hir_id) = path.res { - self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); } } hir::ExprKind::Closure(closure) => { // Interesting control flow (for loops can contain labeled // breaks or continues) - self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); // Make a live_node for each mentioned variable, with the span // being the location that the variable is used. This results @@ -409,15 +409,15 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Yield(..) => { - self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); } hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => { - self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); } // Inline assembly may contain labels. hir::ExprKind::InlineAsm(asm) if asm.contains_label() => { - self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); intravisit::walk_expr(self, expr); } @@ -1297,52 +1297,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn check_is_ty_uninhabited(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode { let ty = self.typeck_results.expr_ty(expr); let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id(); - if ty.is_inhabited_from(self.ir.tcx, m, self.param_env) { - return succ; - } - match self.ir.lnks[succ] { - LiveNodeKind::ExprNode(succ_span, succ_id) => { - self.warn_about_unreachable(expr.span, ty, succ_span, succ_id, "expression"); - } - LiveNodeKind::VarDefNode(succ_span, succ_id) => { - self.warn_about_unreachable(expr.span, ty, succ_span, succ_id, "definition"); - } - _ => {} - }; - self.exit_ln - } - - fn warn_about_unreachable<'desc>( - &mut self, - orig_span: Span, - orig_ty: Ty<'tcx>, - expr_span: Span, - expr_id: HirId, - descr: &'desc str, - ) { - if !orig_ty.is_never() { - // Unreachable code warnings are already emitted during type checking. - // However, during type checking, full type information is being - // calculated but not yet available, so the check for diverging - // expressions due to uninhabited result types is pretty crude and - // only checks whether ty.is_never(). Here, we have full type - // information available and can issue warnings for less obviously - // uninhabited types (e.g. empty enums). The check above is used so - // that we do not emit the same warning twice if the uninhabited type - // is indeed `!`. - - self.ir.tcx.emit_node_span_lint( - lint::builtin::UNREACHABLE_CODE, - expr_id, - expr_span, - errors::UnreachableDueToUninhabited { - expr: expr_span, - orig: orig_span, - descr, - ty: orig_ty, - }, - ); - } + if ty.is_inhabited_from(self.ir.tcx, m, self.param_env) { succ } else { self.exit_ln } } } diff --git a/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff b/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff index f50413656049f..a45cad0a3c5dd 100644 --- a/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff +++ b/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff @@ -3,21 +3,22 @@ fn main() -> () { let mut _0: (); - let _1: char; - let mut _2: main::InvalidChar; - let mut _4: E; - let mut _5: main::InvalidTag; - let mut _7: Empty; - let mut _8: main::NoVariants; + let mut _1: !; + let _2: char; + let mut _3: main::InvalidChar; + let mut _5: E; + let mut _6: main::InvalidTag; + let mut _8: Empty; + let mut _9: main::NoVariants; scope 1 { - debug _invalid_char => _1; - let _3: [E; 1]; + debug _invalid_char => _2; + let _4: [E; 1]; scope 2 { - debug _invalid_tag => _3; - let _6: [Empty; 1]; + debug _invalid_tag => _4; + let _7: [Empty; 1]; scope 3 { debug _enum_without_variants => const [ZeroSized: Empty]; - let _9: main::Str<"���">; + let _10: main::Str<"���">; scope 4 { debug _non_utf8_str => const Str::<"���">; } @@ -26,34 +27,33 @@ } bb0: { - StorageLive(_1); StorageLive(_2); - _2 = InvalidChar { int: const 1114113_u32 }; - _1 = (_2.1: char); - StorageDead(_2); StorageLive(_3); + _3 = InvalidChar { int: const 1114113_u32 }; + _2 = (_3.1: char); + StorageDead(_3); StorageLive(_4); StorageLive(_5); - _5 = InvalidTag { int: const 4_u32 }; - _4 = (_5.1: E); - _3 = [move _4]; - StorageDead(_4); + StorageLive(_6); + _6 = InvalidTag { int: const 4_u32 }; + _5 = (_6.1: E); + _4 = [move _5]; StorageDead(_5); + StorageDead(_6); nop; nop; - StorageLive(_8); - _8 = NoVariants { int: const 0_u32 }; - nop; + StorageLive(_9); + _9 = NoVariants { int: const 0_u32 }; nop; nop; - StorageDead(_8); nop; + StorageDead(_9); nop; nop; nop; - StorageDead(_3); - StorageDead(_1); - return; + StorageDead(_4); + StorageDead(_2); + unreachable; } } diff --git a/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff index 6e5ad8d6b81ac..ccd20f7bfcb2d 100644 --- a/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff +++ b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff @@ -3,24 +3,25 @@ fn main() -> () { let mut _0: (); - let _1: char; - let mut _2: main::InvalidChar; - let mut _4: E; - let mut _5: main::InvalidTag; - let mut _7: Empty; - let mut _8: main::NoVariants; + let mut _1: !; + let _2: char; + let mut _3: main::InvalidChar; + let mut _5: E; + let mut _6: main::InvalidTag; + let mut _8: Empty; + let mut _9: main::NoVariants; scope 1 { - debug _invalid_char => _1; - let _3: [E; 1]; + debug _invalid_char => _2; + let _4: [E; 1]; scope 2 { - debug _invalid_tag => _3; - let _6: [Empty; 1]; + debug _invalid_tag => _4; + let _7: [Empty; 1]; scope 3 { -- debug _enum_without_variants => _6; +- debug _enum_without_variants => _7; + debug _enum_without_variants => const [ZeroSized: Empty]; - let _9: main::Str<"���">; + let _10: main::Str<"���">; scope 4 { -- debug _non_utf8_str => _9; +- debug _non_utf8_str => _10; + debug _non_utf8_str => const Str::<"���">; } } @@ -28,43 +29,41 @@ } bb0: { - StorageLive(_1); StorageLive(_2); - _2 = InvalidChar { int: const 1114113_u32 }; - _1 = (_2.1: char); - StorageDead(_2); StorageLive(_3); + _3 = InvalidChar { int: const 1114113_u32 }; + _2 = (_3.1: char); + StorageDead(_3); StorageLive(_4); StorageLive(_5); - _5 = InvalidTag { int: const 4_u32 }; - _4 = (_5.1: E); - _3 = [move _4]; - StorageDead(_4); + StorageLive(_6); + _6 = InvalidTag { int: const 4_u32 }; + _5 = (_6.1: E); + _4 = [move _5]; StorageDead(_5); -- StorageLive(_6); + StorageDead(_6); - StorageLive(_7); +- StorageLive(_8); + nop; + nop; - StorageLive(_8); - _8 = NoVariants { int: const 0_u32 }; -- _7 = (_8.1: Empty); -- _6 = [move _7]; -- StorageDead(_7); -+ nop; + StorageLive(_9); + _9 = NoVariants { int: const 0_u32 }; +- _8 = (_9.1: Empty); +- _7 = [move _8]; +- StorageDead(_8); + nop; + nop; - StorageDead(_8); -- StorageLive(_9); -- _0 = const (); -- StorageDead(_9); -- StorageDead(_6); + nop; + StorageDead(_9); +- StorageLive(_10); +- StorageDead(_10); +- StorageDead(_7); + nop; + nop; + nop; - StorageDead(_3); - StorageDead(_1); - return; + StorageDead(_4); + StorageDead(_2); + unreachable; } } diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff index 2bbb830fc7790..78198f96ea72e 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff @@ -3,45 +3,46 @@ fn h() -> () { let mut _0: (); - let _1: (!, !); -+ let mut _2: fn() -> ! {sleep}; + let mut _1: !; + let _2: (!, !); ++ let mut _3: fn() -> ! {sleep}; + scope 1 (inlined call_twice:: ! {sleep}>) { -+ debug f => _2; -+ let mut _3: &fn() -> ! {sleep}; -+ let _4: !; -+ let mut _5: &fn() -> ! {sleep}; ++ debug f => _3; ++ let mut _4: &fn() -> ! {sleep}; ++ let _5: !; ++ let mut _6: &fn() -> ! {sleep}; + scope 2 { -+ debug a => _4; -+ let _6: !; ++ debug a => _5; ++ let _7: !; + scope 3 { -+ debug b => _6; ++ debug b => _7; + } + } + } bb0: { - StorageLive(_1); -- _1 = call_twice:: ! {sleep}>(sleep) -> unwind unreachable; -+ StorageLive(_2); -+ _2 = sleep; -+ StorageLive(_4); -+ StorageLive(_6); + StorageLive(_2); +- _2 = call_twice:: ! {sleep}>(sleep) -> unwind unreachable; + StorageLive(_3); -+ _3 = &_2; -+ _4 = ! {sleep} as Fn<()>>::call(move _3, const ()) -> [return: bb1, unwind unreachable]; ++ _3 = sleep; ++ StorageLive(_5); ++ StorageLive(_7); ++ StorageLive(_4); ++ _4 = &_3; ++ _5 = ! {sleep} as Fn<()>>::call(move _4, const ()) -> [return: bb1, unwind unreachable]; + } + + bb1: { -+ StorageDead(_3); -+ StorageLive(_5); -+ _5 = &_2; -+ _6 = ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb2, unwind unreachable]; ++ StorageDead(_4); ++ StorageLive(_6); ++ _6 = &_3; ++ _7 = ! {sleep} as Fn<()>>::call(move _6, const ()) -> [return: bb2, unwind unreachable]; + } + + bb2: { -+ StorageDead(_5); -+ _1 = (_4, _6); -+ drop(_2) -> [return: bb3, unwind unreachable]; ++ StorageDead(_6); ++ _2 = (_5, _7); ++ drop(_3) -> [return: bb3, unwind unreachable]; + } + + bb3: { diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff index bc4f2d24df0b5..1d57946a812c4 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff @@ -3,50 +3,51 @@ fn h() -> () { let mut _0: (); - let _1: (!, !); -+ let mut _2: fn() -> ! {sleep}; + let mut _1: !; + let _2: (!, !); ++ let mut _3: fn() -> ! {sleep}; + scope 1 (inlined call_twice:: ! {sleep}>) { -+ debug f => _2; -+ let mut _3: &fn() -> ! {sleep}; -+ let _4: !; -+ let mut _5: &fn() -> ! {sleep}; -+ let mut _7: !; ++ debug f => _3; ++ let mut _4: &fn() -> ! {sleep}; ++ let _5: !; ++ let mut _6: &fn() -> ! {sleep}; ++ let mut _8: !; + scope 2 { -+ debug a => _4; -+ let _6: !; ++ debug a => _5; ++ let _7: !; + scope 3 { -+ debug b => _6; ++ debug b => _7; + } + } + } bb0: { - StorageLive(_1); -- _1 = call_twice:: ! {sleep}>(sleep) -> unwind continue; -+ StorageLive(_2); -+ _2 = sleep; -+ StorageLive(_6); -+ StorageLive(_4); + StorageLive(_2); +- _2 = call_twice:: ! {sleep}>(sleep) -> unwind continue; + StorageLive(_3); -+ _3 = &_2; -+ _4 = ! {sleep} as Fn<()>>::call(move _3, const ()) -> [return: bb1, unwind: bb5]; ++ _3 = sleep; ++ StorageLive(_7); ++ StorageLive(_5); ++ StorageLive(_4); ++ _4 = &_3; ++ _5 = ! {sleep} as Fn<()>>::call(move _4, const ()) -> [return: bb1, unwind: bb5]; + } + + bb1: { -+ StorageDead(_3); -+ StorageLive(_5); -+ _5 = &_2; -+ _6 = ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb2, unwind: bb4]; ++ StorageDead(_4); ++ StorageLive(_6); ++ _6 = &_3; ++ _7 = ! {sleep} as Fn<()>>::call(move _6, const ()) -> [return: bb2, unwind: bb4]; + } + + bb2: { ++ StorageDead(_6); ++ StorageLive(_8); ++ _8 = move _5; ++ _2 = (move _8, _7); ++ StorageDead(_8); + StorageDead(_5); -+ StorageLive(_7); -+ _7 = move _4; -+ _1 = (move _7, _6); -+ StorageDead(_7); -+ StorageDead(_4); -+ drop(_2) -> [return: bb3, unwind continue]; ++ drop(_3) -> [return: bb3, unwind continue]; + } + + bb3: { @@ -54,11 +55,11 @@ + } + + bb4 (cleanup): { -+ drop(_4) -> [return: bb5, unwind terminate(cleanup)]; ++ drop(_5) -> [return: bb5, unwind terminate(cleanup)]; + } + + bb5 (cleanup): { -+ drop(_2) -> [return: bb6, unwind terminate(cleanup)]; ++ drop(_3) -> [return: bb6, unwind terminate(cleanup)]; + } + + bb6 (cleanup): { diff --git a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir index 51514ba5e5d90..03db0d2b1162f 100644 --- a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir +++ b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir @@ -3,11 +3,12 @@ fn process_void(_1: *const Void) -> () { debug input => _1; let mut _0: (); + let _2: &Void; scope 1 { - debug _input => _1; + debug _input => _2; } bb0: { - return; + unreachable; } } diff --git a/tests/ui/consts/const_discriminant.rs b/tests/ui/consts/const_discriminant.rs index 49d7af1b460b5..2499d36d115d1 100644 --- a/tests/ui/consts/const_discriminant.rs +++ b/tests/ui/consts/const_discriminant.rs @@ -14,7 +14,12 @@ const TEST_A: Discriminant = discriminant(&Test::A(5)); const TEST_A_OTHER: Discriminant = discriminant(&Test::A(17)); const TEST_B: Discriminant = discriminant(&Test::B); -enum Void {} +mod private { + enum PrivateVoid {} + pub struct VoidS(PrivateVoid); + pub enum Void { X(VoidS) } +} +use private::Void; enum SingleVariant { V, diff --git a/tests/ui/consts/issue-64506.rs b/tests/ui/consts/issue-64506.rs index 096d29cbe499c..f152434ff4257 100644 --- a/tests/ui/consts/issue-64506.rs +++ b/tests/ui/consts/issue-64506.rs @@ -6,7 +6,14 @@ pub struct ChildStdin { } #[derive(Copy, Clone)] -enum AnonPipe {} +struct AnonPipe(private::Void); + +mod private { + #[derive(Copy, Clone)] + pub struct Void(PrivateVoid); + #[derive(Copy, Clone)] + enum PrivateVoid {} +} const FOO: () = { union Foo { diff --git a/tests/ui/consts/issue-64506.stderr b/tests/ui/consts/issue-64506.stderr index 4cc2b71374100..3c6f2c31deeb5 100644 --- a/tests/ui/consts/issue-64506.stderr +++ b/tests/ui/consts/issue-64506.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation of constant value failed - --> $DIR/issue-64506.rs:16:22 + --> $DIR/issue-64506.rs:23:22 | LL | let x = unsafe { Foo { b: () }.a }; - | ^^^^^^^^^^^^^^^ constructing invalid value at .inner: encountered a value of uninhabited type `AnonPipe` + | ^^^^^^^^^^^^^^^ constructing invalid value at .inner.0.0: encountered a value of uninhabited type `PrivateVoid` error: aborting due to 1 previous error diff --git a/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs b/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs index e0d1d515deb02..09f567606972f 100644 --- a/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs +++ b/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs @@ -1,9 +1,8 @@ -//@ check-pass #![feature(never_type)] #[derive(Copy, Clone)] pub enum E { A(!), } pub union U { u: (), e: E, } -pub const C: () = { +pub const C: () = { //~ ERROR evaluation of constant value failed let E::A(ref a) = unsafe { &(&U { u: () }).e}; }; diff --git a/tests/ui/consts/let-irrefutable-pattern-ice-120337.stderr b/tests/ui/consts/let-irrefutable-pattern-ice-120337.stderr new file mode 100644 index 0000000000000..5bf7fb5ae8d77 --- /dev/null +++ b/tests/ui/consts/let-irrefutable-pattern-ice-120337.stderr @@ -0,0 +1,12 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/let-irrefutable-pattern-ice-120337.rs:5:19 + | +LL | pub const C: () = { + | ___________________^ +LL | | let E::A(ref a) = unsafe { &(&U { u: () }).e}; +LL | | }; + | |_^ entering unreachable code + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/coroutine/issue-93161.rs b/tests/ui/coroutine/issue-93161.rs index 0c7be8407d0b9..a3bae0b691d44 100644 --- a/tests/ui/coroutine/issue-93161.rs +++ b/tests/ui/coroutine/issue-93161.rs @@ -38,8 +38,8 @@ async fn includes_never(crash: bool, x: u32) -> u32 { } #[allow(unused)] let bad = never(); - result *= async { x + x }.await; - drop(bad); + result *= async { x + x }.await; //~ unreachable statement + drop(bad); //~ unreachable call result } diff --git a/tests/ui/coroutine/issue-93161.stderr b/tests/ui/coroutine/issue-93161.stderr new file mode 100644 index 0000000000000..bd122f73cc79d --- /dev/null +++ b/tests/ui/coroutine/issue-93161.stderr @@ -0,0 +1,20 @@ +warning: unreachable statement + --> $DIR/issue-93161.rs:41:5 + | +LL | let bad = never(); + | ------- this expression has type `Never`, which is uninhabited +LL | result *= async { x + x }.await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | + = note: `#[warn(unreachable_code)]` on by default + +warning: unreachable call + --> $DIR/issue-93161.rs:42:5 + | +LL | drop(bad); + | ^^^^ --- this expression has type `Never`, which is uninhabited + | | + | unreachable call + +warning: 2 warnings emitted + diff --git a/tests/ui/deriving/deriving-all-codegen.stderr b/tests/ui/deriving/deriving-all-codegen.check.stderr similarity index 95% rename from tests/ui/deriving/deriving-all-codegen.stderr rename to tests/ui/deriving/deriving-all-codegen.check.stderr index 503f0cae73b69..a8b9896ef8116 100644 --- a/tests/ui/deriving/deriving-all-codegen.stderr +++ b/tests/ui/deriving/deriving-all-codegen.check.stderr @@ -1,5 +1,5 @@ warning: byte slice in a packed struct that derives a built-in trait - --> $DIR/deriving-all-codegen.rs:80:24 + --> $DIR/deriving-all-codegen.rs:81:24 | LL | #[derive(Debug, Hash)] | ----- in this derive macro expansion @@ -14,7 +14,7 @@ LL | struct PackedUnsizedU8([u8]); = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) warning: byte slice in a packed struct that derives a built-in trait - --> $DIR/deriving-all-codegen.rs:80:24 + --> $DIR/deriving-all-codegen.rs:81:24 | LL | #[derive(Debug, Hash)] | ---- in this derive macro expansion @@ -31,7 +31,7 @@ warning: 2 warnings emitted Future incompatibility report: Future breakage diagnostic: warning: byte slice in a packed struct that derives a built-in trait - --> $DIR/deriving-all-codegen.rs:80:24 + --> $DIR/deriving-all-codegen.rs:81:24 | LL | #[derive(Debug, Hash)] | ----- in this derive macro expansion @@ -47,7 +47,7 @@ LL | struct PackedUnsizedU8([u8]); Future breakage diagnostic: warning: byte slice in a packed struct that derives a built-in trait - --> $DIR/deriving-all-codegen.rs:80:24 + --> $DIR/deriving-all-codegen.rs:81:24 | LL | #[derive(Debug, Hash)] | ---- in this derive macro expansion diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs index 498930fc0c664..bf6defacbdf4c 100644 --- a/tests/ui/deriving/deriving-all-codegen.rs +++ b/tests/ui/deriving/deriving-all-codegen.rs @@ -1,5 +1,6 @@ //@ check-pass -//@ compile-flags: -Zunpretty=expanded +//@ revisions: check unpretty +//@ [unpretty] compile-flags: -Zunpretty=expanded //@ edition:2021 // // This test checks the code generated for all[*] the builtin derivable traits diff --git a/tests/ui/deriving/deriving-all-codegen.unpretty.stderr b/tests/ui/deriving/deriving-all-codegen.unpretty.stderr new file mode 100644 index 0000000000000..a8b9896ef8116 --- /dev/null +++ b/tests/ui/deriving/deriving-all-codegen.unpretty.stderr @@ -0,0 +1,63 @@ +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:81:24 + | +LL | #[derive(Debug, Hash)] + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:81:24 + | +LL | #[derive(Debug, Hash)] + | ---- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 2 warnings emitted + +Future incompatibility report: Future breakage diagnostic: +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:81:24 + | +LL | #[derive(Debug, Hash)] + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:81:24 + | +LL | #[derive(Debug, Hash)] + | ---- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.unpretty.stdout similarity index 99% rename from tests/ui/deriving/deriving-all-codegen.stdout rename to tests/ui/deriving/deriving-all-codegen.unpretty.stdout index a027452797554..b4bb5e20bdbfd 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.unpretty.stdout @@ -1,6 +1,7 @@ #![feature(prelude_import)] //@ check-pass -//@ compile-flags: -Zunpretty=expanded +//@ revisions: check unpretty +//@ [unpretty] compile-flags: -Zunpretty=expanded //@ edition:2021 // // This test checks the code generated for all[*] the builtin derivable traits diff --git a/tests/ui/enum-discriminant/issue-46519.rs b/tests/ui/enum-discriminant/issue-46519.rs index e5f0138c95cee..c6a31ad2dd3ba 100644 --- a/tests/ui/enum-discriminant/issue-46519.rs +++ b/tests/ui/enum-discriminant/issue-46519.rs @@ -6,7 +6,7 @@ #[test] #[should_panic(expected = "creating inhabited type")] fn test() { - FontLanguageOverride::system_font(SystemFont::new()); + FontLanguageOverride::system_font(SystemFont::new()); //~ unreachable call } pub enum FontLanguageOverride { diff --git a/tests/ui/enum-discriminant/issue-46519.stderr b/tests/ui/enum-discriminant/issue-46519.stderr new file mode 100644 index 0000000000000..54da8fc0b8e2c --- /dev/null +++ b/tests/ui/enum-discriminant/issue-46519.stderr @@ -0,0 +1,12 @@ +warning: unreachable call + --> $DIR/issue-46519.rs:9:5 + | +LL | FontLanguageOverride::system_font(SystemFont::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ----------------- this expression has type `SystemFont`, which is uninhabited + | | + | unreachable call + | + = note: `#[warn(unreachable_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/issues/issue-46855.rs b/tests/ui/issues/issue-46855.rs index acea242046fde..432a3b7f73179 100644 --- a/tests/ui/issues/issue-46855.rs +++ b/tests/ui/issues/issue-46855.rs @@ -12,7 +12,7 @@ union Foo { b: Never } -fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 } +fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 } //~ unreachable expression fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x } diff --git a/tests/ui/issues/issue-46855.stderr b/tests/ui/issues/issue-46855.stderr new file mode 100644 index 0000000000000..bc0ae7802fff0 --- /dev/null +++ b/tests/ui/issues/issue-46855.stderr @@ -0,0 +1,12 @@ +warning: unreachable expression + --> $DIR/issue-46855.rs:15:43 + | +LL | fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 } + | -- ^ unreachable expression + | | + | this expression has type `[(Never, u32); 1]`, which is uninhabited + | + = note: `#[warn(unreachable_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/lint/dead-code/issue-85071-2.rs b/tests/ui/lint/dead-code/issue-85071-2.rs index 5db8735899410..caf27cc3d332b 100644 --- a/tests/ui/lint/dead-code/issue-85071-2.rs +++ b/tests/ui/lint/dead-code/issue-85071-2.rs @@ -18,5 +18,5 @@ fn main() { let x = s.f(); //~^ WARNING: unused variable: `x` let _y = x; - //~^ WARNING: unreachable definition + //~^ WARNING: unreachable statement } diff --git a/tests/ui/lint/dead-code/issue-85071-2.stderr b/tests/ui/lint/dead-code/issue-85071-2.stderr index 5e963183d094b..442648431a619 100644 --- a/tests/ui/lint/dead-code/issue-85071-2.stderr +++ b/tests/ui/lint/dead-code/issue-85071-2.stderr @@ -1,17 +1,12 @@ -warning: unreachable definition - --> $DIR/issue-85071-2.rs:20:9 +warning: unreachable statement + --> $DIR/issue-85071-2.rs:20:5 | LL | let x = s.f(); - | ----- any code following this expression is unreachable + | ----- this expression has type `Foo`, which is uninhabited LL | LL | let _y = x; - | ^^ unreachable definition + | ^^^^^^^^^^^ unreachable statement | -note: this expression has type `Foo`, which is uninhabited - --> $DIR/issue-85071-2.rs:18:13 - | -LL | let x = s.f(); - | ^^^^^ note: the lint level is defined here --> $DIR/issue-85071-2.rs:7:26 | diff --git a/tests/ui/lint/dead-code/issue-85071.rs b/tests/ui/lint/dead-code/issue-85071.rs index 84f2c9fc74eeb..4c9daefc109a9 100644 --- a/tests/ui/lint/dead-code/issue-85071.rs +++ b/tests/ui/lint/dead-code/issue-85071.rs @@ -15,5 +15,5 @@ fn main() { let x = f(); //~^ WARNING: unused variable: `x` let _ = x; - //~^ WARNING: unreachable expression + //~^ WARNING: unreachable statement } diff --git a/tests/ui/lint/dead-code/issue-85071.stderr b/tests/ui/lint/dead-code/issue-85071.stderr index 721fb8148d96b..eda5d78c50c3d 100644 --- a/tests/ui/lint/dead-code/issue-85071.stderr +++ b/tests/ui/lint/dead-code/issue-85071.stderr @@ -1,17 +1,12 @@ -warning: unreachable expression - --> $DIR/issue-85071.rs:17:13 +warning: unreachable statement + --> $DIR/issue-85071.rs:17:5 | LL | let x = f(); - | --- any code following this expression is unreachable + | --- this expression has type `Foo`, which is uninhabited LL | LL | let _ = x; - | ^ unreachable expression + | ^^^^^^^^^^ unreachable statement | -note: this expression has type `Foo`, which is uninhabited - --> $DIR/issue-85071.rs:15:13 - | -LL | let x = f(); - | ^^^ note: the lint level is defined here --> $DIR/issue-85071.rs:9:26 | diff --git a/tests/ui/match/match-no-arms-unreachable-after.stderr b/tests/ui/match/match-no-arms-unreachable-after.stderr index 65ac1bae34495..d692be361bbb2 100644 --- a/tests/ui/match/match-no-arms-unreachable-after.stderr +++ b/tests/ui/match/match-no-arms-unreachable-after.stderr @@ -2,7 +2,7 @@ error: unreachable statement --> $DIR/match-no-arms-unreachable-after.rs:8:5 | LL | match v { } - | ----------- any code following this expression is unreachable + | - this expression has type `Void`, which is uninhabited LL | let x = 2; | ^^^^^^^^^^ unreachable statement | diff --git a/tests/ui/pattern/usefulness/impl-trait.rs b/tests/ui/pattern/usefulness/impl-trait.rs index 1fec9a2633eec..380a9e3702a1d 100644 --- a/tests/ui/pattern/usefulness/impl-trait.rs +++ b/tests/ui/pattern/usefulness/impl-trait.rs @@ -135,7 +135,7 @@ fn nested_empty_opaque(x: Void) -> X { let opaque_void = nested_empty_opaque(x); let secretely_void = SecretelyVoid(opaque_void); match secretely_void { - _ => {} //~ ERROR unreachable + _ => {} } } x @@ -148,7 +148,7 @@ fn super_nested_empty_opaque(x: Void) -> Y { let opaque_void = super_nested_empty_opaque(x); let secretely_void = SecretelyDoubleVoid(opaque_void); match secretely_void { - _ => {} //~ ERROR unreachable + _ => {} } } (x, x) diff --git a/tests/ui/pattern/usefulness/impl-trait.stderr b/tests/ui/pattern/usefulness/impl-trait.stderr index ba8b12f9f66c6..01663e9836e24 100644 --- a/tests/ui/pattern/usefulness/impl-trait.stderr +++ b/tests/ui/pattern/usefulness/impl-trait.stderr @@ -74,18 +74,6 @@ LL | _ => {} LL | Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern -error: unreachable pattern - --> $DIR/impl-trait.rs:138:13 - | -LL | _ => {} - | ^ - -error: unreachable pattern - --> $DIR/impl-trait.rs:151:13 - | -LL | _ => {} - | ^ - error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty --> $DIR/impl-trait.rs:23:11 | @@ -114,6 +102,6 @@ LL + _ => todo!(), LL + } | -error: aborting due to 15 previous errors +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/reachable/type-dependent-ctor.rs b/tests/ui/reachable/type-dependent-ctor.rs new file mode 100644 index 0000000000000..db5e6de8dd2be --- /dev/null +++ b/tests/ui/reachable/type-dependent-ctor.rs @@ -0,0 +1,25 @@ +// Verify that we do not warn on type-dependent constructors (`Self::A` below). +//@ check-pass +#![deny(unreachable_code)] + +enum Void {} + +enum Foo { + A(Void), +} + +impl Foo { + fn wrap(x: Void) -> Self { + Self::A(x) + } + + fn make() -> Self { + Self::A(produce()) + } +} + +fn produce() -> Void { + panic!() +} + +fn main() {} 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..32b7060509d02 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 arm } 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..4758b1013dde3 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,13 @@ 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 arm + --> $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 arm + | | + | this expression has type `Void`, which is uninhabited error: aborting due to 4 previous errors diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs index 6b85ada3aadee..67cff0d31a956 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs @@ -15,7 +15,6 @@ fn wild_void(_: Void) -> u32 {} fn wild_let() -> u32 { let ptr: *const Void = std::ptr::null(); unsafe { - //~^ ERROR: mismatched types let _ = *ptr; } } @@ -35,8 +34,8 @@ fn binding_void(_x: Void) -> u32 {} fn binding_let() -> u32 { let ptr: *const Void = std::ptr::null(); unsafe { - //~^ ERROR: mismatched types let _x = *ptr; + //~^ ERROR: cannot move } } diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr index 08a1bbe9bffac..ca335626b9357 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr @@ -7,22 +7,13 @@ LL | fn wild_void(_: Void) -> u32 {} | implicitly returns `()` as its body has no tail or `return` expression error[E0308]: mismatched types - --> $DIR/diverges-not.rs:17:5 - | -LL | / unsafe { -LL | | -LL | | let _ = *ptr; -LL | | } - | |_____^ expected `u32`, found `()` - -error[E0308]: mismatched types - --> $DIR/diverges-not.rs:27:18 + --> $DIR/diverges-not.rs:26:18 | LL | _ => {} | ^^ expected `u32`, found `()` error[E0308]: mismatched types - --> $DIR/diverges-not.rs:32:30 + --> $DIR/diverges-not.rs:31:30 | LL | fn binding_void(_x: Void) -> u32 {} | ------------ ^^^ expected `u32`, found `()` @@ -30,26 +21,30 @@ LL | fn binding_void(_x: Void) -> u32 {} | implicitly returns `()` as its body has no tail or `return` expression error[E0308]: mismatched types - --> $DIR/diverges-not.rs:37:5 - | -LL | / unsafe { -LL | | -LL | | let _x = *ptr; -LL | | } - | |_____^ expected `u32`, found `()` - -error[E0308]: mismatched types - --> $DIR/diverges-not.rs:47:19 + --> $DIR/diverges-not.rs:46:19 | LL | _x => {} | ^^ expected `u32`, found `()` error[E0308]: mismatched types - --> $DIR/diverges-not.rs:54:37 + --> $DIR/diverges-not.rs:53:37 | LL | if let true = true && let ! = x {} | ^^ expected `u32`, found `()` -error: aborting due to 7 previous errors +error[E0507]: cannot move out of `*ptr` which is behind a raw pointer + --> $DIR/diverges-not.rs:37:18 + | +LL | let _x = *ptr; + | ^^^^ move occurs because `*ptr` has type `Void`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - let _x = *ptr; +LL + let _x = ptr; + | + +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0507. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/try-block/try-block-unreachable-code-lint.rs b/tests/ui/try-block/try-block-unreachable-code-lint.rs index 62c74b76d59c0..1b4b1e3756aff 100644 --- a/tests/ui/try-block/try-block-unreachable-code-lint.rs +++ b/tests/ui/try-block/try-block-unreachable-code-lint.rs @@ -50,7 +50,6 @@ fn test_try_block_after_divergent_stmt() { fn test_wrapped_divergent_expr() { let _: Result = { Err(return) - //~^ WARNING unreachable call }; } diff --git a/tests/ui/try-block/try-block-unreachable-code-lint.stderr b/tests/ui/try-block/try-block-unreachable-code-lint.stderr index 9fc0b661f1e7d..739659b409f4d 100644 --- a/tests/ui/try-block/try-block-unreachable-code-lint.stderr +++ b/tests/ui/try-block/try-block-unreachable-code-lint.stderr @@ -17,16 +17,8 @@ note: the lint level is defined here LL | #![warn(unreachable_code)] | ^^^^^^^^^^^^^^^^ -warning: unreachable call - --> $DIR/try-block-unreachable-code-lint.rs:52:9 - | -LL | Err(return) - | ^^^ ------ any code following this expression is unreachable - | | - | unreachable call - warning: unreachable expression - --> $DIR/try-block-unreachable-code-lint.rs:63:9 + --> $DIR/try-block-unreachable-code-lint.rs:62:9 | LL | / loop { LL | | err()?; @@ -36,5 +28,5 @@ LL | LL | 42 | ^^ unreachable expression -warning: 3 warnings emitted +warning: 2 warnings emitted diff --git a/tests/ui/break-diverging-value.rs b/tests/ui/uninhabited/break-diverging-value-pass.rs similarity index 63% rename from tests/ui/break-diverging-value.rs rename to tests/ui/uninhabited/break-diverging-value-pass.rs index d070fddaffc19..b9ad722727680 100644 --- a/tests/ui/break-diverging-value.rs +++ b/tests/ui/uninhabited/break-diverging-value-pass.rs @@ -1,3 +1,4 @@ +//@ check-pass #![feature(never_type)] fn loop_break_return() -> i32 { @@ -8,30 +9,36 @@ fn loop_break_loop() -> i32 { let loop_value = loop { break loop {} }; // ok } -fn loop_break_break() -> i32 { //~ ERROR mismatched types - let loop_value = loop { break break }; -} - fn loop_break_return_2() -> i32 { let loop_value = loop { break { return 0; () } }; // ok } +fn get_never() -> ! { + panic!() +} + +fn loop_break_never() -> i32 { + let loop_value = loop { break get_never() }; // ok +} + enum Void {} fn get_void() -> Void { panic!() } -fn loop_break_void() -> i32 { //~ ERROR mismatched types - let loop_value = loop { break get_void() }; +fn loop_break_void() -> i32 { + let loop_value = loop { break get_void() }; // ok } -fn get_never() -> ! { +struct IndirectVoid(Void); + +fn get_indirect_void() -> IndirectVoid { panic!() } -fn loop_break_never() -> i32 { - let loop_value = loop { break get_never() }; // ok +fn loop_break_indirect_void() -> i32 { + let loop_value = loop { break get_indirect_void() }; // ok } fn main() {} diff --git a/tests/ui/uninhabited/break-diverging-value.rs b/tests/ui/uninhabited/break-diverging-value.rs new file mode 100644 index 0000000000000..52e8b7a9de150 --- /dev/null +++ b/tests/ui/uninhabited/break-diverging-value.rs @@ -0,0 +1,61 @@ +#![feature(never_type)] + +fn loop_break_return() -> i32 { + let loop_value = loop { break return 0 }; // ok +} + +fn loop_break_loop() -> i32 { + let loop_value = loop { break loop {} }; // ok +} + +fn loop_break_break() -> i32 { //~ ERROR mismatched types + let loop_value = loop { break break }; +} + +fn loop_break_return_2() -> i32 { + let loop_value = loop { break { return 0; () } }; // ok +} + +fn get_never() -> ! { + panic!() +} + +fn loop_break_never() -> i32 { + let loop_value = loop { break get_never() }; // ok +} + +enum Void {} + +fn get_void() -> Void { + panic!() +} + +fn loop_break_void() -> i32 { + let loop_value = loop { break get_void() }; // ok +} + +struct IndirectVoid(Void); + +fn get_indirect_void() -> IndirectVoid { + panic!() +} + +fn loop_break_indirect_void() -> i32 { + let loop_value = loop { break get_indirect_void() }; // ok +} + +mod private { + pub struct PrivateVoid(super::Void); + + pub fn get_private_void() -> PrivateVoid { + panic!() + } +} + +fn loop_break_private_void() -> i32 { //~ ERROR mismatched types + // The field inside `PrivateVoid` is private, so the typeck is not allowed to use + // `PrivateVoid`'s uninhabitedness to guide inference. + let loop_value = loop { break private::get_private_void() }; +} + +fn main() {} diff --git a/tests/ui/break-diverging-value.stderr b/tests/ui/uninhabited/break-diverging-value.stderr similarity index 76% rename from tests/ui/break-diverging-value.stderr rename to tests/ui/uninhabited/break-diverging-value.stderr index 69edcd2408002..998212cc79292 100644 --- a/tests/ui/break-diverging-value.stderr +++ b/tests/ui/uninhabited/break-diverging-value.stderr @@ -7,10 +7,10 @@ LL | fn loop_break_break() -> i32 { | implicitly returns `()` as its body has no tail or `return` expression error[E0308]: mismatched types - --> $DIR/break-diverging-value.rs:25:25 + --> $DIR/break-diverging-value.rs:55:33 | -LL | fn loop_break_void() -> i32 { - | --------------- ^^^ expected `i32`, found `()` +LL | fn loop_break_private_void() -> i32 { + | ----------------------- ^^^ expected `i32`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression diff --git a/tests/ui/uninhabited/uninhabited-struct-match.rs b/tests/ui/uninhabited/uninhabited-struct-match.rs new file mode 100644 index 0000000000000..641831abbfe21 --- /dev/null +++ b/tests/ui/uninhabited/uninhabited-struct-match.rs @@ -0,0 +1,24 @@ +#![crate_type = "lib"] + +#![warn(unused)] + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Void {} + +pub struct UnStruct { + x: u32, + v: Void +} + +pub fn match_struct(x: UnStruct) { + match x {} //~ non-exhaustive patterns: type `UnStruct` is non-empty +} + +pub fn match_inhabited_field(x: UnStruct) { + match x.x {} //~ non-exhaustive patterns: type `u32` is non-empty + //~| unreachable expression +} + +pub fn match_uninhabited_field(x: UnStruct) { + match x.v {} // ok +} diff --git a/tests/ui/uninhabited/uninhabited-struct-match.stderr b/tests/ui/uninhabited/uninhabited-struct-match.stderr new file mode 100644 index 0000000000000..2239db2f67e54 --- /dev/null +++ b/tests/ui/uninhabited/uninhabited-struct-match.stderr @@ -0,0 +1,52 @@ +warning: unreachable expression + --> $DIR/uninhabited-struct-match.rs:18:11 + | +LL | match x.x {} + | -^^ + | | + | unreachable expression + | this expression has type `UnStruct`, which is uninhabited + | +note: the lint level is defined here + --> $DIR/uninhabited-struct-match.rs:3:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unreachable_code)]` implied by `#[warn(unused)]` + +error[E0004]: non-exhaustive patterns: type `UnStruct` is non-empty + --> $DIR/uninhabited-struct-match.rs:14:11 + | +LL | match x {} + | ^ + | +note: `UnStruct` defined here + --> $DIR/uninhabited-struct-match.rs:8:12 + | +LL | pub struct UnStruct { + | ^^^^^^^^ + = note: the matched value is of type `UnStruct` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `u32` is non-empty + --> $DIR/uninhabited-struct-match.rs:18:11 + | +LL | match x.x {} + | ^^^ + | + = note: the matched value is of type `u32` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x.x { +LL + _ => todo!(), +LL ~ } + | + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0004`.