From 90698b61169a335a73343ae932f1bcaf3acf9fc9 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 9 Aug 2022 12:49:17 -0500 Subject: [PATCH 1/5] Refactor Diverges in typeck Avoid deriving PartialOrd on Diverges since it includes fields which should not affect ordering. --- compiler/rustc_hir_typeck/src/_match.rs | 14 ++---- compiler/rustc_hir_typeck/src/check.rs | 8 ++- compiler/rustc_hir_typeck/src/diverges.rs | 50 +++++++++---------- compiler/rustc_hir_typeck/src/expr.rs | 10 ++-- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 18 ++++--- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 9 ++-- compiler/rustc_hir_typeck/src/lib.rs | 2 +- 7 files changed, 54 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index bc0ed4a7fa99d..ea84f357556b7 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -10,7 +10,7 @@ use rustc_trait_selection::traits::{ }; use crate::coercion::{AsCoercionSite, CoerceMany}; -use crate::{Diverges, Expectation, FnCtxt, Needs}; +use crate::{DivergeReason, Diverges, Expectation, FnCtxt, Needs}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug", ret)] @@ -30,7 +30,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If there are no arms, that is a diverging match; a special case. if arms.is_empty() { - self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); + self.diverges + .set(self.diverges.get() | Diverges::Always(DivergeReason::Other, expr.span)); return tcx.types.never; } @@ -151,13 +152,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we can emit a better note. Rather than pointing // at a diverging expression in an arbitrary arm, // we can point at the entire `match` expression - if let (Diverges::Always { .. }, hir::MatchSource::Normal) = (all_arms_diverge, match_src) { - all_arms_diverge = Diverges::Always { - span: expr.span, - custom_note: Some( - "any code following this `match` expression is unreachable, as all arms diverge", - ), - }; + if let (Diverges::Always(..), hir::MatchSource::Normal) = (all_arms_diverge, match_src) { + all_arms_diverge = Diverges::Always(DivergeReason::AllArmsDiverge, expr.span); } // We won't diverge unless the scrutinee or all arms diverge. diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 89df464cca040..0c35fe588321e 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -15,7 +15,7 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; use crate::coercion::CoerceMany; use crate::gather_locals::GatherLocalsVisitor; -use crate::{CoroutineTypes, Diverges, FnCtxt}; +use crate::{CoroutineTypes, DivergeReason, Diverges, FnCtxt}; /// Helper used for fns and closures. Does the grungy work of checking a function /// body and returns the function context used for that purpose, since in the case of a fn item @@ -88,10 +88,8 @@ pub(super) fn check_fn<'a, 'tcx>( let ty_span = ty.map(|ty| ty.span); fcx.check_pat_top(param.pat, param_ty, ty_span, None, None); if param.pat.is_never_pattern() { - fcx.function_diverges_because_of_empty_arguments.set(Diverges::Always { - span: param.pat.span, - custom_note: Some("any code following a never pattern is unreachable"), - }); + fcx.function_diverges_because_of_empty_arguments + .set(Diverges::Always(DivergeReason::NeverPattern, param.pat.span)); } // Check that argument is Sized. diff --git a/compiler/rustc_hir_typeck/src/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs index aa30fb0f0af39..6b1900cc5256b 100644 --- a/compiler/rustc_hir_typeck/src/diverges.rs +++ b/compiler/rustc_hir_typeck/src/diverges.rs @@ -1,13 +1,13 @@ use std::{cmp, ops}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; /// Tracks whether executing a node may exit normally (versus /// return/break/panic, which "diverge", leaving dead code in their /// wake). Tracked semi-automatically (through type variables marked /// as diverging), with some manual adjustments for control-flow /// primitives (approximating a CFG). -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug)] pub enum Diverges { /// Potentially unknown, some cases converge, /// others require a CFG to determine them. @@ -15,20 +15,7 @@ pub enum Diverges { /// Definitely known to diverge and therefore /// not reach the next sibling or its parent. - Always { - /// The `Span` points to the expression - /// that caused us to diverge - /// (e.g. `return`, `break`, etc). - span: Span, - /// In some cases (e.g. a `match` expression - /// where all arms diverge), we may be - /// able to provide a more informative - /// message to the user. - /// If this is `None`, a default message - /// will be generated, which is suitable - /// for most cases. - custom_note: Option<&'static str>, - }, + Always(DivergeReason, Span), /// Same as `Always` but with a reachability /// warning already emitted. @@ -40,14 +27,15 @@ pub enum Diverges { impl ops::BitAnd for Diverges { type Output = Self; fn bitand(self, other: Self) -> Self { - cmp::min(self, other) + cmp::min_by_key(self, other, Self::ordinal) } } impl ops::BitOr for Diverges { type Output = Self; fn bitor(self, other: Self) -> Self { - cmp::max(self, other) + // argument order is to prefer `self` if ordinal is equal + cmp::max_by_key(other, self, Self::ordinal) } } @@ -64,15 +52,25 @@ impl ops::BitOrAssign for Diverges { } impl Diverges { - /// Creates a `Diverges::Always` with the provided `span` and the default note message. - pub(super) fn always(span: Span) -> Diverges { - Diverges::Always { span, custom_note: None } + pub(super) fn is_always(self) -> bool { + match self { + Self::Maybe => false, + Self::Always(..) | Self::WarnedAlways => true, + } } - pub(super) fn is_always(self) -> bool { - // Enum comparison ignores the - // contents of fields, so we just - // fill them in with garbage here. - self >= Diverges::Always { span: DUMMY_SP, custom_note: None } + fn ordinal(&self) -> u8 { + match self { + Self::Maybe => 0, + Self::Always { .. } => 1, + Self::WarnedAlways => 2, + } } } + +#[derive(Clone, Copy, Debug)] +pub enum DivergeReason { + AllArmsDiverge, + NeverPattern, + Other, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d6ff0cb9462f5..c555fdc488e72 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -47,7 +47,7 @@ use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectatio use crate::TupleArgumentsFlag::DontTupleArguments; use crate::{ cast, fatally_break_rust, report_unexpected_variant_res, type_error_struct, BreakableCtxt, - CoroutineTypes, Diverges, FnCtxt, Needs, + CoroutineTypes, DivergeReason, Diverges, FnCtxt, Needs, }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -239,7 +239,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Any expression that produces a value of type `!` must have diverged if ty.is_never() { - self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); + self.diverges + .set(self.diverges.get() | Diverges::Always(DivergeReason::Other, expr.span)); } // Record the type, which applies it effects. @@ -1307,7 +1308,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // of a `break` or an outer `break` or `return`. self.diverges.set(Diverges::Maybe); } else { - self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); + self.diverges + .set(self.diverges.get() | Diverges::Always(DivergeReason::Other, expr.span)); } // If we permit break with a value, then result type is @@ -1410,7 +1412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .unwrap_or_else(|| self.next_ty_var(expr.span)); let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); - assert_eq!(self.diverges.get(), Diverges::Maybe); + assert!(matches!(self.diverges.get(), Diverges::Maybe)); for e in args { let e_ty = self.check_expr_with_hint(e, coerce_to); let cause = self.misc(e.span); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 841d25b54cc88..4ae58fa322427 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -42,13 +42,15 @@ use rustc_trait_selection::traits::{ use crate::callee::{self, DeferredCallResolution}; use crate::errors::{self, CtorIsPrivate}; use crate::method::{self, MethodCallee}; -use crate::{rvalue_scopes, BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy}; +use crate::{ + rvalue_scopes, BreakableCtxt, DivergeReason, Diverges, Expectation, FnCtxt, LoweredTy, +}; 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 { span: orig_span, custom_note } = self.diverges.get() else { + let Diverges::Always(reason, orig_span) = self.diverges.get() else { return; }; @@ -79,10 +81,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = format!("unreachable {kind}"); self.tcx().node_span_lint(lint::builtin::UNREACHABLE_CODE, id, span, |lint| { lint.primary_message(msg.clone()); - lint.span_label(span, msg).span_label( - orig_span, - custom_note.unwrap_or("any code following this expression is unreachable"), - ); + let custom_note = match reason { + DivergeReason::AllArmsDiverge => { + "any code following this `match` expression is unreachable, as all arms diverge" + } + DivergeReason::NeverPattern => "any code following a never pattern is unreachable", + DivergeReason::Other => "any code following this expression is unreachable", + }; + lint.span_label(span, msg).span_label(orig_span, custom_note); }) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 89e7227eda2c7..3d597bedb210f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -40,8 +40,8 @@ use crate::method::MethodCallee; use crate::Expectation::*; use crate::TupleArgumentsFlag::*; use crate::{ - errors, struct_span_code_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs, - TupleArgumentsFlag, + errors, struct_span_code_err, BreakableCtxt, DivergeReason, Diverges, Expectation, FnCtxt, + LoweredTy, Needs, TupleArgumentsFlag, }; #[derive(Clone, Copy, Default)] @@ -1703,10 +1703,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) { self.check_decl(local.into()); if local.pat.is_never_pattern() { - self.diverges.set(Diverges::Always { - span: local.pat.span, - custom_note: Some("any code following a never pattern is unreachable"), - }); + self.diverges.set(Diverges::Always(DivergeReason::NeverPattern, local.pat.span)); } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 758a1cefe6341..67a48389b27e1 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -64,7 +64,7 @@ use typeck_root_ctxt::TypeckRootCtxt; use crate::check::check_fn; use crate::coercion::DynamicCoerceMany; -use crate::diverges::Diverges; +use crate::diverges::{DivergeReason, Diverges}; use crate::expectation::Expectation; use crate::fn_ctxt::LoweredTy; use crate::gather_locals::GatherLocalsVisitor; From 446a159f53316251285eb4b68169ec84d04bc44a Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sun, 7 Aug 2022 13:59:21 -0500 Subject: [PATCH 2/5] Check for uninhabited types in typeck --- compiler/rustc_hir_typeck/src/diverges.rs | 2 + compiler/rustc_hir_typeck/src/expr.rs | 79 +++++++++++++++++-- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 25 +++++- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 3 + .../ty/inhabitedness/inhabited_predicate.rs | 22 +----- compiler/rustc_passes/src/liveness.rs | 71 +++-------------- .../const_prop/invalid_constant.main.GVN.diff | 52 ++++++------ .../invalid_constant.main.RemoveZsts.diff | 71 ++++++++--------- ...inline_diverging.h.Inline.panic-abort.diff | 49 ++++++------ ...nline_diverging.h.Inline.panic-unwind.diff | 61 +++++++------- ...rocess_void.SimplifyLocals-final.after.mir | 5 +- tests/ui/consts/const_discriminant.rs | 7 +- tests/ui/consts/issue-64506.rs | 9 ++- tests/ui/consts/issue-64506.stderr | 4 +- .../let-irrefutable-pattern-ice-120337.rs | 3 +- .../let-irrefutable-pattern-ice-120337.stderr | 12 +++ tests/ui/coroutine/issue-93161.rs | 4 +- tests/ui/coroutine/issue-93161.stderr | 20 +++++ tests/ui/deriving/deriving-all-codegen.rs | 3 +- ...t => deriving-all-codegen.unpretty.stdout} | 3 +- tests/ui/enum-discriminant/issue-46519.rs | 2 +- tests/ui/enum-discriminant/issue-46519.stderr | 12 +++ tests/ui/issues/issue-46855.rs | 2 +- tests/ui/issues/issue-46855.stderr | 12 +++ tests/ui/lint/dead-code/issue-85071-2.rs | 2 +- tests/ui/lint/dead-code/issue-85071-2.stderr | 13 +-- tests/ui/lint/dead-code/issue-85071.rs | 2 +- tests/ui/lint/dead-code/issue-85071.stderr | 13 +-- .../match-no-arms-unreachable-after.stderr | 2 +- tests/ui/pattern/usefulness/impl-trait.rs | 4 +- tests/ui/pattern/usefulness/impl-trait.stderr | 18 +---- tests/ui/reachable/type-dependent-ctor.rs | 25 ++++++ .../diverge-causes-unreachable-code.rs | 2 +- .../diverge-causes-unreachable-code.stderr | 13 ++- .../rfc-0000-never_patterns/diverges-not.rs | 3 +- .../diverges-not.stderr | 46 ++++++----- .../try-block-unreachable-code-lint.rs | 1 - .../try-block-unreachable-code-lint.stderr | 12 +-- .../break-diverging-value-pass.rs} | 25 +++--- tests/ui/uninhabited/break-diverging-value.rs | 61 ++++++++++++++ .../break-diverging-value.stderr | 6 +- .../uninhabited/uninhabited-struct-match.rs | 24 ++++++ .../uninhabited-struct-match.stderr | 33 ++++++++ 43 files changed, 523 insertions(+), 315 deletions(-) create mode 100644 tests/ui/consts/let-irrefutable-pattern-ice-120337.stderr create mode 100644 tests/ui/coroutine/issue-93161.stderr rename tests/ui/deriving/{deriving-all-codegen.stdout => deriving-all-codegen.unpretty.stdout} (99%) create mode 100644 tests/ui/enum-discriminant/issue-46519.stderr create mode 100644 tests/ui/issues/issue-46855.stderr create mode 100644 tests/ui/reachable/type-dependent-ctor.rs rename tests/ui/{break-diverging-value.rs => uninhabited/break-diverging-value-pass.rs} (63%) create mode 100644 tests/ui/uninhabited/break-diverging-value.rs rename tests/ui/{ => uninhabited}/break-diverging-value.stderr (76%) create mode 100644 tests/ui/uninhabited/uninhabited-struct-match.rs create mode 100644 tests/ui/uninhabited/uninhabited-struct-match.stderr diff --git a/compiler/rustc_hir_typeck/src/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs index 6b1900cc5256b..9ce1c364c9b10 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 @@ -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 c555fdc488e72..e6db86860cf1c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -230,17 +230,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. @@ -257,6 +280,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, @@ -3524,3 +3554,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 4ae58fa322427..ada2d75f8eb73 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; @@ -76,17 +77,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Don't warn twice. 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, |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 33f80dd3773fa..f271a521e0230 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(crate) 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 54b8507babfa9..66ca1abdb99bc 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/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index d3b85da4630ef..6b965ec439ace 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::{kw, sym, Symbol}; 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/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.rs b/tests/ui/deriving/deriving-all-codegen.rs index eab2b4f1f5335..ae6524b560d1f 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.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 6503c87099040..e13186eba86b8 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 c1cc279f74ce9..c4ec3d5480c17 100644 --- a/tests/ui/pattern/usefulness/impl-trait.rs +++ b/tests/ui/pattern/usefulness/impl-trait.rs @@ -134,7 +134,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 @@ -147,7 +147,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 92932e4853881..9396d7dbea997 100644 --- a/tests/ui/pattern/usefulness/impl-trait.stderr +++ b/tests/ui/pattern/usefulness/impl-trait.stderr @@ -91,22 +91,6 @@ LL | _ => {} LL | Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern -error: unreachable pattern - --> $DIR/impl-trait.rs:137:13 - | -LL | _ => {} - | ^ - | - = note: this pattern matches no values because `SecretelyVoid` is uninhabited - -error: unreachable pattern - --> $DIR/impl-trait.rs:150:13 - | -LL | _ => {} - | ^ - | - = note: this pattern matches no values because `SecretelyDoubleVoid` is uninhabited - error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty --> $DIR/impl-trait.rs:22:11 | @@ -135,6 +119,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..4c943bf6cdc6b 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,33 @@ 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 + | +note: if `Void` implemented `Clone`, you could clone the value + --> $DIR/diverges-not.rs:8:1 + | +LL | enum Void {} + | ^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _x = *ptr; + | ---- you could clone this value + +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..39485ecb01680 --- /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 {} +} + +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..278d9774ab068 --- /dev/null +++ b/tests/ui/uninhabited/uninhabited-struct-match.stderr @@ -0,0 +1,33 @@ +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 `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 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0004`. From 06b713cdae6184a4eb2af79648b356b3a16a252e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 25 Mar 2023 09:47:47 +0000 Subject: [PATCH 3/5] Remove carveouts. --- compiler/rustc_hir_typeck/src/expr.rs | 54 +------------------ compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 3 ++ .../write-to-uninhabited-enum-variant.rs | 1 + tests/ui/enum-discriminant/issue-46519.rs | 2 +- tests/ui/enum-discriminant/issue-46519.stderr | 10 +++- tests/ui/reachable/type-dependent-ctor.rs | 3 +- tests/ui/reachable/type-dependent-ctor.stderr | 24 +++++++++ tests/ui/reachable/unreachable-try-pattern.rs | 1 + .../reachable/unreachable-try-pattern.stderr | 10 +++- .../try-block-unreachable-code-lint.rs | 1 + .../try-block-unreachable-code-lint.stderr | 12 ++++- 11 files changed, 63 insertions(+), 58 deletions(-) create mode 100644 tests/ui/reachable/type-dependent-ctor.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index e6db86860cf1c..b4b49cdb531eb 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -230,18 +230,7 @@ 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, _) => { - 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::Call(callee, _) => self.warn_if_unreachable(expr.hir_id, callee.span, "call"), ExprKind::MethodCall(segment, ..) => { self.warn_if_unreachable(expr.hir_id, segment.ident.span, "call") } @@ -258,7 +247,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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) { + } else if self.ty_is_uninhabited(ty) { // This expression produces a value of uninhabited type. // This means it has diverged somehow. self.diverges @@ -3554,42 +3543,3 @@ 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/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index f271a521e0230..3650077effea3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -49,6 +49,9 @@ 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 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/enum-discriminant/issue-46519.rs b/tests/ui/enum-discriminant/issue-46519.rs index c6a31ad2dd3ba..4b05c30f7904b 100644 --- a/tests/ui/enum-discriminant/issue-46519.rs +++ b/tests/ui/enum-discriminant/issue-46519.rs @@ -19,7 +19,7 @@ pub enum SystemFont {} impl FontLanguageOverride { fn system_font(f: SystemFont) -> Self { - FontLanguageOverride::System(f) + FontLanguageOverride::System(f) //~ unreachable call } } diff --git a/tests/ui/enum-discriminant/issue-46519.stderr b/tests/ui/enum-discriminant/issue-46519.stderr index 54da8fc0b8e2c..06285d334cd33 100644 --- a/tests/ui/enum-discriminant/issue-46519.stderr +++ b/tests/ui/enum-discriminant/issue-46519.stderr @@ -8,5 +8,13 @@ LL | FontLanguageOverride::system_font(SystemFont::new()); | = note: `#[warn(unreachable_code)]` on by default -warning: 1 warning emitted +warning: unreachable call + --> $DIR/issue-46519.rs:22:9 + | +LL | FontLanguageOverride::System(f) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `SystemFont`, which is uninhabited + | | + | unreachable call + +warning: 2 warnings emitted diff --git a/tests/ui/reachable/type-dependent-ctor.rs b/tests/ui/reachable/type-dependent-ctor.rs index db5e6de8dd2be..4555ebad2e242 100644 --- a/tests/ui/reachable/type-dependent-ctor.rs +++ b/tests/ui/reachable/type-dependent-ctor.rs @@ -1,5 +1,4 @@ // Verify that we do not warn on type-dependent constructors (`Self::A` below). -//@ check-pass #![deny(unreachable_code)] enum Void {} @@ -11,10 +10,12 @@ enum Foo { impl Foo { fn wrap(x: Void) -> Self { Self::A(x) + //~^ ERROR unreachable call } fn make() -> Self { Self::A(produce()) + //~^ ERROR unreachable call } } diff --git a/tests/ui/reachable/type-dependent-ctor.stderr b/tests/ui/reachable/type-dependent-ctor.stderr new file mode 100644 index 0000000000000..e22813ca066a8 --- /dev/null +++ b/tests/ui/reachable/type-dependent-ctor.stderr @@ -0,0 +1,24 @@ +error: unreachable call + --> $DIR/type-dependent-ctor.rs:12:9 + | +LL | Self::A(x) + | ^^^^^^^ - this expression has type `Void`, which is uninhabited + | | + | unreachable call + | +note: the lint level is defined here + --> $DIR/type-dependent-ctor.rs:2:9 + | +LL | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable call + --> $DIR/type-dependent-ctor.rs:17:9 + | +LL | Self::A(produce()) + | ^^^^^^^ --------- this expression has type `Void`, which is uninhabited + | | + | unreachable call + +error: aborting due to 2 previous errors + diff --git a/tests/ui/reachable/unreachable-try-pattern.rs b/tests/ui/reachable/unreachable-try-pattern.rs index 22cbfb95af084..cba91d9211fe0 100644 --- a/tests/ui/reachable/unreachable-try-pattern.rs +++ b/tests/ui/reachable/unreachable-try-pattern.rs @@ -29,6 +29,7 @@ fn qux(x: Result) -> Result { fn vom(x: Result) -> Result { let y = (match x { Ok(n) => Ok(n), Err(e) => Err(e) })?; //~^ WARN unreachable pattern + //~| WARN unreachable call Ok(y) } diff --git a/tests/ui/reachable/unreachable-try-pattern.stderr b/tests/ui/reachable/unreachable-try-pattern.stderr index bc1a6fffda648..e9ca321d85e1f 100644 --- a/tests/ui/reachable/unreachable-try-pattern.stderr +++ b/tests/ui/reachable/unreachable-try-pattern.stderr @@ -13,6 +13,14 @@ note: the lint level is defined here LL | #![warn(unreachable_code)] | ^^^^^^^^^^^^^^^^ +warning: unreachable call + --> $DIR/unreachable-try-pattern.rs:30:50 + | +LL | let y = (match x { Ok(n) => Ok(n), Err(e) => Err(e) })?; + | ^^^ - this expression has type `Void`, which is uninhabited + | | + | unreachable call + warning: unreachable pattern --> $DIR/unreachable-try-pattern.rs:19:24 | @@ -34,5 +42,5 @@ LL | let y = (match x { Ok(n) => Ok(n), Err(e) => Err(e) })?; | = note: this pattern matches no values because `Void` is uninhabited -warning: 3 warnings emitted +warning: 4 warnings emitted 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 1b4b1e3756aff..ed0a1639cfeb8 100644 --- a/tests/ui/try-block/try-block-unreachable-code-lint.rs +++ b/tests/ui/try-block/try-block-unreachable-code-lint.rs @@ -50,6 +50,7 @@ fn test_try_block_after_divergent_stmt() { fn test_wrapped_divergent_expr() { let _: Result = { Err(return) + //~^ WARN 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 739659b409f4d..9fc0b661f1e7d 100644 --- a/tests/ui/try-block/try-block-unreachable-code-lint.stderr +++ b/tests/ui/try-block/try-block-unreachable-code-lint.stderr @@ -17,8 +17,16 @@ 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:62:9 + --> $DIR/try-block-unreachable-code-lint.rs:63:9 | LL | / loop { LL | | err()?; @@ -28,5 +36,5 @@ LL | LL | 42 | ^^ unreachable expression -warning: 2 warnings emitted +warning: 3 warnings emitted From 756cb48689fd15125ab909339e4023b57fb76e65 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 7 May 2023 22:13:19 +0000 Subject: [PATCH 4/5] Pacify tidy. --- src/tools/tidy/src/ui_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 41f7778c95272..1daf01234a95c 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1673; +const ISSUES_ENTRY_LIMIT: u32 = 1674; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files From 7e37e3690550b6f5874cf7175e55f596d2eba7e5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 18 Aug 2024 11:33:46 +0000 Subject: [PATCH 5/5] Introduce lint DivergeReason. --- compiler/rustc_hir_typeck/src/diverges.rs | 16 +++++-- compiler/rustc_hir_typeck/src/expr.rs | 9 ++-- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 18 ++++++-- .../let-irrefutable-pattern-ice-120337.rs | 3 +- .../let-irrefutable-pattern-ice-120337.stderr | 12 ----- .../match-no-arms-unreachable-after.stderr | 2 +- .../diverge-causes-unreachable-code.rs | 1 + .../diverge-causes-unreachable-code.stderr | 13 +++++- .../rfc-0000-never_patterns/diverges-not.rs | 3 +- .../diverges-not.stderr | 46 ++++++++++--------- .../uninhabited/break-diverging-value.stderr | 18 +++++++- 11 files changed, 90 insertions(+), 51 deletions(-) delete mode 100644 tests/ui/consts/let-irrefutable-pattern-ice-120337.stderr diff --git a/compiler/rustc_hir_typeck/src/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs index 9ce1c364c9b10..5aee8cfecc418 100644 --- a/compiler/rustc_hir_typeck/src/diverges.rs +++ b/compiler/rustc_hir_typeck/src/diverges.rs @@ -14,6 +14,14 @@ pub 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), @@ -55,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, } } @@ -63,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, } } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index b4b49cdb531eb..5b4f3eef2cd3d 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -238,20 +238,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Field(..) if matches!( self.diverges.get(), - Diverges::Always(DivergeReason::UninhabitedExpr(_), _) + Diverges::UninhabitedExpr(_, _) ) && self.ty_is_uninhabited(ty) => {} _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"), } - if !self.diverges.get().is_always() { + let cur_diverges = self.diverges.get(); + if !cur_diverges.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)); + 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(Diverges::Always(DivergeReason::UninhabitedExpr(expr.hir_id), expr.span)); + .set(cur_diverges | Diverges::UninhabitedExpr(expr.hir_id, expr.span)); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ada2d75f8eb73..c7bce26aee9e1 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -51,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() { @@ -74,9 +78,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } - // Don't warn twice. - 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) { @@ -87,6 +88,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + // Don't warn twice. + 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}"); diff --git a/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs b/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs index 09f567606972f..e0d1d515deb02 100644 --- a/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs +++ b/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs @@ -1,8 +1,9 @@ +//@ check-pass #![feature(never_type)] #[derive(Copy, Clone)] pub enum E { A(!), } pub union U { u: (), e: E, } -pub const C: () = { //~ ERROR evaluation of constant value failed +pub const C: () = { 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 deleted file mode 100644 index 5bf7fb5ae8d77..0000000000000 --- a/tests/ui/consts/let-irrefutable-pattern-ice-120337.stderr +++ /dev/null @@ -1,12 +0,0 @@ -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/match/match-no-arms-unreachable-after.stderr b/tests/ui/match/match-no-arms-unreachable-after.stderr index d692be361bbb2..65ac1bae34495 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 { } - | - this expression has type `Void`, which is uninhabited + | ----------- any code following this expression is unreachable LL | let x = 2; | ^^^^^^^^^^ unreachable statement | 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 32b7060509d02..520fd8da6f0bc 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 @@ -33,4 +33,5 @@ fn never_match() -> u32 { //~^ 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 4758b1013dde3..4055e6dcff16b 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 @@ -42,5 +42,16 @@ LL | match *ptr { ! }; | | | this expression has type `Void`, which is uninhabited -error: aborting due to 4 previous errors +error: unreachable statement + --> $DIR/diverge-causes-unreachable-code.rs:34:5 + | +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) + +error: aborting due to 5 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 67cff0d31a956..6b85ada3aadee 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs @@ -15,6 +15,7 @@ fn wild_void(_: Void) -> u32 {} fn wild_let() -> u32 { let ptr: *const Void = std::ptr::null(); unsafe { + //~^ ERROR: mismatched types let _ = *ptr; } } @@ -34,8 +35,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 4c943bf6cdc6b..08a1bbe9bffac 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr @@ -7,13 +7,22 @@ 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:26:18 + --> $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 | LL | _ => {} | ^^ expected `u32`, found `()` error[E0308]: mismatched types - --> $DIR/diverges-not.rs:31:30 + --> $DIR/diverges-not.rs:32:30 | LL | fn binding_void(_x: Void) -> u32 {} | ------------ ^^^ expected `u32`, found `()` @@ -21,33 +30,26 @@ 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:46:19 + --> $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 | LL | _x => {} | ^^ expected `u32`, found `()` error[E0308]: mismatched types - --> $DIR/diverges-not.rs:53:37 + --> $DIR/diverges-not.rs:54:37 | LL | if let true = true && let ! = x {} | ^^ expected `u32`, found `()` -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 - | -note: if `Void` implemented `Clone`, you could clone the value - --> $DIR/diverges-not.rs:8:1 - | -LL | enum Void {} - | ^^^^^^^^^ consider implementing `Clone` for this type -... -LL | let _x = *ptr; - | ---- you could clone this value - -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0308, E0507. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/uninhabited/break-diverging-value.stderr b/tests/ui/uninhabited/break-diverging-value.stderr index 998212cc79292..bc99239f71978 100644 --- a/tests/ui/uninhabited/break-diverging-value.stderr +++ b/tests/ui/uninhabited/break-diverging-value.stderr @@ -6,6 +6,22 @@ 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:33:25 + | +LL | fn loop_break_void() -> i32 { + | --------------- ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0308]: mismatched types + --> $DIR/break-diverging-value.rs:43:34 + | +LL | fn loop_break_indirect_void() -> i32 { + | ------------------------ ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + error[E0308]: mismatched types --> $DIR/break-diverging-value.rs:55:33 | @@ -14,6 +30,6 @@ LL | fn loop_break_private_void() -> i32 { | | | implicitly returns `()` as its body has no tail or `return` expression -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`.