diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 0286838f5da8b..e3ecf4afad413 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -249,7 +249,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// warn the user about the match arms being unreachable. fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) { for arm in arms { - self.warn_if_unreachable(arm.body.hir_id, arm.body.span, "arm"); + if !arm.pat.is_never_pattern() { + self.warn_if_unreachable(arm.body.hir_id, arm.body.span, "arm"); + } } } diff --git a/compiler/rustc_hir_typeck/src/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs index 83b0c17d6d12f..6327d2098bd50 100644 --- a/compiler/rustc_hir_typeck/src/diverges.rs +++ b/compiler/rustc_hir_typeck/src/diverges.rs @@ -1,5 +1,6 @@ use std::{cmp, ops}; +use rustc_hir::HirId; use rustc_span::Span; /// Tracks whether executing a node may exit normally (versus @@ -13,6 +14,14 @@ pub(crate) enum Diverges { /// others require a CFG to determine them. Maybe, + /// This expression is uninhabited, we want to + /// emit a diagnostic but not pollute type checking. + UninhabitedExpr(HirId, Span), + + /// Same as `UninhabitedExpr` but with reachability + /// warning already emitted. + Warned, + /// Definitely known to diverge and therefore /// not reach the next sibling or its parent. Always(DivergeReason, Span), @@ -54,7 +63,7 @@ impl ops::BitOrAssign for Diverges { impl Diverges { pub(super) fn is_always(self) -> bool { match self { - Self::Maybe => false, + Self::Maybe | Diverges::UninhabitedExpr(..) | Diverges::Warned => false, Self::Always(..) | Self::WarnedAlways => true, } } @@ -62,8 +71,10 @@ impl Diverges { fn ordinal(&self) -> u8 { match self { Self::Maybe => 0, - Self::Always { .. } => 1, - Self::WarnedAlways => 2, + Self::UninhabitedExpr(..) => 1, + Self::Warned => 2, + Self::Always { .. } => 3, + Self::WarnedAlways => 4, } } } @@ -72,5 +83,6 @@ impl Diverges { pub(crate) 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 5730895e5ab1a..d793f3f6cad40 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -234,10 +234,24 @@ 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, _) => { + // Do not emit a warning for a call to a constructor. + let emit_warning = if let ExprKind::Path(ref qpath) = callee.kind { + 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 is uninhabited. + ExprKind::Field(..) + if matches!(self.diverges.get(), Diverges::UninhabitedExpr(_, _)) => {} _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"), } @@ -245,9 +259,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // unless it's a place expression that isn't being read from, in which case // diverging would be unsound since we may never actually read the `!`. // e.g. `let _ = *never_ptr;` with `never_ptr: *const !`. - if ty.is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) { - self.diverges - .set(self.diverges.get() | Diverges::Always(DivergeReason::Other, expr.span)); + let cur_diverges = self.diverges.get(); + if !cur_diverges.is_always() && self.expr_guaranteed_to_constitute_read_for_never(expr) { + if ty.is_never() { + // Any expression that produces a value of type `!` must have diverged. + self.diverges.set(cur_diverges | Diverges::Always(DivergeReason::Other, expr.span)); + } else if self.ty_is_uninhabited(ty) { + // This expression produces a value of uninhabited type. + // This means it has diverged somehow. + self.diverges.set(cur_diverges | Diverges::UninhabitedExpr(expr.hir_id, expr.span)); + } } // Record the type, which applies it effects. @@ -353,6 +374,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.pat_guaranteed_to_constitute_read_for_never(*pat) } + hir::Node::Pat(parent_pat) => match parent_pat.kind { + hir::PatKind::Lit(..) | hir::PatKind::Range(..) => false, + + // These nodes do not have direct sub-exprs. + hir::PatKind::Wild + | hir::PatKind::Binding(..) + | hir::PatKind::Struct(..) + | hir::PatKind::TupleStruct(..) + | hir::PatKind::Or(..) + | hir::PatKind::Never + | hir::PatKind::Path(..) + | hir::PatKind::Tuple(..) + | hir::PatKind::Box(..) + | hir::PatKind::Deref(..) + | hir::PatKind::Ref(..) + | hir::PatKind::Slice(..) + | hir::PatKind::Err(..) => { + unreachable!("no sub-expr expected for {parent_pat:?}") + } + }, + // These nodes (if they have a sub-expr) do constitute a read. hir::Node::Block(_) | hir::Node::Arm(_) @@ -382,7 +424,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | hir::Node::Ty(_) | hir::Node::AssocItemConstraint(_) | hir::Node::TraitRef(_) - | hir::Node::Pat(_) | hir::Node::PatField(_) | hir::Node::LetStmt(_) | hir::Node::Synthetic @@ -443,6 +484,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + 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, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index a727d271dfa5f..dc43eb3c13dfe 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::collections::hash_map::Entry; use std::slice; @@ -31,7 +32,7 @@ use rustc_session::lint; use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; -use rustc_span::symbol::kw; +use rustc_span::symbol::{kw, sym}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::traits::{ @@ -50,8 +51,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Produces warning on the given node, if the current point in the /// function is unreachable, and there hasn't been another warning. pub(crate) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str) { - let Diverges::Always(reason, orig_span) = self.diverges.get() else { - return; + let (reason, orig_span) = match self.diverges.get() { + Diverges::UninhabitedExpr(hir_id, orig_span) => { + (DivergeReason::UninhabitedExpr(hir_id), orig_span) + } + Diverges::Always(reason, orig_span) => (reason, orig_span), + Diverges::Maybe | Diverges::Warned | Diverges::WarnedAlways => return, }; match span.desugaring_kind() { @@ -73,20 +78,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } + 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; + } + } + } + // Don't warn twice. - self.diverges.set(Diverges::WarnedAlways); + self.diverges.set(match self.diverges.get() { + Diverges::UninhabitedExpr(..) => Diverges::Warned, + Diverges::Always(..) => Diverges::WarnedAlways, + Diverges::Maybe | Diverges::Warned | Diverges::WarnedAlways => bug!(), + }); 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, |lint| { lint.primary_message(msg.clone()); - let custom_note = match reason { + let custom_note: 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, custom_note); }) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 3940d138deb0a..8597c816742a8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -49,6 +49,11 @@ pub(crate) struct FnCtxt<'a, 'tcx> { /// eventually). pub(super) param_env: ty::ParamEnv<'tcx>, + /// The module in which the current function is defined. This + /// is used to compute type inhabitedness, which accounts for + /// visibility information. + 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 +132,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 bf741f63a3d4f..3ee7efde6675a 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -92,27 +92,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/messages.ftl b/compiler/rustc_passes/messages.ftl index e5e70ba203384..c916de197c340 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -752,11 +752,6 @@ passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been pa passes_unnecessary_stable_feature = the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable -passes_unreachable_due_to_uninhabited = unreachable {$descr} - .label = unreachable {$descr} - .label_orig = any code following this expression is unreachable - .note = this expression has type `{$ty}`, which is uninhabited - passes_unrecognized_field = unrecognized field name `{$name}` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 8bd767c1243d9..2d8acb074f032 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1679,18 +1679,6 @@ pub(crate) struct SkippingConstChecks { pub span: Span, } -#[derive(LintDiagnostic)] -#[diag(passes_unreachable_due_to_uninhabited)] -pub(crate) struct UnreachableDueToUninhabited<'desc, 'tcx> { - pub descr: &'desc str, - #[label] - pub expr: Span, - #[label(passes_label_orig)] - #[note] - pub orig: Span, - pub ty: Ty<'tcx>, -} - #[derive(LintDiagnostic)] #[diag(passes_unused_var_maybe_capture_ref)] #[help] diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 366f7dd293c44..f0470182c8bc4 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -94,7 +94,7 @@ use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; use rustc_index::IndexVec; use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; +use rustc_middle::ty::{self, RootVariableMinCaptureList, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{Symbol, kw, sym}; use rustc_span::{BytePos, Span}; @@ -119,8 +119,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, @@ -130,8 +130,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/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs b/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs index f4130319eea5d..9ae40e8a98f0c 100644 --- a/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs +++ b/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs @@ -1,5 +1,6 @@ //@ run-pass #![allow(unreachable_patterns)] +#![allow(unreachable_code)] #![allow(dead_code)] enum Empty {} 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/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/pattern/usefulness/impl-trait.rs b/tests/ui/pattern/usefulness/impl-trait.rs index 16560a092675f..e082a500079f3 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 75cba4b5f0276..2a6b7bc366193 100644 --- a/tests/ui/pattern/usefulness/impl-trait.stderr +++ b/tests/ui/pattern/usefulness/impl-trait.stderr @@ -109,28 +109,6 @@ LL | _ => {} LL | Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this -error: unreachable pattern - --> $DIR/impl-trait.rs:138:13 - | -LL | _ => {} - | ^------ - | | - | matches no values because `SecretelyVoid` is uninhabited - | help: remove the match arm - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - -error: unreachable pattern - --> $DIR/impl-trait.rs:151:13 - | -LL | _ => {} - | ^------ - | | - | matches no values because `SecretelyDoubleVoid` is uninhabited - | help: remove the match arm - | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty --> $DIR/impl-trait.rs:23:11 | @@ -159,6 +137,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/try-block/try-block-unreachable-code-lint.rs b/tests/ui/try-block/try-block-unreachable-code-lint.rs index 62c74b76d59c0..f82fd33357e4c 100644 --- a/tests/ui/try-block/try-block-unreachable-code-lint.rs +++ b/tests/ui/try-block/try-block-unreachable-code-lint.rs @@ -9,6 +9,10 @@ fn err() -> Result { Err(()) } +fn make_err(x: U) -> Result { + Err(x) +} + // In the following cases unreachable code is autogenerated and should not be reported. fn test_ok_wrapped_divergent_expr_1() { @@ -49,7 +53,7 @@ fn test_try_block_after_divergent_stmt() { fn test_wrapped_divergent_expr() { let _: Result = { - Err(return) + make_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..112c8f817f98a 100644 --- a/tests/ui/try-block/try-block-unreachable-code-lint.stderr +++ b/tests/ui/try-block/try-block-unreachable-code-lint.stderr @@ -1,5 +1,5 @@ warning: unreachable expression - --> $DIR/try-block-unreachable-code-lint.rs:41:9 + --> $DIR/try-block-unreachable-code-lint.rs:45:9 | LL | return; | ------ any code following this expression is unreachable @@ -18,15 +18,15 @@ LL | #![warn(unreachable_code)] | ^^^^^^^^^^^^^^^^ warning: unreachable call - --> $DIR/try-block-unreachable-code-lint.rs:52:9 + --> $DIR/try-block-unreachable-code-lint.rs:56:9 | -LL | Err(return) - | ^^^ ------ any code following this expression is unreachable +LL | make_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:67:9 | LL | / loop { LL | | err()?;